From ffa6fc2a67e3c2bd2c225a8089045bdeeb90d9e1 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 13 Feb 2026 07:36:15 +0900 Subject: [PATCH] core/crypto/_weierstrass: Add scalar field inversion --- .../_fiat/field_scalarp256r1/field.odin | 270 ++++++++++++- .../_fiat/field_scalarp384r1/field.odin | 370 +++++++++++++++++- core/crypto/_weierstrass/sc.odin | 7 +- .../crypto/test_core_crypto_weierstrass.odin | 35 +- 4 files changed, 677 insertions(+), 5 deletions(-) diff --git a/core/crypto/_fiat/field_scalarp256r1/field.odin b/core/crypto/_fiat/field_scalarp256r1/field.odin index 70e55d9e3..802f3382e 100644 --- a/core/crypto/_fiat/field_scalarp256r1/field.odin +++ b/core/crypto/_fiat/field_scalarp256r1/field.odin @@ -135,7 +135,7 @@ fe_equal :: proc "contextless" (arg1, arg2: ^Montgomery_Domain_Field_Element) -> tmp: Montgomery_Domain_Field_Element = --- fe_sub(&tmp, arg1, arg2) - is_eq := subtle.u64_is_zero(fe_non_zero(&tmp)) + is_eq := subtle.eq(fe_non_zero(&tmp), 0) fe_clear(&tmp) @@ -208,3 +208,271 @@ fe_cond_negate :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Eleme fe_clear(&tmp1) } + +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 + // _100 = 2*_10 + // _101 = 1 + _100 + // _110 = 1 + _101 + // _1001 = _100 + _101 + // _1111 = _110 + _1001 + // _10010 = 2*_1001 + // _10101 = _110 + _1111 + // _11000 = _110 + _10010 + // _11010 = _10 + _11000 + // _101111 = _10101 + _11010 + // _111000 = _1001 + _101111 + // _111101 = _101 + _111000 + // _111111 = _10 + _111101 + // _1001111 = _10010 + _111101 + // _1100001 = _10010 + _1001111 + // _1100011 = _10 + _1100001 + // _1110011 = _10010 + _1100001 + // _1110111 = _100 + _1110011 + // _1111101 = _110 + _1110111 + // _10010101 = _11000 + _1111101 + // _10100111 = _10010 + _10010101 + // _10101101 = _110 + _10100111 + // _11100101 = _111000 + _10101101 + // _11111111 = _11010 + _11100101 + // x16 = _11111111 << 8 + _11111111 + // x32 = x16 << 16 + x16 + // i133 = ((x32 << 48 + x16) << 16 + x16) << 16 + // i158 = ((x16 + i133) << 16 + x16) << 6 + _101111 + // i186 = ((i158 << 9 + _1110011) << 8 + _1111101) << 9 + // i206 = ((_10101101 + i186) << 8 + _10100111) << 9 + _101111 + // i236 = ((i206 << 8 + _111101) << 11 + _1001111) << 9 + // i257 = ((_1110111 + i236) << 10 + _11100101) << 8 + _1100001 + // i286 = ((i257 << 7 + _111111) << 10 + _1100011) << 10 + // return (_10010101 + i286) << 6 + _1111 + // + // Operations: 251 squares 43 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.4.0. + + // Note: Need to stash `arg1` (`xx`) in the case that `out1`/`arg1` alias, + // as `arg1` is used after `out1` has been altered. + t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, xx: Montgomery_Domain_Field_Element = ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, arg1^ + + // Step 1: t1 = x^0x2 + fe_square(&t1, arg1) + + // Step 2: t5 = x^0x4 + fe_square(&t5, &t1) + + // Step 3: t2 = x^0x5 + fe_mul(&t2, arg1, &t5) + + // Step 4: t10 = x^0x6 + fe_mul(&t10, arg1, &t2) + + // Step 5: t3 = x^0x9 + fe_mul(&t3, &t5, &t2) + + // Step 6: z = x^0xf + fe_mul(out1, &t10, &t3) + + // Step 7: t9 = x^0x12 + fe_square(&t9, &t3) + + // Step 8: t4 = x^0x15 + fe_mul(&t4, &t10, out1) + + // Step 9: t0 = x^0x18 + fe_mul(&t0, &t10, &t9) + + // Step 10: t13 = x^0x1a + fe_mul(&t13, &t1, &t0) + + // Step 11: t8 = x^0x2f + fe_mul(&t8, &t4, &t13) + + // Step 12: t4 = x^0x38 + fe_mul(&t4, &t3, &t8) + + // Step 13: t7 = x^0x3d + fe_mul(&t7, &t2, &t4) + + // Step 14: t2 = x^0x3f + fe_mul(&t2, &t1, &t7) + + // Step 15: t6 = x^0x4f + fe_mul(&t6, &t9, &t7) + + // Step 16: t3 = x^0x61 + fe_mul(&t3, &t9, &t6) + + // Step 17: t1 = x^0x63 + fe_mul(&t1, &t1, &t3) + + // Step 18: t12 = x^0x73 + fe_mul(&t12, &t9, &t3) + + // Step 19: t5 = x^0x77 + fe_mul(&t5, &t5, &t12) + + // Step 20: t11 = x^0x7d + fe_mul(&t11, &t10, &t5) + + // Step 21: t0 = x^0x95 + fe_mul(&t0, &t0, &t11) + + // Step 22: t9 = x^0xa7 + fe_mul(&t9, &t9, &t0) + + // Step 23: t10 = x^0xad + fe_mul(&t10, &t10, &t9) + + // Step 24: t4 = x^0xe5 + fe_mul(&t4, &t4, &t10) + + // Step 25: t13 = x^0xff + fe_mul(&t13, &t13, &t4) + + // Step 33: t14 = x^0xff00 + fe_pow2k(&t14, &t13, 8) + + // Step 34: t13 = x^0xffff + fe_mul(&t13, &t13, &t14) + + // Step 50: t14 = x^0xffff0000 + fe_pow2k(&t14, &t13, 16) + + // Step 51: t14 = x^0xffffffff + fe_mul(&t14, &t13, &t14) + + // Step 99: t14 = x^0xffffffff000000000000 + fe_pow2k(&t14, &t14, 48) + + // Step 100: t14 = x^0xffffffff00000000ffff + fe_mul(&t14, &t13, &t14) + + // Step 116: t14 = x^0xffffffff00000000ffff0000 + fe_pow2k(&t14, &t14, 16) + + // Step 117: t14 = x^0xffffffff00000000ffffffff + fe_mul(&t14, &t13, &t14) + + // Step 133: t14 = x^0xffffffff00000000ffffffff0000 + fe_pow2k(&t14, &t14, 16) + + // Step 134: t14 = x^0xffffffff00000000ffffffffffff + fe_mul(&t14, &t13, &t14) + + // Step 150: t14 = x^0xffffffff00000000ffffffffffff0000 + fe_pow2k(&t14, &t14, 16) + + // Step 151: t13 = x^0xffffffff00000000ffffffffffffffff + fe_mul(&t13, &t13, &t14) + + // Step 157: t13 = x^0x3fffffffc00000003fffffffffffffffc0 + fe_pow2k(&t13, &t13, 6) + + // Step 158: t13 = x^0x3fffffffc00000003fffffffffffffffef + fe_mul(&t13, &t8, &t13) + + // Step 167: t13 = x^0x7fffffff800000007fffffffffffffffde00 + fe_pow2k(&t13, &t13, 9) + + // Step 168: t12 = x^0x7fffffff800000007fffffffffffffffde73 + fe_mul(&t12, &t12, &t13) + + // Step 176: t12 = x^0x7fffffff800000007fffffffffffffffde7300 + fe_pow2k(&t12, &t12, 8) + + // Step 177: t11 = x^0x7fffffff800000007fffffffffffffffde737d + fe_mul(&t11, &t11, &t12) + + // Step 186: t11 = x^0xffffffff00000000ffffffffffffffffbce6fa00 + fe_pow2k(&t11, &t11, 9) + + // Step 187: t10 = x^0xffffffff00000000ffffffffffffffffbce6faad + fe_mul(&t10, &t10, &t11) + + // Step 195: t10 = x^0xffffffff00000000ffffffffffffffffbce6faad00 + fe_pow2k(&t10, &t10, 8) + + // Step 196: t9 = x^0xffffffff00000000ffffffffffffffffbce6faada7 + fe_mul(&t9, &t9, &t10) + + // Step 205: t9 = x^0x1fffffffe00000001ffffffffffffffff79cdf55b4e00 + fe_pow2k(&t9, &t9, 9) + + // Step 206: t8 = x^0x1fffffffe00000001ffffffffffffffff79cdf55b4e2f + fe_mul(&t8, &t8, &t9) + + // Step 214: t8 = x^0x1fffffffe00000001ffffffffffffffff79cdf55b4e2f00 + fe_pow2k(&t8, &t8, 8) + + // Step 215: t7 = x^0x1fffffffe00000001ffffffffffffffff79cdf55b4e2f3d + fe_mul(&t7, &t7, &t8) + + // Step 226: t7 = x^0xffffffff00000000ffffffffffffffffbce6faada7179e800 + fe_pow2k(&t7, &t7, 11) + + // Step 227: t6 = x^0xffffffff00000000ffffffffffffffffbce6faada7179e84f + fe_mul(&t6, &t6, &t7) + + // Step 236: t6 = x^0x1fffffffe00000001ffffffffffffffff79cdf55b4e2f3d09e00 + fe_pow2k(&t6, &t6, 9) + + // Step 237: t5 = x^0x1fffffffe00000001ffffffffffffffff79cdf55b4e2f3d09e77 + fe_mul(&t5, &t5, &t6) + + // Step 247: t5 = x^0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dc00 + fe_pow2k(&t5, &t5, 10) + + // Step 248: t4 = x^0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5 + fe_mul(&t4, &t4, &t5) + + // Step 256: t4 = x^0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dce500 + fe_pow2k(&t4, &t4, 8) + + // Step 257: t3 = x^0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dce561 + fe_mul(&t3, &t3, &t4) + + // Step 264: t3 = x^0x3fffffffc00000003fffffffffffffffef39beab69c5e7a13cee72b080 + fe_pow2k(&t3, &t3, 7) + + // Step 265: t2 = x^0x3fffffffc00000003fffffffffffffffef39beab69c5e7a13cee72b0bf + fe_mul(&t2, &t2, &t3) + + // Step 275: t2 = x^0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc00 + fe_pow2k(&t2, &t2, 10) + + // Step 276: t1 = x^0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63 + fe_mul(&t1, &t1, &t2) + + // Step 286: t1 = x^0x3fffffffc00000003fffffffffffffffef39beab69c5e7a13cee72b0bf18c00 + fe_pow2k(&t1, &t1, 10) + + // Step 287: t0 = x^0x3fffffffc00000003fffffffffffffffef39beab69c5e7a13cee72b0bf18c95 + fe_mul(&t0, &t0, &t1) + + // Step 293: t0 = x^0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632540 + fe_pow2k(&t0, &t0, 6) + + // Step 294: z = x^0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f + fe_mul(out1, out1, &t0) + + fe_clear_vec([]^Montgomery_Domain_Field_Element{&t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9, &t10, &t11, &t12, &t13, &t14, &xx}) +} diff --git a/core/crypto/_fiat/field_scalarp384r1/field.odin b/core/crypto/_fiat/field_scalarp384r1/field.odin index 9b9e5d350..cfc27f322 100644 --- a/core/crypto/_fiat/field_scalarp384r1/field.odin +++ b/core/crypto/_fiat/field_scalarp384r1/field.odin @@ -148,7 +148,7 @@ fe_equal :: proc "contextless" (arg1, arg2: ^Montgomery_Domain_Field_Element) -> tmp: Montgomery_Domain_Field_Element = --- fe_sub(&tmp, arg1, arg2) - is_eq := subtle.u64_is_zero(fe_non_zero(&tmp)) + is_eq := subtle.eq(fe_non_zero(&tmp), 0) fe_clear(&tmp) @@ -237,3 +237,371 @@ fe_cond_negate :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Eleme fe_clear(&tmp1) } + +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 + // _101 = _10 + _11 + // _111 = _10 + _101 + // _1001 = _10 + _111 + // _1011 = _10 + _1001 + // _1101 = _10 + _1011 + // _1111 = _10 + _1101 + // _11110 = 2*_1111 + // _11111 = 1 + _11110 + // _1111100 = _11111 << 2 + // i14 = _1111100 << 2 + // i26 = (i14 << 3 + _1111100) << 7 + i14 + // i42 = i26 << 15 + i26 + // x64 = i42 << 30 + i42 + _1111 + // x128 = x64 << 64 + x64 + // x192 = x128 << 64 + x64 + // x194 = x192 << 2 + _11 + // i225 = ((x194 << 6 + _111) << 3 + _11) << 7 + // i235 = 2*((_1101 + i225) << 6 + _1101) + 1 + // i258 = ((i235 << 11 + _11111) << 2 + 1) << 8 + // i269 = ((_1101 + i258) << 2 + _11) << 6 + _1011 + // i286 = ((i269 << 4 + _111) << 6 + _11111) << 5 + // i308 = ((_1011 + i286) << 10 + _1101) << 9 + _1101 + // i323 = ((i308 << 4 + _1011) << 6 + _1001) << 3 + // i340 = ((1 + i323) << 7 + _1011) << 7 + _101 + // i357 = ((i340 << 5 + _111) << 5 + _1111) << 5 + // i369 = ((_1011 + i357) << 4 + _1011) << 5 + _111 + // i387 = ((i369 << 3 + _11) << 7 + _11) << 6 + // i397 = ((_1011 + i387) << 4 + _101) << 3 + _11 + // i413 = ((i397 << 4 + _11) << 4 + _11) << 6 + // i427 = ((_101 + i413) << 5 + _101) << 6 + _1011 + // return (2*i427 + 1) << 4 + 1 + // + // Operations: 381 squares 53 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.4.0. + + // Note: Need to stash `arg1` (`xx`) in the case that `out1`/`arg1` alias, + // as `arg1` is used after `out1` has been altered. + t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, xx: Montgomery_Domain_Field_Element = ---, ---, ---, ---, ---, ---, ---, ---, ---, ---, arg1^ + + // Step 1: t3 = x^0x2 + fe_square(&t3, arg1) + + // Step 2: t1 = x^0x3 + fe_mul(&t1, arg1, &t3) + + // Step 3: t0 = x^0x5 + fe_mul(&t0, &t3, &t1) + + // Step 4: t2 = x^0x7 + fe_mul(&t2, &t3, &t0) + + // Step 5: t4 = x^0x9 + fe_mul(&t4, &t3, &t2) + + // Step 6: z = x^0xb + fe_mul(out1, &t3, &t4) + + // Step 7: t5 = x^0xd + fe_mul(&t5, &t3, out1) + + // Step 8: t3 = x^0xf + fe_mul(&t3, &t3, &t5) + + // Step 9: t6 = x^0x1e + fe_square(&t6, &t3) + + // Step 10: t6 = x^0x1f + fe_mul(&t6, &xx, &t6) + + // Step 12: t8 = x^0x7c + fe_pow2k(&t8, &t6, 2) + + // Step 14: t7 = x^0x1f0 + fe_pow2k(&t7, &t8, 2) + + // Step 17: t9 = x^0xf80 + fe_pow2k(&t9, &t7, 3) + + // Step 18: t8 = x^0xffc + fe_mul(&t8, &t8, &t9) + + // Step 25: t8 = x^0x7fe00 + fe_pow2k(&t8, &t8, 7) + + // Step 26: t7 = x^0x7fff0 + fe_mul(&t7, &t7, &t8) + + // Step 41: t8 = x^0x3fff80000 + fe_pow2k(&t8, &t7, 15) + + // Step 42: t7 = x^0x3fffffff0 + fe_mul(&t7, &t7, &t8) + + // Step 72: t8 = x^0xfffffffc00000000 + fe_pow2k(&t8, &t7, 30) + + // Step 73: t7 = x^0xfffffffffffffff0 + fe_mul(&t7, &t7, &t8) + + // Step 74: t7 = x^0xffffffffffffffff + fe_mul(&t7, &t3, &t7) + + // Step 138: t8 = x^0xffffffffffffffff0000000000000000 + fe_pow2k(&t8, &t7, 64) + + // Step 139: t8 = x^0xffffffffffffffffffffffffffffffff + fe_mul(&t8, &t7, &t8) + + // Step 203: t8 = x^0xffffffffffffffffffffffffffffffff0000000000000000 + fe_pow2k(&t8, &t8, 64) + + // Step 204: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffff + fe_mul(&t7, &t7, &t8) + + // Step 206: t7 = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffc + fe_pow2k(&t7, &t7, 2) + + // Step 207: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff + fe_mul(&t7, &t1, &t7) + + // Step 213: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc0 + fe_pow2k(&t7, &t7, 6) + + // Step 214: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7 + fe_mul(&t7, &t2, &t7) + + // Step 217: t7 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe38 + fe_pow2k(&t7, &t7, 3) + + // Step 218: t7 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b + fe_mul(&t7, &t1, &t7) + + // Step 225: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d80 + fe_pow2k(&t7, &t7, 7) + + // Step 226: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d + fe_mul(&t7, &t5, &t7) + + // Step 232: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc76340 + fe_pow2k(&t7, &t7, 6) + + // Step 233: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d + fe_mul(&t7, &t5, &t7) + + // Step 234: t7 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69a + fe_square(&t7, &t7) + + // Step 235: t7 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b + fe_mul(&t7, &xx, &t7) + + // Step 246: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d800 + fe_pow2k(&t7, &t7, 11) + + // Step 247: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f + fe_mul(&t7, &t6, &t7) + + // Step 249: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607c + fe_pow2k(&t7, &t7, 2) + + // Step 250: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d + fe_mul(&t7, &xx, &t7) + + // Step 258: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d00 + fe_pow2k(&t7, &t7, 8) + + // Step 259: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0d + fe_mul(&t7, &t5, &t7) + + // Step 261: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f434 + fe_pow2k(&t7, &t7, 2) + + // Step 262: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f437 + fe_mul(&t7, &t1, &t7) + + // Step 268: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dc0 + fe_pow2k(&t7, &t7, 6) + + // Step 269: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb + fe_mul(&t7, out1, &t7) + + // Step 273: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb0 + fe_pow2k(&t7, &t7, 4) + + // Step 274: t7 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb7 + fe_mul(&t7, &t2, &t7) + + // Step 280: t7 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372dc0 + fe_pow2k(&t7, &t7, 6) + + // Step 281: t6 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf + fe_mul(&t6, &t6, &t7) + + // Step 286: t6 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbe0 + fe_pow2k(&t6, &t6, 5) + + // Step 287: t6 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb + fe_mul(&t6, out1, &t6) + + // Step 297: t6 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac00 + fe_pow2k(&t6, &t6, 10) + + // Step 298: t6 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d + fe_mul(&t6, &t5, &t6) + + // Step 307: t6 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a00 + fe_pow2k(&t6, &t6, 9) + + // Step 308: t5 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0d + fe_mul(&t5, &t5, &t6) + + // Step 312: t5 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0d0 + fe_pow2k(&t5, &t5, 4) + + // Step 313: t5 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db + fe_mul(&t5, out1, &t5) + + // Step 319: t5 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c0 + fe_pow2k(&t5, &t5, 6) + + // Step 320: t4 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c9 + fe_mul(&t4, &t4, &t5) + + // Step 323: t4 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b648 + fe_pow2k(&t4, &t4, 3) + + // Step 324: t4 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b649 + fe_mul(&t4, &xx, &t4) + + // Step 331: t4 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db2480 + fe_pow2k(&t4, &t4, 7) + + // Step 332: t4 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b + fe_mul(&t4, out1, &t4) + + // Step 339: t4 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d924580 + fe_pow2k(&t4, &t4, 7) + + // Step 340: t4 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d924585 + fe_mul(&t4, &t0, &t4) + + // Step 345: t4 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a0 + fe_pow2k(&t4, &t4, 5) + + // Step 346: t4 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a7 + fe_mul(&t4, &t2, &t4) + + // Step 351: t4 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b6491614e0 + fe_pow2k(&t4, &t4, 5) + + // Step 352: t3 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b6491614ef + fe_mul(&t3, &t3, &t4) + + // Step 357: t3 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29de0 + fe_pow2k(&t3, &t3, 5) + + // Step 358: t3 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29deb + fe_mul(&t3, out1, &t3) + + // Step 362: t3 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29deb0 + fe_pow2k(&t3, &t3, 4) + + // Step 363: t3 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb + fe_mul(&t3, out1, &t3) + + // Step 368: t3 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd760 + fe_pow2k(&t3, &t3, 5) + + // Step 369: t2 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd767 + fe_mul(&t2, &t2, &t3) + + // Step 372: t2 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb38 + fe_pow2k(&t2, &t2, 3) + + // Step 373: t2 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb3b + fe_mul(&t2, &t1, &t2) + + // Step 380: t2 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b6491614ef5d9d80 + fe_pow2k(&t2, &t2, 7) + + // Step 381: t2 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b6491614ef5d9d83 + fe_mul(&t2, &t1, &t2) + + // Step 387: t2 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760c0 + fe_pow2k(&t2, &t2, 6) + + // Step 388: t2 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760cb + fe_mul(&t2, out1, &t2) + + // Step 392: t2 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760cb0 + fe_pow2k(&t2, &t2, 4) + + // Step 393: t2 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760cb5 + fe_mul(&t2, &t0, &t2) + + // Step 396: t2 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb3b065a8 + fe_pow2k(&t2, &t2, 3) + + // Step 397: t2 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb3b065ab + fe_mul(&t2, &t1, &t2) + + // Step 401: t2 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb3b065ab0 + fe_pow2k(&t2, &t2, 4) + + // Step 402: t2 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb3b065ab3 + fe_mul(&t2, &t1, &t2) + + // Step 406: t2 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb3b065ab30 + fe_pow2k(&t2, &t2, 4) + + // Step 407: t1 = x^0x3ffffffffffffffffffffffffffffffffffffffffffffffff1d8d3607d0dcb77d606836c922c29debb3b065ab33 + fe_mul(&t1, &t1, &t2) + + // Step 413: t1 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc0 + fe_pow2k(&t1, &t1, 6) + + // Step 414: t1 = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc5 + fe_mul(&t1, &t0, &t1) + + // Step 419: t1 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b6491614ef5d9d832d5998a0 + fe_pow2k(&t1, &t1, 5) + + // Step 420: t0 = x^0x1ffffffffffffffffffffffffffffffffffffffffffffffff8ec69b03e86e5bbeb0341b6491614ef5d9d832d5998a5 + fe_mul(&t0, &t0, &t1) + + // Step 426: t0 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760cb56662940 + fe_pow2k(&t0, &t0, 6) + + // Step 427: z = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b + fe_mul(out1, out1, &t0) + + // Step 428: z = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc5296 + fe_square(out1, out1) + + // Step 429: z = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc5297 + fe_mul(out1, &xx, out1) + + // Step 433: z = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52970 + fe_pow2k(out1, out1, 4) + + // Step 434: z = x^0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52971 + fe_mul(out1, &xx, out1) + + fe_clear_vec([]^Montgomery_Domain_Field_Element{&t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9, &xx}) +} diff --git a/core/crypto/_weierstrass/sc.odin b/core/crypto/_weierstrass/sc.odin index e119eec2e..0fc64e028 100644 --- a/core/crypto/_weierstrass/sc.odin +++ b/core/crypto/_weierstrass/sc.odin @@ -40,7 +40,7 @@ sc_zero :: proc { p384r1.fe_zero, } -sc_one_p256r1 :: proc { +sc_one :: proc { p256r1.fe_one, p384r1.fe_one, } @@ -70,6 +70,11 @@ sc_square :: proc { p384r1.fe_square, } +sc_inv :: proc { + p256r1.fe_inv, + p384r1.fe_inv, +} + sc_cond_assign :: proc { p256r1.fe_cond_assign, p384r1.fe_cond_assign, diff --git a/tests/core/crypto/test_core_crypto_weierstrass.odin b/tests/core/crypto/test_core_crypto_weierstrass.odin index ac5acac21..dcb17aa3d 100644 --- a/tests/core/crypto/test_core_crypto_weierstrass.odin +++ b/tests/core/crypto/test_core_crypto_weierstrass.odin @@ -1,5 +1,6 @@ package test_core_crypto +import "core:crypto" import ec "core:crypto/_weierstrass" import "core:encoding/hex" import "core:math/big" @@ -881,7 +882,7 @@ test_p384_scalar_mul :: proc(t: ^testing.T) { } @(test) -test_p256_s11n_sec_identity ::proc(t: ^testing.T) { +test_p256_s11n_sec_identity :: proc(t: ^testing.T) { p: ec.Point_p256r1 ec.pt_generator(&p) @@ -901,7 +902,7 @@ test_p256_s11n_sec_identity ::proc(t: ^testing.T) { } @(test) -test_p256_s11n_sec_generator ::proc(t: ^testing.T) { +test_p256_s11n_sec_generator :: proc(t: ^testing.T) { p, g: ec.Point_p256r1 ec.pt_generator(&g) @@ -917,3 +918,33 @@ test_p256_s11n_sec_generator ::proc(t: ^testing.T) { testing.expectf(t, ok, "%s", s) testing.expect(t, ec.pt_equal(&g, &p) == 1) } + +@(test) +test_p256_sc_inv :: proc(t: ^testing.T) { + if crypto.HAS_RAND_BYTES == false { + return + } + + sc, sc_inv, sc_prod, sc_one: ec.Scalar_p256r1 + ec.sc_set_random(&sc) + ec.sc_inv(&sc_inv, &sc) + ec.sc_one(&sc_one) + + ec.sc_mul(&sc_prod, &sc, &sc_inv) + testing.expect(t, ec.sc_equal(&sc_prod, &sc_one) == 1) +} + +@(test) +test_p384_sc_inv :: proc(t: ^testing.T) { + if crypto.HAS_RAND_BYTES == false { + return + } + + sc, sc_inv, sc_prod, sc_one: ec.Scalar_p384r1 + ec.sc_set_random(&sc) + ec.sc_inv(&sc_inv, &sc) + ec.sc_one(&sc_one) + + ec.sc_mul(&sc_prod, &sc, &sc_inv) + testing.expect(t, ec.sc_equal(&sc_prod, &sc_one) == 1) +} \ No newline at end of file