nx_p256_verify_timing.nx source
↩ module page · 138 lines · 5963 B
1// nx_p256_verify_timing.nx -- end-to-end ECDSA-P256 verify timing on the
2// RFC 6979 A.2.5 vector, to report where cert-verify lands with the Solinas
3// field multiply on the hot path. Read-only: calls the PUBLIC verify only,
4// modifies nothing. Warms up + asserts the signature verifies before timing
5// so we never time a wrong result.
6//
7// license_tier: ORIGINAL
8
9import "nx_syscalls.nx"
10import "nx_u256.nx"
11import "nx_p256_field.nx"
12import "nx_p256_modn.nx"
13import "nx_ecdsa_p256.nx"
14
15func _vt_print_dec(n: i64) -> i64 {
16 let out: *u8 = sys_mmap(32)
17 if n == 0 {
18 out[0] = 48 as u8
19 sys_write(1, out, 1)
20 return 0
21 }
22 let tmp: *u8 = sys_mmap(32)
23 var v: i64 = n
24 var i: i64 = 0
25 while v > 0 {
26 let d: i64 = v - (v / 10) * 10
27 tmp[i] = (48 + d) as u8
28 v = v / 10
29 i = i + 1
30 }
31 var j: i64 = 0
32 while i > 0 {
33 i = i - 1
34 out[j] = tmp[i]
35 j = j + 1
36 }
37 sys_write(1, out, j)
38 return 0
39}
40
41func main() -> i64 {
42 // ---- RFC 6979 A.2.5 (NIST P-256 + SHA-256, msg="sample") ----
43 let qx_bytes: *u8 = sys_mmap(32)
44 qx_bytes[0] = 0x60; qx_bytes[1] = 0xFE; qx_bytes[2] = 0xD4; qx_bytes[3] = 0xBA
45 qx_bytes[4] = 0x25; qx_bytes[5] = 0x5A; qx_bytes[6] = 0x9D; qx_bytes[7] = 0x31
46 qx_bytes[8] = 0xC9; qx_bytes[9] = 0x61; qx_bytes[10] = 0xEB; qx_bytes[11] = 0x74
47 qx_bytes[12] = 0xC6; qx_bytes[13] = 0x35; qx_bytes[14] = 0x6D; qx_bytes[15] = 0x68
48 qx_bytes[16] = 0xC0; qx_bytes[17] = 0x49; qx_bytes[18] = 0xB8; qx_bytes[19] = 0x92
49 qx_bytes[20] = 0x3B; qx_bytes[21] = 0x61; qx_bytes[22] = 0xFA; qx_bytes[23] = 0x6C
50 qx_bytes[24] = 0xE6; qx_bytes[25] = 0x69; qx_bytes[26] = 0x62; qx_bytes[27] = 0x2E
51 qx_bytes[28] = 0x60; qx_bytes[29] = 0xF2; qx_bytes[30] = 0x9F; qx_bytes[31] = 0xB6
52
53 let qy_bytes: *u8 = sys_mmap(32)
54 qy_bytes[0] = 0x79; qy_bytes[1] = 0x03; qy_bytes[2] = 0xFE; qy_bytes[3] = 0x10
55 qy_bytes[4] = 0x08; qy_bytes[5] = 0xB8; qy_bytes[6] = 0xBC; qy_bytes[7] = 0x99
56 qy_bytes[8] = 0xA4; qy_bytes[9] = 0x1A; qy_bytes[10] = 0xE9; qy_bytes[11] = 0xE9
57 qy_bytes[12] = 0x56; qy_bytes[13] = 0x28; qy_bytes[14] = 0xBC; qy_bytes[15] = 0x64
58 qy_bytes[16] = 0xF2; qy_bytes[17] = 0xF1; qy_bytes[18] = 0xB2; qy_bytes[19] = 0x0C
59 qy_bytes[20] = 0x2D; qy_bytes[21] = 0x7E; qy_bytes[22] = 0x9F; qy_bytes[23] = 0x51
60 qy_bytes[24] = 0x77; qy_bytes[25] = 0xA3; qy_bytes[26] = 0xC2; qy_bytes[27] = 0x94
61 qy_bytes[28] = 0xD4; qy_bytes[29] = 0x46; qy_bytes[30] = 0x22; qy_bytes[31] = 0x99
62
63 let e_bytes: *u8 = sys_mmap(32)
64 e_bytes[0] = 0xAF; e_bytes[1] = 0x2B; e_bytes[2] = 0xDB; e_bytes[3] = 0xE1
65 e_bytes[4] = 0xAA; e_bytes[5] = 0x9B; e_bytes[6] = 0x6E; e_bytes[7] = 0xC1
66 e_bytes[8] = 0xE2; e_bytes[9] = 0xAD; e_bytes[10] = 0xE1; e_bytes[11] = 0xD6
67 e_bytes[12] = 0x94; e_bytes[13] = 0xF4; e_bytes[14] = 0x1F; e_bytes[15] = 0xC7
68 e_bytes[16] = 0x1A; e_bytes[17] = 0x83; e_bytes[18] = 0x1D; e_bytes[19] = 0x02
69 e_bytes[20] = 0x68; e_bytes[21] = 0xE9; e_bytes[22] = 0x89; e_bytes[23] = 0x15
70 e_bytes[24] = 0x62; e_bytes[25] = 0x11; e_bytes[26] = 0x3D; e_bytes[27] = 0x8A
71 e_bytes[28] = 0x62; e_bytes[29] = 0xAD; e_bytes[30] = 0xD1; e_bytes[31] = 0xBF
72
73 let r_bytes: *u8 = sys_mmap(32)
74 r_bytes[0] = 0xEF; r_bytes[1] = 0xD4; r_bytes[2] = 0x8B; r_bytes[3] = 0x2A
75 r_bytes[4] = 0xAC; r_bytes[5] = 0xB6; r_bytes[6] = 0xA8; r_bytes[7] = 0xFD
76 r_bytes[8] = 0x11; r_bytes[9] = 0x40; r_bytes[10] = 0xDD; r_bytes[11] = 0x9C
77 r_bytes[12] = 0xD4; r_bytes[13] = 0x5E; r_bytes[14] = 0x81; r_bytes[15] = 0xD6
78 r_bytes[16] = 0x9D; r_bytes[17] = 0x2C; r_bytes[18] = 0x87; r_bytes[19] = 0x7B
79 r_bytes[20] = 0x56; r_bytes[21] = 0xAA; r_bytes[22] = 0xF9; r_bytes[23] = 0x91
80 r_bytes[24] = 0xC3; r_bytes[25] = 0x4D; r_bytes[26] = 0x0E; r_bytes[27] = 0xA8
81 r_bytes[28] = 0x4E; r_bytes[29] = 0xAF; r_bytes[30] = 0x37; r_bytes[31] = 0x16
82
83 let s_bytes: *u8 = sys_mmap(32)
84 s_bytes[0] = 0xF7; s_bytes[1] = 0xCB; s_bytes[2] = 0x1C; s_bytes[3] = 0x94
85 s_bytes[4] = 0x2D; s_bytes[5] = 0x65; s_bytes[6] = 0x7C; s_bytes[7] = 0x41
86 s_bytes[8] = 0xD4; s_bytes[9] = 0x36; s_bytes[10] = 0xC7; s_bytes[11] = 0xA1
87 s_bytes[12] = 0xB6; s_bytes[13] = 0xE2; s_bytes[14] = 0x9F; s_bytes[15] = 0x65
88 s_bytes[16] = 0xF3; s_bytes[17] = 0xE9; s_bytes[18] = 0x00; s_bytes[19] = 0xDB
89 s_bytes[20] = 0xB9; s_bytes[21] = 0xAF; s_bytes[22] = 0xF4; s_bytes[23] = 0x06
90 s_bytes[24] = 0x4D; s_bytes[25] = 0xC4; s_bytes[26] = 0xAB; s_bytes[27] = 0x2F
91 s_bytes[28] = 0x84; s_bytes[29] = 0x3A; s_bytes[30] = 0xCD; s_bytes[31] = 0xA8
92
93 let qx: *i64 = u256_alloc()
94 let qy: *i64 = u256_alloc()
95 let e: *i64 = u256_alloc()
96 let r: *i64 = u256_alloc()
97 let s: *i64 = u256_alloc()
98 u256_load_be(qx, qx_bytes)
99 u256_load_be(qy, qy_bytes)
100 u256_load_be(e, e_bytes)
101 u256_load_be(r, r_bytes)
102 u256_load_be(s, s_bytes)
103
104 // Warm up + assert valid before timing (never time a wrong verdict).
105 if nx_ecdsa_p256_verify(qx, qy, e, r, s) != NX_ECDSA_OK {
106 sys_write(2, "verify NOT OK -- aborting timing\n" as *u8, 33)
107 return 1
108 }
109
110 let ITERS: i64 = 200
111 let t0: i64 = sys_now_us()
112 var i: i64 = 0
113 var acc: i64 = 0
114 while i < ITERS {
115 acc = acc + nx_ecdsa_p256_verify(qx, qy, e, r, s)
116 i = i + 1
117 }
118 let t1: i64 = sys_now_us()
119
120 let us: i64 = t1 - t0
121 let perv: i64 = us / ITERS
122 let ms_int: i64 = perv / 1000
123 let ms_ten: i64 = (perv - ms_int * 1000) / 100
124
125 sys_write(1, "ecdsa_verify x" as *u8, 14)
126 _vt_print_dec(ITERS)
127 sys_write(1, ": total=" as *u8, 8)
128 _vt_print_dec(us)
129 sys_write(1, "us per_verify=" as *u8, 15)
130 _vt_print_dec(perv)
131 sys_write(1, "us (" as *u8, 4)
132 _vt_print_dec(ms_int)
133 sys_write(1, "." as *u8, 1)
134 _vt_print_dec(ms_ten)
135 sys_write(1, "ms)\n" as *u8, 4)
136
137 return acc & 255
138}