mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-12 06:18:39 +00:00
core/crypto: Start work on the NIST curves
This commit is contained in:
346
core/crypto/_fiat/field_p256r1/field.odin
Normal file
346
core/crypto/_fiat/field_p256r1/field.odin
Normal 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)
|
||||
}
|
||||
501
core/crypto/_fiat/field_p256r1/field64.odin
Normal file
501
core/crypto/_fiat/field_p256r1/field64.odin
Normal 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
|
||||
}
|
||||
210
core/crypto/_fiat/field_scalarp256r1/field.odin
Normal file
210
core/crypto/_fiat/field_scalarp256r1/field.odin
Normal 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)
|
||||
}
|
||||
569
core/crypto/_fiat/field_scalarp256r1/field64.odin
Normal file
569
core/crypto/_fiat/field_scalarp256r1/field64.odin
Normal 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
|
||||
}
|
||||
135
core/crypto/_weierstrass/fe.odin
Normal file
135
core/crypto/_weierstrass/fe.odin
Normal 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)
|
||||
}
|
||||
548
core/crypto/_weierstrass/point.odin
Normal file
548
core/crypto/_weierstrass/point.odin
Normal 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)
|
||||
}
|
||||
95
core/crypto/_weierstrass/point_s11n_sec.odin
Normal file
95
core/crypto/_weierstrass/point_s11n_sec.odin
Normal 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
|
||||
}
|
||||
76
core/crypto/_weierstrass/sc.odin
Normal file
76
core/crypto/_weierstrass/sc.odin
Normal 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)))
|
||||
}
|
||||
204
core/crypto/_weierstrass/scalar_mul.odin
Normal file
204
core/crypto/_weierstrass/scalar_mul.odin
Normal 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))
|
||||
}
|
||||
}
|
||||
3985
core/crypto/_weierstrass/secp256r1_table.odin
Normal file
3985
core/crypto/_weierstrass/secp256r1_table.odin
Normal file
File diff suppressed because it is too large
Load Diff
99
core/crypto/_weierstrass/tools/ecc_gen_tables.odin
Normal file
99
core/crypto/_weierstrass/tools/ecc_gen_tables.odin
Normal 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)))
|
||||
}
|
||||
@@ -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
|
||||
|
||||
486
tests/core/crypto/test_core_crypto_weierstrass.odin
Normal file
486
tests/core/crypto/test_core_crypto_weierstrass.odin
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user