code wiki / (root) / nx_p256_verify_timing.nx

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}