nx_p256_fieldmul_mulx.nx source
↩ module page · 46 lines · 2212 B
1// nx_p256_fieldmul_mulx.nx -- P-256 field multiply using the FUSED __mul256_wide intrinsic
2// (ADX/BMI2 mulx+adcx+adox) for the 256x256->512 product, then the EXISTING NIST Solinas reducer.
3// This is the drop-in fast path for p256_field_mul: identical reduction, only the multiply changes.
4// Kept in a SEPARATE file (imports nx_p256_field_mul.nx for _p256_solinas_reduce) so the live
5// crypto source stays clean -- a file that USES __mul256_wide only builds with a compiler that has
6// the intrinsic (the candidate), never breaking the live-compiler build of the P-256 stack.
7// Correctness: nx_p256_fieldmul_mulx_difftest proves p256_field_mul_mulx == p256_field_mul bit-exact.
8// license_tier: ORIGINAL
9import "nx_p256_field_mul.nx" // _p256_solinas_reduce + p256_field_mul (reference) + u256 constants
10
11// 8x32 field element (a[0..7]) -> 4x64 (packed little-endian).
12func fmx_pack64(dst64: *i64, src32: *i64) -> i64 {
13 var k: i64 = 0
14 while k < 4 { dst64[k] = (src32[2*k] & 0xffffffff) | ((src32[2*k+1] & 0xffffffff) << 32); k = k + 1 }
15 return 0
16}
17// 8x64 product -> 16x32 product words c0..c15 (what _p256_solinas_reduce consumes).
18func fmx_split32(c16: *i64, prod64: *i64) -> i64 {
19 var k: i64 = 0
20 while k < 8 { c16[2*k] = prod64[k] & 0xffffffff; c16[2*k+1] = (prod64[k] >> 32) & 0xffffffff; k = k + 1 }
21 return 0
22}
23
24// (a*b) mod p, canonical. Same contract as p256_field_mul (out_8/a/b are 8x32). Self-contained.
25func p256_field_mul_mulx(out_8: *i64, a: *i64, b: *i64) -> i64 {
26 let a64: *i64 = sys_mmap(4 * 8) as *i64
27 let b64: *i64 = sys_mmap(4 * 8) as *i64
28 let prod: *i64 = sys_mmap(8 * 8) as *i64
29 let c16: *i64 = sys_mmap(16 * 8) as *i64
30 fmx_pack64(a64, a)
31 fmx_pack64(b64, b)
32 __mul256_wide(prod, a64, b64)
33 fmx_split32(c16, prod)
34 _p256_solinas_reduce(out_8, c16)
35 return 0
36}
37
38// scratch-passed variant (NO per-call mmap) -- for honest benchmarking of the arithmetic.
39func p256_field_mul_mulx_s(out_8: *i64, a: *i64, b: *i64, a64: *i64, b64: *i64, prod: *i64, c16: *i64) -> i64 {
40 fmx_pack64(a64, a)
41 fmx_pack64(b64, b)
42 __mul256_wide(prod, a64, b64)
43 fmx_split32(c16, prod)
44 _p256_solinas_reduce(out_8, c16)
45 return 0
46}