code wiki / (root) / nx_p384_point_add.nx

nx_p384_point_add.nx source

↩ module page · 129 lines · 3803 B

1// nx_p384_point_add.nx -- Jacobian point addition for P-384. 2// 3// Mirror of nx_p256_point_add.nx. Same formula structure; only 4// the underlying field arithmetic differs (12-limb vs 8-limb). 5// 6// add-2007-bl Jacobian point addition (P1 != P2 general case): 7// U1 = X1 * Z2^2 8// U2 = X2 * Z1^2 9// S1 = Y1 * Z2^3 10// S2 = Y2 * Z1^3 11// if U1 == U2: 12// if S1 == S2: return 2*P1 (same point -> doubling) 13// else: return O (P1 = -P2) 14// H = U2 - U1 15// R = S2 - S1 16// X3 = R^2 - H^3 - 2*U1*H^2 17// Y3 = R * (U1*H^2 - X3) - S1*H^3 18// Z3 = H * Z1 * Z2 19// 20// license_tier: INDEPENDENT_REDERIVE 21// genealogy_id: international-research-sources/nist/sec1_v2_2.2.1.2 22// lineage_id: nishi_p384_point_add_q10 23 24// nx_safety_envelope: 25// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 26// sil_target: SIL1 27// evidence: [bulk_applied_2026-05-20, p384-point-add-jacobian] 28// verdict: NOT_YET_EVALUATED 29 30import "nx_syscalls.nx" 31import "nx_u384.nx" 32import "nx_p384_field.nx" 33import "nx_p384_field_mul_fast.nx" // FAST Solinas reduction (drop-in, KAT-gated vs the slow bit-by-bit mul) -- was the ~640ms/verify bottleneck 34import "nx_p384_point.nx" 35 36// out = p1 + p2 on the curve. Aliasing-safe across all combos. 37func p384_point_add(out: *P384Point, p1: *P384Point, p2: *P384Point) -> i64 { 38 if p384_point_is_infinity(p1) == 1 { 39 p384_point_copy(out, p2) 40 return 0 41 } 42 if p384_point_is_infinity(p2) == 1 { 43 p384_point_copy(out, p1) 44 return 0 45 } 46 47 let X1: *i64 = u384_alloc() 48 let Y1: *i64 = u384_alloc() 49 let Z1: *i64 = u384_alloc() 50 let X2: *i64 = u384_alloc() 51 let Y2: *i64 = u384_alloc() 52 let Z2: *i64 = u384_alloc() 53 u384_copy(X1, p1.x) 54 u384_copy(Y1, p1.y) 55 u384_copy(Z1, p1.z) 56 u384_copy(X2, p2.x) 57 u384_copy(Y2, p2.y) 58 u384_copy(Z2, p2.z) 59 60 let Z1_sq: *i64 = u384_alloc() 61 let Z2_sq: *i64 = u384_alloc() 62 p384_field_sq_fast(Z1_sq, Z1) 63 p384_field_sq_fast(Z2_sq, Z2) 64 let U1: *i64 = u384_alloc() 65 let U2: *i64 = u384_alloc() 66 p384_field_mul_fast(U1, X1, Z2_sq) 67 p384_field_mul_fast(U2, X2, Z1_sq) 68 69 let Z1_cu: *i64 = u384_alloc() 70 let Z2_cu: *i64 = u384_alloc() 71 p384_field_mul_fast(Z1_cu, Z1_sq, Z1) 72 p384_field_mul_fast(Z2_cu, Z2_sq, Z2) 73 let S1: *i64 = u384_alloc() 74 let S2: *i64 = u384_alloc() 75 p384_field_mul_fast(S1, Y1, Z2_cu) 76 p384_field_mul_fast(S2, Y2, Z1_cu) 77 78 if p384_field_eq(U1, U2) == 1 { 79 if p384_field_eq(S1, S2) == 1 { 80 let snap: *P384Point = p384_point_alloc() 81 u384_copy(snap.x, X1) 82 u384_copy(snap.y, Y1) 83 u384_copy(snap.z, Z1) 84 p384_point_double(out, snap) 85 return 0 86 } 87 p384_point_zero(out) 88 return 0 89 } 90 91 let H: *i64 = u384_alloc() 92 let R: *i64 = u384_alloc() 93 p384_field_sub(H, U2, U1) 94 p384_field_sub(R, S2, S1) 95 96 let H2: *i64 = u384_alloc() 97 let H3: *i64 = u384_alloc() 98 let U1H2: *i64 = u384_alloc() 99 p384_field_sq_fast(H2, H) 100 p384_field_mul_fast(H3, H, H2) 101 p384_field_mul_fast(U1H2, U1, H2) 102 103 let X3: *i64 = u384_alloc() 104 let tmp: *i64 = u384_alloc() 105 p384_field_sq_fast(X3, R) 106 p384_field_sub(X3, X3, H3) 107 p384_field_add(tmp, U1H2, U1H2) 108 p384_field_sub(X3, X3, tmp) 109 110 let Y3: *i64 = u384_alloc() 111 let inner: *i64 = u384_alloc() 112 p384_field_sub(inner, U1H2, X3) 113 p384_field_mul_fast(Y3, R, inner) 114 p384_field_mul_fast(tmp, S1, H3) 115 p384_field_sub(Y3, Y3, tmp) 116 117 let Z3: *i64 = u384_alloc() 118 p384_field_mul_fast(Z3, H, Z1) 119 p384_field_mul_fast(Z3, Z3, Z2) 120 121 u384_copy(out.x, X3) 122 u384_copy(out.y, Y3) 123 u384_copy(out.z, Z3) 124 return 0 125} 126 127func main() -> i64 { 128 return 0 129}