code wiki / (root) / nx_p384_field.nx

nx_p384_field.nx source

↩ module page · 120 lines · 3687 B

1// nx_p384_field.nx -- NIST P-384 field arithmetic mod p. 2// 3// p = 2^384 - 2^128 - 2^96 + 2^32 - 1 (FIPS 186-5 D.1.2.4) 4// = 0xffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 5// ffffffff fffffffe ffffffff 00000000 00000000 ffffffff 6// 7// Mirrors nx_p256_field.nx structure on the 12-limb u384 layout. 8// Provides add / sub / neg mod p, plus shipped u384 wrappers under 9// the field name. Mul + invert ship separately as 10// nx_p384_field_mul + nx_p384_field_inv (matching the P-256 split). 11// 12// API: 13// p384_field_load_p(out) 14// p384_field_zero/one/copy/eq (wrappers over u384_*) 15// p384_field_add(r, a, b) r = (a + b) mod p 16// p384_field_sub(r, a, b) r = (a - b) mod p 17// p384_field_neg(r, a) r = (-a) mod p 18// 19// license_tier: INDEPENDENT_REDERIVE 20// genealogy_id: international-research-sources/nist/fips_186_5 21// lineage_id: nishi_p384_field_q10 22 23// nx_safety_envelope: 24// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 25// sil_target: SIL1 26// evidence: [bulk_applied_2026-05-20, p384-field-add-sub-neg] 27// verdict: NOT_YET_EVALUATED 28 29import "nx_syscalls.nx" 30import "nx_u384.nx" 31 32const NX_P384_FIELD_OK: i64 = 1 33const NX_P384_FIELD_BAD: i64 = 2 34const NX_P384_FIELD_VERDICT_N: i64 = 3 35 36func nx_p384_field_verdict_is_valid(v: i64) -> i64 { 37 if v < NX_P384_FIELD_OK { return 0 } 38 if v >= NX_P384_FIELD_VERDICT_N { return 0 } 39 return 1 40} 41 42// Load the NIST P-384 prime p into out (12-limb LE). 43// Hex (MSB first): ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 44// ffffffff fffffffe ffffffff 00000000 00000000 ffffffff 45// Limbs (LSB first): 46// limb[0] = 0xFFFFFFFF 47// limb[1] = 0x00000000 48// limb[2] = 0x00000000 49// limb[3] = 0xFFFFFFFF 50// limb[4] = 0xFFFFFFFE 51// limb[5..11] = 0xFFFFFFFF 52func p384_field_load_p(out: *i64) -> i64 { 53 out[0] = 0xFFFFFFFF 54 out[1] = 0 55 out[2] = 0 56 out[3] = 0xFFFFFFFF 57 out[4] = 0xFFFFFFFE 58 out[5] = 0xFFFFFFFF 59 out[6] = 0xFFFFFFFF 60 out[7] = 0xFFFFFFFF 61 out[8] = 0xFFFFFFFF 62 out[9] = 0xFFFFFFFF 63 out[10] = 0xFFFFFFFF 64 out[11] = 0xFFFFFFFF 65 return 0 66} 67 68// Wrapper aliases. 69func p384_field_zero(out: *i64) -> i64 { return u384_zero(out) } 70func p384_field_one(out: *i64) -> i64 { return u384_one(out) } 71func p384_field_copy(out: *i64, src: *i64) -> i64 { return u384_copy(out, src) } 72func p384_field_eq(a: *i64, b: *i64) -> i64 { return u384_eq(a, b) } 73 74// r = (a + b) mod p. Algorithm same as P-256: 75// 1. (r, carry) = a + b 76// 2. (t, borrow) = r - p 77// 3. If carry == 1 OR borrow == 0: r = t (overflowed or r >= p) 78// 4. Else: r already canonical 79func p384_field_add(r: *i64, a: *i64, b: *i64) -> i64 { 80 let t: *i64 = u384_alloc() 81 let p: *i64 = u384_alloc() 82 p384_field_load_p(p) 83 let carry: i64 = u384_add_with_carry(r, a, b) 84 let borrow: i64 = u384_sub_with_borrow(t, r, p) 85 if carry == 1 { 86 u384_copy(r, t) 87 } else { 88 if borrow == 0 { 89 u384_copy(r, t) 90 } 91 } 92 return 0 93} 94 95// r = (a - b) mod p. If a < b, add p back to bring into [0, p). 96func p384_field_sub(r: *i64, a: *i64, b: *i64) -> i64 { 97 let p: *i64 = u384_alloc() 98 p384_field_load_p(p) 99 let borrow: i64 = u384_sub_with_borrow(r, a, b) 100 if borrow == 1 { 101 u384_add_with_carry(r, r, p) 102 } 103 return 0 104} 105 106// r = (-a) mod p. 107func p384_field_neg(r: *i64, a: *i64) -> i64 { 108 if u384_is_zero(a) == 1 { 109 u384_zero(r) 110 return 0 111 } 112 let p: *i64 = u384_alloc() 113 p384_field_load_p(p) 114 u384_sub_with_borrow(r, p, a) 115 return 0 116} 117 118func main() -> i64 { 119 return 0 120}