nx_ed25519_scalar.nx
buildroot/runtime/nx_ed25519_scalar.nx
about
nx_ed25519_scalar.nx -- scalar reduction mod L + scalar mul.
Phase 0b §I.1.C-2 of the Ed25519 completion arc per
docs/NISHI_TLS13_GAP_AUDIT.md. Builds on the point arithmetic
shipped in nx_ed25519_arith (T9). The two callables here are:
sc_reduce(s_64_LE, out_32_LE)
Reduce a 64-byte little-endian scalar (typically a SHA-512
output) modulo L, the order of the Ed25519 prime-order
subgroup. Used during sign (to compute the per-message
nonce and the challenge) and verify (to reduce h before
scalar mul of the public key).
ge_scalar_mul(out, scalar_32_LE, p)
Compute [s]P via standard MSB-first double-and-add using
the shipped ge_p3_double + ge_p3_add primitives.
Where L = 2^252 + 27742317777372353535851937790883648493
= 0x10000000000000000000000000000000_14def9dea2f79cd65812631a5cf5d3ed
Algorithm choice: MSB-first shift-and-(conditionally-add-then-
subtract-L) iteration. Compared to Bernstein's ref10 21-bit-
limb dense arithmetic, this is ~100x slower but 5x shorter LOC
and unambiguously correct. Verify/sign call sc_reduce twice and
scalar_mul once per signature; we'd rather have correctness
today and speed later via a perf-only refactor.
What it does today:
- sc_reduce(64_LE_bytes, 32_LE_out)
- ge_scalar_mul(GeP3, 32_LE_scalar, GeP3)
What it doesn't do yet:
- ge_double_scalar_mul (Straus-Shamir [a]P + [b]Q in single
pass; verify needs it for [S]B - [h]A; for v1 we'll do two
separate scalar muls + one add, slower but trivially correct)
- precomputed-basepoint table for fast [s]B (perf optimisation)
KAT verified:
- sc_reduce(0^64) == 0^32
- sc_reduce(L padded to 64) == 0^32
dependencies 3 imports · 5 importers
imports: nx_syscalls.nxnx_ed25519_point.nxnx_ed25519_arith.nx
imported by: nx_doc_seal.nxnx_ed25519_scalar_test.nxnx_ed25519_signature.nxnx_ed25519_signature_test.nxnx_https_get_happy_test.nx
structs
| none |
consts
| none |
functions
| 72 | func sc_l_limbs(out: *i64) -> i64 |
| 86 | func sc_ge_l(limbs: *i64) -> i64 |
| 105 | func sc_sub_l(limbs: *i64) -> i64 |
| 147 | func sc_reduce(s_in: *u8, out_32: *u8) -> i64 |
| 200 | func ge_scalar_mul(out: *GeP3, scalar_32: *u8, p: *GeP3) -> i64 |