core/crypto: Start work on the NIST curves

This commit is contained in:
Yawning Angel
2025-10-02 07:42:52 +09:00
parent 6bbd060352
commit 5ce448a8d5
13 changed files with 7257 additions and 0 deletions

View File

@@ -0,0 +1,346 @@
package field_p256r1
import subtle "core:crypto/_subtle"
import "core:encoding/endian"
import "core:math/bits"
import "core:mem"
fe_clear :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) {
mem.zero_explicit(arg1, size_of(Montgomery_Domain_Field_Element))
}
fe_clear_vec :: proc "contextless" (
arg1: []^Montgomery_Domain_Field_Element,
) {
for fe in arg1 {
fe_clear(fe)
}
}
fe_from_bytes :: proc "contextless" (
out1: ^Montgomery_Domain_Field_Element,
arg1: []byte,
unsafe_assume_canonical := false,
) -> bool {
ensure_contextless(len(arg1) == 32, "p256r1: invalid fe input buffer")
// Note: We assume the input is in big-endian.
tmp := Non_Montgomery_Domain_Field_Element {
endian.unchecked_get_u64be(arg1[24:]),
endian.unchecked_get_u64be(arg1[16:]),
endian.unchecked_get_u64be(arg1[8:]),
endian.unchecked_get_u64be(arg1[0:]),
}
defer mem.zero_explicit(&tmp, size_of(tmp))
// Check that tmp is in the the range [0, ELL).
if !unsafe_assume_canonical {
_, borrow := bits.sub_u64(ELL[0] - 1, tmp[0], 0)
_, borrow = bits.sub_u64(ELL[1], tmp[1], borrow)
_, borrow = bits.sub_u64(ELL[2], tmp[2], borrow)
_, borrow = bits.sub_u64(ELL[3], tmp[3], borrow)
if borrow != 0 {
return false
}
}
fe_to_montgomery(out1, &tmp)
return true
}
fe_to_bytes :: proc "contextless" (out1: []byte, arg1: ^Montgomery_Domain_Field_Element) {
ensure_contextless(len(out1) == 32, "p256r1: invalid fe output buffer")
tmp: Non_Montgomery_Domain_Field_Element
fe_from_montgomery(&tmp, arg1)
// Note: Likewise, output in big-endian.
endian.unchecked_put_u64be(out1[24:], tmp[0])
endian.unchecked_put_u64be(out1[16:], tmp[1])
endian.unchecked_put_u64be(out1[8:], tmp[2])
endian.unchecked_put_u64be(out1[0:], tmp[3])
mem.zero_explicit(&tmp, size_of(tmp))
}
@(require_results)
fe_equal :: proc "contextless" (arg1, arg2: ^Montgomery_Domain_Field_Element) -> int {
tmp: Montgomery_Domain_Field_Element
fe_sub(&tmp, arg1, arg2)
// This will only underflow iff arg1 == arg2, and we return the borrow,
// which will be 1.
is_eq := subtle.u64_is_zero(fe_non_zero(&tmp))
fe_clear(&tmp)
return int(is_eq)
}
@(require_results)
fe_is_odd :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> int {
tmp: Non_Montgomery_Domain_Field_Element
defer mem.zero_explicit(&tmp, size_of(tmp))
fe_from_montgomery(&tmp, arg1)
return int(tmp[0] & 1)
}
fe_pow2k :: proc "contextless" (
out1: ^Montgomery_Domain_Field_Element,
arg1: ^Montgomery_Domain_Field_Element,
arg2: uint,
) {
// Special case: `arg1^(2 * 0) = 1`, though this should never happen.
if arg2 == 0 {
fe_one(out1)
return
}
fe_square(out1, arg1)
for _ in 1 ..< arg2 {
fe_square(out1, out1)
}
}
fe_inv :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) {
// Inversion computation is derived from the addition chain:
//
// _10 = 2*1
// _11 = 1 + _10
// _110 = 2*_11
// _111 = 1 + _110
// _111000 = _111 << 3
// _111111 = _111 + _111000
// x12 = _111111 << 6 + _111111
// x15 = x12 << 3 + _111
// x16 = 2*x15 + 1
// x32 = x16 << 16 + x16
// i53 = x32 << 15
// x47 = x15 + i53
// i263 = ((i53 << 17 + 1) << 143 + x47) << 47
// return (x47 + i263) << 2
//
// Operations: 255 squares 11 multiplies
//
// Generated by github.com/mmcloughlin/addchain v0.4.0.
// Note: Need to stash `arg1` (`xx`) in the case that `out1`/`arg1` alias,
// as `arg1` is used after `out1` has been altered.
t0, t1, xx: Montgomery_Domain_Field_Element = ---, ---, arg1^
// Step 1: z = x^0x2
fe_square(out1, arg1)
// Step 2: z = x^0x3
fe_mul(out1, &xx, out1)
// Step 3: z = x^0x6
fe_square(out1, out1)
// Step 4: z = x^0x7
fe_mul(out1, &xx, out1)
// Step 7: t0 = x^0x38
fe_pow2k(&t0, out1, 3)
// Step 8: t0 = x^0x3f
fe_mul(&t0, out1, &t0)
// Step 14: t1 = x^0xfc0
fe_pow2k(&t1, &t0, 6)
// Step 15: t0 = x^0xfff
fe_mul(&t0, &t0, &t1)
// Step 18: t0 = x^0x7ff8
fe_pow2k(&t0, &t0, 3)
// Step 19: z = x^0x7fff
fe_mul(out1, out1, &t0)
// Step 20: t0 = x^0xfffe
fe_square(&t0, out1)
// Step 21: t0 = x^0xffff
fe_mul(&t0, &xx, &t0)
// Step 37: t1 = x^0xffff0000
fe_pow2k(&t1, &t0, 16)
// Step 38: t0 = x^0xffffffff
fe_mul(&t0, &t0, &t1)
// Step 53: t0 = x^0x7fffffff8000
fe_pow2k(&t0, &t0, 15)
// Step 54: z = x^0x7fffffffffff
fe_mul(out1, out1, &t0)
// Step 71: t0 = x^0xffffffff00000000
fe_pow2k(&t0, &t0, 17)
// Step 72: t0 = x^0xffffffff00000001
fe_mul(&t0, &xx, &t0)
// Step 215: t0 = x^0x7fffffff80000000800000000000000000000000000000000000
fe_pow2k(&t0, &t0, 143)
// Step 216: t0 = x^0x7fffffff800000008000000000000000000000007fffffffffff
fe_mul(&t0, out1, &t0)
// Step 263: t0 = x^0x3fffffffc00000004000000000000000000000003fffffffffff800000000000
fe_pow2k(&t0, &t0, 47)
// Step 264: z = x^0x3fffffffc00000004000000000000000000000003fffffffffffffffffffffff
fe_mul(out1, out1, &t0)
// Step 266: z = x^0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc
fe_pow2k(out1, out1, 2)
fe_mul(out1, out1, &xx)
fe_clear_vec([]^Montgomery_Domain_Field_Element{&t0, &t1, &xx})
}
@(require_results)
fe_sqrt :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) -> int {
// Square root candidate can be derived via exponentiation by `(p + 1) / 4`
// From sage: 28948022302589062190674361737351893382521535853822578548883407827216774463488
//
// // Inversion computation is derived from the addition chain:
//
// _10 = 2*1
// _11 = 1 + _10
// _1100 = _11 << 2
// _1111 = _11 + _1100
// _11110000 = _1111 << 4
// _11111111 = _1111 + _11110000
// x16 = _11111111 << 8 + _11111111
// x32 = x16 << 16 + x16
// return ((x32 << 32 + 1) << 96 + 1) << 94
//
// Operations: 253 squares 7 multiplies
//
// Generated by github.com/mmcloughlin/addchain v0.4.0.
// Likewise this tramples over arg1, so stash another copy.
t0, xx: Montgomery_Domain_Field_Element = ---, arg1^
// Step 1: z = x^0x2
fe_square(out1, arg1)
// Step 2: z = x^0x3
fe_mul(out1, &xx, out1)
// Step 4: t0 = x^0xc
fe_pow2k(&t0, &xx, 2)
// Step 5: z = x^0xf
fe_mul(out1, out1, &t0)
// Step 9: t0 = x^0xf0
fe_pow2k(&t0, out1, 4)
// Step 10: z = x^0xff
fe_mul(out1, out1, &t0)
// Step 18: t0 = x^0xff00
fe_pow2k(&t0, out1, 8)
// Step 19: z = x^0xffff
fe_mul(out1, out1, &t0)
// Step 35: t0 = x^0xffff0000
fe_pow2k(&t0, out1, 16)
// Step 36: z = x^0xffffffff
fe_mul(out1, out1, &t0)
// Step 68: z = x^0xffffffff00000000
fe_pow2k(out1, out1, 32)
// Step 69: z = x^0xffffffff00000001
fe_mul(out1, &xx, out1)
// Step 165: z = x^0xffffffff00000001000000000000000000000000
fe_pow2k(out1, out1, 96)
// Step 166: z = x^0xffffffff00000001000000000000000000000001
fe_mul(out1, &xx, out1)
// Step 260: z = x^0x3fffffffc0000000400000000000000000000000400000000000000000000000
fe_pow2k(out1, out1, 94)
// Ensure that our candidate is actually the square root.
check, zero: Montgomery_Domain_Field_Element
fe_square(&check, out1)
is_valid := fe_equal(&check, &xx)
fe_cond_select(out1, &zero, out1, is_valid)
fe_clear_vec([]^Montgomery_Domain_Field_Element{&t0, &xx, &check})
return is_valid
}
fe_zero :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) {
out1[0] = 0
out1[1] = 0
out1[2] = 0
out1[3] = 0
}
fe_set :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) {
x1 := arg1[0]
x2 := arg1[1]
x3 := arg1[2]
x4 := arg1[3]
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
}
@(optimization_mode = "none")
fe_cond_swap :: #force_no_inline proc "contextless" (out1, out2: ^Montgomery_Domain_Field_Element, arg1: int) {
mask := (u64(arg1) * 0xffffffffffffffff)
x := (out1[0] ~ out2[0]) & mask
x1, y1 := out1[0] ~ x, out2[0] ~ x
x = (out1[1] ~ out2[1]) & mask
x2, y2 := out1[1] ~ x, out2[1] ~ x
x = (out1[2] ~ out2[2]) & mask
x3, y3 := out1[2] ~ x, out2[2] ~ x
x = (out1[3] ~ out2[3]) & mask
x4, y4 := out1[3] ~ x, out2[3] ~ x
out1[0], out2[0] = x1, y1
out1[1], out2[1] = x2, y2
out1[2], out2[2] = x3, y3
out1[3], out2[3] = x4, y4
}
@(optimization_mode = "none")
fe_cond_select :: #force_no_inline proc "contextless" (
out1, arg1, arg2: ^Montgomery_Domain_Field_Element,
arg3: int,
) {
mask := (u64(arg3) * 0xffffffffffffffff)
x1 := ((mask & arg2[0]) | ((~mask) & arg1[0]))
x2 := ((mask & arg2[1]) | ((~mask) & arg1[1]))
x3 := ((mask & arg2[2]) | ((~mask) & arg1[2]))
x4 := ((mask & arg2[3]) | ((~mask) & arg1[3]))
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
}
fe_cond_negate :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element, ctrl: int) {
tmp1: Montgomery_Domain_Field_Element = ---
fe_opp(&tmp1, arg1)
fe_cond_select(out1, arg1, &tmp1, ctrl)
fe_clear(&tmp1)
}

View File

@@ -0,0 +1,501 @@
// The BSD 1-Clause License (BSD-1-Clause)
//
// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design,
// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package field_p256r1
// The file provides arithmetic on the field Z/(2^256 - 2^224 + 2^192 + 2^96 - 1)
// using a 64-bit Montgomery form internal representation. It is derived
// primarily from the machine generated Golang output from the fiat-crypto
// project.
//
// While the base implementation is provably correct, this implementation
// makes no such claims as the port and optimizations were done by hand.
//
// WARNING: While big-endian is the common representation used for this
// curve, the fiat output uses least-significant-limb first.
import fiat "core:crypto/_fiat"
import "core:math/bits"
// ELL is the saturated representation of the field order, least-significant
// limb first.
ELL :: [4]u64{0xffffffffffffffff, 0xffffffff, 0x0, 0xffffffff00000001}
Montgomery_Domain_Field_Element :: distinct [4]u64
Non_Montgomery_Domain_Field_Element :: distinct [4]u64
fe_mul :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) {
x1 := arg1[1]
x2 := arg1[2]
x3 := arg1[3]
x4 := arg1[0]
x6, x5 := bits.mul_u64(x4, arg2[3])
x8, x7 := bits.mul_u64(x4, arg2[2])
x10, x9 := bits.mul_u64(x4, arg2[1])
x12, x11 := bits.mul_u64(x4, arg2[0])
x13, x14 := bits.add_u64(x12, x9, u64(0x0))
x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14)))
x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16)))
x19 := (u64(fiat.u1(x18)) + x6)
x21, x20 := bits.mul_u64(x11, 0xffffffff00000001)
x23, x22 := bits.mul_u64(x11, 0xffffffff)
x25, x24 := bits.mul_u64(x11, 0xffffffffffffffff)
x26, x27 := bits.add_u64(x25, x22, u64(0x0))
x28 := (u64(fiat.u1(x27)) + x23)
_, x30 := bits.add_u64(x11, x24, u64(0x0))
x31, x32 := bits.add_u64(x13, x26, u64(fiat.u1(x30)))
x33, x34 := bits.add_u64(x15, x28, u64(fiat.u1(x32)))
x35, x36 := bits.add_u64(x17, x20, u64(fiat.u1(x34)))
x37, x38 := bits.add_u64(x19, x21, u64(fiat.u1(x36)))
x40, x39 := bits.mul_u64(x1, arg2[3])
x42, x41 := bits.mul_u64(x1, arg2[2])
x44, x43 := bits.mul_u64(x1, arg2[1])
x46, x45 := bits.mul_u64(x1, arg2[0])
x47, x48 := bits.add_u64(x46, x43, u64(0x0))
x49, x50 := bits.add_u64(x44, x41, u64(fiat.u1(x48)))
x51, x52 := bits.add_u64(x42, x39, u64(fiat.u1(x50)))
x53 := (u64(fiat.u1(x52)) + x40)
x54, x55 := bits.add_u64(x31, x45, u64(0x0))
x56, x57 := bits.add_u64(x33, x47, u64(fiat.u1(x55)))
x58, x59 := bits.add_u64(x35, x49, u64(fiat.u1(x57)))
x60, x61 := bits.add_u64(x37, x51, u64(fiat.u1(x59)))
x62, x63 := bits.add_u64(u64(fiat.u1(x38)), x53, u64(fiat.u1(x61)))
x65, x64 := bits.mul_u64(x54, 0xffffffff00000001)
x67, x66 := bits.mul_u64(x54, 0xffffffff)
x69, x68 := bits.mul_u64(x54, 0xffffffffffffffff)
x70, x71 := bits.add_u64(x69, x66, u64(0x0))
x72 := (u64(fiat.u1(x71)) + x67)
_, x74 := bits.add_u64(x54, x68, u64(0x0))
x75, x76 := bits.add_u64(x56, x70, u64(fiat.u1(x74)))
x77, x78 := bits.add_u64(x58, x72, u64(fiat.u1(x76)))
x79, x80 := bits.add_u64(x60, x64, u64(fiat.u1(x78)))
x81, x82 := bits.add_u64(x62, x65, u64(fiat.u1(x80)))
x83 := (u64(fiat.u1(x82)) + u64(fiat.u1(x63)))
x85, x84 := bits.mul_u64(x2, arg2[3])
x87, x86 := bits.mul_u64(x2, arg2[2])
x89, x88 := bits.mul_u64(x2, arg2[1])
x91, x90 := bits.mul_u64(x2, arg2[0])
x92, x93 := bits.add_u64(x91, x88, u64(0x0))
x94, x95 := bits.add_u64(x89, x86, u64(fiat.u1(x93)))
x96, x97 := bits.add_u64(x87, x84, u64(fiat.u1(x95)))
x98 := (u64(fiat.u1(x97)) + x85)
x99, x100 := bits.add_u64(x75, x90, u64(0x0))
x101, x102 := bits.add_u64(x77, x92, u64(fiat.u1(x100)))
x103, x104 := bits.add_u64(x79, x94, u64(fiat.u1(x102)))
x105, x106 := bits.add_u64(x81, x96, u64(fiat.u1(x104)))
x107, x108 := bits.add_u64(x83, x98, u64(fiat.u1(x106)))
x110, x109 := bits.mul_u64(x99, 0xffffffff00000001)
x112, x111 := bits.mul_u64(x99, 0xffffffff)
x114, x113 := bits.mul_u64(x99, 0xffffffffffffffff)
x115, x116 := bits.add_u64(x114, x111, u64(0x0))
x117 := (u64(fiat.u1(x116)) + x112)
_, x119 := bits.add_u64(x99, x113, u64(0x0))
x120, x121 := bits.add_u64(x101, x115, u64(fiat.u1(x119)))
x122, x123 := bits.add_u64(x103, x117, u64(fiat.u1(x121)))
x124, x125 := bits.add_u64(x105, x109, u64(fiat.u1(x123)))
x126, x127 := bits.add_u64(x107, x110, u64(fiat.u1(x125)))
x128 := (u64(fiat.u1(x127)) + u64(fiat.u1(x108)))
x130, x129 := bits.mul_u64(x3, arg2[3])
x132, x131 := bits.mul_u64(x3, arg2[2])
x134, x133 := bits.mul_u64(x3, arg2[1])
x136, x135 := bits.mul_u64(x3, arg2[0])
x137, x138 := bits.add_u64(x136, x133, u64(0x0))
x139, x140 := bits.add_u64(x134, x131, u64(fiat.u1(x138)))
x141, x142 := bits.add_u64(x132, x129, u64(fiat.u1(x140)))
x143 := (u64(fiat.u1(x142)) + x130)
x144, x145 := bits.add_u64(x120, x135, u64(0x0))
x146, x147 := bits.add_u64(x122, x137, u64(fiat.u1(x145)))
x148, x149 := bits.add_u64(x124, x139, u64(fiat.u1(x147)))
x150, x151 := bits.add_u64(x126, x141, u64(fiat.u1(x149)))
x152, x153 := bits.add_u64(x128, x143, u64(fiat.u1(x151)))
x155, x154 := bits.mul_u64(x144, 0xffffffff00000001)
x157, x156 := bits.mul_u64(x144, 0xffffffff)
x159, x158 := bits.mul_u64(x144, 0xffffffffffffffff)
x160, x161 := bits.add_u64(x159, x156, u64(0x0))
x162 := (u64(fiat.u1(x161)) + x157)
_, x164 := bits.add_u64(x144, x158, u64(0x0))
x165, x166 := bits.add_u64(x146, x160, u64(fiat.u1(x164)))
x167, x168 := bits.add_u64(x148, x162, u64(fiat.u1(x166)))
x169, x170 := bits.add_u64(x150, x154, u64(fiat.u1(x168)))
x171, x172 := bits.add_u64(x152, x155, u64(fiat.u1(x170)))
x173 := (u64(fiat.u1(x172)) + u64(fiat.u1(x153)))
x174, x175 := bits.sub_u64(x165, 0xffffffffffffffff, u64(0x0))
x176, x177 := bits.sub_u64(x167, 0xffffffff, u64(fiat.u1(x175)))
x178, x179 := bits.sub_u64(x169, u64(0x0), u64(fiat.u1(x177)))
x180, x181 := bits.sub_u64(x171, 0xffffffff00000001, u64(fiat.u1(x179)))
_, x183 := bits.sub_u64(x173, u64(0x0), u64(fiat.u1(x181)))
x184 := fiat.cmovznz_u64(fiat.u1(x183), x174, x165)
x185 := fiat.cmovznz_u64(fiat.u1(x183), x176, x167)
x186 := fiat.cmovznz_u64(fiat.u1(x183), x178, x169)
x187 := fiat.cmovznz_u64(fiat.u1(x183), x180, x171)
out1[0] = x184
out1[1] = x185
out1[2] = x186
out1[3] = x187
}
fe_square :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) {
x1 := arg1[1]
x2 := arg1[2]
x3 := arg1[3]
x4 := arg1[0]
x6, x5 := bits.mul_u64(x4, arg1[3])
x8, x7 := bits.mul_u64(x4, arg1[2])
x10, x9 := bits.mul_u64(x4, arg1[1])
x12, x11 := bits.mul_u64(x4, arg1[0])
x13, x14 := bits.add_u64(x12, x9, u64(0x0))
x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14)))
x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16)))
x19 := (u64(fiat.u1(x18)) + x6)
x21, x20 := bits.mul_u64(x11, 0xffffffff00000001)
x23, x22 := bits.mul_u64(x11, 0xffffffff)
x25, x24 := bits.mul_u64(x11, 0xffffffffffffffff)
x26, x27 := bits.add_u64(x25, x22, u64(0x0))
x28 := (u64(fiat.u1(x27)) + x23)
_, x30 := bits.add_u64(x11, x24, u64(0x0))
x31, x32 := bits.add_u64(x13, x26, u64(fiat.u1(x30)))
x33, x34 := bits.add_u64(x15, x28, u64(fiat.u1(x32)))
x35, x36 := bits.add_u64(x17, x20, u64(fiat.u1(x34)))
x37, x38 := bits.add_u64(x19, x21, u64(fiat.u1(x36)))
x40, x39 := bits.mul_u64(x1, arg1[3])
x42, x41 := bits.mul_u64(x1, arg1[2])
x44, x43 := bits.mul_u64(x1, arg1[1])
x46, x45 := bits.mul_u64(x1, arg1[0])
x47, x48 := bits.add_u64(x46, x43, u64(0x0))
x49, x50 := bits.add_u64(x44, x41, u64(fiat.u1(x48)))
x51, x52 := bits.add_u64(x42, x39, u64(fiat.u1(x50)))
x53 := (u64(fiat.u1(x52)) + x40)
x54, x55 := bits.add_u64(x31, x45, u64(0x0))
x56, x57 := bits.add_u64(x33, x47, u64(fiat.u1(x55)))
x58, x59 := bits.add_u64(x35, x49, u64(fiat.u1(x57)))
x60, x61 := bits.add_u64(x37, x51, u64(fiat.u1(x59)))
x62, x63 := bits.add_u64(u64(fiat.u1(x38)), x53, u64(fiat.u1(x61)))
x65, x64 := bits.mul_u64(x54, 0xffffffff00000001)
x67, x66 := bits.mul_u64(x54, 0xffffffff)
x69, x68 := bits.mul_u64(x54, 0xffffffffffffffff)
x70, x71 := bits.add_u64(x69, x66, u64(0x0))
x72 := (u64(fiat.u1(x71)) + x67)
_, x74 := bits.add_u64(x54, x68, u64(0x0))
x75, x76 := bits.add_u64(x56, x70, u64(fiat.u1(x74)))
x77, x78 := bits.add_u64(x58, x72, u64(fiat.u1(x76)))
x79, x80 := bits.add_u64(x60, x64, u64(fiat.u1(x78)))
x81, x82 := bits.add_u64(x62, x65, u64(fiat.u1(x80)))
x83 := (u64(fiat.u1(x82)) + u64(fiat.u1(x63)))
x85, x84 := bits.mul_u64(x2, arg1[3])
x87, x86 := bits.mul_u64(x2, arg1[2])
x89, x88 := bits.mul_u64(x2, arg1[1])
x91, x90 := bits.mul_u64(x2, arg1[0])
x92, x93 := bits.add_u64(x91, x88, u64(0x0))
x94, x95 := bits.add_u64(x89, x86, u64(fiat.u1(x93)))
x96, x97 := bits.add_u64(x87, x84, u64(fiat.u1(x95)))
x98 := (u64(fiat.u1(x97)) + x85)
x99, x100 := bits.add_u64(x75, x90, u64(0x0))
x101, x102 := bits.add_u64(x77, x92, u64(fiat.u1(x100)))
x103, x104 := bits.add_u64(x79, x94, u64(fiat.u1(x102)))
x105, x106 := bits.add_u64(x81, x96, u64(fiat.u1(x104)))
x107, x108 := bits.add_u64(x83, x98, u64(fiat.u1(x106)))
x110, x109 := bits.mul_u64(x99, 0xffffffff00000001)
x112, x111 := bits.mul_u64(x99, 0xffffffff)
x114, x113 := bits.mul_u64(x99, 0xffffffffffffffff)
x115, x116 := bits.add_u64(x114, x111, u64(0x0))
x117 := (u64(fiat.u1(x116)) + x112)
_, x119 := bits.add_u64(x99, x113, u64(0x0))
x120, x121 := bits.add_u64(x101, x115, u64(fiat.u1(x119)))
x122, x123 := bits.add_u64(x103, x117, u64(fiat.u1(x121)))
x124, x125 := bits.add_u64(x105, x109, u64(fiat.u1(x123)))
x126, x127 := bits.add_u64(x107, x110, u64(fiat.u1(x125)))
x128 := (u64(fiat.u1(x127)) + u64(fiat.u1(x108)))
x130, x129 := bits.mul_u64(x3, arg1[3])
x132, x131 := bits.mul_u64(x3, arg1[2])
x134, x133 := bits.mul_u64(x3, arg1[1])
x136, x135 := bits.mul_u64(x3, arg1[0])
x137, x138 := bits.add_u64(x136, x133, u64(0x0))
x139, x140 := bits.add_u64(x134, x131, u64(fiat.u1(x138)))
x141, x142 := bits.add_u64(x132, x129, u64(fiat.u1(x140)))
x143 := (u64(fiat.u1(x142)) + x130)
x144, x145 := bits.add_u64(x120, x135, u64(0x0))
x146, x147 := bits.add_u64(x122, x137, u64(fiat.u1(x145)))
x148, x149 := bits.add_u64(x124, x139, u64(fiat.u1(x147)))
x150, x151 := bits.add_u64(x126, x141, u64(fiat.u1(x149)))
x152, x153 := bits.add_u64(x128, x143, u64(fiat.u1(x151)))
x155, x154 := bits.mul_u64(x144, 0xffffffff00000001)
x157, x156 := bits.mul_u64(x144, 0xffffffff)
x159, x158 := bits.mul_u64(x144, 0xffffffffffffffff)
x160, x161 := bits.add_u64(x159, x156, u64(0x0))
x162 := (u64(fiat.u1(x161)) + x157)
_, x164 := bits.add_u64(x144, x158, u64(0x0))
x165, x166 := bits.add_u64(x146, x160, u64(fiat.u1(x164)))
x167, x168 := bits.add_u64(x148, x162, u64(fiat.u1(x166)))
x169, x170 := bits.add_u64(x150, x154, u64(fiat.u1(x168)))
x171, x172 := bits.add_u64(x152, x155, u64(fiat.u1(x170)))
x173 := (u64(fiat.u1(x172)) + u64(fiat.u1(x153)))
x174, x175 := bits.sub_u64(x165, 0xffffffffffffffff, u64(0x0))
x176, x177 := bits.sub_u64(x167, 0xffffffff, u64(fiat.u1(x175)))
x178, x179 := bits.sub_u64(x169, u64(0x0), u64(fiat.u1(x177)))
x180, x181 := bits.sub_u64(x171, 0xffffffff00000001, u64(fiat.u1(x179)))
_, x183 := bits.sub_u64(x173, u64(0x0), u64(fiat.u1(x181)))
x184 := fiat.cmovznz_u64(fiat.u1(x183), x174, x165)
x185 := fiat.cmovznz_u64(fiat.u1(x183), x176, x167)
x186 := fiat.cmovznz_u64(fiat.u1(x183), x178, x169)
x187 := fiat.cmovznz_u64(fiat.u1(x183), x180, x171)
out1[0] = x184
out1[1] = x185
out1[2] = x186
out1[3] = x187
}
fe_add :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) {
x1, x2 := bits.add_u64(arg1[0], arg2[0], u64(0x0))
x3, x4 := bits.add_u64(arg1[1], arg2[1], u64(fiat.u1(x2)))
x5, x6 := bits.add_u64(arg1[2], arg2[2], u64(fiat.u1(x4)))
x7, x8 := bits.add_u64(arg1[3], arg2[3], u64(fiat.u1(x6)))
x9, x10 := bits.sub_u64(x1, 0xffffffffffffffff, u64(0x0))
x11, x12 := bits.sub_u64(x3, 0xffffffff, u64(fiat.u1(x10)))
x13, x14 := bits.sub_u64(x5, u64(0x0), u64(fiat.u1(x12)))
x15, x16 := bits.sub_u64(x7, 0xffffffff00000001, u64(fiat.u1(x14)))
_, x18 := bits.sub_u64(u64(fiat.u1(x8)), u64(0x0), u64(fiat.u1(x16)))
x19 := fiat.cmovznz_u64(fiat.u1(x18), x9, x1)
x20 := fiat.cmovznz_u64(fiat.u1(x18), x11, x3)
x21 := fiat.cmovznz_u64(fiat.u1(x18), x13, x5)
x22 := fiat.cmovznz_u64(fiat.u1(x18), x15, x7)
out1[0] = x19
out1[1] = x20
out1[2] = x21
out1[3] = x22
}
fe_sub :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) {
x1, x2 := bits.sub_u64(arg1[0], arg2[0], u64(0x0))
x3, x4 := bits.sub_u64(arg1[1], arg2[1], u64(fiat.u1(x2)))
x5, x6 := bits.sub_u64(arg1[2], arg2[2], u64(fiat.u1(x4)))
x7, x8 := bits.sub_u64(arg1[3], arg2[3], u64(fiat.u1(x6)))
x9 := fiat.cmovznz_u64(fiat.u1(x8), u64(0x0), 0xffffffffffffffff)
x10, x11 := bits.add_u64(x1, x9, u64(0x0))
x12, x13 := bits.add_u64(x3, (x9 & 0xffffffff), u64(fiat.u1(x11)))
x14, x15 := bits.add_u64(x5, u64(0x0), u64(fiat.u1(x13)))
x16, _ := bits.add_u64(x7, (x9 & 0xffffffff00000001), u64(fiat.u1(x15)))
out1[0] = x10
out1[1] = x12
out1[2] = x14
out1[3] = x16
}
fe_opp :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) {
x1, x2 := bits.sub_u64(u64(0x0), arg1[0], u64(0x0))
x3, x4 := bits.sub_u64(u64(0x0), arg1[1], u64(fiat.u1(x2)))
x5, x6 := bits.sub_u64(u64(0x0), arg1[2], u64(fiat.u1(x4)))
x7, x8 := bits.sub_u64(u64(0x0), arg1[3], u64(fiat.u1(x6)))
x9 := fiat.cmovznz_u64(fiat.u1(x8), u64(0x0), 0xffffffffffffffff)
x10, x11 := bits.add_u64(x1, x9, u64(0x0))
x12, x13 := bits.add_u64(x3, (x9 & 0xffffffff), u64(fiat.u1(x11)))
x14, x15 := bits.add_u64(x5, u64(0x0), u64(fiat.u1(x13)))
x16, _ := bits.add_u64(x7, (x9 & 0xffffffff00000001), u64(fiat.u1(x15)))
out1[0] = x10
out1[1] = x12
out1[2] = x14
out1[3] = x16
}
fe_one :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) {
out1[0] = 0x1
out1[1] = 0xffffffff00000000
out1[2] = 0xffffffffffffffff
out1[3] = 0xfffffffe
}
fe_non_zero :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> u64 {
return arg1[0] | (arg1[1] | (arg1[2] | arg1[3]))
}
@(optimization_mode = "none")
fe_cond_assign :: #force_no_inline proc "contextless" (
out1, arg1: ^Montgomery_Domain_Field_Element,
arg2: int,
) {
x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0])
x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1])
x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2])
x4 := fiat.cmovznz_u64(fiat.u1(arg2), out1[3], arg1[3])
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
}
fe_from_montgomery :: proc "contextless" (
out1: ^Non_Montgomery_Domain_Field_Element,
arg1: ^Montgomery_Domain_Field_Element,
) {
x1 := arg1[0]
x3, x2 := bits.mul_u64(x1, 0xffffffff00000001)
x5, x4 := bits.mul_u64(x1, 0xffffffff)
x7, x6 := bits.mul_u64(x1, 0xffffffffffffffff)
x8, x9 := bits.add_u64(x7, x4, u64(0x0))
_, x11 := bits.add_u64(x1, x6, u64(0x0))
x12, x13 := bits.add_u64(u64(0x0), x8, u64(fiat.u1(x11)))
x14, x15 := bits.add_u64(x12, arg1[1], u64(0x0))
x17, x16 := bits.mul_u64(x14, 0xffffffff00000001)
x19, x18 := bits.mul_u64(x14, 0xffffffff)
x21, x20 := bits.mul_u64(x14, 0xffffffffffffffff)
x22, x23 := bits.add_u64(x21, x18, u64(0x0))
_, x25 := bits.add_u64(x14, x20, u64(0x0))
x26, x27 := bits.add_u64((u64(fiat.u1(x15)) + (u64(fiat.u1(x13)) + (u64(fiat.u1(x9)) + x5))), x22, u64(fiat.u1(x25)))
x28, x29 := bits.add_u64(x2, (u64(fiat.u1(x23)) + x19), u64(fiat.u1(x27)))
x30, x31 := bits.add_u64(x3, x16, u64(fiat.u1(x29)))
x32, x33 := bits.add_u64(x26, arg1[2], u64(0x0))
x34, x35 := bits.add_u64(x28, u64(0x0), u64(fiat.u1(x33)))
x36, x37 := bits.add_u64(x30, u64(0x0), u64(fiat.u1(x35)))
x39, x38 := bits.mul_u64(x32, 0xffffffff00000001)
x41, x40 := bits.mul_u64(x32, 0xffffffff)
x43, x42 := bits.mul_u64(x32, 0xffffffffffffffff)
x44, x45 := bits.add_u64(x43, x40, u64(0x0))
_, x47 := bits.add_u64(x32, x42, u64(0x0))
x48, x49 := bits.add_u64(x34, x44, u64(fiat.u1(x47)))
x50, x51 := bits.add_u64(x36, (u64(fiat.u1(x45)) + x41), u64(fiat.u1(x49)))
x52, x53 := bits.add_u64((u64(fiat.u1(x37)) + (u64(fiat.u1(x31)) + x17)), x38, u64(fiat.u1(x51)))
x54, x55 := bits.add_u64(x48, arg1[3], u64(0x0))
x56, x57 := bits.add_u64(x50, u64(0x0), u64(fiat.u1(x55)))
x58, x59 := bits.add_u64(x52, u64(0x0), u64(fiat.u1(x57)))
x61, x60 := bits.mul_u64(x54, 0xffffffff00000001)
x63, x62 := bits.mul_u64(x54, 0xffffffff)
x65, x64 := bits.mul_u64(x54, 0xffffffffffffffff)
x66, x67 := bits.add_u64(x65, x62, u64(0x0))
_, x69 := bits.add_u64(x54, x64, u64(0x0))
x70, x71 := bits.add_u64(x56, x66, u64(fiat.u1(x69)))
x72, x73 := bits.add_u64(x58, (u64(fiat.u1(x67)) + x63), u64(fiat.u1(x71)))
x74, x75 := bits.add_u64((u64(fiat.u1(x59)) + (u64(fiat.u1(x53)) + x39)), x60, u64(fiat.u1(x73)))
x76 := (u64(fiat.u1(x75)) + x61)
x77, x78 := bits.sub_u64(x70, 0xffffffffffffffff, u64(0x0))
x79, x80 := bits.sub_u64(x72, 0xffffffff, u64(fiat.u1(x78)))
x81, x82 := bits.sub_u64(x74, u64(0x0), u64(fiat.u1(x80)))
x83, x84 := bits.sub_u64(x76, 0xffffffff00000001, u64(fiat.u1(x82)))
_, x86 := bits.sub_u64(u64(0x0), u64(0x0), u64(fiat.u1(x84)))
x87 := fiat.cmovznz_u64(fiat.u1(x86), x77, x70)
x88 := fiat.cmovznz_u64(fiat.u1(x86), x79, x72)
x89 := fiat.cmovznz_u64(fiat.u1(x86), x81, x74)
x90 := fiat.cmovznz_u64(fiat.u1(x86), x83, x76)
out1[0] = x87
out1[1] = x88
out1[2] = x89
out1[3] = x90
}
fe_to_montgomery :: proc "contextless" (
out1: ^Montgomery_Domain_Field_Element,
arg1: ^Non_Montgomery_Domain_Field_Element,
) {
x1 := arg1[1]
x2 := arg1[2]
x3 := arg1[3]
x4 := arg1[0]
x6, x5 := bits.mul_u64(x4, 0x4fffffffd)
x8, x7 := bits.mul_u64(x4, 0xfffffffffffffffe)
x10, x9 := bits.mul_u64(x4, 0xfffffffbffffffff)
x12, x11 := bits.mul_u64(x4, 0x3)
x13, x14 := bits.add_u64(x12, x9, u64(0x0))
x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14)))
x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16)))
x20, x19 := bits.mul_u64(x11, 0xffffffff00000001)
x22, x21 := bits.mul_u64(x11, 0xffffffff)
x24, x23 := bits.mul_u64(x11, 0xffffffffffffffff)
x25, x26 := bits.add_u64(x24, x21, u64(0x0))
_, x28 := bits.add_u64(x11, x23, u64(0x0))
x29, x30 := bits.add_u64(x13, x25, u64(fiat.u1(x28)))
x31, x32 := bits.add_u64(x15, (u64(fiat.u1(x26)) + x22), u64(fiat.u1(x30)))
x33, x34 := bits.add_u64(x17, x19, u64(fiat.u1(x32)))
x35, x36 := bits.add_u64((u64(fiat.u1(x18)) + x6), x20, u64(fiat.u1(x34)))
x38, x37 := bits.mul_u64(x1, 0x4fffffffd)
x40, x39 := bits.mul_u64(x1, 0xfffffffffffffffe)
x42, x41 := bits.mul_u64(x1, 0xfffffffbffffffff)
x44, x43 := bits.mul_u64(x1, 0x3)
x45, x46 := bits.add_u64(x44, x41, u64(0x0))
x47, x48 := bits.add_u64(x42, x39, u64(fiat.u1(x46)))
x49, x50 := bits.add_u64(x40, x37, u64(fiat.u1(x48)))
x51, x52 := bits.add_u64(x29, x43, u64(0x0))
x53, x54 := bits.add_u64(x31, x45, u64(fiat.u1(x52)))
x55, x56 := bits.add_u64(x33, x47, u64(fiat.u1(x54)))
x57, x58 := bits.add_u64(x35, x49, u64(fiat.u1(x56)))
x60, x59 := bits.mul_u64(x51, 0xffffffff00000001)
x62, x61 := bits.mul_u64(x51, 0xffffffff)
x64, x63 := bits.mul_u64(x51, 0xffffffffffffffff)
x65, x66 := bits.add_u64(x64, x61, u64(0x0))
_, x68 := bits.add_u64(x51, x63, u64(0x0))
x69, x70 := bits.add_u64(x53, x65, u64(fiat.u1(x68)))
x71, x72 := bits.add_u64(x55, (u64(fiat.u1(x66)) + x62), u64(fiat.u1(x70)))
x73, x74 := bits.add_u64(x57, x59, u64(fiat.u1(x72)))
x75, x76 := bits.add_u64(((u64(fiat.u1(x58)) + u64(fiat.u1(x36))) + (u64(fiat.u1(x50)) + x38)), x60, u64(fiat.u1(x74)))
x78, x77 := bits.mul_u64(x2, 0x4fffffffd)
x80, x79 := bits.mul_u64(x2, 0xfffffffffffffffe)
x82, x81 := bits.mul_u64(x2, 0xfffffffbffffffff)
x84, x83 := bits.mul_u64(x2, 0x3)
x85, x86 := bits.add_u64(x84, x81, u64(0x0))
x87, x88 := bits.add_u64(x82, x79, u64(fiat.u1(x86)))
x89, x90 := bits.add_u64(x80, x77, u64(fiat.u1(x88)))
x91, x92 := bits.add_u64(x69, x83, u64(0x0))
x93, x94 := bits.add_u64(x71, x85, u64(fiat.u1(x92)))
x95, x96 := bits.add_u64(x73, x87, u64(fiat.u1(x94)))
x97, x98 := bits.add_u64(x75, x89, u64(fiat.u1(x96)))
x100, x99 := bits.mul_u64(x91, 0xffffffff00000001)
x102, x101 := bits.mul_u64(x91, 0xffffffff)
x104, x103 := bits.mul_u64(x91, 0xffffffffffffffff)
x105, x106 := bits.add_u64(x104, x101, u64(0x0))
_, x108 := bits.add_u64(x91, x103, u64(0x0))
x109, x110 := bits.add_u64(x93, x105, u64(fiat.u1(x108)))
x111, x112 := bits.add_u64(x95, (u64(fiat.u1(x106)) + x102), u64(fiat.u1(x110)))
x113, x114 := bits.add_u64(x97, x99, u64(fiat.u1(x112)))
x115, x116 := bits.add_u64(((u64(fiat.u1(x98)) + u64(fiat.u1(x76))) + (u64(fiat.u1(x90)) + x78)), x100, u64(fiat.u1(x114)))
x118, x117 := bits.mul_u64(x3, 0x4fffffffd)
x120, x119 := bits.mul_u64(x3, 0xfffffffffffffffe)
x122, x121 := bits.mul_u64(x3, 0xfffffffbffffffff)
x124, x123 := bits.mul_u64(x3, 0x3)
x125, x126 := bits.add_u64(x124, x121, u64(0x0))
x127, x128 := bits.add_u64(x122, x119, u64(fiat.u1(x126)))
x129, x130 := bits.add_u64(x120, x117, u64(fiat.u1(x128)))
x131, x132 := bits.add_u64(x109, x123, u64(0x0))
x133, x134 := bits.add_u64(x111, x125, u64(fiat.u1(x132)))
x135, x136 := bits.add_u64(x113, x127, u64(fiat.u1(x134)))
x137, x138 := bits.add_u64(x115, x129, u64(fiat.u1(x136)))
x140, x139 := bits.mul_u64(x131, 0xffffffff00000001)
x142, x141 := bits.mul_u64(x131, 0xffffffff)
x144, x143 := bits.mul_u64(x131, 0xffffffffffffffff)
x145, x146 := bits.add_u64(x144, x141, u64(0x0))
_, x148 := bits.add_u64(x131, x143, u64(0x0))
x149, x150 := bits.add_u64(x133, x145, u64(fiat.u1(x148)))
x151, x152 := bits.add_u64(x135, (u64(fiat.u1(x146)) + x142), u64(fiat.u1(x150)))
x153, x154 := bits.add_u64(x137, x139, u64(fiat.u1(x152)))
x155, x156 := bits.add_u64(((u64(fiat.u1(x138)) + u64(fiat.u1(x116))) + (u64(fiat.u1(x130)) + x118)), x140, u64(fiat.u1(x154)))
x157, x158 := bits.sub_u64(x149, 0xffffffffffffffff, u64(0x0))
x159, x160 := bits.sub_u64(x151, 0xffffffff, u64(fiat.u1(x158)))
x161, x162 := bits.sub_u64(x153, u64(0x0), u64(fiat.u1(x160)))
x163, x164 := bits.sub_u64(x155, 0xffffffff00000001, u64(fiat.u1(x162)))
_, x166 := bits.sub_u64(u64(fiat.u1(x156)), u64(0x0), u64(fiat.u1(x164)))
x167 := fiat.cmovznz_u64(fiat.u1(x166), x157, x149)
x168 := fiat.cmovznz_u64(fiat.u1(x166), x159, x151)
x169 := fiat.cmovznz_u64(fiat.u1(x166), x161, x153)
x170 := fiat.cmovznz_u64(fiat.u1(x166), x163, x155)
out1[0] = x167
out1[1] = x168
out1[2] = x169
out1[3] = x170
}

View File

@@ -0,0 +1,210 @@
package field_scalarp256r1
import subtle "core:crypto/_subtle"
import "core:encoding/endian"
import "core:math/bits"
import "core:mem"
@(private, rodata)
TWO_192 := Montgomery_Domain_Field_Element{
2482910415990817935,
2879494685571067143,
8732918506673730078,
85565669603516024,
}
@(private, rodata)
TWO_384 := Montgomery_Domain_Field_Element{
2127524300190691059,
17014302137236182484,
16604910261202196099,
3621421107472562910,
}
// 2^384 % p (From sage)
// 0x431905529c0166ce652e96b7ccca0a99679b73e19ad16947f01cf013fc632551
fe_clear :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) {
mem.zero_explicit(arg1, size_of(Montgomery_Domain_Field_Element))
}
fe_clear_vec :: proc "contextless" (
arg1: []^Montgomery_Domain_Field_Element,
) {
for fe in arg1 {
fe_clear(fe)
}
}
fe_from_bytes :: proc "contextless" (
out1: ^Montgomery_Domain_Field_Element,
arg1: []byte,
) -> bool {
ensure_contextless(len(out1) <= 64, "p256r1: invalid scalar input buffer")
is_canonical := false
s_len := len(arg1)
switch {
case s_len < 32:
// No way this can be greater than the order.
fe_unchecked_set(out1, arg1)
is_canonical = true
case s_len == 32:
// It is quite likely that a reduction mod p is required,
// as the order of the curve is sufficiently smaller than
// 2^256-1, so just check if we actually needed to reduced
// and do the reduction anyway, so that things that require
// canonical scalars can reject non-canonical encodings.
is_canonical = fe_is_canonical(arg1)
fallthrough
case:
// Use Frank Denis' trick, as documented by Filippo Valsorda
// at https://words.filippo.io/dispatches/wide-reduction/
//
// "I represent the value as a+b*2^192+c*2^384"
//
// Note: Omitting the `c` computation is fine as, reduction
// being length dependent provides no useful timing information.
// Zero extend to 512-bits.
src_512: [64]byte
copy(src_512[64-s_len:], arg1)
defer mem.zero_explicit(&src_512, size_of(src_512))
fe_unchecked_set(out1, src_512[40:]) // a
b: Montgomery_Domain_Field_Element
fe_unchecked_set(&b, src_512[16:40]) // b
fe_mul(&b, &b, &TWO_192)
fe_add(out1, out1, &b)
if s_len >= 48 {
c: Montgomery_Domain_Field_Element
fe_unchecked_set(&c, src_512[:16]) // c
fe_mul(&c, &c, &TWO_384)
fe_add(out1, out1, &c)
fe_clear(&c)
}
fe_clear(&b)
}
return !is_canonical
}
@(private)
fe_is_canonical :: proc "contextless" (arg1: []byte) -> bool {
_, borrow := bits.sub_u64(ELL[0] - 1, endian.unchecked_get_u64be(arg1[24:]), 0)
_, borrow = bits.sub_u64(ELL[1], endian.unchecked_get_u64be(arg1[16:]), borrow)
_, borrow = bits.sub_u64(ELL[2], endian.unchecked_get_u64be(arg1[8:]), borrow)
_, borrow = bits.sub_u64(ELL[3], endian.unchecked_get_u64be(arg1[0:]), borrow)
return borrow == 0
}
@(private)
fe_unchecked_set :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element, arg1: []byte) {
arg1_256: [32]byte
defer mem.zero_explicit(&arg1_256, size_of(arg1_256))
copy(arg1_256[32-len(arg1):], arg1)
tmp := Non_Montgomery_Domain_Field_Element {
endian.unchecked_get_u64be(arg1_256[24:]),
endian.unchecked_get_u64be(arg1_256[16:]),
endian.unchecked_get_u64be(arg1_256[8:]),
endian.unchecked_get_u64be(arg1_256[0:]),
}
defer mem.zero_explicit(&tmp, size_of(tmp))
fe_to_montgomery(out1, &tmp)
}
fe_to_bytes :: proc "contextless" (out1: []byte, arg1: ^Montgomery_Domain_Field_Element) {
ensure_contextless(len(out1) == 32, "p256r1: invalid scalar output buffer")
tmp: Non_Montgomery_Domain_Field_Element
fe_from_montgomery(&tmp, arg1)
// Note: Likewise, output in big-endian.
endian.unchecked_put_u64be(out1[24:], tmp[0])
endian.unchecked_put_u64be(out1[16:], tmp[1])
endian.unchecked_put_u64be(out1[8:], tmp[2])
endian.unchecked_put_u64be(out1[0:], tmp[3])
mem.zero_explicit(&tmp, size_of(tmp))
}
fe_equal :: proc "contextless" (arg1, arg2: ^Montgomery_Domain_Field_Element) -> int {
tmp: Montgomery_Domain_Field_Element
fe_sub(&tmp, arg1, arg2)
is_eq := subtle.u64_is_zero(fe_non_zero(&tmp))
fe_clear(&tmp)
return int(is_eq)
}
fe_is_odd :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> int {
tmp: Non_Montgomery_Domain_Field_Element
defer mem.zero_explicit(&tmp, size_of(tmp))
fe_from_montgomery(&tmp, arg1)
return int(tmp[0] & 1)
}
fe_zero :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) {
out1[0] = 0
out1[1] = 0
out1[2] = 0
out1[3] = 0
}
fe_set :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) {
x1 := arg1[0]
x2 := arg1[1]
x3 := arg1[2]
x4 := arg1[3]
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
}
@(optimization_mode = "none")
fe_cond_swap :: #force_no_inline proc "contextless" (out1, out2: ^Montgomery_Domain_Field_Element, arg1: int) {
mask := (u64(arg1) * 0xffffffffffffffff)
x := (out1[0] ~ out2[0]) & mask
x1, y1 := out1[0] ~ x, out2[0] ~ x
x = (out1[1] ~ out2[1]) & mask
x2, y2 := out1[1] ~ x, out2[1] ~ x
x = (out1[2] ~ out2[2]) & mask
x3, y3 := out1[2] ~ x, out2[2] ~ x
x = (out1[3] ~ out2[3]) & mask
x4, y4 := out1[3] ~ x, out2[3] ~ x
out1[0], out2[0] = x1, y1
out1[1], out2[1] = x2, y2
out1[2], out2[2] = x3, y3
out1[3], out2[3] = x4, y4
}
@(optimization_mode = "none")
fe_cond_select :: #force_no_inline proc "contextless" (
out1, arg1, arg2: ^Montgomery_Domain_Field_Element,
arg3: int,
) {
mask := (u64(arg3) * 0xffffffffffffffff)
x1 := ((mask & arg2[0]) | ((~mask) & arg1[0]))
x2 := ((mask & arg2[1]) | ((~mask) & arg1[1]))
x3 := ((mask & arg2[2]) | ((~mask) & arg1[2]))
x4 := ((mask & arg2[3]) | ((~mask) & arg1[3]))
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
}
fe_cond_negate :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element, ctrl: int) {
tmp1: Montgomery_Domain_Field_Element = ---
fe_opp(&tmp1, arg1)
fe_cond_select(out1, arg1, &tmp1, ctrl)
fe_clear(&tmp1)
}

View File

@@ -0,0 +1,569 @@
// The BSD 1-Clause License (BSD-1-Clause)
//
// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design,
// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package field_scalarp256r1
// The file provides arithmetic on the field Z/(2^256 - 2^224 + 2^192 -
// 89188191075325690597107910205041859247) using a 64-bit Montgomery form
// internal representation. It is derived primarily from the machine
// generated Golang output from the fiat-crypto project.
//
// While the base implementation is provably correct, this implementation
// makes no such claims as the port and optimizations were done by hand.
//
// WARNING: While big-endian is the common representation used for this
// curve, the fiat output uses least-significant-limb first.
import fiat "core:crypto/_fiat"
import "core:math/bits"
// ELL is the saturated representation of the field order, least-significant
// limb first.
ELL :: [4]u64{0xf3b9cac2fc632551, 0xbce6faada7179e84, 0xffffffffffffffff, 0xffffffff00000000}
Montgomery_Domain_Field_Element :: distinct [4]u64
Non_Montgomery_Domain_Field_Element :: distinct [4]u64
fe_mul :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) {
x1 := arg1[1]
x2 := arg1[2]
x3 := arg1[3]
x4 := arg1[0]
x6, x5 := bits.mul_u64(x4, arg2[3])
x8, x7 := bits.mul_u64(x4, arg2[2])
x10, x9 := bits.mul_u64(x4, arg2[1])
x12, x11 := bits.mul_u64(x4, arg2[0])
x13, x14 := bits.add_u64(x12, x9, u64(0x0))
x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14)))
x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16)))
x19 := (u64(fiat.u1(x18)) + x6)
_, x20 := bits.mul_u64(x11, 0xccd1c8aaee00bc4f)
x23, x22 := bits.mul_u64(x20, 0xffffffff00000000)
x25, x24 := bits.mul_u64(x20, 0xffffffffffffffff)
x27, x26 := bits.mul_u64(x20, 0xbce6faada7179e84)
x29, x28 := bits.mul_u64(x20, 0xf3b9cac2fc632551)
x30, x31 := bits.add_u64(x29, x26, u64(0x0))
x32, x33 := bits.add_u64(x27, x24, u64(fiat.u1(x31)))
x34, x35 := bits.add_u64(x25, x22, u64(fiat.u1(x33)))
x36 := (u64(fiat.u1(x35)) + x23)
_, x38 := bits.add_u64(x11, x28, u64(0x0))
x39, x40 := bits.add_u64(x13, x30, u64(fiat.u1(x38)))
x41, x42 := bits.add_u64(x15, x32, u64(fiat.u1(x40)))
x43, x44 := bits.add_u64(x17, x34, u64(fiat.u1(x42)))
x45, x46 := bits.add_u64(x19, x36, u64(fiat.u1(x44)))
x48, x47 := bits.mul_u64(x1, arg2[3])
x50, x49 := bits.mul_u64(x1, arg2[2])
x52, x51 := bits.mul_u64(x1, arg2[1])
x54, x53 := bits.mul_u64(x1, arg2[0])
x55, x56 := bits.add_u64(x54, x51, u64(0x0))
x57, x58 := bits.add_u64(x52, x49, u64(fiat.u1(x56)))
x59, x60 := bits.add_u64(x50, x47, u64(fiat.u1(x58)))
x61 := (u64(fiat.u1(x60)) + x48)
x62, x63 := bits.add_u64(x39, x53, u64(0x0))
x64, x65 := bits.add_u64(x41, x55, u64(fiat.u1(x63)))
x66, x67 := bits.add_u64(x43, x57, u64(fiat.u1(x65)))
x68, x69 := bits.add_u64(x45, x59, u64(fiat.u1(x67)))
x70, x71 := bits.add_u64(u64(fiat.u1(x46)), x61, u64(fiat.u1(x69)))
_, x72 := bits.mul_u64(x62, 0xccd1c8aaee00bc4f)
x75, x74 := bits.mul_u64(x72, 0xffffffff00000000)
x77, x76 := bits.mul_u64(x72, 0xffffffffffffffff)
x79, x78 := bits.mul_u64(x72, 0xbce6faada7179e84)
x81, x80 := bits.mul_u64(x72, 0xf3b9cac2fc632551)
x82, x83 := bits.add_u64(x81, x78, u64(0x0))
x84, x85 := bits.add_u64(x79, x76, u64(fiat.u1(x83)))
x86, x87 := bits.add_u64(x77, x74, u64(fiat.u1(x85)))
x88 := (u64(fiat.u1(x87)) + x75)
_, x90 := bits.add_u64(x62, x80, u64(0x0))
x91, x92 := bits.add_u64(x64, x82, u64(fiat.u1(x90)))
x93, x94 := bits.add_u64(x66, x84, u64(fiat.u1(x92)))
x95, x96 := bits.add_u64(x68, x86, u64(fiat.u1(x94)))
x97, x98 := bits.add_u64(x70, x88, u64(fiat.u1(x96)))
x99 := (u64(fiat.u1(x98)) + u64(fiat.u1(x71)))
x101, x100 := bits.mul_u64(x2, arg2[3])
x103, x102 := bits.mul_u64(x2, arg2[2])
x105, x104 := bits.mul_u64(x2, arg2[1])
x107, x106 := bits.mul_u64(x2, arg2[0])
x108, x109 := bits.add_u64(x107, x104, u64(0x0))
x110, x111 := bits.add_u64(x105, x102, u64(fiat.u1(x109)))
x112, x113 := bits.add_u64(x103, x100, u64(fiat.u1(x111)))
x114 := (u64(fiat.u1(x113)) + x101)
x115, x116 := bits.add_u64(x91, x106, u64(0x0))
x117, x118 := bits.add_u64(x93, x108, u64(fiat.u1(x116)))
x119, x120 := bits.add_u64(x95, x110, u64(fiat.u1(x118)))
x121, x122 := bits.add_u64(x97, x112, u64(fiat.u1(x120)))
x123, x124 := bits.add_u64(x99, x114, u64(fiat.u1(x122)))
_, x125 := bits.mul_u64(x115, 0xccd1c8aaee00bc4f)
x128, x127 := bits.mul_u64(x125, 0xffffffff00000000)
x130, x129 := bits.mul_u64(x125, 0xffffffffffffffff)
x132, x131 := bits.mul_u64(x125, 0xbce6faada7179e84)
x134, x133 := bits.mul_u64(x125, 0xf3b9cac2fc632551)
x135, x136 := bits.add_u64(x134, x131, u64(0x0))
x137, x138 := bits.add_u64(x132, x129, u64(fiat.u1(x136)))
x139, x140 := bits.add_u64(x130, x127, u64(fiat.u1(x138)))
x141 := (u64(fiat.u1(x140)) + x128)
_, x143 := bits.add_u64(x115, x133, u64(0x0))
x144, x145 := bits.add_u64(x117, x135, u64(fiat.u1(x143)))
x146, x147 := bits.add_u64(x119, x137, u64(fiat.u1(x145)))
x148, x149 := bits.add_u64(x121, x139, u64(fiat.u1(x147)))
x150, x151 := bits.add_u64(x123, x141, u64(fiat.u1(x149)))
x152 := (u64(fiat.u1(x151)) + u64(fiat.u1(x124)))
x154, x153 := bits.mul_u64(x3, arg2[3])
x156, x155 := bits.mul_u64(x3, arg2[2])
x158, x157 := bits.mul_u64(x3, arg2[1])
x160, x159 := bits.mul_u64(x3, arg2[0])
x161, x162 := bits.add_u64(x160, x157, u64(0x0))
x163, x164 := bits.add_u64(x158, x155, u64(fiat.u1(x162)))
x165, x166 := bits.add_u64(x156, x153, u64(fiat.u1(x164)))
x167 := (u64(fiat.u1(x166)) + x154)
x168, x169 := bits.add_u64(x144, x159, u64(0x0))
x170, x171 := bits.add_u64(x146, x161, u64(fiat.u1(x169)))
x172, x173 := bits.add_u64(x148, x163, u64(fiat.u1(x171)))
x174, x175 := bits.add_u64(x150, x165, u64(fiat.u1(x173)))
x176, x177 := bits.add_u64(x152, x167, u64(fiat.u1(x175)))
_, x178 := bits.mul_u64(x168, 0xccd1c8aaee00bc4f)
x181, x180 := bits.mul_u64(x178, 0xffffffff00000000)
x183, x182 := bits.mul_u64(x178, 0xffffffffffffffff)
x185, x184 := bits.mul_u64(x178, 0xbce6faada7179e84)
x187, x186 := bits.mul_u64(x178, 0xf3b9cac2fc632551)
x188, x189 := bits.add_u64(x187, x184, u64(0x0))
x190, x191 := bits.add_u64(x185, x182, u64(fiat.u1(x189)))
x192, x193 := bits.add_u64(x183, x180, u64(fiat.u1(x191)))
x194 := (u64(fiat.u1(x193)) + x181)
_, x196 := bits.add_u64(x168, x186, u64(0x0))
x197, x198 := bits.add_u64(x170, x188, u64(fiat.u1(x196)))
x199, x200 := bits.add_u64(x172, x190, u64(fiat.u1(x198)))
x201, x202 := bits.add_u64(x174, x192, u64(fiat.u1(x200)))
x203, x204 := bits.add_u64(x176, x194, u64(fiat.u1(x202)))
x205 := (u64(fiat.u1(x204)) + u64(fiat.u1(x177)))
x206, x207 := bits.sub_u64(x197, 0xf3b9cac2fc632551, u64(0x0))
x208, x209 := bits.sub_u64(x199, 0xbce6faada7179e84, u64(fiat.u1(x207)))
x210, x211 := bits.sub_u64(x201, 0xffffffffffffffff, u64(fiat.u1(x209)))
x212, x213 := bits.sub_u64(x203, 0xffffffff00000000, u64(fiat.u1(x211)))
_, x215 := bits.sub_u64(x205, u64(0x0), u64(fiat.u1(x213)))
x216 := fiat.cmovznz_u64(fiat.u1(x215), x206, x197)
x217 := fiat.cmovznz_u64(fiat.u1(x215), x208, x199)
x218 := fiat.cmovznz_u64(fiat.u1(x215), x210, x201)
x219 := fiat.cmovznz_u64(fiat.u1(x215), x212, x203)
out1[0] = x216
out1[1] = x217
out1[2] = x218
out1[3] = x219
}
fe_square :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) {
x1 := arg1[1]
x2 := arg1[2]
x3 := arg1[3]
x4 := arg1[0]
x6, x5 := bits.mul_u64(x4, arg1[3])
x8, x7 := bits.mul_u64(x4, arg1[2])
x10, x9 := bits.mul_u64(x4, arg1[1])
x12, x11 := bits.mul_u64(x4, arg1[0])
x13, x14 := bits.add_u64(x12, x9, u64(0x0))
x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14)))
x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16)))
x19 := (u64(fiat.u1(x18)) + x6)
_, x20 := bits.mul_u64(x11, 0xccd1c8aaee00bc4f)
x23, x22 := bits.mul_u64(x20, 0xffffffff00000000)
x25, x24 := bits.mul_u64(x20, 0xffffffffffffffff)
x27, x26 := bits.mul_u64(x20, 0xbce6faada7179e84)
x29, x28 := bits.mul_u64(x20, 0xf3b9cac2fc632551)
x30, x31 := bits.add_u64(x29, x26, u64(0x0))
x32, x33 := bits.add_u64(x27, x24, u64(fiat.u1(x31)))
x34, x35 := bits.add_u64(x25, x22, u64(fiat.u1(x33)))
x36 := (u64(fiat.u1(x35)) + x23)
_, x38 := bits.add_u64(x11, x28, u64(0x0))
x39, x40 := bits.add_u64(x13, x30, u64(fiat.u1(x38)))
x41, x42 := bits.add_u64(x15, x32, u64(fiat.u1(x40)))
x43, x44 := bits.add_u64(x17, x34, u64(fiat.u1(x42)))
x45, x46 := bits.add_u64(x19, x36, u64(fiat.u1(x44)))
x48, x47 := bits.mul_u64(x1, arg1[3])
x50, x49 := bits.mul_u64(x1, arg1[2])
x52, x51 := bits.mul_u64(x1, arg1[1])
x54, x53 := bits.mul_u64(x1, arg1[0])
x55, x56 := bits.add_u64(x54, x51, u64(0x0))
x57, x58 := bits.add_u64(x52, x49, u64(fiat.u1(x56)))
x59, x60 := bits.add_u64(x50, x47, u64(fiat.u1(x58)))
x61 := (u64(fiat.u1(x60)) + x48)
x62, x63 := bits.add_u64(x39, x53, u64(0x0))
x64, x65 := bits.add_u64(x41, x55, u64(fiat.u1(x63)))
x66, x67 := bits.add_u64(x43, x57, u64(fiat.u1(x65)))
x68, x69 := bits.add_u64(x45, x59, u64(fiat.u1(x67)))
x70, x71 := bits.add_u64(u64(fiat.u1(x46)), x61, u64(fiat.u1(x69)))
_, x72 := bits.mul_u64(x62, 0xccd1c8aaee00bc4f)
x75, x74 := bits.mul_u64(x72, 0xffffffff00000000)
x77, x76 := bits.mul_u64(x72, 0xffffffffffffffff)
x79, x78 := bits.mul_u64(x72, 0xbce6faada7179e84)
x81, x80 := bits.mul_u64(x72, 0xf3b9cac2fc632551)
x82, x83 := bits.add_u64(x81, x78, u64(0x0))
x84, x85 := bits.add_u64(x79, x76, u64(fiat.u1(x83)))
x86, x87 := bits.add_u64(x77, x74, u64(fiat.u1(x85)))
x88 := (u64(fiat.u1(x87)) + x75)
_, x90 := bits.add_u64(x62, x80, u64(0x0))
x91, x92 := bits.add_u64(x64, x82, u64(fiat.u1(x90)))
x93, x94 := bits.add_u64(x66, x84, u64(fiat.u1(x92)))
x95, x96 := bits.add_u64(x68, x86, u64(fiat.u1(x94)))
x97, x98 := bits.add_u64(x70, x88, u64(fiat.u1(x96)))
x99 := (u64(fiat.u1(x98)) + u64(fiat.u1(x71)))
x101, x100 := bits.mul_u64(x2, arg1[3])
x103, x102 := bits.mul_u64(x2, arg1[2])
x105, x104 := bits.mul_u64(x2, arg1[1])
x107, x106 := bits.mul_u64(x2, arg1[0])
x108, x109 := bits.add_u64(x107, x104, u64(0x0))
x110, x111 := bits.add_u64(x105, x102, u64(fiat.u1(x109)))
x112, x113 := bits.add_u64(x103, x100, u64(fiat.u1(x111)))
x114 := (u64(fiat.u1(x113)) + x101)
x115, x116 := bits.add_u64(x91, x106, u64(0x0))
x117, x118 := bits.add_u64(x93, x108, u64(fiat.u1(x116)))
x119, x120 := bits.add_u64(x95, x110, u64(fiat.u1(x118)))
x121, x122 := bits.add_u64(x97, x112, u64(fiat.u1(x120)))
x123, x124 := bits.add_u64(x99, x114, u64(fiat.u1(x122)))
_, x125 := bits.mul_u64(x115, 0xccd1c8aaee00bc4f)
x128, x127 := bits.mul_u64(x125, 0xffffffff00000000)
x130, x129 := bits.mul_u64(x125, 0xffffffffffffffff)
x132, x131 := bits.mul_u64(x125, 0xbce6faada7179e84)
x134, x133 := bits.mul_u64(x125, 0xf3b9cac2fc632551)
x135, x136 := bits.add_u64(x134, x131, u64(0x0))
x137, x138 := bits.add_u64(x132, x129, u64(fiat.u1(x136)))
x139, x140 := bits.add_u64(x130, x127, u64(fiat.u1(x138)))
x141 := (u64(fiat.u1(x140)) + x128)
_, x143 := bits.add_u64(x115, x133, u64(0x0))
x144, x145 := bits.add_u64(x117, x135, u64(fiat.u1(x143)))
x146, x147 := bits.add_u64(x119, x137, u64(fiat.u1(x145)))
x148, x149 := bits.add_u64(x121, x139, u64(fiat.u1(x147)))
x150, x151 := bits.add_u64(x123, x141, u64(fiat.u1(x149)))
x152 := (u64(fiat.u1(x151)) + u64(fiat.u1(x124)))
x154, x153 := bits.mul_u64(x3, arg1[3])
x156, x155 := bits.mul_u64(x3, arg1[2])
x158, x157 := bits.mul_u64(x3, arg1[1])
x160, x159 := bits.mul_u64(x3, arg1[0])
x161, x162 := bits.add_u64(x160, x157, u64(0x0))
x163, x164 := bits.add_u64(x158, x155, u64(fiat.u1(x162)))
x165, x166 := bits.add_u64(x156, x153, u64(fiat.u1(x164)))
x167 := (u64(fiat.u1(x166)) + x154)
x168, x169 := bits.add_u64(x144, x159, u64(0x0))
x170, x171 := bits.add_u64(x146, x161, u64(fiat.u1(x169)))
x172, x173 := bits.add_u64(x148, x163, u64(fiat.u1(x171)))
x174, x175 := bits.add_u64(x150, x165, u64(fiat.u1(x173)))
x176, x177 := bits.add_u64(x152, x167, u64(fiat.u1(x175)))
_, x178 := bits.mul_u64(x168, 0xccd1c8aaee00bc4f)
x181, x180 := bits.mul_u64(x178, 0xffffffff00000000)
x183, x182 := bits.mul_u64(x178, 0xffffffffffffffff)
x185, x184 := bits.mul_u64(x178, 0xbce6faada7179e84)
x187, x186 := bits.mul_u64(x178, 0xf3b9cac2fc632551)
x188, x189 := bits.add_u64(x187, x184, u64(0x0))
x190, x191 := bits.add_u64(x185, x182, u64(fiat.u1(x189)))
x192, x193 := bits.add_u64(x183, x180, u64(fiat.u1(x191)))
x194 := (u64(fiat.u1(x193)) + x181)
_, x196 := bits.add_u64(x168, x186, u64(0x0))
x197, x198 := bits.add_u64(x170, x188, u64(fiat.u1(x196)))
x199, x200 := bits.add_u64(x172, x190, u64(fiat.u1(x198)))
x201, x202 := bits.add_u64(x174, x192, u64(fiat.u1(x200)))
x203, x204 := bits.add_u64(x176, x194, u64(fiat.u1(x202)))
x205 := (u64(fiat.u1(x204)) + u64(fiat.u1(x177)))
x206, x207 := bits.sub_u64(x197, 0xf3b9cac2fc632551, u64(0x0))
x208, x209 := bits.sub_u64(x199, 0xbce6faada7179e84, u64(fiat.u1(x207)))
x210, x211 := bits.sub_u64(x201, 0xffffffffffffffff, u64(fiat.u1(x209)))
x212, x213 := bits.sub_u64(x203, 0xffffffff00000000, u64(fiat.u1(x211)))
_, x215 := bits.sub_u64(x205, u64(0x0), u64(fiat.u1(x213)))
x216 := fiat.cmovznz_u64(fiat.u1(x215), x206, x197)
x217 := fiat.cmovznz_u64(fiat.u1(x215), x208, x199)
x218 := fiat.cmovznz_u64(fiat.u1(x215), x210, x201)
x219 := fiat.cmovznz_u64(fiat.u1(x215), x212, x203)
out1[0] = x216
out1[1] = x217
out1[2] = x218
out1[3] = x219
}
fe_add :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) {
x1, x2 := bits.add_u64(arg1[0], arg2[0], u64(0x0))
x3, x4 := bits.add_u64(arg1[1], arg2[1], u64(fiat.u1(x2)))
x5, x6 := bits.add_u64(arg1[2], arg2[2], u64(fiat.u1(x4)))
x7, x8 := bits.add_u64(arg1[3], arg2[3], u64(fiat.u1(x6)))
x9, x10 := bits.sub_u64(x1, 0xf3b9cac2fc632551, u64(0x0))
x11, x12 := bits.sub_u64(x3, 0xbce6faada7179e84, u64(fiat.u1(x10)))
x13, x14 := bits.sub_u64(x5, 0xffffffffffffffff, u64(fiat.u1(x12)))
x15, x16 := bits.sub_u64(x7, 0xffffffff00000000, u64(fiat.u1(x14)))
_, x18 := bits.sub_u64(u64(fiat.u1(x8)), u64(0x0), u64(fiat.u1(x16)))
x19 := fiat.cmovznz_u64(fiat.u1(x18), x9, x1)
x20 := fiat.cmovznz_u64(fiat.u1(x18), x11, x3)
x21 := fiat.cmovznz_u64(fiat.u1(x18), x13, x5)
x22 := fiat.cmovznz_u64(fiat.u1(x18), x15, x7)
out1[0] = x19
out1[1] = x20
out1[2] = x21
out1[3] = x22
}
fe_sub :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) {
x1, x2 := bits.sub_u64(arg1[0], arg2[0], u64(0x0))
x3, x4 := bits.sub_u64(arg1[1], arg2[1], u64(fiat.u1(x2)))
x5, x6 := bits.sub_u64(arg1[2], arg2[2], u64(fiat.u1(x4)))
x7, x8 := bits.sub_u64(arg1[3], arg2[3], u64(fiat.u1(x6)))
x9 := fiat.cmovznz_u64(fiat.u1(x8), u64(0x0), 0xffffffffffffffff)
x10, x11 := bits.add_u64(x1, (x9 & 0xf3b9cac2fc632551), u64(0x0))
x12, x13 := bits.add_u64(x3, (x9 & 0xbce6faada7179e84), u64(fiat.u1(x11)))
x14, x15 := bits.add_u64(x5, x9, u64(fiat.u1(x13)))
x16, _ := bits.add_u64(x7, (x9 & 0xffffffff00000000), u64(fiat.u1(x15)))
out1[0] = x10
out1[1] = x12
out1[2] = x14
out1[3] = x16
}
fe_opp :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) {
x1, x2 := bits.sub_u64(u64(0x0), arg1[0], u64(0x0))
x3, x4 := bits.sub_u64(u64(0x0), arg1[1], u64(fiat.u1(x2)))
x5, x6 := bits.sub_u64(u64(0x0), arg1[2], u64(fiat.u1(x4)))
x7, x8 := bits.sub_u64(u64(0x0), arg1[3], u64(fiat.u1(x6)))
x9 := fiat.cmovznz_u64(fiat.u1(x8), u64(0x0), 0xffffffffffffffff)
x10, x11 := bits.add_u64(x1, (x9 & 0xf3b9cac2fc632551), u64(0x0))
x12, x13 := bits.add_u64(x3, (x9 & 0xbce6faada7179e84), u64(fiat.u1(x11)))
x14, x15 := bits.add_u64(x5, x9, u64(fiat.u1(x13)))
x16, _ := bits.add_u64(x7, (x9 & 0xffffffff00000000), u64(fiat.u1(x15)))
out1[0] = x10
out1[1] = x12
out1[2] = x14
out1[3] = x16
}
fe_one :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) {
out1[0] = 0xc46353d039cdaaf
out1[1] = 0x4319055258e8617b
out1[2] = u64(0x0)
out1[3] = 0xffffffff
}
fe_non_zero :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> u64 {
return arg1[0] | (arg1[1] | (arg1[2] | arg1[3]))
}
@(optimization_mode = "none")
fe_cond_assign :: #force_no_inline proc "contextless" (
out1, arg1: ^Montgomery_Domain_Field_Element,
arg2: int,
) {
x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0])
x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1])
x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2])
x4 := fiat.cmovznz_u64(fiat.u1(arg2), out1[3], arg1[3])
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
}
fe_from_montgomery :: proc "contextless" (
out1: ^Non_Montgomery_Domain_Field_Element,
arg1: ^Montgomery_Domain_Field_Element,
) {
x1 := arg1[0]
_, x2 := bits.mul_u64(x1, 0xccd1c8aaee00bc4f)
x5, x4 := bits.mul_u64(x2, 0xffffffff00000000)
x7, x6 := bits.mul_u64(x2, 0xffffffffffffffff)
x9, x8 := bits.mul_u64(x2, 0xbce6faada7179e84)
x11, x10 := bits.mul_u64(x2, 0xf3b9cac2fc632551)
x12, x13 := bits.add_u64(x11, x8, u64(0x0))
x14, x15 := bits.add_u64(x9, x6, u64(fiat.u1(x13)))
x16, x17 := bits.add_u64(x7, x4, u64(fiat.u1(x15)))
_, x19 := bits.add_u64(x1, x10, u64(0x0))
x20, x21 := bits.add_u64(u64(0x0), x12, u64(fiat.u1(x19)))
x22, x23 := bits.add_u64(u64(0x0), x14, u64(fiat.u1(x21)))
x24, x25 := bits.add_u64(u64(0x0), x16, u64(fiat.u1(x23)))
x26, x27 := bits.add_u64(x20, arg1[1], u64(0x0))
x28, x29 := bits.add_u64(x22, u64(0x0), u64(fiat.u1(x27)))
x30, x31 := bits.add_u64(x24, u64(0x0), u64(fiat.u1(x29)))
_, x32 := bits.mul_u64(x26, 0xccd1c8aaee00bc4f)
x35, x34 := bits.mul_u64(x32, 0xffffffff00000000)
x37, x36 := bits.mul_u64(x32, 0xffffffffffffffff)
x39, x38 := bits.mul_u64(x32, 0xbce6faada7179e84)
x41, x40 := bits.mul_u64(x32, 0xf3b9cac2fc632551)
x42, x43 := bits.add_u64(x41, x38, u64(0x0))
x44, x45 := bits.add_u64(x39, x36, u64(fiat.u1(x43)))
x46, x47 := bits.add_u64(x37, x34, u64(fiat.u1(x45)))
_, x49 := bits.add_u64(x26, x40, u64(0x0))
x50, x51 := bits.add_u64(x28, x42, u64(fiat.u1(x49)))
x52, x53 := bits.add_u64(x30, x44, u64(fiat.u1(x51)))
x54, x55 := bits.add_u64((u64(fiat.u1(x31)) + (u64(fiat.u1(x25)) + (u64(fiat.u1(x17)) + x5))), x46, u64(fiat.u1(x53)))
x56, x57 := bits.add_u64(x50, arg1[2], u64(0x0))
x58, x59 := bits.add_u64(x52, u64(0x0), u64(fiat.u1(x57)))
x60, x61 := bits.add_u64(x54, u64(0x0), u64(fiat.u1(x59)))
_, x62 := bits.mul_u64(x56, 0xccd1c8aaee00bc4f)
x65, x64 := bits.mul_u64(x62, 0xffffffff00000000)
x67, x66 := bits.mul_u64(x62, 0xffffffffffffffff)
x69, x68 := bits.mul_u64(x62, 0xbce6faada7179e84)
x71, x70 := bits.mul_u64(x62, 0xf3b9cac2fc632551)
x72, x73 := bits.add_u64(x71, x68, u64(0x0))
x74, x75 := bits.add_u64(x69, x66, u64(fiat.u1(x73)))
x76, x77 := bits.add_u64(x67, x64, u64(fiat.u1(x75)))
_, x79 := bits.add_u64(x56, x70, u64(0x0))
x80, x81 := bits.add_u64(x58, x72, u64(fiat.u1(x79)))
x82, x83 := bits.add_u64(x60, x74, u64(fiat.u1(x81)))
x84, x85 := bits.add_u64((u64(fiat.u1(x61)) + (u64(fiat.u1(x55)) + (u64(fiat.u1(x47)) + x35))), x76, u64(fiat.u1(x83)))
x86, x87 := bits.add_u64(x80, arg1[3], u64(0x0))
x88, x89 := bits.add_u64(x82, u64(0x0), u64(fiat.u1(x87)))
x90, x91 := bits.add_u64(x84, u64(0x0), u64(fiat.u1(x89)))
_, x92 := bits.mul_u64(x86, 0xccd1c8aaee00bc4f)
x95, x94 := bits.mul_u64(x92, 0xffffffff00000000)
x97, x96 := bits.mul_u64(x92, 0xffffffffffffffff)
x99, x98 := bits.mul_u64(x92, 0xbce6faada7179e84)
x101, x100 := bits.mul_u64(x92, 0xf3b9cac2fc632551)
x102, x103 := bits.add_u64(x101, x98, u64(0x0))
x104, x105 := bits.add_u64(x99, x96, u64(fiat.u1(x103)))
x106, x107 := bits.add_u64(x97, x94, u64(fiat.u1(x105)))
_, x109 := bits.add_u64(x86, x100, u64(0x0))
x110, x111 := bits.add_u64(x88, x102, u64(fiat.u1(x109)))
x112, x113 := bits.add_u64(x90, x104, u64(fiat.u1(x111)))
x114, x115 := bits.add_u64((u64(fiat.u1(x91)) + (u64(fiat.u1(x85)) + (u64(fiat.u1(x77)) + x65))), x106, u64(fiat.u1(x113)))
x116 := (u64(fiat.u1(x115)) + (u64(fiat.u1(x107)) + x95))
x117, x118 := bits.sub_u64(x110, 0xf3b9cac2fc632551, u64(0x0))
x119, x120 := bits.sub_u64(x112, 0xbce6faada7179e84, u64(fiat.u1(x118)))
x121, x122 := bits.sub_u64(x114, 0xffffffffffffffff, u64(fiat.u1(x120)))
x123, x124 := bits.sub_u64(x116, 0xffffffff00000000, u64(fiat.u1(x122)))
_, x126 := bits.sub_u64(u64(0x0), u64(0x0), u64(fiat.u1(x124)))
x127 := fiat.cmovznz_u64(fiat.u1(x126), x117, x110)
x128 := fiat.cmovznz_u64(fiat.u1(x126), x119, x112)
x129 := fiat.cmovznz_u64(fiat.u1(x126), x121, x114)
x130 := fiat.cmovznz_u64(fiat.u1(x126), x123, x116)
out1[0] = x127
out1[1] = x128
out1[2] = x129
out1[3] = x130
}
fe_to_montgomery :: proc "contextless" (
out1: ^Montgomery_Domain_Field_Element,
arg1: ^Non_Montgomery_Domain_Field_Element,
) {
x1 := arg1[1]
x2 := arg1[2]
x3 := arg1[3]
x4 := arg1[0]
x6, x5 := bits.mul_u64(x4, 0x66e12d94f3d95620)
x8, x7 := bits.mul_u64(x4, 0x2845b2392b6bec59)
x10, x9 := bits.mul_u64(x4, 0x4699799c49bd6fa6)
x12, x11 := bits.mul_u64(x4, 0x83244c95be79eea2)
x13, x14 := bits.add_u64(x12, x9, u64(0x0))
x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14)))
x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16)))
_, x19 := bits.mul_u64(x11, 0xccd1c8aaee00bc4f)
x22, x21 := bits.mul_u64(x19, 0xffffffff00000000)
x24, x23 := bits.mul_u64(x19, 0xffffffffffffffff)
x26, x25 := bits.mul_u64(x19, 0xbce6faada7179e84)
x28, x27 := bits.mul_u64(x19, 0xf3b9cac2fc632551)
x29, x30 := bits.add_u64(x28, x25, u64(0x0))
x31, x32 := bits.add_u64(x26, x23, u64(fiat.u1(x30)))
x33, x34 := bits.add_u64(x24, x21, u64(fiat.u1(x32)))
_, x36 := bits.add_u64(x11, x27, u64(0x0))
x37, x38 := bits.add_u64(x13, x29, u64(fiat.u1(x36)))
x39, x40 := bits.add_u64(x15, x31, u64(fiat.u1(x38)))
x41, x42 := bits.add_u64(x17, x33, u64(fiat.u1(x40)))
x43, x44 := bits.add_u64((u64(fiat.u1(x18)) + x6), (u64(fiat.u1(x34)) + x22), u64(fiat.u1(x42)))
x46, x45 := bits.mul_u64(x1, 0x66e12d94f3d95620)
x48, x47 := bits.mul_u64(x1, 0x2845b2392b6bec59)
x50, x49 := bits.mul_u64(x1, 0x4699799c49bd6fa6)
x52, x51 := bits.mul_u64(x1, 0x83244c95be79eea2)
x53, x54 := bits.add_u64(x52, x49, u64(0x0))
x55, x56 := bits.add_u64(x50, x47, u64(fiat.u1(x54)))
x57, x58 := bits.add_u64(x48, x45, u64(fiat.u1(x56)))
x59, x60 := bits.add_u64(x37, x51, u64(0x0))
x61, x62 := bits.add_u64(x39, x53, u64(fiat.u1(x60)))
x63, x64 := bits.add_u64(x41, x55, u64(fiat.u1(x62)))
x65, x66 := bits.add_u64(x43, x57, u64(fiat.u1(x64)))
_, x67 := bits.mul_u64(x59, 0xccd1c8aaee00bc4f)
x70, x69 := bits.mul_u64(x67, 0xffffffff00000000)
x72, x71 := bits.mul_u64(x67, 0xffffffffffffffff)
x74, x73 := bits.mul_u64(x67, 0xbce6faada7179e84)
x76, x75 := bits.mul_u64(x67, 0xf3b9cac2fc632551)
x77, x78 := bits.add_u64(x76, x73, u64(0x0))
x79, x80 := bits.add_u64(x74, x71, u64(fiat.u1(x78)))
x81, x82 := bits.add_u64(x72, x69, u64(fiat.u1(x80)))
_, x84 := bits.add_u64(x59, x75, u64(0x0))
x85, x86 := bits.add_u64(x61, x77, u64(fiat.u1(x84)))
x87, x88 := bits.add_u64(x63, x79, u64(fiat.u1(x86)))
x89, x90 := bits.add_u64(x65, x81, u64(fiat.u1(x88)))
x91, x92 := bits.add_u64(((u64(fiat.u1(x66)) + u64(fiat.u1(x44))) + (u64(fiat.u1(x58)) + x46)), (u64(fiat.u1(x82)) + x70), u64(fiat.u1(x90)))
x94, x93 := bits.mul_u64(x2, 0x66e12d94f3d95620)
x96, x95 := bits.mul_u64(x2, 0x2845b2392b6bec59)
x98, x97 := bits.mul_u64(x2, 0x4699799c49bd6fa6)
x100, x99 := bits.mul_u64(x2, 0x83244c95be79eea2)
x101, x102 := bits.add_u64(x100, x97, u64(0x0))
x103, x104 := bits.add_u64(x98, x95, u64(fiat.u1(x102)))
x105, x106 := bits.add_u64(x96, x93, u64(fiat.u1(x104)))
x107, x108 := bits.add_u64(x85, x99, u64(0x0))
x109, x110 := bits.add_u64(x87, x101, u64(fiat.u1(x108)))
x111, x112 := bits.add_u64(x89, x103, u64(fiat.u1(x110)))
x113, x114 := bits.add_u64(x91, x105, u64(fiat.u1(x112)))
_, x115 := bits.mul_u64(x107, 0xccd1c8aaee00bc4f)
x118, x117 := bits.mul_u64(x115, 0xffffffff00000000)
x120, x119 := bits.mul_u64(x115, 0xffffffffffffffff)
x122, x121 := bits.mul_u64(x115, 0xbce6faada7179e84)
x124, x123 := bits.mul_u64(x115, 0xf3b9cac2fc632551)
x125, x126 := bits.add_u64(x124, x121, u64(0x0))
x127, x128 := bits.add_u64(x122, x119, u64(fiat.u1(x126)))
x129, x130 := bits.add_u64(x120, x117, u64(fiat.u1(x128)))
_, x132 := bits.add_u64(x107, x123, u64(0x0))
x133, x134 := bits.add_u64(x109, x125, u64(fiat.u1(x132)))
x135, x136 := bits.add_u64(x111, x127, u64(fiat.u1(x134)))
x137, x138 := bits.add_u64(x113, x129, u64(fiat.u1(x136)))
x139, x140 := bits.add_u64(((u64(fiat.u1(x114)) + u64(fiat.u1(x92))) + (u64(fiat.u1(x106)) + x94)), (u64(fiat.u1(x130)) + x118), u64(fiat.u1(x138)))
x142, x141 := bits.mul_u64(x3, 0x66e12d94f3d95620)
x144, x143 := bits.mul_u64(x3, 0x2845b2392b6bec59)
x146, x145 := bits.mul_u64(x3, 0x4699799c49bd6fa6)
x148, x147 := bits.mul_u64(x3, 0x83244c95be79eea2)
x149, x150 := bits.add_u64(x148, x145, u64(0x0))
x151, x152 := bits.add_u64(x146, x143, u64(fiat.u1(x150)))
x153, x154 := bits.add_u64(x144, x141, u64(fiat.u1(x152)))
x155, x156 := bits.add_u64(x133, x147, u64(0x0))
x157, x158 := bits.add_u64(x135, x149, u64(fiat.u1(x156)))
x159, x160 := bits.add_u64(x137, x151, u64(fiat.u1(x158)))
x161, x162 := bits.add_u64(x139, x153, u64(fiat.u1(x160)))
_, x163 := bits.mul_u64(x155, 0xccd1c8aaee00bc4f)
x166, x165 := bits.mul_u64(x163, 0xffffffff00000000)
x168, x167 := bits.mul_u64(x163, 0xffffffffffffffff)
x170, x169 := bits.mul_u64(x163, 0xbce6faada7179e84)
x172, x171 := bits.mul_u64(x163, 0xf3b9cac2fc632551)
x173, x174 := bits.add_u64(x172, x169, u64(0x0))
x175, x176 := bits.add_u64(x170, x167, u64(fiat.u1(x174)))
x177, x178 := bits.add_u64(x168, x165, u64(fiat.u1(x176)))
_, x180 := bits.add_u64(x155, x171, u64(0x0))
x181, x182 := bits.add_u64(x157, x173, u64(fiat.u1(x180)))
x183, x184 := bits.add_u64(x159, x175, u64(fiat.u1(x182)))
x185, x186 := bits.add_u64(x161, x177, u64(fiat.u1(x184)))
x187, x188 := bits.add_u64(((u64(fiat.u1(x162)) + u64(fiat.u1(x140))) + (u64(fiat.u1(x154)) + x142)), (u64(fiat.u1(x178)) + x166), u64(fiat.u1(x186)))
x189, x190 := bits.sub_u64(x181, 0xf3b9cac2fc632551, u64(0x0))
x191, x192 := bits.sub_u64(x183, 0xbce6faada7179e84, u64(fiat.u1(x190)))
x193, x194 := bits.sub_u64(x185, 0xffffffffffffffff, u64(fiat.u1(x192)))
x195, x196 := bits.sub_u64(x187, 0xffffffff00000000, u64(fiat.u1(x194)))
_, x198 := bits.sub_u64(u64(fiat.u1(x188)), u64(0x0), u64(fiat.u1(x196)))
x199 := fiat.cmovznz_u64(fiat.u1(x198), x189, x181)
x200 := fiat.cmovznz_u64(fiat.u1(x198), x191, x183)
x201 := fiat.cmovznz_u64(fiat.u1(x198), x193, x185)
x202 := fiat.cmovznz_u64(fiat.u1(x198), x195, x187)
out1[0] = x199
out1[1] = x200
out1[2] = x201
out1[3] = x202
}

View File

@@ -0,0 +1,135 @@
package _weierstrass
import p256r1 "core:crypto/_fiat/field_p256r1"
import "core:math/bits"
Field_Element_p256r1 :: p256r1.Montgomery_Domain_Field_Element
FE_SIZE_P256R1 :: 32
fe_clear :: proc {
p256r1.fe_clear,
}
fe_clear_vec :: proc {
p256r1.fe_clear_vec,
}
fe_set_bytes :: proc {
p256r1.fe_from_bytes,
}
fe_bytes :: proc {
p256r1.fe_to_bytes,
}
fe_set :: proc {
p256r1.fe_set,
}
fe_zero :: proc {
p256r1.fe_zero,
}
fe_a :: proc {
fe_a_p256r1,
}
fe_b :: proc {
fe_b_p256r1,
}
fe_gen_x :: proc {
fe_gen_x_p256r1,
}
fe_gen_y :: proc {
fe_gen_y_p256r1,
}
fe_one :: proc {
p256r1.fe_one,
}
fe_add :: proc {
p256r1.fe_add,
}
fe_sub :: proc {
p256r1.fe_sub,
}
fe_negate :: proc {
p256r1.fe_opp,
}
fe_mul :: proc {
p256r1.fe_mul,
}
fe_square :: proc {
p256r1.fe_square,
}
fe_inv :: proc {
p256r1.fe_inv,
}
fe_sqrt :: proc {
p256r1.fe_sqrt,
}
fe_equal :: proc {
p256r1.fe_equal,
}
fe_is_odd :: proc {
p256r1.fe_is_odd,
}
fe_is_zero :: proc {
fe_is_zero_p256r1,
}
fe_cond_select :: proc {
p256r1.fe_cond_select,
}
fe_a_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) {
// a = 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc
// = -3 mod p
fe[0] = 18446744073709551612
fe[1] = 17179869183
fe[2] = 0
fe[3] = 18446744056529682436
}
fe_b_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) {
// b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
fe[0] = 15608596021259845087
fe[1] = 12461466548982526096
fe[2] = 16546823903870267094
fe[3] = 15866188208926050356
}
fe_gen_x_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) {
// G_x = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
fe[0] = 8784043285714375740
fe[1] = 8483257759279461889
fe[2] = 8789745728267363600
fe[3] = 1770019616739251654
}
fe_gen_y_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) {
// G_y = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
fe[0] = 15992936863339206154
fe[1] = 10037038012062884956
fe[2] = 15197544864945402661
fe[3] = 9615747158586711429
}
@(require_results)
fe_is_zero_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) -> int {
ctrl := p256r1.fe_non_zero(fe)
_, borrow := bits.sub_u64(ctrl, 1, 0)
return int(borrow)
}

View File

@@ -0,0 +1,548 @@
package _weierstrass
/*
This implements prime order short Weierstrass curves defined over a field
k with char(k) != 2, 3 (`y^2 = x^3 + ax + b`). for the purpose of
implementing ECDH and ECDSA. Use of this package for other purposes is
NOT RECOMMENDED.
As an explicit simplicity/performance tradeoff, projective representation
was chosen so that it is possible to use the complete addition
formulas.
See:
- https://eprint.iacr.org/2015/1060.pdf
- https://hyperelliptic.org/EFD/g1p/auto-shortw-projective.html
WARNING: The point addition and doubling formulas are specialized for
`a = -3`, which covers secp256r1, secp384r1, secp521r1, FRP256v1, SM2,
and GOST 34.10. The brainpool curves and secp256k1 are NOT SUPPORTED
and would require slightly different formulas.
*/
Point_p256r1 :: struct {
x: Field_Element_p256r1,
y: Field_Element_p256r1,
z: Field_Element_p256r1,
}
@(require_results)
pt_set_xy_bytes :: proc "contextless" (p: ^$T, x_raw, y_raw: []byte) -> bool {
when T == Point_p256r1 {
FE_SZ :: FE_SIZE_P256R1
x, y: Field_Element_p256r1
defer fe_clear_vec([]^Field_Element_p256r1{&x, &y})
} else {
#panic("weierstrass: invalid curve")
}
if len(x_raw) != FE_SZ || len(y_raw) != FE_SZ {
return false
}
if !fe_set_bytes(&x, x_raw) {
return false
}
if !fe_set_bytes(&y, y_raw) {
return false
}
if !is_on_curve(&x, &y) {
return false
}
fe_set(&p.x, &x)
fe_set(&p.y, &y)
fe_one(&p.z)
return true
}
@(require_results)
pt_set_x_bytes :: proc "contextless" (p: ^$T, x_raw: []byte, y_is_odd: int) -> bool {
when T == Point_p256r1 {
FE_SZ :: FE_SIZE_P256R1
x, y, yy, y_neg: Field_Element_p256r1
defer fe_clear_vec([]^Field_Element_p256r1{&x, &y, &yy, &y_neg})
} else {
#panic("weierstrass: invalid curve")
}
if len(x_raw) != FE_SZ {
return false
}
if !fe_set_bytes(&x, x_raw) {
return false
}
set_yy_candidate(&yy, &x)
if fe_sqrt(&y, &yy) != 1 {
return false
}
// Pick the correct y-coordinate.
fe_negate(&y_neg, &y)
parity_neq := (y_is_odd ~ fe_is_odd(&y)) & 1
fe_set(&p.x, &x)
fe_cond_select(&p.y, &y, &y_neg, parity_neq)
fe_one(&p.z)
return true
}
@(require_results)
pt_bytes :: proc "contextless" (x, y: []byte, p: ^$T) -> bool {
when T == Point_p256r1 {
FE_SZ :: FE_SIZE_P256R1
} else {
#panic("weierstrass: invalid curve")
}
if pt_is_identity(p) == 1 {
return false
}
// Convert to affine coordinates.
pt_rescale(p, p)
switch len(x) {
case 0:
case FE_SZ:
fe_bytes(x, &p.x)
case:
panic_contextless("weierstrass: invalid x buffer")
}
switch len(y) {
case 0:
case FE_SZ:
fe_bytes(y, &p.y)
case:
panic_contextless("weierstrass: invalid y buffer")
}
return true
}
pt_set :: proc "contextless" (p, q: ^$T) {
fe_set(&p.x, &q.x)
fe_set(&p.y, &q.y)
fe_set(&p.z, &q.z)
}
pt_identity :: proc "contextless" (p: ^$T) {
fe_zero(&p.x)
fe_one(&p.y)
fe_zero(&p.z)
}
pt_generator :: proc "contextless" (p: ^$T) {
fe_gen_x(&p.x)
fe_gen_y(&p.y)
fe_one(&p.z)
}
pt_clear :: proc "contextless" (p: ^$T) {
fe_clear(&p.x)
fe_clear(&p.y)
fe_clear(&p.z)
}
pt_clear_vec :: proc "contextless" (arg: []^$T) {
for p in arg {
pt_clear(p)
}
}
pt_add :: proc "contextless" (p, a, b: ^$T) {
// Algorithm 4 from "Complete addition formulas for prime
// order elliptic curves" by Renes, Costello, and Batina.
//
// The formula is complete in that it is valid for all a and b,
// without exceptions or extra assumptions about the inputs.
//
// The operation costs are `12M + 2mb + 29a`.
when T == Point_p256r1 {
t0, t1, t2, t3, t4, b_fe: Field_Element_p256r1
x3, y3, z3: Field_Element_p256r1
defer fe_clear_vec([]^Field_Element_p256r1{&t0, &t1, &t2, &t3, &t4, &x3, &y3, &z3})
} else {
#panic("weierstrass: invalid curve")
}
x1, y1, z1 := &a.x, &a.y, &a.z
x2, y2, z2 := &b.x, &b.y, &b.z
fe_b(&b_fe)
// t0 := X1 * X2 ; t1 := Y1 * Y2 ; t2 := Z1 * Z2 ;
fe_mul(&t0, x1, x2)
fe_mul(&t1, y1, y2)
fe_mul(&t2, z1, z2)
// t3 := X1 + Y1 ; t4 := X2 + Y2 ; t3 := t3 * t4 ;
fe_add(&t3, x1, y1)
fe_add(&t4, x2, y2)
fe_mul(&t3, &t3, &t4)
// t4 := t0 + t1 ; t3 := t3 - t4 ; t4 := Y1 + Z1 ;
fe_add(&t4, &t0, &t1)
fe_sub(&t3, &t3, &t4)
fe_add(&t4, y1, z1)
// X3 := Y2 + Z2 ; t4 := t4 * X3 ; X3 := t1 + t2 ;
fe_add(&x3, y2, z2)
fe_mul(&t4, &t4, &x3)
fe_add(&x3, &t1, &t2)
// t4 := t4 - X3 ; X3 := X1 + Z1 ; Y3 := X2 + Z2 ;
fe_sub(&t4, &t4, &x3)
fe_add(&x3, x1, z1)
fe_add(&y3, x2, z2)
// X3 := X3 * Y3 ; Y3 := t0 + t2 ; Y3 := X3 - Y3 ;
fe_mul(&x3, &x3, &y3)
fe_add(&y3, &t0, &t2)
fe_sub(&y3, &x3, &y3)
// Z3 := b * t2 ; X3 := Y3 - Z3 ; Z3 := X3 + X3 ;
fe_mul(&z3, &b_fe, &t2)
fe_sub(&x3, &y3, &z3)
fe_add(&z3, &x3, &x3)
// X3 := X3 + Z3 ; Z3 := t1 - X3 ; X3 := t1 + X3 ;
fe_add(&x3, &x3, &z3)
fe_sub(&z3, &t1, &x3)
fe_add(&x3, &t1, &x3)
// Y3 := b * Y3 ; t1 := t2 + t2 ; t2 := t1 + t2 ;
fe_mul(&y3, &b_fe, &y3)
fe_add(&t1, &t2, &t2)
fe_add(&t2, &t1, &t2)
// Y3 := Y3 - t2 ; Y3 := Y3 - t0 ; t1 := Y3 + Y3 ;
fe_sub(&y3, &y3, &t2)
fe_sub(&y3, &y3, &t0)
fe_add(&t1, &y3, &y3)
// Y3 := t1 + Y3 ; t1 := t0 + t0 ; t0 := t1 + t0 ;
fe_add(&y3, &t1, &y3)
fe_add(&t1, &t0, &t0)
fe_add(&t0, &t1, &t0)
// t0 := t0 - t2 ; t1 := t4 * Y3 ; t2 := t0 * Y3 ;
fe_sub(&t0, &t0, &t2)
fe_mul(&t1, &t4, &y3)
fe_mul(&t2, &t0, &y3)
// Y3 := X3 * Z3 ; Y3 := Y3 + t2 ; X3 := t3 * X3 ;
fe_mul(&y3, &x3, &z3)
fe_add(&y3, &y3, &t2)
fe_mul(&x3, &t3, &x3)
// X3 := X3 - t1 ; Z3 := t4 * Z3 ; t1 := t3 * t0 ;
fe_sub(&x3, &x3, &t1)
fe_mul(&z3, &t4, &z3)
fe_mul(&t1, &t3, &t0)
// Z3 := Z3 + t1 ;
fe_add(&z3, &z3, &t1)
// return X3 , Y3 , Z3 ;
fe_set(&p.x, &x3)
fe_set(&p.y, &y3)
fe_set(&p.z, &z3)
}
@(private)
pt_add_mixed :: proc "contextless" (p, a: ^$T, x2, y2: ^$U) {
// Algorithm 5 from "Complete addition formulas for prime
// order elliptic curves" by Renes, Costello, and Batina.
//
// The formula is mixed in that it assumes the z-coordinate
// of the addend (`Z2`) is `1`, meaning that it CAN NOT
// handle the addend being the point at infinity.
//
// The operation costs are `11M + 2mb + 23a` saving
// `1M + 6a` over `pt_add`.
when T == Point_p256r1 && U == Field_Element_p256r1 {
t0, t1, t2, t3, t4, b_fe: Field_Element_p256r1
x3, y3, z3: Field_Element_p256r1
defer fe_clear_vec([]^Field_Element_p256r1{&t0, &t1, &t2, &t3, &t4, &x3, &y3, &z3})
} else {
#panic("weierstrass: invalid curve")
}
x1, y1, z1 := &a.x, &a.y, &a.z
fe_b(&b_fe)
// t0 := X1 * X2 ; t1 := Y1 * Y2 ; t3 := X2 + Y2 ;
fe_mul(&t0, x1, x2)
fe_mul(&t1, y1, y2)
fe_add(&t3, x2, y2)
// t4 := X1 + Y1 ; t3 := t3 * t4 ; t4 := t0 + t1 ;
fe_add(&t4, x1, y1)
fe_mul(&t3, &t3, &t4)
fe_add(&t4, &t0, &t1)
// t3 := t3 t4 ; t4 := Y2 * Z1 ; t4 := t4 + Y1 ;
fe_sub(&t3, &t3, &t4)
fe_mul(&t4, y2, z1)
fe_add(&t4, &t4, y1)
// Y3 := X2 * Z1 ; Y3 := Y3 + X1 ; Z3 := b * Z1 ;
fe_mul(&y3, x2, z1)
fe_add(&y3, &y3, x1)
fe_mul(&z3, &b_fe, z1)
// X3 := Y3 Z3 ; Z3 := X3 + X3 ; X3 := X3 + Z3 ;
fe_sub(&x3, &y3, &z3)
fe_add(&z3, &x3, &x3)
fe_add(&x3, &x3, &z3)
// Z3 := t1 X3 ; X3 := t1 + X3 ;. Y3 := b * Y3 ;
fe_sub(&z3, &t1, &x3)
fe_add(&x3, &t1, &x3)
fe_mul(&y3, &b_fe, &y3)
// t1 := Z1 + Z1 ; t2 := t1 + Z1 ; Y3 := Y3 t2 ;
fe_add(&t1, z1, z1)
fe_add(&t2, &t1, z1)
fe_sub(&y3, &y3, &t2)
// Y3 := Y3 t0 ; t1 := Y3 + Y3 ; Y3 := t1 + Y3 ;
fe_sub(&y3, &y3, &t0)
fe_add(&t1, &y3, &y3)
fe_add(&y3, &t1, &y3)
// t1 := t0 + t0 ; t0 := t1 + t0 ; t0 := t0 t2 ;
fe_add(&t1, &t0, &t0)
fe_add(&t0, &t1, &t0)
fe_sub(&t0, &t0, &t2)
// t1 := t4 * Y3 ; t2 := t0 * Y3 ; Y3 := X3 * Z3 ;
fe_mul(&t1, &t4, &y3)
fe_mul(&t2, &t0, &y3)
fe_mul(&y3, &x3, &z3)
// Y3 := Y3 + t2 ; X3 := t3 * X3 ; X3 := X3 t1 ;
fe_add(&y3, &y3, &t2)
fe_mul(&x3, &t3, &x3)
fe_sub(&x3, &x3, &t1)
// Z3 := t4 * Z3 ; t1 := t3 * t0 ; Z3 := Z3 + t1 ;
fe_mul(&z3, &t4, &z3)
fe_mul(&t1, &t3, &t0)
fe_add(&z3, &z3, &t1)
// return X3 , Y3 , Z3 ;
fe_set(&p.x, &x3)
fe_set(&p.y, &y3)
fe_set(&p.z, &z3)
}
pt_double :: proc "contextless" (p, a: ^$T) {
// Algorithm 6 from "Complete addition formulas for prime
// order elliptic curves" by Renes, Costello, and Batina.
//
// The formula is complete in that it is valid for all a,
// without exceptions or extra assumptions about the inputs.
//
// The operation costs are `8M + 3S + 2mb + 21a`.
when T == Point_p256r1 {
t0, t1, t2, t3, b_fe: Field_Element_p256r1
x3, y3, z3: Field_Element_p256r1
defer fe_clear_vec([]^Field_Element_p256r1{&t0, &t1, &t2, &t3, &x3, &y3, &z3})
} else {
#panic("weierstrass: invalid curve")
}
x, y, z := &a.x, &a.y, &a.z
fe_b(&b_fe)
// t0 := X ^2; t1 := Y ^2; t2 := Z ^2;
fe_square(&t0, x)
fe_square(&t1, y)
fe_square(&t2, z)
// t3 := X * Y ; t3 := t3 + t3 ; Z3 := X * Z ;
fe_mul(&t3, x, y)
fe_add(&t3, &t3, &t3)
fe_mul(&z3, x, z)
// Z3 := Z3 + Z3 ; Y3 := b * t2 ; Y3 := Y3 - Z3 ;
fe_add(&z3, &z3, &z3)
fe_mul(&y3, &b_fe, &t2)
fe_sub(&y3, &y3, &z3)
// X3 := Y3 + Y3 ; Y3 := X3 + Y3 ; X3 := t1 - Y3 ;
fe_add(&x3, &y3, &y3)
fe_add(&y3, &x3, &y3)
fe_sub(&x3, &t1, &y3)
// Y3 := t1 + Y3 ; Y3 := X3 * Y3 ; X3 := X3 * t3 ;
fe_add(&y3, &t1, &y3)
fe_mul(&y3, &x3, &y3)
fe_mul(&x3, &x3, &t3)
// t3 := t2 + t2 ; t2 := t2 + t3 ; Z3 := b * Z3 ;
fe_add(&t3, &t2, &t2)
fe_add(&t2, &t2, &t3)
fe_mul(&z3, &b_fe, &z3)
// Z3 := Z3 - t2 ; Z3 := Z3 - t0 ; t3 := Z3 + Z3 ;
fe_sub(&z3, &z3, &t2)
fe_sub(&z3, &z3, &t0)
fe_add(&t3, &z3, &z3)
// Z3 := Z3 + t3 ; t3 := t0 + t0 ; t0 := t3 + t0 ;
fe_add(&z3, &z3, &t3)
fe_add(&t3, &t0, &t0)
fe_add(&t0, &t3, &t0)
// t0 := t0 - t2 ; t0 := t0 * Z3 ; Y3 := Y3 + t0 ;
fe_sub(&t0, &t0, &t2)
fe_mul(&t0, &t0, &z3)
fe_add(&y3, &y3, &t0)
// t0 := Y * Z ; t0 := t0 + t0 ; Z3 := t0 * Z3 ;
fe_mul(&t0, y, z)
fe_add(&t0, &t0, &t0)
fe_mul(&z3, &t0, &z3)
// X3 := X3 - Z3 ; Z3 := t0 * t1 ; Z3 := Z3 + Z3 ;
fe_sub(&x3, &x3, &z3)
fe_mul(&z3, &t0, &t1)
fe_add(&z3, &z3, &z3)
// Z3 := Z3 + Z3 ;
fe_add(&z3, &z3, &z3)
// return X3 , Y3 , Z3 ;
fe_set(&p.x, &x3)
fe_set(&p.y, &y3)
fe_set(&p.z, &z3)
}
pt_sub :: proc "contextless" (p, a, b: ^$T) {
b_neg: T
pt_negate(&b_neg, b)
pt_add(p, a, &b_neg)
fe_clear(&b_neg)
}
pt_negate :: proc "contextless" (p, a: ^$T) {
fe_set(&p.x, &a.x)
fe_negate(&p.y, &a.y)
fe_set(&p.z, &a.z)
}
pt_rescale :: proc "contextless" (p, a: ^$T) {
// A = 1/Z1
// X3 = A*X1
// Y3 = A*Y1
// Z3 = 1
//
// As per "From A to Z: Projective coordinates leakage in the wild"
// leaking the Z-coordinate is bad. The modular inversion algorithm
// used in this library is based on Fermat's Little Theorem.
//
// See: https://eprint.iacr.org/2020/432.pdf
was_identity := pt_is_identity(a)
when T == Point_p256r1 {
z_inv: Field_Element_p256r1
} else {
#panic("weierstrass: invalid curve")
}
ident: T
fe_inv(&z_inv, &a.z)
fe_mul(&p.x, &a.x, &z_inv)
fe_mul(&p.y, &a.y, &z_inv)
fe_one(&p.z)
pt_identity(&ident)
pt_cond_select(p, p, &ident, was_identity)
fe_clear(&z_inv)
}
pt_cond_select :: proc "contextless" (p, a, b: ^$T, ctrl: int) {
fe_cond_select(&p.x, &a.x, &b.x, ctrl)
fe_cond_select(&p.y, &a.y, &b.y, ctrl)
fe_cond_select(&p.z, &a.z, &b.z, ctrl)
}
@(require_results)
pt_equal :: proc "contextless" (a, b: ^$T) -> int {
when T == Point_p256r1 {
x1z2, x2z1, y1z2, y2z1: Field_Element_p256r1
} else {
#panic("weierstrass: invalid curve")
}
// Check X1Z2 == X2Z1 && Y1Z2 == Y2Z1
fe_mul(&x1z2, &a.x, &b.z)
fe_mul(&x2z1, &b.x, &a.z)
fe_mul(&y1z2, &a.y, &b.z)
fe_mul(&y2z1, &b.y, &a.z)
return fe_equal(&x1z2, &x2z1) & fe_equal(&y1z2, &y2z1)
}
@(require_results)
pt_is_identity :: proc "contextless" (p: ^$T) -> int {
return fe_is_zero(&p.z)
}
@(require_results)
pt_is_y_odd :: proc "contextless" (p: ^$T) -> int {
tmp: T
defer pt_clear(&tmp)
fe_set(&tmp, p)
pt_rescale(&tmp)
return fe_is_odd(&tmp.y)
}
@(private)
is_on_curve :: proc "contextless" (x, y: ^$T) -> bool {
maybe_yy, yy: T
defer fe_clear_vec([]^T{&maybe_yy, &yy})
// RHS: x^3 + ax + b
set_yy_candidate(&maybe_yy, x)
// LHS: y^2
fe_square(&yy, y)
return fe_equal(&maybe_yy, &yy) == 1
}
@(private)
set_yy_candidate :: proc "contextless" (maybe_yy, x: ^$T) {
// RHS: x^3 + ax + b
rhs, tmp: T
fe_square(&tmp, x)
fe_mul(&rhs, &tmp, x)
fe_a(&tmp)
fe_mul(&tmp, &tmp, x)
fe_add(&rhs, &rhs, &tmp)
fe_b(&tmp)
fe_add(maybe_yy, &rhs, &tmp)
fe_clear(&rhs)
}

View File

@@ -0,0 +1,95 @@
package _weierstrass
@(require) import "core:mem"
@(private)
SEC_PREFIX_IDENTITY :: 0x00
@(private)
SEC_PREFIX_COMPRESSED_EVEN :: 0x02
@(private)
SEC_PREFIX_COMPRESSED_ODD :: 0x03
SEC_PREFIX_UNCOMPRESSED :: 0x04
@(require_results)
pt_set_sec_bytes :: proc "contextless" (p: ^$T, b: []byte) -> bool {
when T == Point_p256r1 {
FE_SZ :: FE_SIZE_P256R1
} else {
#panic("weierstrass: invalid curve")
}
b_len := len(b)
if b_len < 1 {
return false
}
switch b[0] {
case SEC_PREFIX_IDENTITY:
if b_len != 1 {
return false
}
pt_identity(p)
return true
case SEC_PREFIX_COMPRESSED_EVEN, SEC_PREFIX_COMPRESSED_ODD:
if b_len != 1 + FE_SZ {
return false
}
y_is_odd := b[0] - SEC_PREFIX_COMPRESSED_EVEN
return pt_set_x_bytes(p, b[1:], int(y_is_odd))
case SEC_PREFIX_UNCOMPRESSED:
if b_len != 1 + 2 * FE_SZ {
return false
}
x, y := b[1:1+FE_SZ], b[1+FE_SZ:]
return pt_set_xy_bytes(p, x, y)
case:
return false
}
}
@(require_results)
pt_sec_bytes :: proc "contextless" (b: []byte, p: ^$T, compressed: bool) -> bool {
when T == Point_p256r1 {
FE_SZ :: FE_SIZE_P256R1
} else {
#panic("weierstrass: invalid curve")
}
b_len := len(b)
if pt_is_identity(p) == 1 {
if b_len != 1 {
return false
}
b[0] = SEC_PREFIX_IDENTITY
return true
}
x, y: []byte
y_: [FE_SZ]byte
switch compressed {
case true:
if b_len != 1 + FE_SZ {
return false
}
x, y = b[1:], y_[:]
case false:
if b_len != 1 + 2 * FE_SZ {
return false
}
b[0]= SEC_PREFIX_UNCOMPRESSED
x, y = b[1:1+FE_SZ], b[1+FE_SZ:]
}
if !pt_bytes(x, y, p) {
return false
}
if compressed {
// Instead of calling pt_is_y_odd, just serializing
// y into a temp buffer and checking the parity saves
// 1 redundant rescale call.
y_is_odd := byte(y[FE_SZ-1] & 1)
b[0] = SEC_PREFIX_COMPRESSED_EVEN + y_is_odd
mem.zero_explicit(&y_, size_of(y_))
}
return true
}

View File

@@ -0,0 +1,76 @@
package _weierstrass
import p256r1 "core:crypto/_fiat/field_scalarp256r1"
import subtle "core:crypto/_subtle"
Scalar_p256r1 :: p256r1.Montgomery_Domain_Field_Element
SC_SIZE_P256R1 :: 32
sc_clear :: proc {
p256r1.fe_clear,
}
sc_clear_vec :: proc {
p256r1.fe_clear_vec,
}
sc_set_bytes :: proc {
p256r1.fe_from_bytes,
}
sc_bytes :: proc {
p256r1.fe_to_bytes,
}
sc_set :: proc {
p256r1.fe_set,
}
sc_zero :: proc {
p256r1.fe_zero,
}
sc_one_p256r1 :: proc {
p256r1.fe_one,
}
sc_add :: proc {
p256r1.fe_add,
}
sc_sub :: proc {
p256r1.fe_sub,
}
sc_negate :: proc {
p256r1.fe_opp,
}
sc_mul :: proc {
p256r1.fe_mul,
}
sc_square :: proc {
p256r1.fe_square,
}
sc_cond_assign :: proc {
p256r1.fe_cond_assign,
}
sc_equal :: proc {
p256r1.fe_equal,
}
sc_is_odd :: proc {
p256r1.fe_is_odd,
}
sc_is_zero :: proc {
sc_is_zero_p256r1,
}
@(require_results)
sc_is_zero_p256r1 :: proc "contextless" (fe: ^Scalar_p256r1) -> int {
return int(subtle.u64_is_zero(p256r1.fe_non_zero(fe)))
}

View File

@@ -0,0 +1,204 @@
package _weierstrass
import "core:crypto"
import subtle "core:crypto/_subtle"
import "core:mem"
pt_scalar_mul :: proc "contextless" (
p, a: ^$T,
sc: ^$S,
unsafe_is_vartime: bool = false,
) {
when T == Point_p256r1 && S == Scalar_p256r1 {
SC_SZ :: SC_SIZE_P256R1
} else {
#panic("weierstrass: invalid curve")
}
b: [SC_SZ]byte = ---
sc_bytes(b[:], sc)
pt_scalar_mul_bytes(p, a, b[:], unsafe_is_vartime)
if !unsafe_is_vartime {
mem.zero_explicit(&b, size_of(b))
}
}
pt_scalar_mul_bytes :: proc "contextless" (
p, a: ^$T,
sc: []byte,
unsafe_is_vartime: bool = false,
) {
when T == Point_p256r1 {
p_tbl: Multiply_Table_p256r1 = ---
q, tmp: Point_p256r1 = ---, ---
SC_SZ :: SC_SIZE_P256R1
} else {
#panic("weierstrass: invalid curve")
}
assert_contextless(len(sc) == SC_SZ, "weierstrass: invalid scalar size")
mul_tbl_set(&p_tbl, a, unsafe_is_vartime)
pt_identity(&q)
for limb_byte, i in sc {
hi, lo := (limb_byte >> 4) & 0x0f, limb_byte & 0x0f
if i != 0 {
pt_double(&q, &q)
pt_double(&q, &q)
pt_double(&q, &q)
pt_double(&q, &q)
}
mul_tbl_lookup_add(&q, &tmp, &p_tbl, u64(hi), unsafe_is_vartime)
pt_double(&q, &q)
pt_double(&q, &q)
pt_double(&q, &q)
pt_double(&q, &q)
mul_tbl_lookup_add(&q, &tmp, &p_tbl, u64(lo), unsafe_is_vartime)
}
pt_set(p, &q)
if !unsafe_is_vartime {
mem.zero_explicit(&p_tbl, size_of(p_tbl))
pt_clear_vec([]^T{&q, &tmp})
}
}
when crypto.COMPACT_IMPLS == true {
pt_scalar_mul_generator :: proc "contextless" (
p: ^$T,
sc: ^$S,
unsafe_is_vartime: bool = false,
) {
g: T
pt_generator(&g)
pt_scalar_mul(p, &g, sc, unsafe_is_vartime)
}
} else {
pt_scalar_mul_generator :: proc "contextless" (
p: ^$T,
sc: ^$S,
unsafe_is_vartime: bool = false,
) {
when T == Point_p256r1 && S == Scalar_p256r1 {
p_tbl_hi := &Gen_Multiply_Table_p256r1_hi
p_tbl_lo := &Gen_Multiply_Table_p256r1_lo
tmp: Point_p256r1 = ---
SC_SZ :: SC_SIZE_P256R1
} else {
#panic("weierstrass: invalid curve")
}
b: [SC_SZ]byte
sc_bytes(b[:], sc)
pt_identity(p)
for limb_byte, i in b {
hi, lo := (limb_byte >> 4) & 0x0f, limb_byte & 0x0f
mul_affine_tbl_lookup_add(p, &tmp, &p_tbl_hi[i], u64(hi), unsafe_is_vartime)
mul_affine_tbl_lookup_add(p, &tmp, &p_tbl_lo[i], u64(lo), unsafe_is_vartime)
}
if !unsafe_is_vartime {
mem.zero_explicit(&b, size_of(b))
pt_clear(&tmp)
}
}
}
@(private="file")
Multiply_Table_p256r1 :: [15]Point_p256r1
@(private="file")
mul_tbl_set :: proc "contextless"(
tbl: ^$T,
point: ^$U,
unsafe_is_vartime: bool,
) {
when T == Multiply_Table_p256r1 && U == Point_p256r1{
tmp: Point_p256r1
pt_set(&tmp, point)
} else {
#panic("weierstrass: invalid curve")
}
pt_set(&tbl[0], &tmp)
for i in 1 ..<15 {
pt_add(&tmp, &tmp, point)
pt_set(&tbl[i], &tmp)
}
if !unsafe_is_vartime {
pt_clear(&tmp)
}
}
@(private="file")
mul_tbl_lookup_add :: proc "contextless" (
point, tmp: ^$T,
tbl: ^$U,
idx: u64,
unsafe_is_vartime: bool,
) {
if unsafe_is_vartime {
switch idx {
case 0:
case:
pt_add(point, point, &tbl[idx - 1])
}
return
}
pt_identity(tmp)
for i in u64(1)..<16 {
ctrl := subtle.eq(i, idx)
pt_cond_select(tmp, tmp, &tbl[i - 1], int(ctrl))
}
pt_add(point, point, tmp)
}
when crypto.COMPACT_IMPLS == false {
@(private)
Affine_Point_p256r1 :: struct {
x: Field_Element_p256r1,
y: Field_Element_p256r1,
}
@(private="file")
mul_affine_tbl_lookup_add :: proc "contextless" (
point, tmp: ^$T,
tbl: ^$U,
idx: u64,
unsafe_is_vartime: bool,
) {
if unsafe_is_vartime {
switch idx {
case 0:
case:
pt_add_mixed(point, point, &tbl[idx - 1].x, &tbl[idx - 1].y)
}
return
}
pt_identity(tmp)
for i in u64(1)..<16 {
ctrl := int(subtle.eq(i, idx))
fe_cond_select(&tmp.x, &tmp.x, &tbl[i - 1].x, ctrl)
fe_cond_select(&tmp.y, &tmp.y, &tbl[i - 1].y, ctrl)
}
// The mixed addition formula assumes that the addend is not
// the neutral element. Do the addition regardless, and then
// conditionally select the right result.
pt_add_mixed(tmp, point, &tmp.x, &tmp.y)
ctrl := subtle.u64_is_non_zero(idx)
pt_cond_select(point, point, tmp, int(ctrl))
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,99 @@
package weistrass_tools
import secec "core:crypto/_weierstrass"
import "core:fmt"
import path "core:path/filepath"
import "core:os"
import "core:strings"
// Yes this leaks memory, fite me IRL.
GENERATED :: `/*
------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------
*/`
main :: proc() {
gen_p256r1_tables()
}
gen_p256r1_tables :: proc() {
Affine_Point_p256r1 :: struct {
x: secec.Field_Element_p256r1,
y: secec.Field_Element_p256r1,
}
Multiply_Table_p256r1_hi: [32][15]Affine_Point_p256r1
Multiply_Table_p256r1_lo: [32][15]Affine_Point_p256r1
g, p: secec.Point_p256r1
secec.pt_generator(&g)
// Precompute ([1,15] << n) * G multiples of G, MSB->LSB
for i in 0..<32 {
b: [32]byte
for j in 1..<16 {
b[i] = u8(j) << 4
secec.pt_scalar_mul_bytes(&p, &g, b[:], true)
secec.pt_rescale(&p, &p)
secec.fe_set(&Multiply_Table_p256r1_hi[i][j-1].x, &p.x)
secec.fe_set(&Multiply_Table_p256r1_hi[i][j-1].y, &p.y)
b[i] = u8(j)
secec.pt_scalar_mul_bytes(&p, &g, b[:], true)
secec.pt_rescale(&p, &p)
secec.fe_set(&Multiply_Table_p256r1_lo[i][j-1].x, &p.x)
secec.fe_set(&Multiply_Table_p256r1_lo[i][j-1].y, &p.y)
b[i] = 0
}
}
fn := path.join({ODIN_ROOT, "core", "crypto", "_weierstrass", "secp256r1_table.odin"})
bld: strings.Builder
w := strings.to_writer(&bld)
fmt.wprintln(w, "package _weierstrass")
fmt.wprintln(w, "")
fmt.wprintln(w, GENERATED)
fmt.wprintln(w, "")
fmt.wprintln(w, "import \"core:crypto\"")
fmt.wprintln(w, "")
fmt.wprintln(w, "when crypto.COMPACT_IMPLS == false {")
fmt.wprintln(w, "\t@(private,rodata)")
fmt.wprintln(w, "\tGen_Multiply_Table_p256r1_hi := [32][15]Affine_Point_p256r1 {")
for &v, i in Multiply_Table_p256r1_hi {
fmt.wprintln(w, "\t\t{")
for &ap, j in v {
fmt.wprintln(w, "\t\t\t{")
x, y := &ap.x, &ap.y
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d},\n", x[0], x[1], x[2], x[3])
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d},\n", y[0], y[1], y[2], y[3])
fmt.wprintln(w, "\t\t\t},")
}
fmt.wprintln(w, "\t\t},")
}
fmt.wprintln(w, "\t}\n")
fmt.wprintln(w, "\t@(private,rodata)")
fmt.wprintln(w, "\tGen_Multiply_Table_p256r1_lo := [32][15]Affine_Point_p256r1 {")
for &v, i in Multiply_Table_p256r1_lo {
fmt.wprintln(w, "\t\t{")
for &ap, j in v {
fmt.wprintln(w, "\t\t\t{")
x, y := &ap.x, &ap.y
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d},\n", x[0], x[1], x[2], x[3])
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d},\n", y[0], y[1], y[2], y[3])
fmt.wprintln(w, "\t\t\t},")
}
fmt.wprintln(w, "\t\t},")
}
fmt.wprintln(w, "\t}")
fmt.wprintln(w, "}")
_ = os.write_entire_file(fn, transmute([]byte)(strings.to_string(bld)))
}

View File

@@ -5,6 +5,9 @@ import "base:runtime"
import subtle "core:crypto/_subtle"
import "core:mem"
// Omit large precomputed tables, trading off performance for size.
COMPACT_IMPLS: bool : #config(ODIN_CRYPTO_COMPACT, false)
// HAS_RAND_BYTES is true iff the runtime provides a cryptographic
// entropy source.
HAS_RAND_BYTES :: runtime.HAS_RAND_BYTES

View File

@@ -0,0 +1,486 @@
package test_core_crypto
import ec "core:crypto/_weierstrass"
import "core:encoding/hex"
import "core:math/big"
import "core:testing"
@(private="file")
P256_G_X :: "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"
@(private="file")
P256_G_Y :: "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
@(private="file")
P256_G_UNCOMPRESSED :: "04" + P256_G_X + P256_G_Y
@(test)
test_p256_a :: proc(t: ^testing.T) {
a_str := "ffffffff00000001000000000000000000000000fffffffffffffffffffffffc"
fe, a_fe: ec.Field_Element_p256r1
ec.fe_a(&fe)
ec.fe_a(&a_fe)
b: [32]byte
ec.fe_bytes(b[:], &fe)
s := (string)(hex.encode(b[:], context.temp_allocator))
testing.expect(t, s == a_str)
ec.fe_zero(&fe)
ec.fe_set_bytes(&fe, b[:])
testing.expect(t, ec.fe_equal(&fe, &a_fe) == 1)
}
@(test)
test_p256_b :: proc(t: ^testing.T) {
b_str := "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"
fe, b_fe: ec.Field_Element_p256r1
ec.fe_b(&fe)
ec.fe_b(&b_fe)
b: [32]byte
ec.fe_bytes(b[:], &fe)
s := (string)(hex.encode(b[:], context.temp_allocator))
testing.expect(t, s == b_str)
ec.fe_zero(&fe)
ec.fe_set_bytes(&fe, b[:])
testing.expect(t, ec.fe_equal(&fe, &b_fe) == 1)
}
@(test)
test_p256_g_x :: proc(t: ^testing.T) {
fe, x_fe: ec.Field_Element_p256r1
ec.fe_gen_x(&fe)
ec.fe_gen_x(&x_fe)
b: [32]byte
ec.fe_bytes(b[:], &fe)
s := (string)(hex.encode(b[:], context.temp_allocator))
testing.expect(t, s == P256_G_X)
ec.fe_zero(&fe)
ec.fe_set_bytes(&fe, b[:])
testing.expect(t, ec.fe_equal(&fe, &x_fe) == 1)
}
@(test)
test_p256_g_y :: proc(t: ^testing.T) {
fe, y_fe: ec.Field_Element_p256r1
ec.fe_gen_y(&fe)
ec.fe_gen_y(&y_fe)
b: [32]byte
ec.fe_bytes(b[:], &fe)
s := (string)(hex.encode(b[:], context.temp_allocator))
testing.expect(t, s == P256_G_Y)
ec.fe_zero(&fe)
ec.fe_set_bytes(&fe, b[:])
testing.expect(t, ec.fe_equal(&fe, &y_fe) == 1)
}
@(test)
test_p256_scalar_reduce :: proc(t: ^testing.T) {
test_vectors := []struct {
raw: string,
reduced: string,
} {
// n
{
"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
"0000000000000000000000000000000000000000000000000000000000000000",
},
// n + 1
{
"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552",
"0000000000000000000000000000000000000000000000000000000000000001",
},
// 2^384 (Sage)
{
"01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"431905529c0166ce652e96b7ccca0a99679b73e19ad16947f01cf013fc632551",
},
// SHA384 odin-linux-amd64-dev-2026-01.tar.gz (Sage)
{
"87622f79b4b0e76001f9c99b0337b61a0bcd2b5a8e9a3937176825ad75ef0fe8742a348a251dd2682d711f76b33df3e6",
"f66db86e28d903033d1e17d818c0eb13fe3d1ae095b4d2ecbcd1a1eccf9f2f8c",
},
// SHA512 odin-linux-amd64-dev-2026-01.tar.gz (Sage)
{
"6f85507cec3a35fdb3d4f40d23583681144561e77bc4ea88ab0ea219d5c17b7c9178f5f5a6296a2d18eddd4bdf19e61830fc85d7de23fd4fbde31c4cf6694719",
"3217ecbee32c8b0dfcca0f10a884fe43658fbe91458f25d0f1bf2075759c5ebe",
},
}
for v, _ in test_vectors {
raw_bytes, _ := hex.decode(transmute([]byte)(v.raw), context.temp_allocator)
sc: ec.Scalar_p256r1
_ = ec.sc_set_bytes(&sc, raw_bytes)
b: [ec.SC_SIZE_P256R1]byte
ec.sc_bytes(b[:], &sc)
s := (string)(hex.encode(b[:], context.temp_allocator))
testing.expectf(t, v.reduced == s, "sc: raw %s reduced: %s, expected: %s", v.raw, s, v.reduced)
}
}
@(test)
test_p256_scalar_mul :: proc(t: ^testing.T) {
test_vectors := []struct {
scalar: string, // NOTE: Base 10
x, y: string,
} {
// Test vectors from http://point-at-infinity.org/ecc/nisttv
{
"1",
"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
"4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
},
{
"2",
"7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978",
"07775510DB8ED040293D9AC69F7430DBBA7DADE63CE982299E04B79D227873D1",
},
{
"3",
"5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C",
"8734640C4998FF7E374B06CE1A64A2ECD82AB036384FB83D9A79B127A27D5032",
},
{
"4",
"E2534A3532D08FBBA02DDE659EE62BD0031FE2DB785596EF509302446B030852",
"E0F1575A4C633CC719DFEE5FDA862D764EFC96C3F30EE0055C42C23F184ED8C6",
},
{
"5",
"51590B7A515140D2D784C85608668FDFEF8C82FD1F5BE52421554A0DC3D033ED",
"E0C17DA8904A727D8AE1BF36BF8A79260D012F00D4D80888D1D0BB44FDA16DA4",
},
{
"6",
"B01A172A76A4602C92D3242CB897DDE3024C740DEBB215B4C6B0AAE93C2291A9",
"E85C10743237DAD56FEC0E2DFBA703791C00F7701C7E16BDFD7C48538FC77FE2",
},
{
"7",
"8E533B6FA0BF7B4625BB30667C01FB607EF9F8B8A80FEF5B300628703187B2A3",
"73EB1DBDE03318366D069F83A6F5900053C73633CB041B21C55E1A86C1F400B4",
},
{
"8",
"62D9779DBEE9B0534042742D3AB54CADC1D238980FCE97DBB4DD9DC1DB6FB393",
"AD5ACCBD91E9D8244FF15D771167CEE0A2ED51F6BBE76A78DA540A6A0F09957E",
},
{
"9",
"EA68D7B6FEDF0B71878938D51D71F8729E0ACB8C2C6DF8B3D79E8A4B90949EE0",
"2A2744C972C9FCE787014A964A8EA0C84D714FEAA4DE823FE85A224A4DD048FA",
},
{
"10",
"CEF66D6B2A3A993E591214D1EA223FB545CA6C471C48306E4C36069404C5723F",
"878662A229AAAE906E123CDD9D3B4C10590DED29FE751EEECA34BBAA44AF0773",
},
{
"11",
"3ED113B7883B4C590638379DB0C21CDA16742ED0255048BF433391D374BC21D1",
"9099209ACCC4C8A224C843AFA4F4C68A090D04DA5E9889DAE2F8EEFCE82A3740",
},
{
"12",
"741DD5BDA817D95E4626537320E5D55179983028B2F82C99D500C5EE8624E3C4",
"0770B46A9C385FDC567383554887B1548EEB912C35BA5CA71995FF22CD4481D3",
},
{
"13",
"177C837AE0AC495A61805DF2D85EE2FC792E284B65EAD58A98E15D9D46072C01",
"63BB58CD4EBEA558A24091ADB40F4E7226EE14C3A1FB4DF39C43BBE2EFC7BFD8",
},
{
"14",
"54E77A001C3862B97A76647F4336DF3CF126ACBE7A069C5E5709277324D2920B",
"F599F1BB29F4317542121F8C05A2E7C37171EA77735090081BA7C82F60D0B375",
},
{
"15",
"F0454DC6971ABAE7ADFB378999888265AE03AF92DE3A0EF163668C63E59B9D5F",
"B5B93EE3592E2D1F4E6594E51F9643E62A3B21CE75B5FA3F47E59CDE0D034F36",
},
{
"16",
"76A94D138A6B41858B821C629836315FCD28392EFF6CA038A5EB4787E1277C6E",
"A985FE61341F260E6CB0A1B5E11E87208599A0040FC78BAA0E9DDD724B8C5110",
},
{
"17",
"47776904C0F1CC3A9C0984B66F75301A5FA68678F0D64AF8BA1ABCE34738A73E",
"AA005EE6B5B957286231856577648E8381B2804428D5733F32F787FF71F1FCDC",
},
{
"18",
"1057E0AB5780F470DEFC9378D1C7C87437BB4C6F9EA55C63D936266DBD781FDA",
"F6F1645A15CBE5DC9FA9B7DFD96EE5A7DCC11B5C5EF4F1F78D83B3393C6A45A2",
},
{
"19",
"CB6D2861102C0C25CE39B7C17108C507782C452257884895C1FC7B74AB03ED83",
"58D7614B24D9EF515C35E7100D6D6CE4A496716E30FA3E03E39150752BCECDAA",
},
{
"20",
"83A01A9378395BAB9BCD6A0AD03CC56D56E6B19250465A94A234DC4C6B28DA9A",
"76E49B6DE2F73234AE6A5EB9D612B75C9F2202BB6923F54FF8240AAA86F640B8",
},
{
"112233445566778899",
"339150844EC15234807FE862A86BE77977DBFB3AE3D96F4C22795513AEAAB82F",
"B1C14DDFDC8EC1B2583F51E85A5EB3A155840F2034730E9B5ADA38B674336A21",
},
{
"112233445566778899112233445566778899",
"1B7E046A076CC25E6D7FA5003F6729F665CC3241B5ADAB12B498CD32F2803264",
"BFEA79BE2B666B073DB69A2A241ADAB0738FE9D2DD28B5604EB8C8CF097C457B",
},
{
"029852220098221261079183923314599206100666902414330245206392788703677545185283",
"9EACE8F4B071E677C5350B02F2BB2B384AAE89D58AA72CA97A170572E0FB222F",
"1BBDAEC2430B09B93F7CB08678636CE12EAAFD58390699B5FD2F6E1188FC2A78",
},
{
"057896042899961394862005778464643882389978449576758748073725983489954366354431",
"878F22CC6DB6048D2B767268F22FFAD8E56AB8E2DC615F7BD89F1E350500DD8D",
"714A5D7BB901C9C5853400D12341A892EF45D87FC553786756C4F0C9391D763E",
},
{
"57896042899961394862005778464643882389978449576758748073725983489954366354431",
"878F22CC6DB6048D2B767268F22FFAD8E56AB8E2DC615F7BD89F1E350500DD8D",
"714A5D7BB901C9C5853400D12341A892EF45D87FC553786756C4F0C9391D763E",
},
{
"1766845392945710151501889105729049882997660004824848915955419660366636031",
"659A379625AB122F2512B8DADA02C6348D53B54452DFF67AC7ACE4E8856295CA",
"49D81AB97B648464D0B4A288BD7818FAB41A16426E943527C4FED8736C53D0F6",
},
{
"28948025760307534517734791687894775804466072615242963443097661355606862201087",
"CBCEAAA8A4DD44BBCE58E8DB7740A5510EC2CB7EA8DA8D8F036B3FB04CDA4DE4",
"4BD7AA301A80D7F59FD983FEDBE59BB7B2863FE46494935E3745B360E32332FA",
},
{
"113078210460870548944811695960290644973229224625838436424477095834645696384",
"F0C4A0576154FF3A33A3460D42EAED806E854DFA37125221D37935124BA462A4",
"5B392FA964434D29EEC6C9DBC261CF116796864AA2FAADB984A2DF38D1AEF7A3",
},
{
"12078056106883488161242983286051341125085761470677906721917479268909056",
"5E6C8524B6369530B12C62D31EC53E0288173BD662BDF680B53A41ECBCAD00CC",
"447FE742C2BFEF4D0DB14B5B83A2682309B5618E0064A94804E9282179FE089F",
},
{
"57782969857385448082319957860328652998540760998293976083718804450708503920639",
"03792E541BC209076A3D7920A915021ECD396A6EB5C3960024BE5575F3223484",
"FC774AE092403101563B712F68170312304F20C80B40C06282063DB25F268DE4",
},
{
"57896017119460046759583662757090100341435943767777707906455551163257755533312",
"2379FF85AB693CDF901D6CE6F2473F39C04A2FE3DCD842CE7AAB0E002095BCF8",
"F8B476530A634589D5129E46F322B02FBC610A703D80875EE70D7CE1877436A1",
},
{
"452312848374287284681282171017647412726433684238464212999305864837160993279",
"C1E4072C529BF2F44DA769EFC934472848003B3AF2C0F5AA8F8DDBD53E12ED7C",
"39A6EE77812BB37E8079CD01ED649D3830FCA46F718C1D3993E4A591824ABCDB",
},
{
"904571339174065134293634407946054000774746055866917729876676367558469746684",
"34DFBC09404C21E250A9B40FA8772897AC63A094877DB65862B61BD1507B34F3",
"CF6F8A876C6F99CEAEC87148F18C7E1E0DA6E165FFC8ED82ABB65955215F77D3",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044349",
"83A01A9378395BAB9BCD6A0AD03CC56D56E6B19250465A94A234DC4C6B28DA9A",
"891B64911D08CDCC5195A14629ED48A360DDFD4596DC0AB007DBF5557909BF47",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044350",
"CB6D2861102C0C25CE39B7C17108C507782C452257884895C1FC7B74AB03ED83",
"A7289EB3DB2610AFA3CA18EFF292931B5B698E92CF05C1FC1C6EAF8AD4313255",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044351",
"1057E0AB5780F470DEFC9378D1C7C87437BB4C6F9EA55C63D936266DBD781FDA",
"090E9BA4EA341A246056482026911A58233EE4A4A10B0E08727C4CC6C395BA5D",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044352",
"47776904C0F1CC3A9C0984B66F75301A5FA68678F0D64AF8BA1ABCE34738A73E",
"55FFA1184A46A8D89DCE7A9A889B717C7E4D7FBCD72A8CC0CD0878008E0E0323",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044353",
"76A94D138A6B41858B821C629836315FCD28392EFF6CA038A5EB4787E1277C6E",
"567A019DCBE0D9F2934F5E4A1EE178DF7A665FFCF0387455F162228DB473AEEF",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044354",
"F0454DC6971ABAE7ADFB378999888265AE03AF92DE3A0EF163668C63E59B9D5F",
"4A46C11BA6D1D2E1B19A6B1AE069BC19D5C4DE328A4A05C0B81A6321F2FCB0C9",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044355",
"54E77A001C3862B97A76647F4336DF3CF126ACBE7A069C5E5709277324D2920B",
"0A660E43D60BCE8BBDEDE073FA5D183C8E8E15898CAF6FF7E45837D09F2F4C8A",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044356",
"177C837AE0AC495A61805DF2D85EE2FC792E284B65EAD58A98E15D9D46072C01",
"9C44A731B1415AA85DBF6E524BF0B18DD911EB3D5E04B20C63BC441D10384027",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044357",
"741DD5BDA817D95E4626537320E5D55179983028B2F82C99D500C5EE8624E3C4",
"F88F4B9463C7A024A98C7CAAB7784EAB71146ED4CA45A358E66A00DD32BB7E2C",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044358",
"3ED113B7883B4C590638379DB0C21CDA16742ED0255048BF433391D374BC21D1",
"6F66DF64333B375EDB37BC505B0B3975F6F2FB26A16776251D07110317D5C8BF",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044359",
"CEF66D6B2A3A993E591214D1EA223FB545CA6C471C48306E4C36069404C5723F",
"78799D5CD655517091EDC32262C4B3EFA6F212D7018AE11135CB4455BB50F88C",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044360",
"EA68D7B6FEDF0B71878938D51D71F8729E0ACB8C2C6DF8B3D79E8A4B90949EE0",
"D5D8BB358D36031978FEB569B5715F37B28EB0165B217DC017A5DDB5B22FB705",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044361",
"62D9779DBEE9B0534042742D3AB54CADC1D238980FCE97DBB4DD9DC1DB6FB393",
"52A533416E1627DCB00EA288EE98311F5D12AE0A4418958725ABF595F0F66A81",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044362",
"8E533B6FA0BF7B4625BB30667C01FB607EF9F8B8A80FEF5B300628703187B2A3",
"8C14E2411FCCE7CA92F9607C590A6FFFAC38C9CD34FBE4DE3AA1E5793E0BFF4B",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044363",
"B01A172A76A4602C92D3242CB897DDE3024C740DEBB215B4C6B0AAE93C2291A9",
"17A3EF8ACDC8252B9013F1D20458FC86E3FF0890E381E9420283B7AC7038801D",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044364",
"51590B7A515140D2D784C85608668FDFEF8C82FD1F5BE52421554A0DC3D033ED",
"1F3E82566FB58D83751E40C9407586D9F2FED1002B27F7772E2F44BB025E925B",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044365",
"E2534A3532D08FBBA02DDE659EE62BD0031FE2DB785596EF509302446B030852",
"1F0EA8A4B39CC339E62011A02579D289B103693D0CF11FFAA3BD3DC0E7B12739",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044366",
"5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C",
"78CB9BF2B6670082C8B4F931E59B5D1327D54FCAC7B047C265864ED85D82AFCD",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044367",
"7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978",
"F888AAEE24712FC0D6C26539608BCF244582521AC3167DD661FB4862DD878C2E",
},
{
"115792089210356248762697446949407573529996955224135760342422259061068512044368",
"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
"B01CBD1C01E58065711814B583F061E9D431CCA994CEA1313449BF97C840AE0A",
},
}
for v, _ in test_vectors {
x_bytes, _ := hex.decode(transmute([]byte)(v.x), context.temp_allocator)
y_bytes, _ := hex.decode(transmute([]byte)(v.y), context.temp_allocator)
k_big: big.Int
err := big.set(&k_big, v.scalar, 10, context.temp_allocator)
testing.expectf(t, err == nil, "failed to parse k", err)
k_sz: int
k_sz, err = big.int_to_bytes_size(&k_big, allocator = context.temp_allocator)
testing.expect(t, err == nil)
k_bytes := make([]byte, k_sz, context.temp_allocator)
err = big.int_to_bytes_big(&k_big, k_bytes, allocator = context.temp_allocator)
p, q, expected, g: ec.Point_p256r1
sc: ec.Scalar_p256r1
_ = ec.sc_set_bytes(&sc, k_bytes)
ec.pt_generator(&g)
ok := ec.pt_set_xy_bytes(&expected, x_bytes, y_bytes)
testing.expectf(t, ok, "failed to set point; %s, %s", v.x, v.y)
ec.pt_scalar_mul(&p, &g, &sc)
ec.pt_scalar_mul_generator(&q, &sc)
ec.pt_rescale(&p, &p)
ec.pt_rescale(&q, &q)
testing.expect(t, ec.pt_equal(&p, &q) == 1)
testing.expectf(t, ec.pt_equal(&p, &expected) == 1, "sc: %s actual: %v expected: %v", v.scalar, &p, &expected)
}
}
@(test)
test_p256_s11n_sec_identity ::proc(t: ^testing.T) {
p: ec.Point_p256r1
ec.pt_generator(&p)
ok := ec.pt_set_sec_bytes(&p, []byte{0x00})
testing.expect(t, ok)
testing.expectf(t, ec.pt_is_identity(&p) == 1, "%v", p)
b := []byte{0xff}
ok = ec.pt_sec_bytes(b, &p, true)
testing.expect(t, ok)
testing.expect(t, b[0] == 0x00)
b = []byte{0xff}
ok = ec.pt_sec_bytes(b, &p, false)
testing.expect(t, ok)
testing.expect(t, b[0] == 0x00)
}
@(test)
test_p256_s11n_sec_generator ::proc(t: ^testing.T) {
p, g: ec.Point_p256r1
ec.pt_generator(&g)
ec.pt_identity(&p)
b: [65]byte
ok := ec.pt_sec_bytes(b[:], &g, false)
testing.expect(t, ok)
s := (string)(hex.encode(b[:], context.temp_allocator))
testing.expectf(t, s == P256_G_UNCOMPRESSED, "g: %v bytes: %v, %v", g, P256_G_UNCOMPRESSED, s)
ok = ec.pt_set_sec_bytes(&p, b[:])
testing.expectf(t, ok, "%s", s)
testing.expect(t, ec.pt_equal(&g, &p) == 1)
}