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}