nx_ecdsa_p256.nx
buildroot/runtime/nx_ecdsa_p256.nx
about
nx_ecdsa_p256.nx -- ECDSA signature verification over NIST P-256.
Phase 0b §I.3 FINAL piece 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 (48e8e69d)
✓ 2. p256_point double + on_curve + to_affine (ecc7ad5f)
✓ 2b. p256_point_add (190acf1f)
✓ 2c. p256_scalar_mul (also shipped earlier)
✓ 3. p256_modn (Z/nZ arithmetic) (7e836066)
✓ 4. ecdsa_p256_verify (THIS commit)
This is the primitive that x509_validate's signature dispatch
will call for ECDSA-signed certs -- including every modern
Web PKI cert chain (google.com, Cloudflare, ~80% of the Web).
Algorithm (FIPS 186-5 §6.4.2 / SEC 1 v2.0 §4.1.4):
Input: pubkey Q = (Qx, Qy) (affine point on curve, != O)
msg hash e (256-bit, already truncated/computed)
signature (r, s) -- both 256-bit
1. Verify 1 <= r < n and 1 <= s < n. Reject otherwise.
2. Verify Q is on the curve. Reject otherwise.
3. e_n = e mod n (truncate-and-reduce; SHA-256 output
has the same bit-length as n for
P-256 + SHA-256, so this is just a
conditional subtract.)
4. s_inv = s^(-1) mod n
5. u1 = (e_n * s_inv) mod n
6. u2 = (r * s_inv) mod n
7. R = u1 * G + u2 * Q
8. Reject if R = O (point at infinity).
9. Convert R to affine; v = x_R mod n
10. Accept iff v == r.
Public API:
nx_ecdsa_p256_verify(pub_x, pub_y, hash_e, sig_r, sig_s) -> verdict
dependencies 9 imports · 12 importers
diagram shows first 10 each side; +0 more imports, +2 more importers in the complete lists below.
imports: nx_syscalls.nxnx_u256.nxnx_p256_field.nxnx_p256_point.nxnx_p256_point_add.nxnx_p256_scalar_mul.nxnx_p256_modn.nxnx_p256_comb.nxnx_p256_scalar_mul_wnaf.nx
imported by: nx_bench_sign.nxnx_bench_verify.nxnx_crypto_bench_full.nxnx_ecdsa_p256_sign.nxnx_ecdsa_p256_sign_test.nxnx_ecdsa_p256_test.nxnx_jose_es256.nxnx_p256_verify_bench.nxnx_p256_verify_timing.nxnx_x509_build.nxnx_x509_verify_ecdsa.nxnx_x509_verify_ecdsa_test.nx
structs
| none |
consts
| 84 | const NX_ECDSA_OK: i64 = 1 |
| 85 | const NX_ECDSA_BAD_R_RANGE: i64 = 2 |
| 86 | const NX_ECDSA_BAD_S_RANGE: i64 = 3 |
| 87 | const NX_ECDSA_PUBKEY_NOT_ON_CURVE: i64 = 4 |
| 88 | const NX_ECDSA_PUBKEY_INFINITY: i64 = 5 |
| 89 | const NX_ECDSA_INFINITY_RESULT: i64 = 6 |
| 90 | const NX_ECDSA_BAD_SIG: i64 = 7 |
| 91 | const NX_ECDSA_VERDICT_N: i64 = 8 |
functions
| 93 | func nx_ecdsa_p256_verdict_is_valid(v: i64) -> i64 called by 1: main |
| 105 | func _p256_comb_table() -> *i64 |
| 118 | func _nx_ecdsa_p256_verify_impl(pub_x: *i64, pub_y: *i64, called by 1: nx_ecdsa_p256_verify calls 19: u256_allocp256_modn_load_np256_modn_oneu256_is_zerou256_cmpp256_point_alloc+13 |
| 186 | func nx_ecdsa_p256_verify(pub_x: *i64, pub_y: *i64, called by 8: mainmainmainmainmainmain+2 calls 3: nx_scratch_save_nx_ecdsa_p256_verify_implnx_scratch_restore |
| 196 | func main() -> i64 |