nx_p256_scalar_mul.nx
buildroot/runtime/nx_p256_scalar_mul.nx
about
nx_p256_scalar_mul.nx -- P-256 scalar multiplication k * P.
Phase 0b §I.3 piece 2c of the ECDSA-P256 arc:
✓ 2b. p256_point_add (190acf1f)
✓ 2c. p256_scalar_mul (THIS commit)
- 3. p256_scalar mod n (queued)
- 4. ecdsa_p256 verify (queued)
Algorithm: binary double-and-add, left-to-right (MSB-first):
result := O (infinity)
for bit_pos = 255 down to 0:
result := double(result)
if bit_pos-th bit of k is set:
result := add(result, P)
return result
Cost: 256 doublings + up to 256 adds. For a typical 256-bit
scalar (~128 set bits), roughly 256 doubles + 128 adds = 384
point ops. Each point op composes ~10-15 field ops; with our
slow field_mul at ~4100 limb-ops, one scalar-mult is roughly
~20-25M limb-ops, or ~2-3s on qemu-riscv64-static.
ECDSA verify needs TWO scalar mults (u1*G + u2*Q). Shamir's
trick (compute both via one shared doubling chain by walking
the bits of u1 and u2 in lockstep against a 4-element
precomputed point table {O, G, Q, G+Q}) is an optimization
queued for a follow-up. For first-cut correctness this
commit ships the simpler standalone scalar_mul.
Public API:
p256_scalar_mul(out, k_8, p)
-- k_8: 8-limb 256-bit scalar (LE limb order, MUST be < n
in practice but no defensive check here -- caller's
ECDSA verify already reduces u1, u2 mod n)
-- p: input point (Jacobian)
-- out: result point (Jacobian); MAY alias p
Edge cases handled:
- k == 0: returns O (infinity)
dependencies 5 imports · 23 importers
diagram shows first 10 each side; +0 more imports, +13 more importers in the complete lists below.
imports: nx_syscalls.nxnx_u256.nxnx_p256_field.nxnx_p256_point.nxnx_p256_point_add.nx
imported by: nx_bench_comb.nxnx_bench_kg.nxnx_bench_sign.nxnx_bench_verify.nxnx_cert_gen.nxnx_crypto_bench_full.nxnx_ecdsa_p256.nxnx_ecdsa_p256_sign.nxnx_ecdsa_p256_sign_test.nxnx_jose_es256.nxnx_opaque_core.nxnx_opaque_pake.nxnx_p256_comb_bench.nxnx_p256_comb_test.nxnx_p256_ecdh.nxnx_p256_ecverify_core_bench.nxnx_p256_keyshare_test.nxnx_p256_scalar_mul_test.nxnx_p256_verify_bench.nxnx_p256_verify_components.nxnx_p256_wnaf_bench.nxnx_p256_wnaf_difftest.nxnx_voprf.nx
structs
| none |
consts
| none |
functions
| 70 | func p256_scalar_mul(out: *P256Point, k_8: *i64, p: *P256Point) -> i64 |
| 102 | func main() -> i64 |