core/crypto/_weierstrass: Add secp384r1

This commit is contained in:
Yawning Angel
2026-02-01 02:32:09 +09:00
parent bd0cfe4a81
commit 64ce2bdf0e
12 changed files with 9446 additions and 42 deletions

View File

@@ -0,0 +1,436 @@
package field_p384r1
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) == 48, "p384r1: invalid fe input buffer")
// Note: We assume the input is in big-endian.
tmp := Non_Montgomery_Domain_Field_Element {
endian.unchecked_get_u64be(arg1[40:]),
endian.unchecked_get_u64be(arg1[32:]),
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)
_, borrow = bits.sub_u64(ELL[4], tmp[4], borrow)
_, borrow = bits.sub_u64(ELL[5], tmp[5], 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) == 48, "p384r1: 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[40:], tmp[0])
endian.unchecked_put_u64be(out1[32:], tmp[1])
endian.unchecked_put_u64be(out1[24:], tmp[2])
endian.unchecked_put_u64be(out1[16:], tmp[3])
endian.unchecked_put_u64be(out1[8:], tmp[4])
endian.unchecked_put_u64be(out1[0:], tmp[5])
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
// x24 = x12 << 12 + x12
// x30 = x24 << 6 + _111111
// x31 = 2*x30 + 1
// x32 = 2*x31 + 1
// x63 = x32 << 31 + x31
// x126 = x63 << 63 + x63
// x252 = x126 << 126 + x126
// x255 = x252 << 3 + _111
// return ((x255 << 33 + x32) << 94 + x30) << 2
//
// Operations: 383 squares 14 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, t2, t3, 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: t1 = x^0x7
fe_mul(&t1, &xx, out1)
// Step 7: z = x^0x38
fe_pow2k(out1, &t1, 3)
// Step 8: z = x^0x3f
fe_mul(out1, &t1, out1)
// Step 14: t0 = x^0xfc0
fe_pow2k(&t0, out1, 6)
// Step 15: t0 = x^0xfff
fe_mul(&t0, out1, &t0)
// Step 27: t2 = x^0xfff000
fe_pow2k(&t2, &t0, 12)
// Step 28: t0 = x^0xffffff
fe_mul(&t0, &t0, &t2)
// Step 34: t0 = x^0x3fffffc0
fe_pow2k(&t0, &t0, 6)
// Step 35: z = x^0x3fffffff
fe_mul(out1, out1, &t0)
// Step 36: t0 = x^0x7ffffffe
fe_square(&t0, out1)
// Step 37: t2 = x^0x7fffffff
fe_mul(&t2, &xx, &t0)
// Step 38: t0 = x^0xfffffffe
fe_square(&t0, &t2)
// Step 39: t0 = x^0xffffffff
fe_mul(&t0, &xx, &t0)
// Step 70: t3 = x^0x7fffffff80000000
fe_pow2k(&t3, &t0, 31)
// Step 71: t2 = x^0x7fffffffffffffff
fe_mul(&t2, &t2, &t3)
// Step 134: t3 = x^0x3fffffffffffffff8000000000000000
fe_pow2k(&t3, &t2, 63)
// Step 135: t2 = x^0x3fffffffffffffffffffffffffffffff
fe_mul(&t2, &t2, &t3)
// Step 261: t3 = x^0xfffffffffffffffffffffffffffffffc0000000000000000000000000000000
fe_pow2k(&t3, &t2, 126)
// Step 262: t2 = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
fe_mul(&t2, &t2, &t3)
// Step 265: t2 = x^0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8
fe_pow2k(&t2, &t2, 3)
// Step 266: t1 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
fe_mul(&t1, &t1, &t2)
// Step 299: t1 = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00000000
fe_pow2k(&t1, &t1, 33)
// Step 300: t0 = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff
fe_mul(&t0, &t0, &t1)
// Step 394: t0 = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffc00000000000000000000000
fe_pow2k(&t0, &t0, 94)
// Step 395: z = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffc0000000000000003fffffff
fe_mul(out1, out1, &t0)
// Step 397: z = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc
fe_pow2k(out1, out1, 2)
fe_mul(out1, out1, &xx)
fe_clear_vec([]^Montgomery_Domain_Field_Element{&t0, &t1, &t2, &t3, &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: 9850501549098619803069760025035903451269934817616361666987073351061430442874217582261816522064734500465401743278080
//
// 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
// x24 = x12 << 12 + x12
// x30 = x24 << 6 + _111111
// x31 = 2*x30 + 1
// x32 = 2*x31 + 1
// x63 = x32 << 31 + x31
// x126 = x63 << 63 + x63
// x252 = x126 << 126 + x126
// x255 = x252 << 3 + _111
// return ((x255 << 33 + x32) << 94 + x30) << 2
//
// Operations: 383 squares 14 multiplies
//
// Generated by github.com/mmcloughlin/addchain v0.4.0.
// Likewise this tramples over arg1, so stash another copy.
t0, t1, t2, t3, 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: t1 = x^0x7
fe_mul(&t1, &xx, out1)
// Step 7: z = x^0x38
fe_pow2k(out1, &t1, 3)
// Step 8: z = x^0x3f
fe_mul(out1, &t1, out1)
// Step 14: t0 = x^0xfc0
fe_pow2k(&t0, out1, 6)
// Step 15: t0 = x^0xfff
fe_mul(&t0, out1, &t0)
// Step 27: t2 = x^0xfff000
fe_pow2k(&t2, &t0, 12)
// Step 28: t0 = x^0xffffff
fe_mul(&t0, &t0, &t2)
// Step 34: t0 = x^0x3fffffc0
fe_pow2k(&t0, &t0, 6)
// Step 35: z = x^0x3fffffff
fe_mul(out1, out1, &t0)
// Step 36: t0 = x^0x7ffffffe
fe_square(&t0, out1)
// Step 37: t2 = x^0x7fffffff
fe_mul(&t2, &xx, &t0)
// Step 38: t0 = x^0xfffffffe
fe_square(&t0, &t2)
// Step 39: t0 = x^0xffffffff
fe_mul(&t0, &xx, &t0)
// Step 70: t3 = x^0x7fffffff80000000
fe_pow2k(&t3, &t0, 31)
// Step 71: t2 = x^0x7fffffffffffffff
fe_mul(&t2, &t2, &t3)
// Step 134: t3 = x^0x3fffffffffffffff8000000000000000
fe_pow2k(&t3, &t2, 63)
// Step 135: t2 = x^0x3fffffffffffffffffffffffffffffff
fe_mul(&t2, &t2, &t3)
// Step 261: t3 = x^0xfffffffffffffffffffffffffffffffc0000000000000000000000000000000
fe_pow2k(&t3, &t2, 126)
// Step 262: t2 = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
fe_mul(&t2, &t2, &t3)
// Step 265: t2 = x^0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8
fe_pow2k(&t2, &t2, 3)
// Step 266: t1 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
fe_mul(&t1, &t1, &t2)
// Step 299: t1 = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00000000
fe_pow2k(&t1, &t1, 33)
// Step 300: t0 = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff
fe_mul(&t0, &t0, &t1)
// Step 394: t0 = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffc00000000000000000000000
fe_pow2k(&t0, &t0, 94)
// Step 395: z = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffc0000000000000003fffffff
fe_mul(out1, out1, &t0)
// Step 397: z = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc
fe_pow2k(out1, out1, 2)
// 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, &t1, &t2, &t3, &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
out1[4] = 0
out1[5] = 0
}
fe_set :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) {
x1 := arg1[0]
x2 := arg1[1]
x3 := arg1[2]
x4 := arg1[3]
x5 := arg1[4]
x6 := arg1[5]
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
out1[4] = x5
out1[5] = x6
}
@(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
x = (out1[4] ~ out2[4]) & mask
x5, y5 := out1[4] ~ x, out2[4] ~ x
x = (out1[5] ~ out2[5]) & mask
x6, y6 := out1[5] ~ x, out2[5] ~ 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
out1[4], out2[4] = x5, y5
out1[5], out2[5] = x6, y6
}
@(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]))
x5 := ((mask & arg2[4]) | ((~mask) & arg1[4]))
x6 := ((mask & arg2[5]) | ((~mask) & arg1[5]))
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
out1[4] = x5
out1[5] = x6
}
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)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,239 @@
package field_scalarp384r1
import subtle "core:crypto/_subtle"
import "core:encoding/endian"
import "core:math/bits"
import "core:mem"
@(private, rodata)
TWO_256 := Montgomery_Domain_Field_Element{
17975668497346362272,
12895982994901192340,
1913828944324294218,
902107514168524577,
1374695839762142861,
12098342389602539653,
}
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, "p384r1: invalid scalar input buffer")
is_canonical := false
s_len := len(arg1)
switch {
case s_len < 48:
// No way this can be greater than the order.
fe_unchecked_set(out1, arg1)
is_canonical = true
case s_len == 48:
// There is no way for any 384-bit value to be >= 2n, so
// the reduction can be done by `src - n` and a conditional
// select based on the underflow.
//
// It is *extremely* unlikely that the reduction is actually
// needed.
tmp: Non_Montgomery_Domain_Field_Element = ---
fe_unchecked_set_saturated(&tmp, arg1)
reduced := tmp
defer mem.zero_explicit(&tmp, size_of(tmp))
defer mem.zero_explicit(&reduced, size_of(reduced))
borrow: u64
reduced[0], borrow = bits.sub_u64(tmp[0], ELL[0], borrow)
reduced[1], borrow = bits.sub_u64(tmp[1], ELL[1], borrow)
reduced[2], borrow = bits.sub_u64(tmp[2], ELL[2], borrow)
reduced[3], borrow = bits.sub_u64(tmp[3], ELL[3], borrow)
reduced[4], borrow = bits.sub_u64(tmp[4], ELL[4], borrow)
reduced[5], borrow = bits.sub_u64(tmp[5], ELL[5], borrow)
need_reduced := subtle.u64_is_zero(borrow)
fe_cond_select(&tmp, &tmp, &reduced, int(need_reduced))
fe_to_montgomery(out1, &tmp)
is_canonical = need_reduced == 0
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"
//
// Since digests beyond 512-bits are unrealistic, we do
// "a+b*2^256"
// 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[32:]) // a
b: Montgomery_Domain_Field_Element
fe_unchecked_set(&b, src_512[:32]) // b
fe_mul(&b, &b, &TWO_256)
fe_add(out1, out1, &b)
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[40:]), 0)
_, borrow = bits.sub_u64(ELL[1], endian.unchecked_get_u64be(arg1[32:]), borrow)
_, borrow = bits.sub_u64(ELL[2], endian.unchecked_get_u64be(arg1[24:]), borrow)
_, borrow = bits.sub_u64(ELL[3], endian.unchecked_get_u64be(arg1[16:]), borrow)
_, borrow = bits.sub_u64(ELL[4], endian.unchecked_get_u64be(arg1[8:]), borrow)
_, borrow = bits.sub_u64(ELL[5], endian.unchecked_get_u64be(arg1[0:]), borrow)
return borrow == 0
}
@(private="file")
fe_unchecked_set_saturated :: proc "contextless" (out1: ^Non_Montgomery_Domain_Field_Element, arg1: []byte) {
out1[0] = endian.unchecked_get_u64be(arg1[40:])
out1[1] = endian.unchecked_get_u64be(arg1[32:])
out1[2] = endian.unchecked_get_u64be(arg1[24:])
out1[3] = endian.unchecked_get_u64be(arg1[16:])
out1[4] = endian.unchecked_get_u64be(arg1[8:])
out1[5] = endian.unchecked_get_u64be(arg1[0:])
}
@(private)
fe_unchecked_set :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element, arg1: []byte) {
arg1_384: [48]byte
defer mem.zero_explicit(&arg1_384, size_of(arg1_384))
copy(arg1_384[48-len(arg1):], arg1)
tmp: Non_Montgomery_Domain_Field_Element = ---
fe_unchecked_set_saturated(&tmp, arg1_384[:])
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) == 48, "p384r1: 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[40:], tmp[0])
endian.unchecked_put_u64be(out1[32:], tmp[1])
endian.unchecked_put_u64be(out1[24:], tmp[2])
endian.unchecked_put_u64be(out1[16:], tmp[3])
endian.unchecked_put_u64be(out1[8:], tmp[4])
endian.unchecked_put_u64be(out1[0:], tmp[5])
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
out1[4] = 0
out1[5] = 0
}
fe_set :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) {
x1 := arg1[0]
x2 := arg1[1]
x3 := arg1[2]
x4 := arg1[3]
x5 := arg1[4]
x6 := arg1[5]
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
out1[4] = x5
out1[5] = x6
}
@(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
x = (out1[4] ~ out2[4]) & mask
x5, y5 := out1[4] ~ x, out2[4] ~ x
x = (out1[5] ~ out2[5]) & mask
x6, y6 := out1[5] ~ x, out2[5] ~ 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
out1[4], out2[4] = x5, y5
out1[5], out2[5] = x6, y6
}
@(optimization_mode = "none")
fe_cond_select :: #force_no_inline proc "contextless" (
out1, arg1, arg2: ^$T,
arg3: int,
) where T == Montgomery_Domain_Field_Element || T == Non_Montgomery_Domain_Field_Element {
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]))
x5 := ((mask & arg2[4]) | ((~mask) & arg1[4]))
x6 := ((mask & arg2[5]) | ((~mask) & arg1[5]))
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
out1[4] = x5
out1[5] = x6
}
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)
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,97 +1,123 @@
package _weierstrass
import p256r1 "core:crypto/_fiat/field_p256r1"
import "core:math/bits"
import p384r1 "core:crypto/_fiat/field_p384r1"
import subtle "core:crypto/_subtle"
Field_Element_p256r1 :: p256r1.Montgomery_Domain_Field_Element
Field_Element_p384r1 :: p384r1.Montgomery_Domain_Field_Element
FE_SIZE_P256R1 :: 32
FE_SIZE_P384R1 :: 48
fe_clear :: proc {
p256r1.fe_clear,
p384r1.fe_clear,
}
fe_clear_vec :: proc {
p256r1.fe_clear_vec,
p384r1.fe_clear_vec,
}
fe_set_bytes :: proc {
p256r1.fe_from_bytes,
p384r1.fe_from_bytes,
}
fe_bytes :: proc {
p256r1.fe_to_bytes,
p384r1.fe_to_bytes,
}
fe_set :: proc {
p256r1.fe_set,
p384r1.fe_set,
}
fe_zero :: proc {
p256r1.fe_zero,
p384r1.fe_zero,
}
fe_a :: proc {
fe_a_p256r1,
fe_a_p384r1,
}
fe_b :: proc {
fe_b_p256r1,
fe_b_p384r1,
}
fe_gen_x :: proc {
fe_gen_x_p256r1,
fe_gen_x_p384r1,
}
fe_gen_y :: proc {
fe_gen_y_p256r1,
fe_gen_y_p384r1,
}
fe_one :: proc {
p256r1.fe_one,
p384r1.fe_one,
}
fe_add :: proc {
p256r1.fe_add,
p384r1.fe_add,
}
fe_sub :: proc {
p256r1.fe_sub,
p384r1.fe_sub,
}
fe_negate :: proc {
p256r1.fe_opp,
p384r1.fe_opp,
}
fe_mul :: proc {
p256r1.fe_mul,
p384r1.fe_mul,
}
fe_square :: proc {
p256r1.fe_square,
p384r1.fe_square,
}
fe_inv :: proc {
p256r1.fe_inv,
p384r1.fe_inv,
}
fe_sqrt :: proc {
p256r1.fe_sqrt,
p384r1.fe_sqrt,
}
fe_equal :: proc {
p256r1.fe_equal,
p384r1.fe_equal,
}
fe_is_odd :: proc {
p256r1.fe_is_odd,
p384r1.fe_is_odd,
}
fe_is_zero :: proc {
fe_is_zero_p256r1,
fe_is_zero_p384r1,
}
fe_cond_select :: proc {
p256r1.fe_cond_select,
p384r1.fe_cond_select,
}
fe_a_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) {
@@ -127,9 +153,53 @@ fe_gen_y_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) {
fe[3] = 9615747158586711429
}
fe_a_p384r1 :: proc "contextless" (fe: ^Field_Element_p384r1) {
// a = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc
// = -3 mod p
fe[0] = 17179869180
fe[1] = 18446744056529682432
fe[2] = 18446744073709551611
fe[3] = 18446744073709551615
fe[4] = 18446744073709551615
fe[5] = 18446744073709551615
}
fe_b_p384r1 :: proc "contextless" (fe: ^Field_Element_p384r1) {
// b = 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef
fe[0] = 581395848458481100
fe[1] = 17809957346689692396
fe[2] = 8643006485390950958
fe[3] = 16372638458395724514
fe[4] = 13126622871277412500
fe[5] = 14774077593024970745
}
fe_gen_x_p384r1 :: proc "contextless" (fe: ^Field_Element_p384r1) {
// G_x = 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7
fe[0] = 4454189113653900584
fe[1] = 2369870743683386936
fe[2] = 9771750146904378734
fe[3] = 7229551204834152191
fe[4] = 9308930686126579243
fe[5] = 5564951339003155731
}
fe_gen_y_p384r1 :: proc "contextless" (fe: ^Field_Element_p384r1) {
// G_y = 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f
fe[0] = 2523209505731486974
fe[1] = 11655219901025790380
fe[2] = 10064955099576512592
fe[3] = 14322381509056856025
fe[4] = 15960759442596276288
fe[5] = 3132442392059561449
}
@(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)
return int(subtle.u64_is_zero(p256r1.fe_non_zero(fe)))
}
@(require_results)
fe_is_zero_p384r1 :: proc "contextless" (fe: ^Field_Element_p384r1) -> int {
return int(subtle.u64_is_zero(p384r1.fe_non_zero(fe)))
}

View File

@@ -26,12 +26,22 @@ Point_p256r1 :: struct {
z: Field_Element_p256r1,
}
Point_p384r1 :: struct {
x: Field_Element_p384r1,
y: Field_Element_p384r1,
z: Field_Element_p384r1,
}
@(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 when T == Point_p384r1 {
FE_SZ :: FE_SIZE_P384R1
x, y: Field_Element_p384r1
defer fe_clear_vec([]^Field_Element_p384r1{&x, &y})
} else {
#panic("weierstrass: invalid curve")
}
@@ -63,6 +73,10 @@ pt_set_x_bytes :: proc "contextless" (p: ^$T, x_raw: []byte, y_is_odd: int) -> b
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 when T == Point_p384r1 {
FE_SZ :: FE_SIZE_P384R1
x, y, yy, y_neg: Field_Element_p384r1
defer fe_clear_vec([]^Field_Element_p384r1{&x, &y, &yy, &y_neg})
} else {
#panic("weierstrass: invalid curve")
}
@@ -94,6 +108,8 @@ pt_set_x_bytes :: proc "contextless" (p: ^$T, x_raw: []byte, y_is_odd: int) -> b
pt_bytes :: proc "contextless" (x, y: []byte, p: ^$T) -> bool {
when T == Point_p256r1 {
FE_SZ :: FE_SIZE_P256R1
} else when T == Point_p384r1 {
FE_SZ :: FE_SIZE_P384R1
} else {
#panic("weierstrass: invalid curve")
}
@@ -166,6 +182,10 @@ pt_add :: proc "contextless" (p, a, b: ^$T) {
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 when T == Point_p384r1 {
t0, t1, t2, t3, t4, b_fe: Field_Element_p384r1
x3, y3, z3: Field_Element_p384r1
defer fe_clear_vec([]^Field_Element_p384r1{&t0, &t1, &t2, &t3, &t4, &x3, &y3, &z3})
} else {
#panic("weierstrass: invalid curve")
}
@@ -270,6 +290,10 @@ pt_add_mixed :: proc "contextless" (p, a: ^$T, x2, y2: ^$U) {
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 when T == Point_p384r1 {
t0, t1, t2, t3, t4, b_fe: Field_Element_p384r1
x3, y3, z3: Field_Element_p384r1
defer fe_clear_vec([]^Field_Element_p384r1{&t0, &t1, &t2, &t3, &t4, &x3, &y3, &z3})
} else {
#panic("weierstrass: invalid curve")
}
@@ -357,6 +381,10 @@ pt_double :: proc "contextless" (p, a: ^$T) {
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 when T == Point_p384r1 {
t0, t1, t2, t3, b_fe: Field_Element_p384r1
x3, y3, z3: Field_Element_p384r1
defer fe_clear_vec([]^Field_Element_p384r1{&t0, &t1, &t2, &t3, &x3, &y3, &z3})
} else {
#panic("weierstrass: invalid curve")
}
@@ -459,6 +487,8 @@ pt_rescale :: proc "contextless" (p, a: ^$T) {
when T == Point_p256r1 {
z_inv: Field_Element_p256r1
} else when T == Point_p384r1 {
z_inv: Field_Element_p384r1
} else {
#panic("weierstrass: invalid curve")
}
@@ -485,6 +515,8 @@ pt_cond_select :: proc "contextless" (p, a, b: ^$T, ctrl: int) {
pt_equal :: proc "contextless" (a, b: ^$T) -> int {
when T == Point_p256r1 {
x1z2, x2z1, y1z2, y2z1: Field_Element_p256r1
} else when T == Point_p384r1 {
x1z2, x2z1, y1z2, y2z1: Field_Element_p384r1
} else {
#panic("weierstrass: invalid curve")
}

View File

@@ -14,6 +14,8 @@ SEC_PREFIX_UNCOMPRESSED :: 0x04
pt_set_sec_bytes :: proc "contextless" (p: ^$T, b: []byte) -> bool {
when T == Point_p256r1 {
FE_SZ :: FE_SIZE_P256R1
} else when T == Point_p384r1 {
FE_SZ :: FE_SIZE_P384R1
} else {
#panic("weierstrass: invalid curve")
}
@@ -51,6 +53,8 @@ pt_set_sec_bytes :: proc "contextless" (p: ^$T, b: []byte) -> bool {
pt_sec_bytes :: proc "contextless" (b: []byte, p: ^$T, compressed: bool) -> bool {
when T == Point_p256r1 {
FE_SZ :: FE_SIZE_P256R1
} else when T == Point_p384r1 {
FE_SZ :: FE_SIZE_P384R1
} else {
#panic("weierstrass: invalid curve")
}

View File

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

View File

@@ -1,8 +1,8 @@
package _weierstrass
import "core:crypto"
import subtle "core:crypto/_subtle"
import "core:mem"
@(require) import subtle "core:crypto/_subtle"
@(require) import "core:mem"
pt_scalar_mul :: proc "contextless" (
p, a: ^$T,
@@ -11,6 +11,8 @@ pt_scalar_mul :: proc "contextless" (
) {
when T == Point_p256r1 && S == Scalar_p256r1 {
SC_SZ :: SC_SIZE_P256R1
} else when T == Point_p384r1 && S == Scalar_p384r1 {
SC_SZ :: SC_SIZE_P384R1
} else {
#panic("weierstrass: invalid curve")
}
@@ -34,6 +36,10 @@ pt_scalar_mul_bytes :: proc "contextless" (
p_tbl: Multiply_Table_p256r1 = ---
q, tmp: Point_p256r1 = ---, ---
SC_SZ :: SC_SIZE_P256R1
} else when T == Point_p384r1 {
p_tbl: Multiply_Table_p384r1 = ---
q, tmp: Point_p384r1 = ---, ---
SC_SZ :: SC_SIZE_P384R1
} else {
#panic("weierstrass: invalid curve")
}
@@ -90,6 +96,11 @@ when crypto.COMPACT_IMPLS == true {
p_tbl_lo := &Gen_Multiply_Table_p256r1_lo
tmp: Point_p256r1 = ---
SC_SZ :: SC_SIZE_P256R1
} else when T == Point_p384r1 && S == Scalar_p384r1 {
p_tbl_hi := &Gen_Multiply_Table_p384r1_hi
p_tbl_lo := &Gen_Multiply_Table_p384r1_lo
tmp: Point_p384r1 = ---
SC_SZ :: SC_SIZE_P384R1
} else {
#panic("weierstrass: invalid curve")
}
@@ -113,6 +124,8 @@ when crypto.COMPACT_IMPLS == true {
@(private="file")
Multiply_Table_p256r1 :: [15]Point_p256r1
@(private="file")
Multiply_Table_p384r1 :: [15]Point_p384r1
@(private="file")
mul_tbl_set :: proc "contextless"(
@@ -122,11 +135,13 @@ mul_tbl_set :: proc "contextless"(
) {
when T == Multiply_Table_p256r1 && U == Point_p256r1{
tmp: Point_p256r1
pt_set(&tmp, point)
} else when T == Multiply_Table_p384r1 && U == Point_p384r1{
tmp: Point_p384r1
} else {
#panic("weierstrass: invalid curve")
}
pt_set(&tmp, point)
pt_set(&tbl[0], &tmp)
for i in 1 ..<15 {
pt_add(&tmp, &tmp, point)
@@ -170,6 +185,12 @@ when crypto.COMPACT_IMPLS == false {
y: Field_Element_p256r1,
}
@(private)
Affine_Point_p384r1 :: struct {
x: Field_Element_p384r1,
y: Field_Element_p384r1,
}
@(private="file")
mul_affine_tbl_lookup_add :: proc "contextless" (
point, tmp: ^$T,

File diff suppressed because it is too large Load Diff

View File

@@ -13,41 +13,62 @@ GENERATED :: `/*
*/`
main :: proc() {
gen_p256r1_tables()
gen_tables("p256r1")
gen_tables("p384r1")
}
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
gen_tables :: proc($CURVE: string) {
when CURVE == "p256r1" {
Affine_Point_p256r1 :: struct {
x: secec.Field_Element_p256r1,
y: secec.Field_Element_p256r1,
}
Multiply_Table_hi: [32][15]Affine_Point_p256r1
Multiply_Table_lo: [32][15]Affine_Point_p256r1
SC_LEN :: 32
g, p: secec.Point_p256r1
} else when CURVE == "p384r1" {
Affine_Point_p384r1 :: struct {
x: secec.Field_Element_p384r1,
y: secec.Field_Element_p384r1,
}
Multiply_Table_hi: [48][15]Affine_Point_p384r1
Multiply_Table_lo: [48][15]Affine_Point_p384r1
SC_LEN :: 48
g, p: secec.Point_p384r1
} else {
#panic("weistrass/tools: invalid curve")
}
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 i in 0..<SC_LEN {
b: [SC_LEN]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)
secec.fe_set(&Multiply_Table_hi[i][j-1].x, &p.x)
secec.fe_set(&Multiply_Table_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)
secec.fe_set(&Multiply_Table_lo[i][j-1].x, &p.x)
secec.fe_set(&Multiply_Table_lo[i][j-1].y, &p.y)
b[i] = 0
}
}
fn := path.join({ODIN_ROOT, "core", "crypto", "_weierstrass", "secp256r1_table.odin"})
fn_ := "sec" + CURVE + "_table.odin"
fn := path.join({ODIN_ROOT, "core", "crypto", "_weierstrass", fn_})
bld: strings.Builder
w := strings.to_writer(&bld)
@@ -60,15 +81,20 @@ gen_p256r1_tables :: proc() {
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.wprintf(w, "\tGen_Multiply_Table_%s_hi := [%d][15]Affine_Point_%s {{\n", CURVE, SC_LEN, CURVE)
for &v, i in Multiply_Table_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])
when CURVE == "p256r1" {
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])
} else when CURVE == "p384r1" {
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d, %d},\n", x[0], x[1], x[2], x[3], x[4], x[5])
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d, %d},\n", y[0], y[1], y[2], y[3], y[4], y[5])
}
fmt.wprintln(w, "\t\t\t},")
}
@@ -77,15 +103,20 @@ gen_p256r1_tables :: proc() {
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.wprintf(w, "\tGen_Multiply_Table_%s_lo := [%d][15]Affine_Point_%s {{\n", CURVE, SC_LEN, CURVE)
for &v, i in Multiply_Table_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])
when CURVE == "p256r1" {
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])
} else when CURVE == "p384r1" {
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d, %d},\n", x[0], x[1], x[2], x[3], x[4], x[5])
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d, %d},\n", y[0], y[1], y[2], y[3], y[4], y[5])
}
fmt.wprintln(w, "\t\t\t},")
}

View File

@@ -6,13 +6,17 @@ import "core:math/big"
import "core:testing"
@(private="file")
P256_G_X :: "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"
P256_G_X : string : "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"
@(private="file")
P256_G_Y :: "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
P256_G_Y : string : "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
@(private="file")
P256_G_UNCOMPRESSED :: "04" + P256_G_X + P256_G_Y
@(private="file")
P384_G_X : string : "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7"
@(private="file")
P384_G_Y : string : "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"
@(test)
test_p256_a :: proc(t: ^testing.T) {
a_str := "ffffffff00000001000000000000000000000000fffffffffffffffffffffffc"
@@ -28,10 +32,32 @@ test_p256_a :: proc(t: ^testing.T) {
testing.expect(t, s == a_str)
b_, _ := hex.decode(transmute([]byte)(a_str), context.temp_allocator)
ec.fe_zero(&fe)
ec.fe_set_bytes(&fe, b[:])
ec.fe_set_bytes(&fe, b_)
testing.expect(t, ec.fe_equal(&fe, &a_fe) == 1)
testing.expectf(t, ec.fe_equal(&fe, &a_fe) == 1, "%v", &fe)
}
@(test)
test_p384_a :: proc(t: ^testing.T) {
a_str := "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc"
fe, a_fe: ec.Field_Element_p384r1
ec.fe_a(&fe)
ec.fe_a(&a_fe)
b: [48]byte
ec.fe_bytes(b[:], &fe)
s := (string)(hex.encode(b[:], context.temp_allocator))
testing.expect(t, s == a_str)
b_, _ := hex.decode(transmute([]byte)(a_str), context.temp_allocator)
ec.fe_zero(&fe)
ec.fe_set_bytes(&fe, b_)
testing.expectf(t, ec.fe_equal(&fe, &a_fe) == 1, "%v", &fe)
}
@(test)
@@ -49,10 +75,32 @@ test_p256_b :: proc(t: ^testing.T) {
testing.expect(t, s == b_str)
b_, _ := hex.decode(transmute([]byte)(b_str), context.temp_allocator)
ec.fe_zero(&fe)
ec.fe_set_bytes(&fe, b[:])
ec.fe_set_bytes(&fe, b_)
testing.expect(t, ec.fe_equal(&fe, &b_fe) == 1)
testing.expectf(t, ec.fe_equal(&fe, &b_fe) == 1, "%v", &fe)
}
@(test)
test_p384_b :: proc(t: ^testing.T) {
b_str := "b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef"
fe, b_fe: ec.Field_Element_p384r1
ec.fe_b(&fe)
ec.fe_b(&b_fe)
b: [48]byte
ec.fe_bytes(b[:], &fe)
s := (string)(hex.encode(b[:], context.temp_allocator))
testing.expect(t, s == b_str)
b_, _ := hex.decode(transmute([]byte)(b_str), context.temp_allocator)
ec.fe_zero(&fe)
ec.fe_set_bytes(&fe, b_)
testing.expectf(t, ec.fe_equal(&fe, &b_fe) == 1, "%v", &fe)
}
@(test)
@@ -67,10 +115,30 @@ test_p256_g_x :: proc(t: ^testing.T) {
s := (string)(hex.encode(b[:], context.temp_allocator))
testing.expect(t, s == P256_G_X)
b_, _ := hex.decode(transmute([]byte)(P256_G_X), context.temp_allocator)
ec.fe_zero(&fe)
ec.fe_set_bytes(&fe, b[:])
ec.fe_set_bytes(&fe, b_)
testing.expect(t, ec.fe_equal(&fe, &x_fe) == 1)
testing.expectf(t, ec.fe_equal(&fe, &x_fe) == 1, "%v", &fe)
}
@(test)
test_p384_g_x :: proc(t: ^testing.T) {
fe, x_fe: ec.Field_Element_p384r1
ec.fe_gen_x(&fe)
ec.fe_gen_x(&x_fe)
b: [48]byte
ec.fe_bytes(b[:], &fe)
s := (string)(hex.encode(b[:], context.temp_allocator))
testing.expect(t, s == P384_G_X)
b_, _ := hex.decode(transmute([]byte)(P384_G_X), context.temp_allocator)
ec.fe_zero(&fe)
ec.fe_set_bytes(&fe, b_)
testing.expectf(t, ec.fe_equal(&fe, &x_fe) == 1, "%v", &fe)
}
@(test)
@@ -85,10 +153,30 @@ test_p256_g_y :: proc(t: ^testing.T) {
s := (string)(hex.encode(b[:], context.temp_allocator))
testing.expect(t, s == P256_G_Y)
b_, _ := hex.decode(transmute([]byte)(P256_G_Y), context.temp_allocator)
ec.fe_zero(&fe)
ec.fe_set_bytes(&fe, b[:])
ec.fe_set_bytes(&fe, b_)
testing.expect(t, ec.fe_equal(&fe, &y_fe) == 1)
testing.expectf(t, ec.fe_equal(&fe, &y_fe) == 1, "%v", &fe)
}
@(test)
test_p384_g_y :: proc(t: ^testing.T) {
fe, y_fe: ec.Field_Element_p384r1
ec.fe_gen_y(&fe)
ec.fe_gen_y(&y_fe)
b: [48]byte
ec.fe_bytes(b[:], &fe)
s := (string)(hex.encode(b[:], context.temp_allocator))
testing.expect(t, s == P384_G_Y)
b_, _ := hex.decode(transmute([]byte)(P384_G_Y), context.temp_allocator)
ec.fe_zero(&fe)
ec.fe_set_bytes(&fe, b_)
testing.expectf(t, ec.fe_equal(&fe, &y_fe) == 1, "%v", &fe)
}
@(test)
@@ -138,6 +226,48 @@ test_p256_scalar_reduce :: proc(t: ^testing.T) {
}
}
@(test)
test_p384_scalar_reduce :: proc(t: ^testing.T) {
test_vectors := []struct {
raw: string,
reduced: string,
} {
// n
{
"ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973",
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
},
// n + 1
{
"ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52974",
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
},
// SHA384 odin-linux-amd64-dev-2026-01.tar.gz
{
"87622f79b4b0e76001f9c99b0337b61a0bcd2b5a8e9a3937176825ad75ef0fe8742a348a251dd2682d711f76b33df3e6",
"87622f79b4b0e76001f9c99b0337b61a0bcd2b5a8e9a3937176825ad75ef0fe8742a348a251dd2682d711f76b33df3e6",
},
// SHA512 odin-linux-amd64-dev-2026-01.tar.gz (Sage)
{
"6f85507cec3a35fdb3d4f40d23583681144561e77bc4ea88ab0ea219d5c17b7c9178f5f5a6296a2d18eddd4bdf19e61830fc85d7de23fd4fbde31c4cf6694719",
"144561e77bc4ea88c3b80eb3d044daa78b2dd5878dca766578e9c1aad3dba0d211ec862c36d2a7412917b70237c92226",
},
}
for v, _ in test_vectors {
raw_bytes, _ := hex.decode(transmute([]byte)(v.raw), context.temp_allocator)
sc: ec.Scalar_p384r1
_ = ec.sc_set_bytes(&sc, raw_bytes)
b: [ec.SC_SIZE_P384R1]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 (%v), expected: %s", v.raw, s, &sc, v.reduced)
}
}
@(test)
test_p256_scalar_mul :: proc(t: ^testing.T) {
test_vectors := []struct {
@@ -447,6 +577,309 @@ test_p256_scalar_mul :: proc(t: ^testing.T) {
}
}
@(test)
test_p384_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",
"AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
"3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
},
{
"2",
"08D999057BA3D2D969260045C55B97F089025959A6F434D651D207D19FB96E9E4FE0E86EBE0E64F85B96A9C75295DF61",
"8E80F1FA5B1B3CEDB7BFE8DFFD6DBA74B275D875BC6CC43E904E505F256AB4255FFD43E94D39E22D61501E700A940E80",
},
{
"3",
"077A41D4606FFA1464793C7E5FDC7D98CB9D3910202DCD06BEA4F240D3566DA6B408BBAE5026580D02D7E5C70500C831",
"C995F7CA0B0C42837D0BBE9602A9FC998520B41C85115AA5F7684C0EDC111EACC24ABD6BE4B5D298B65F28600A2F1DF1",
},
{
"4",
"138251CD52AC9298C1C8AAD977321DEB97E709BD0B4CA0ACA55DC8AD51DCFC9D1589A1597E3A5120E1EFD631C63E1835",
"CACAE29869A62E1631E8A28181AB56616DC45D918ABC09F3AB0E63CF792AA4DCED7387BE37BBA569549F1C02B270ED67",
},
{
"5",
"11DE24A2C251C777573CAC5EA025E467F208E51DBFF98FC54F6661CBE56583B037882F4A1CA297E60ABCDBC3836D84BC",
"8FA696C77440F92D0F5837E90A00E7C5284B447754D5DEE88C986533B6901AEB3177686D0AE8FB33184414ABE6C1713A",
},
{
"6",
"627BE1ACD064D2B2226FE0D26F2D15D3C33EBCBB7F0F5DA51CBD41F26257383021317D7202FF30E50937F0854E35C5DF",
"09766A4CB3F8B1C21BE6DDA6C14F1575B2C95352644F774C99864F613715441604C45B8D84E165311733A408D3F0F934",
},
{
"7",
"283C1D7365CE4788F29F8EBF234EDFFEAD6FE997FBEA5FFA2D58CC9DFA7B1C508B05526F55B9EBB2040F05B48FB6D0E1",
"9475C99061E41B88BA52EFDB8C1690471A61D867ED799729D9C92CD01DBD225630D84EDE32A78F9E64664CDAC512EF8C",
},
{
"8",
"1692778EA596E0BE75114297A6FA383445BF227FBE58190A900C3C73256F11FB5A3258D6F403D5ECE6E9B269D822C87D",
"DCD2365700D4106A835388BA3DB8FD0E22554ADC6D521CD4BD1C30C2EC0EEC196BADE1E9CDD1708D6F6ABFA4022B0AD2",
},
{
"9",
"8F0A39A4049BCB3EF1BF29B8B025B78F2216F7291E6FD3BAC6CB1EE285FB6E21C388528BFEE2B9535C55E4461079118B",
"62C77E1438B601D6452C4A5322C3A9799A9B3D7CA3C400C6B7678854AED9B3029E743EFEDFD51B68262DA4F9AC664AF8",
},
{
"10",
"A669C5563BD67EEC678D29D6EF4FDE864F372D90B79B9E88931D5C29291238CCED8E85AB507BF91AA9CB2D13186658FB",
"A988B72AE7C1279F22D9083DB5F0ECDDF70119550C183C31C502DF78C3B705A8296D8195248288D997784F6AB73A21DD",
},
{
"11",
"099056E27DA7B998DA1EEEC2904816C57FE935ED5837C37456C9FD14892D3F8C4749B66E3AFB81D626356F3B55B4DDD8",
"2E4C0C234E30AB96688505544AC5E0396FC4EED8DFC363FD43FF93F41B52A3255466D51263AAFF357D5DBA8138C5E0BB",
},
{
"12",
"952A7A349BD49289AB3AC421DCF683D08C2ED5E41F6D0E21648AF2691A481406DA4A5E22DA817CB466DA2EA77D2A7022",
"A0320FAF84B5BC0563052DEAE6F66F2E09FB8036CE18A0EBB9028B096196B50D031AA64589743E229EF6BACCE21BD16E",
},
{
"13",
"A567BA97B67AEA5BAFDAF5002FFCC6AB9632BFF9F01F873F6267BCD1F0F11C139EE5F441ABD99F1BAAF1CA1E3B5CBCE7",
"DE1B38B3989F3318644E4147AF164ECC5185595046932EC086329BE057857D66776BCB8272218A7D6423A12736F429CC",
},
{
"14",
"E8C8F94D44FBC2396BBEAC481B89D2B0877B1DFFD23E7DC95DE541EB651CCA2C41ABA24DBC02DE6637209ACCF0F59EA0",
"891AE44356FC8AE0932BCBF6DE52C8A933B86191E7728D79C8319413A09D0F48FC468BA05509DE22D7EE5C9E1B67B888",
},
{
"15",
"B3D13FC8B32B01058CC15C11D813525522A94156FFF01C205B21F9F7DA7C4E9CA849557A10B6383B4B88701A9606860B",
"152919E7DF9162A61B049B2536164B1BEEBAC4A11D749AF484D1114373DFBFD9838D24F8B284AF50985D588D33F7BD62",
},
{
"16",
"D5D89C3B5282369C5FBD88E2B231511A6B80DFF0E5152CF6A464FA9428A8583BAC8EBC773D157811A462B892401DAFCF",
"D815229DE12906D241816D5E9A9448F1D41D4FC40E2A3BDB9CABA57E440A7ABAD1210CB8F49BF2236822B755EBAB3673",
},
{
"17",
"4099952208B4889600A5EBBCB13E1A32692BEFB0733B41E6DCC614E42E5805F817012A991AF1F486CAF3A9ADD9FFCC03",
"5ECF94777833059839474594AF603598163AD3F8008AD0CD9B797D277F2388B304DA4D2FAA9680ECFA650EF5E23B09A0",
},
{
"18",
"DFB1FE3A40F7AC9B64C41D39360A7423828B97CB088A4903315E402A7089FA0F8B6C2355169CC9C99DFB44692A9B93DD",
"453ACA1243B5EC6B423A68A25587E1613A634C1C42D2EE7E6C57F449A1C91DC89168B7036EC0A7F37A366185233EC522",
},
{
"19",
"8D481DAB912BC8AB16858A211D750B77E07DBECCA86CD9B012390B430467AABF59C8651060801C0E9599E68713F5D41B",
"A1592FF0121460857BE99F2A60669050B2291B68A1039AA0594B32FD7ADC0E8C11FFBA5608004E646995B07E75E52245",
},
{
"20",
"605508EC02C534BCEEE9484C86086D2139849E2B11C1A9CA1E2808DEC2EAF161AC8A105D70D4F85C50599BE5800A623F",
"5158EE87962AC6B81F00A103B8543A07381B7639A3A65F1353AEF11B733106DDE92E99B78DE367B48E238C38DAD8EEDD",
},
{
"112233445566778899",
"A499EFE48839BC3ABCD1C5CEDBDD51904F9514DB44F4686DB918983B0C9DC3AEE05A88B72433E9515F91A329F5F4FA60",
"3B7CA28EF31F809C2F1BA24AAED847D0F8B406A4B8968542DE139DB5828CA410E615D1182E25B91B1131E230B727D36A",
},
{
"112233445566778899112233445566778899",
"90A0B1CAC601676B083F21E07BC7090A3390FE1B9C7F61D842D27FA315FB38D83667A11A71438773E483F2A114836B24",
"3197D3C6123F0D6CD65D5F0DE106FEF36656CB16DC7CD1A6817EB1D51510135A8F492F72665CFD1053F75ED03A7D04C9",
},
{
"10158184112867540819754776755819761756724522948540419979637868435924061464745859402573149498125806098880003248619520",
"F2A066BD332DC59BBC3D01DA1B124C687D8BB44611186422DE94C1DA4ECF150E664D353CCDB5CB2652685F8EB4D2CD49",
"D6ED0BF75FDD8E53D87765FA746835B673881D6D1907163A2C43990D75B454294F942EC571AD5AAE1806CAF2BB8E9A4A",
},
{
"9850501551105991028245052605056992139810094908912799254115847683881357749738726091734403950439157209401153690566655",
"5C7F9845D1C4AA44747F9137B6F9C39B36B26B8A62E8AF97290434D5F3B214F5A0131550ADB19058DC4C8780C4165C4A",
"712F7FCCC86F647E70DB8798228CB16344AF3D00B139B6F8502939C2A965AF0EB4E39E2E16AB8F597B8D5630A50C9D85",
},
{
"9850502723405747097317271194763310482462751455185699630571661657946308788426092983270628740691202018691293898608608",
"DD5838F7EC3B8ACF1BECFD746F8B668C577107E93548ED93ED0D254C112E76B10F053109EF8428BFCD50D38C4C030C57",
"33244F479CDAC34F160D9E4CE2D19D2FF0E3305B5BF0EEF29E91E9DE6E28F678C61B773AA7E3C03740E1A49D1AA2493C",
},
{
"1146189371817832990947611400450889406070215735255370280811736587845016396640969656447803207438173695115264",
"CB8ED893530BFBA04B4CA655923AAAD109A62BC8411D5925316C32D33602459C33057A1FBCB5F70AEB295D90F9165FBC",
"426AEE3E91B08420F9B357B66D5AFCBCF3956590BF5564DBF9086042EB880493D19DA39AAA6436C6B5FC66CE5596B43F",
},
{
"9619341438217097641865390297189708858938017986426152622639500179774624579127744608993294698873437325090751520764",
"67F714012B6B070182122DDD435CC1C2262A1AB88939BC6A2906CB2B4137C5E82B4582160F6403CAB887ACDF5786A268",
"90E31CF398CE2F8C5897C7380BF541075D1B4D3CB70547262B7095731252F181AC0597C66AF8311C7780DB39DEC0BD32",
},
{
"1231307996623833742387400352380172566077927415136813282735641918395585376659282194317590461518639141730493780722175",
"55A79DF7B53A99D31462C7E1A5ED5623970715BB1021098CB973A7520CBD6365E613E4B2467486FB37E86E01CEE09B8F",
"B95AEB71693189911661B709A886A1867F056A0EFE401EE11C06030E46F7A87731DA4575863178012208707DD666727C",
},
{
"587118838854683800942906722504810343086699021451906946003274128973058942197377013128840514404789143516741631",
"9539A968CF819A0E52E10EEA3BACA1B6480D7E4DF69BC07002C568569047110EE4FE72FCA423FDD5179D6E0E19C44844",
"A7728F37A0AE0DF2716061900D83A4DA149144129F89A214A8260464BAB609BB322E4E67DE5E4C4C6CB8D25983EC19B0",
},
{
"153914077530671739663795070876894766451466019374644150541452557147890542143280855693795882295846834387672681660416",
"933FC13276672AB360D909161CD02D830B1628935DF0D800C6ED602C59D575A86A8A97E3A2D697E3ED06BE741C0097D6",
"F35296BD7A6B4C6C025ED6D84338CCCC7522A45C5D4FBDB1442556CAEFB598128FA188793ADA510EB5F44E90A4E4BEF1",
},
{
"75148784606135150476268171850082176256856776750560539466196504390587921789283134009866871754361028131485122560",
"0CE31E1C4A937071E6EBACA026A93D783848BCC0C1585DAF639518125FCD1F1629D63041ABFB11FFC8F03FA8B6FCF6BF",
"A69EA55BE4BEAB2D5224050FEBFFBDFCFD614624C3B4F228909EB80012F003756D1C377E52F04FA539237F24DD080E2E",
},
{
"19691383761310193665095292424754807745686799029814707849273381514021788371252213000473497648851202400395528761229312",
"6842CFE3589AC268818291F31D44177A9168DCBC19F321ED66D81ECF59E31B54CCA0DDFD4C4136780171748D69A91C54",
"E3A5ECD5AC725F13DBC631F358C6E817EDCF3A613B83832741A9DB591A0BAE767FC714F70C2E7EA891E4312047DECCC0",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942623",
"605508EC02C534BCEEE9484C86086D2139849E2B11C1A9CA1E2808DEC2EAF161AC8A105D70D4F85C50599BE5800A623F",
"AEA7117869D53947E0FF5EFC47ABC5F8C7E489C65C59A0ECAC510EE48CCEF92116D16647721C984B71DC73C825271122",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942624",
"8D481DAB912BC8AB16858A211D750B77E07DBECCA86CD9B012390B430467AABF59C8651060801C0E9599E68713F5D41B",
"5EA6D00FEDEB9F7A841660D59F996FAF4DD6E4975EFC655FA6B4CD028523F172EE0045A8F7FFB19B966A4F828A1ADDBA",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942625",
"DFB1FE3A40F7AC9B64C41D39360A7423828B97CB088A4903315E402A7089FA0F8B6C2355169CC9C99DFB44692A9B93DD",
"BAC535EDBC4A1394BDC5975DAA781E9EC59CB3E3BD2D118193A80BB65E36E2366E9748FB913F580C85C99E7BDCC13ADD",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942626",
"4099952208B4889600A5EBBCB13E1A32692BEFB0733B41E6DCC614E42E5805F817012A991AF1F486CAF3A9ADD9FFCC03",
"A1306B8887CCFA67C6B8BA6B509FCA67E9C52C07FF752F32648682D880DC774BFB25B2CF55697F13059AF10B1DC4F65F",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942627",
"D5D89C3B5282369C5FBD88E2B231511A6B80DFF0E5152CF6A464FA9428A8583BAC8EBC773D157811A462B892401DAFCF",
"27EADD621ED6F92DBE7E92A1656BB70E2BE2B03BF1D5C42463545A81BBF585442EDEF3460B640DDC97DD48AB1454C98C",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942628",
"B3D13FC8B32B01058CC15C11D813525522A94156FFF01C205B21F9F7DA7C4E9CA849557A10B6383B4B88701A9606860B",
"EAD6E618206E9D59E4FB64DAC9E9B4E411453B5EE28B650B7B2EEEBC8C2040257C72DB064D7B50AF67A2A773CC08429D",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942629",
"E8C8F94D44FBC2396BBEAC481B89D2B0877B1DFFD23E7DC95DE541EB651CCA2C41ABA24DBC02DE6637209ACCF0F59EA0",
"76E51BBCA903751F6CD4340921AD3756CC479E6E188D728637CE6BEC5F62F0B603B9745EAAF621DD2811A362E4984777",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942630",
"A567BA97B67AEA5BAFDAF5002FFCC6AB9632BFF9F01F873F6267BCD1F0F11C139EE5F441ABD99F1BAAF1CA1E3B5CBCE7",
"21E4C74C6760CCE79BB1BEB850E9B133AE7AA6AFB96CD13F79CD641FA87A82988894347C8DDE75829BDC5ED9C90BD633",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942631",
"952A7A349BD49289AB3AC421DCF683D08C2ED5E41F6D0E21648AF2691A481406DA4A5E22DA817CB466DA2EA77D2A7022",
"5FCDF0507B4A43FA9CFAD215190990D1F6047FC931E75F1446FD74F69E694AF1FCE559B9768BC1DD610945341DE42E91",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942632",
"099056E27DA7B998DA1EEEC2904816C57FE935ED5837C37456C9FD14892D3F8C4749B66E3AFB81D626356F3B55B4DDD8",
"D1B3F3DCB1CF5469977AFAABB53A1FC6903B1127203C9C02BC006C0BE4AD5CD9AB992AEC9C5500CA82A2457FC73A1F44",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942633",
"A669C5563BD67EEC678D29D6EF4FDE864F372D90B79B9E88931D5C29291238CCED8E85AB507BF91AA9CB2D13186658FB",
"567748D5183ED860DD26F7C24A0F132208FEE6AAF3E7C3CE3AFD20873C48FA56D6927E69DB7D77266887B09648C5DE22",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942634",
"8F0A39A4049BCB3EF1BF29B8B025B78F2216F7291E6FD3BAC6CB1EE285FB6E21C388528BFEE2B9535C55E4461079118B",
"9D3881EBC749FE29BAD3B5ACDD3C56866564C2835C3BFF39489877AB51264CFC618BC100202AE497D9D25B075399B507",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942635",
"1692778EA596E0BE75114297A6FA383445BF227FBE58190A900C3C73256F11FB5A3258D6F403D5ECE6E9B269D822C87D",
"232DC9A8FF2BEF957CAC7745C24702F1DDAAB52392ADE32B42E3CF3D13F113E594521E15322E8F729095405CFDD4F52D",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942636",
"283C1D7365CE4788F29F8EBF234EDFFEAD6FE997FBEA5FFA2D58CC9DFA7B1C508B05526F55B9EBB2040F05B48FB6D0E1",
"6B8A366F9E1BE47745AD102473E96FB8E59E2798128668D62636D32FE242DDA8CF27B120CD5870619B99B3263AED1073",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942637",
"627BE1ACD064D2B2226FE0D26F2D15D3C33EBCBB7F0F5DA51CBD41F26257383021317D7202FF30E50937F0854E35C5DF",
"F68995B34C074E3DE41922593EB0EA8A4D36ACAD9BB088B36679B09EC8EABBE8FB3BA4717B1E9ACEE8CC5BF82C0F06CB",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942638",
"11DE24A2C251C777573CAC5EA025E467F208E51DBFF98FC54F6661CBE56583B037882F4A1CA297E60ABCDBC3836D84BC",
"705969388BBF06D2F0A7C816F5FF183AD7B4BB88AB2A211773679ACC496FE513CE889791F51704CCE7BBEB55193E8EC5",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942639",
"138251CD52AC9298C1C8AAD977321DEB97E709BD0B4CA0ACA55DC8AD51DCFC9D1589A1597E3A5120E1EFD631C63E1835",
"35351D679659D1E9CE175D7E7E54A99E923BA26E7543F60C54F19C3086D55B22128C7840C8445A96AB60E3FE4D8F1298",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942640",
"077A41D4606FFA1464793C7E5FDC7D98CB9D3910202DCD06BEA4F240D3566DA6B408BBAE5026580D02D7E5C70500C831",
"366A0835F4F3BD7C82F44169FD5603667ADF4BE37AEEA55A0897B3F123EEE1523DB542931B4A2D6749A0D7A0F5D0E20E",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942641",
"08D999057BA3D2D969260045C55B97F089025959A6F434D651D207D19FB96E9E4FE0E86EBE0E64F85B96A9C75295DF61",
"717F0E05A4E4C312484017200292458B4D8A278A43933BC16FB1AFA0DA954BD9A002BC15B2C61DD29EAFE190F56BF17F",
},
{
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942642",
"AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
"C9E821B569D9D390A26167406D6D23D6070BE242D765EB831625CEEC4A0F473EF59F4E30E2817E6285BCE2846F15F1A0",
},
}
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_p384r1
sc: ec.Scalar_p384r1
_ = 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