nx_ecdsa_p256_sign_test.nx source
↩ module page · 86 lines · 3926 B
1// nx_ecdsa_p256_sign_smoke.nx -- MONITOR for ECDSA P-256 SIGN.
2//
3// Sign-then-verify round-trip: pure-NishiLang produces (r, s) for
4// a known (priv_key, msg_hash) pair, then feeds (priv_key * G, hash,
5// r, s) to the already-shipped nx_ecdsa_p256_verify. Verify MUST
6// return OK -- closes the loop that the sign side is producing
7// substrate-valid signatures.
8//
9// Test vector: RFC 6979 §A.2.5 NIST P-256 + SHA-256 with the
10// well-known sample privkey + message hash.
11// priv = 0xC9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721
12// hash = SHA-256("sample") = 0xAF2BDBE1AA9B6EC1E2ADE1D694F41FC71A831D0268E9891562113D8A62ADD1BF
13//
14// Expected r = 0xEFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716
15// Expected s = 0xF7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8
16//
17// We don't compare against the RFC vector directly (the byte-order
18// of internal limb representation makes the comparison fiddly); we
19// instead assert that our sign output VERIFIES against the matching
20// public key. That's the load-bearing property: sign produces a
21// signature that the substrate's own verify accepts.
22
23import "nx_syscalls.nx"
24import "nx_u256.nx"
25import "nx_p256_modn.nx"
26import "nx_p256_point.nx"
27import "nx_p256_scalar_mul.nx"
28import "nx_ecdsa_p256.nx"
29import "nx_ecdsa_p256_sign.nx"
30
31func main() -> i64 {
32 // Priv key (32 bytes big-endian).
33 let priv_bytes: *u8 = sys_mmap(32)
34 priv_bytes[0]=0xC9; priv_bytes[1]=0xAF; priv_bytes[2]=0xA9; priv_bytes[3]=0xD8
35 priv_bytes[4]=0x45; priv_bytes[5]=0xBA; priv_bytes[6]=0x75; priv_bytes[7]=0x16
36 priv_bytes[8]=0x6B; priv_bytes[9]=0x5C; priv_bytes[10]=0x21; priv_bytes[11]=0x57
37 priv_bytes[12]=0x67; priv_bytes[13]=0xB1; priv_bytes[14]=0xD6; priv_bytes[15]=0x93
38 priv_bytes[16]=0x4E; priv_bytes[17]=0x50; priv_bytes[18]=0xC3; priv_bytes[19]=0xDB
39 priv_bytes[20]=0x36; priv_bytes[21]=0xE8; priv_bytes[22]=0x9B; priv_bytes[23]=0x12
40 priv_bytes[24]=0x7B; priv_bytes[25]=0x8A; priv_bytes[26]=0x62; priv_bytes[27]=0x2B
41 priv_bytes[28]=0x12; priv_bytes[29]=0x0F; priv_bytes[30]=0x67; priv_bytes[31]=0x21
42
43 let priv_limbs: *i64 = u256_alloc()
44 u256_load_be(priv_limbs, priv_bytes)
45
46 // Message hash = SHA-256("sample") -- the RFC 6979 §A.2.5 vector.
47 let hash_bytes: *u8 = sys_mmap(32)
48 hash_bytes[0]=0xAF; hash_bytes[1]=0x2B; hash_bytes[2]=0xDB; hash_bytes[3]=0xE1
49 hash_bytes[4]=0xAA; hash_bytes[5]=0x9B; hash_bytes[6]=0x6E; hash_bytes[7]=0xC1
50 hash_bytes[8]=0xE2; hash_bytes[9]=0xAD; hash_bytes[10]=0xE1; hash_bytes[11]=0xD6
51 hash_bytes[12]=0x94; hash_bytes[13]=0xF4; hash_bytes[14]=0x1F; hash_bytes[15]=0xC7
52 hash_bytes[16]=0x1A; hash_bytes[17]=0x83; hash_bytes[18]=0x1D; hash_bytes[19]=0x02
53 hash_bytes[20]=0x68; hash_bytes[21]=0xE9; hash_bytes[22]=0x89; hash_bytes[23]=0x15
54 hash_bytes[24]=0x62; hash_bytes[25]=0x11; hash_bytes[26]=0x3D; hash_bytes[27]=0x8A
55 hash_bytes[28]=0x62; hash_bytes[29]=0xAD; hash_bytes[30]=0xD1; hash_bytes[31]=0xBF
56
57 let hash_limbs: *i64 = u256_alloc()
58 u256_load_be(hash_limbs, hash_bytes)
59
60 // Sign.
61 let r: *i64 = u256_alloc()
62 let s: *i64 = u256_alloc()
63 let sv: i64 = nx_ecdsa_p256_sign(priv_limbs, hash_limbs, r, s)
64 if sv != NX_ECDSA_SIGN_OK { return 1 }
65
66 // r and s should be non-zero.
67 if u256_is_zero(r) == 1 { return 2 }
68 if u256_is_zero(s) == 1 { return 3 }
69
70 // Derive public key Q = priv * G.
71 let g: *P256Point = p256_point_alloc()
72 p256_point_load_g(g)
73 let q: *P256Point = p256_point_alloc()
74 p256_scalar_mul(q, priv_limbs, g)
75 p256_point_to_affine(q)
76
77 // Round-trip: verify our (r, s) against Q + hash.
78 let vv: i64 = nx_ecdsa_p256_verify(q.x, q.y, hash_limbs, r, s)
79 if vv != 1 { return 10 } // 1 = verify OK
80
81 let ok: *u8 = sys_mmap(8)
82 ok[0]=80; ok[1]=65; ok[2]=83; ok[3]=83; ok[4]=10 // "PASS\n"
83 sys_write(1, ok, 5)
84 return 0
85 return 0
86}