nx_p256_point_add.nx
buildroot/runtime/nx_p256_point_add.nx
about
nx_p256_point_add.nx -- P-256 Jacobian point addition.
Phase 0b §I.3 piece 2b of the ECDSA-P256 arc:
✓ ...all earlier pieces shipped...
✓ 2. p256_point: struct + double + to_affine + on_curve
(ecc7ad5f)
✓ 2b. p256_point_add (THIS commit)
- 2c. p256_scalar_mul (queued)
- 3. p256_scalar mod n (queued)
- 4. ecdsa_p256 verify (queued)
Algorithm (SEC 1 v2.0 §2.2.1.4, Jacobian + Jacobian):
if Z1 == 0: return P2
if Z2 == 0: return P1
U1 = X1 * Z2^2
U2 = X2 * Z1^2
S1 = Y1 * Z2^3
S2 = Y2 * Z1^3
if U1 == U2:
if S1 == S2: return double(P1) -- P1 == P2
else: return infinity -- P1 == -P2 (additive inverse)
H = U2 - U1
R = S2 - S1
H2 = H^2
H3 = H * H2
U1H2 = U1 * H2
X3 = R^2 - H3 - 2 * U1H2
Y3 = R * (U1H2 - X3) - S1 * H3
Z3 = H * Z1 * Z2
Cost per add: 12 mults + 4 squares + ~6 add/sub. Combined with
our slow field_mul (~4100 limb-ops per mul), one add takes
~70K limb-ops. Double-and-add over a 256-bit scalar is ~256
doublings + ~128 adds = ~25M limb-ops per scalar-mult, or
~2.5s per scalar-mult on qemu. Acceptable for first-cut ECDSA
verify; Solinas reduction will eventually cut this 10-25x.
Public API:
p256_point_add(out, p1, p2)
dependencies 5 imports · 13 importers
diagram shows first 10 each side; +0 more imports, +3 more importers in the complete lists below.
imports: nx_syscalls.nxnx_u256.nxnx_p256_field.nxnx_p256_field_mul.nxnx_p256_point.nx
imported by: nx_ecdsa_p256.nxnx_h2c_p256.nxnx_opaque_core.nxnx_p256_comb.nxnx_p256_ecdh.nxnx_p256_ecverify_core_bench.nxnx_p256_keyshare_test.nxnx_p256_point_add_test.nxnx_p256_pointloop_bench.nxnx_p256_scalar_mul.nxnx_p256_scalar_mul_test.nxnx_p256_scalar_mul_wnaf.nxnx_voprf.nx
structs
| none |
consts
| none |
functions
| 68 | func p256_point_add(out: *P256Point, p1: *P256Point, p2: *P256Point) -> i64 |
| 175 | func main() -> i64 |