code wiki / (root) / nx_ml_dsa_65.nx

nx_ml_dsa_65.nx source

↩ module page · 116 lines · 3935 B

1// ml_dsa_65.nx -- ML-DSA-65 post-quantum digital signature. 2// 3// NIST FIPS 204 (August 2024). Lattice-based (Module-LWE + 4// rejection sampling). Drop-in replacement for Ed25519 once 5// fault-tolerant quantum computers exist -- Ed25519 is broken 6// by Shor's algorithm. 7// 8// Parameters (FIPS 204 Table 2, ML-DSA-65 = NIST security 9// category 3, AES-192 equivalent): 10// n = 256 polynomial degree 11// q = 8380417 prime modulus 12// d = 13 dropped-bits parameter 13// tau = 49 signing challenge weight 14// lambda = 192 collision-resistance security parameter 15// gamma1 = 524288 16// gamma2 = 261888 17// (k, l) = (6, 5) matrix dimensions 18// eta = 4 19// beta = tau * eta = 196 20// omega = 55 21// 22// Key / signature sizes: 23// public key = 1952 bytes 24// secret key = 4032 bytes 25// signature = 3309 bytes 26// 27// Status (2026-04-23): SKELETON. Same scaffolded-then-filled 28// approach as ml_kem_768.nx -- API locked so TLS / X.509 / OTR 29// / email crypto callers can write against the signatures now; 30// the NTT + ExpandA + Keccak-streamed sampling core lands as a 31// separate push (~800 LoC). 32// 33// Dependencies (pending full impl): 34// - sha3.nx: SHAKE-256 for ExpandA, ExpandS, challenge c 35// - rand.nx: 32-byte seed at keygen 36// - ct.nx: constant-time rejection sampling 37// 38// Invariants: 39// DSA1 Output bytes match FIPS 204 Appendix A test vectors. 40// DSA2 Verify ALWAYS accepts a genuine signature from the 41// same (msg, pk) pair; rejects any bit-flip in ct mode. 42// DSA3 Sign uses deterministic (kappa-based) randomness to 43// avoid Sony-PS3-ECDSA class nonce-reuse attacks. 44// 45// license_tier: INDEPENDENT_REDERIVE 46// genealogy_id: international-research-sources/ietf/rfc_8032 47// 48 49// nx_safety_envelope: 50// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 51// sil_target: SIL1 52// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 53// verdict: NOT_YET_EVALUATED 54 55import "nx_syscalls.nx" 56 57const MLDSA_N: i64 = 256 58const MLDSA_Q: i64 = 8380417 59const MLDSA_D: i64 = 13 60const MLDSA_TAU: i64 = 49 61const MLDSA_LAMBDA: i64 = 192 62const MLDSA_K: i64 = 6 63const MLDSA_L: i64 = 5 64const MLDSA_ETA: i64 = 4 65const MLDSA_BETA: i64 = 196 66const MLDSA_OMEGA: i64 = 55 67 68const MLDSA_PK_BYTES: i64 = 1952 69const MLDSA_SK_BYTES: i64 = 4032 70const MLDSA_SIG_BYTES: i64 = 3309 71 72const MLDSA_ERR_PENDING: i64 = -1 73const MLDSA_ERR_RANDOM: i64 = -2 74const MLDSA_ERR_VERIFY: i64 = -3 75 76// KeyGen() -> (pk, sk) 77func ml_dsa_65_keygen(pk_out: *u8, sk_out: *u8) -> i64 { 78 var i: i64 = 0 79 while i < MLDSA_PK_BYTES { pk_out[i] = 0; i = i + 1 } 80 i = 0 81 while i < MLDSA_SK_BYTES { sk_out[i] = 0; i = i + 1 } 82 return MLDSA_ERR_PENDING 83} 84 85// Sign(sk, msg, msg_len) -> sig 86// FIPS 204 ยง5.2 deterministic signing (kappa counter-based nonce). 87func ml_dsa_65_sign(sk_in: *u8, 88 msg: *u8, msg_len: i64, 89 sig_out: *u8) -> i64 { 90 var i: i64 = 0 91 while i < MLDSA_SIG_BYTES { sig_out[i] = 0; i = i + 1 } 92 return MLDSA_ERR_PENDING 93} 94 95// Verify(pk, msg, msg_len, sig) -> 0 if good, MLDSA_ERR_VERIFY 96// if bad. Constant-time in the SIGNATURE; message can branch. 97func ml_dsa_65_verify(pk_in: *u8, 98 msg: *u8, msg_len: i64, 99 sig_in: *u8) -> i64 { 100 return MLDSA_ERR_PENDING 101} 102 103// Compile-only smoke. 104func main() -> i64 { 105 let pk: *u8 = sys_mmap(MLDSA_PK_BYTES) 106 let sk: *u8 = sys_mmap(MLDSA_SK_BYTES) 107 let sig: *u8 = sys_mmap(MLDSA_SIG_BYTES) 108 if ml_dsa_65_keygen(pk, sk) != MLDSA_ERR_PENDING { return 1 } 109 if ml_dsa_65_sign(sk, "hello", 5, sig) != MLDSA_ERR_PENDING { 110 return 2 111 } 112 if ml_dsa_65_verify(pk, "hello", 5, sig) != MLDSA_ERR_PENDING { 113 return 3 114 } 115 return 0 116}