code wiki / (root) / nx_ed25519_point_test.nx

nx_ed25519_point_test.nx source

↩ module page · 110 lines · 4148 B

1// nx_ed25519_point_test.nx -- KAT for Edwards-curve point decompression. 2// 3// Verifies: 4// A. Decompress RFC 8032 §7.1 TEST 1 pubkey -> resulting GeP3 5// satisfies the twisted Edwards equation (-X^2 + Y^2 == 1 + d*X^2*Y^2) 6// B. Decompress the basepoint (RFC 8032 §6 / RFC 7748 base point 7// encoded as Ed25519 pubkey) -> on curve 8// C. Sign-bit flip: decompress P, then decompress P with high 9// bit of byte 31 flipped -> X coordinates have opposite parity 10// (one is the negative of the other) 11// D. Y coordinate round-trips through fe_to_bytes 12// 13// expect_exit: 0 14// license_tier: ORIGINAL 15 16import "nx_syscalls.nx" 17import "nx_x25519.nx" 18import "nx_ed25519_field.nx" 19import "nx_ed25519_point.nx" 20 21func main() -> i64 { 22 // ---- Test A: RFC 8032 §7.1 TEST 1 pubkey ---- 23 // d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a 24 let pk1: *u8 = sys_mmap(64) 25 pk1[0]=0xd7; pk1[1]=0x5a; pk1[2]=0x98; pk1[3]=0x01 26 pk1[4]=0x82; pk1[5]=0xb1; pk1[6]=0x0a; pk1[7]=0xb7 27 pk1[8]=0xd5; pk1[9]=0x4b; pk1[10]=0xfe; pk1[11]=0xd3 28 pk1[12]=0xc9; pk1[13]=0x64; pk1[14]=0x07; pk1[15]=0x3a 29 pk1[16]=0x0e; pk1[17]=0xe1; pk1[18]=0x72; pk1[19]=0xf3 30 pk1[20]=0xda; pk1[21]=0xa6; pk1[22]=0x23; pk1[23]=0x25 31 pk1[24]=0xaf; pk1[25]=0x02; pk1[26]=0x1a; pk1[27]=0x68 32 pk1[28]=0xf7; pk1[29]=0x07; pk1[30]=0x51; pk1[31]=0x1a 33 34 let p1: *GeP3 = ge_p3_alloc() 35 let v1: i64 = ge_p3_decompress(p1, pk1) 36 if v1 != NX_GE_VERDICT_OK { return 1 } 37 if ge_p3_on_curve(p1) != 1 { return 2 } 38 39 // ---- Test B: Ed25519 basepoint compressed encoding ---- 40 // Basepoint Y coordinate per RFC 8032 §5.1: y = 4/5 mod p 41 // Encoded LE: 5866666666666666666666666666666666666666666666666666666666666666 42 // (Y bytes are all 0x66 with byte 0 = 0x58; sign bit of x = 0) 43 let bp: *u8 = sys_mmap(64) 44 bp[0]=0x58 45 var bi: i64 = 1 46 while bi < 32 { 47 bp[bi] = 0x66 48 bi = bi + 1 49 } 50 let p2: *GeP3 = ge_p3_alloc() 51 let v2: i64 = ge_p3_decompress(p2, bp) 52 if v2 != NX_GE_VERDICT_OK { return 10 } 53 if ge_p3_on_curve(p2) != 1 { return 11 } 54 55 // ---- Test C: sign-bit flip produces a different X ---- 56 let pk1_flipped: *u8 = sys_mmap(64) 57 var fi: i64 = 0 58 while fi < 32 { 59 pk1_flipped[fi] = pk1[fi] 60 fi = fi + 1 61 } 62 pk1_flipped[31] = pk1_flipped[31] ^ 0x80 // flip sign-of-x bit 63 let p1_alt: *GeP3 = ge_p3_alloc() 64 let v3: i64 = ge_p3_decompress(p1_alt, pk1_flipped) 65 if v3 != NX_GE_VERDICT_OK { return 20 } 66 if ge_p3_on_curve(p1_alt) != 1 { return 21 } 67 68 // Y MUST be the same (only the sign bit of x was flipped) 69 if fe_canonical_equal(p1.Y, p1_alt.Y) != 1 { return 22 } 70 71 // X MUST differ (one is negative of the other) 72 if fe_canonical_equal(p1.X, p1_alt.X) == 1 { return 23 } 73 74 // Specifically: p1.X + p1_alt.X should equal 0 mod p (sums to zero) 75 let x_sum: *i64 = fe_alloc() 76 fe_add(x_sum, p1.X, p1_alt.X) 77 let zero: *i64 = fe_alloc() 78 fe_zero(zero) 79 if fe_canonical_equal(x_sum, zero) != 1 { return 24 } 80 81 // ---- Test D: Y round-trips through canonical encoding ---- 82 // The Y stored in p1 should encode back to the same bytes 83 // (modulo the sign bit, which is X's not Y's). 84 let y_re: *u8 = sys_mmap(32) 85 fe_to_bytes(y_re, p1.Y) 86 var di: i64 = 0 87 while di < 31 { 88 if (y_re[di] & 0xff) != (pk1[di] & 0xff) { return 40 + di } 89 di = di + 1 90 } 91 // Byte 31: pubkey has sign bit; our Y encoding doesn't. Mask high bit. 92 if (y_re[31] & 0x7f) != (pk1[31] & 0x7f) { return 80 } 93 94 // ---- Test E: T == X * Y (extended-coord consistency) ---- 95 let xy: *i64 = fe_alloc() 96 fe_mul(xy, p1.X, p1.Y) 97 if fe_canonical_equal(p1.T, xy) != 1 { return 90 } 98 99 // ---- Test F: Z == 1 ---- 100 let one: *i64 = fe_alloc() 101 fe_one(one) 102 if fe_canonical_equal(p1.Z, one) != 1 { return 91 } 103 104 // ---- Test G: verdict gate ---- 105 if nx_ge_verdict_is_valid(NX_GE_VERDICT_OK) != 1 { return 100 } 106 if nx_ge_verdict_is_valid(NX_GE_VERDICT_N) != 0 { return 101 } 107 if nx_ge_verdict_is_valid(0 - 1) != 0 { return 102 } 108 109 return 0 110}