nx_p256_field_inv.nx
buildroot/runtime/nx_p256_field_inv.nx
about
nx_p256_field_inv.nx -- P-256 prime-field modular inverse via
Fermat's little theorem.
Phase 0b §I.3 piece 1d of the ECDSA-P256 arc:
✓ 0. u256 big-int (6ff89dd8)
✓ 1. p256_field add/sub/neg (133f16a1)
✓ 1b. u256 wide multiplication (ddb0994a)
✓ 1c. p256_field mul + sq (d295c0a3)
✓ 1d. p256_field inverse (THIS commit)
- 2. p256_point ops (queued)
- 3. p256_scalar mod n (queued)
- 4. ecdsa_p256 verify (queued)
Algorithm: Fermat's little theorem. For prime p and nonzero a:
a^(p-1) = 1 (mod p) => a^(p-2) = a^(-1) (mod p)
We compute a^(p-2) via straightforward left-to-right binary
square-and-multiply over the 256 bits of (p-2). This is the
most-portable form -- no addition-chain optimization, no
constant-time guarantee. An optimized addition-chain variant
(~30 mults vs ~128 here) is queued for piece 1d-fast.
p-2 has 128 set bits in its 256-bit representation:
bits 255..224 set (32 bits, top of p)
bit 192 set (1 bit, "+ 2^192" in p)
bits 95..32 set (64 bits, low 96 bits of p)
bits 31, 30, ..., 2 set (30 bits)
bit 0 set (lowest bit; bit 1 clear because -2)
So 256 squarings + 128 multiplications = ~384 field ops per
inverse. With our slow p256_field_mul at ~4100 limb-ops per
mul, that's ~1.5M limb-ops per inverse. Each ECDSA verify
uses ONE inverse (s^(-1) mod n -- but that's via the scalar
modulus n, not p; this field inverse is used during point
arithmetic's final-step Jacobian-to-affine conversion).
Public API:
p256_field_load_p_minus_2(out)
p256_field_inv(out, a)
p256_field_bit_at(limbs, bit_pos) -> 0|1 (helper)
dependencies 4 imports · 6 importers
imports: nx_syscalls.nxnx_u256.nxnx_p256_field.nxnx_p256_field_mul.nx
imported by: nx_h2c_p256.nxnx_opaque_core.nxnx_p256_field_inv_test.nxnx_p256_point.nxnx_p256_point_test.nxnx_voprf.nx
structs
| none |
consts
| none |
functions
| 74 | func p256_field_load_p_minus_2(out: *i64) -> i64 |
| 88 | func p256_field_bit_at(limbs: *i64, bit_pos: i64) -> i64 |
| 107 | func p256_field_inv(out: *i64, a: *i64) -> i64 |
| 136 | func main() -> i64 |