code wiki / (root) / nx_p384_field_inv.nx

nx_p384_field_inv.nx source

↩ module page · 90 lines · 2771 B

1// nx_p384_field_inv.nx -- P-384 modular inverse via Fermat's 2// little theorem. Mirror of nx_p256_field_inv.nx, adapted to 3// 12-limb / 384-bit width. 4// 5// a^(p-2) mod p computed left-to-right square-and-multiply over 6// the 384 bits of (p-2). 7// 8// Performance note: portable bit-by-bit form (no addition-chain 9// optimization). ~384 squarings + ~variable mults; each mul 10// runs the 385-iteration bit-by-bit reduction in 11// nx_p384_field_mul. Slow but correct. Optimized addition 12// chain queued. 13// 14// API: 15// p384_field_load_p_minus_2(out) 16// p384_field_inv(out, a) out = a^(-1) mod p (Fermat) 17// p384_field_bit_at(limbs, bit_pos) -> 0|1 18// 19// Caveat: p384_field_inv(out, 0) returns 0. 0 has no inverse; 20// callers MUST guard zero by construction (point ops do). 21// 22// license_tier: INDEPENDENT_REDERIVE 23// genealogy_id: international-research-sources/nist/fips_186_5 24// lineage_id: nishi_p384_field_inv_q10 25 26// nx_safety_envelope: 27// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 28// sil_target: SIL1 29// evidence: [bulk_applied_2026-05-20, p384-field-inv] 30// verdict: NOT_YET_EVALUATED 31 32import "nx_syscalls.nx" 33import "nx_u384.nx" 34import "nx_p384_field.nx" 35import "nx_p384_field_mul.nx" 36import "nx_p384_field_mul_fast.nx" // fast Solinas mul+sq for the inverse's hot 384-iteration Fermat loop 37 38// p-2 differs from p only in limb[0]: 0xFFFFFFFF - 2 = 0xFFFFFFFD. 39func p384_field_load_p_minus_2(out: *i64) -> i64 { 40 out[0] = 0xFFFFFFFD 41 out[1] = 0 42 out[2] = 0 43 out[3] = 0xFFFFFFFF 44 out[4] = 0xFFFFFFFE 45 out[5] = 0xFFFFFFFF 46 out[6] = 0xFFFFFFFF 47 out[7] = 0xFFFFFFFF 48 out[8] = 0xFFFFFFFF 49 out[9] = 0xFFFFFFFF 50 out[10] = 0xFFFFFFFF 51 out[11] = 0xFFFFFFFF 52 return 0 53} 54 55// Extract bit at bit_pos (0 = LSB) from a 12-limb (32-bit/limb LE) integer. 56func p384_field_bit_at(limbs: *i64, bit_pos: i64) -> i64 { 57 let limb_idx: i64 = bit_pos / 32 58 let bit_in_limb: i64 = bit_pos - limb_idx * 32 59 let limb: i64 = limbs[limb_idx] & NX_U384_LIMB_MASK 60 return (limb >> bit_in_limb) & 1 61} 62 63// out = a^(-1) mod p via Fermat: a^(p-2). 64func p384_field_inv(out: *i64, a: *i64) -> i64 { 65 let exp: *i64 = u384_alloc() 66 p384_field_load_p_minus_2(exp) 67 68 // Keep input safe in case out aliases a. 69 let base: *i64 = u384_alloc() 70 u384_copy(base, a) 71 72 let result: *i64 = u384_alloc() 73 p384_field_one(result) 74 75 var bit_pos: i64 = 383 76 while bit_pos >= 0 { 77 p384_field_sq_fast(result, result) 78 if p384_field_bit_at(exp, bit_pos) == 1 { 79 p384_field_mul_fast(result, result, base) 80 } 81 bit_pos = bit_pos - 1 82 } 83 84 u384_copy(out, result) 85 return 0 86} 87 88func main() -> i64 { 89 return 0 90}