nx_crypto_bench_full.nx source
↩ module page · 152 lines · 5092 B
1// nx_crypto_bench_full.nx -- 1:1 bits-up crypto bench vs OpenSSL incumbent.
2//
3// Measures (us/op, MONOTONIC clock, warmed up):
4// 1. p256_kG_generic -- generic double-and-add k*G (PRE-COMB baseline)
5// 2. p256_kG_comb -- fixed-base comb k*G (BITS-UP path)
6// 3. ecdsa_p256_sign -- full sign (generic kG path; no comb file on box)
7// 4. ecdsa_p256_verify -- full verify (u1*G + u2*Q, real signature)
8// 5. x25519_ecdh -- variable-base scalar mult (shared secret)
9//
10// The comb path here is exercised in-memory via p256_comb_build +
11// p256_scalar_mul_base (same code the deploy signer uses when the
12// /volume1/.../p256_comb.bin file is present), so we get the honest
13// comb-vs-generic SPEEDUP without needing the NAS file on disk.
14import "nx_syscalls.nx"
15import "nx_csprng.nx"
16import "nx_u256.nx"
17import "nx_p256_modn.nx"
18import "nx_p256_point.nx"
19import "nx_p256_scalar_mul.nx"
20import "nx_p256_comb.nx"
21import "nx_ecdsa_p256.nx"
22import "nx_ecdsa_p256_sign.nx"
23import "nx_x25519_ephemeral.nx"
24
25func bstrlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != 0 { n = n + 1 } return n }
26
27// print "<label>=<value> us/op (N=<n>)"
28func bprint(label: *u8, total_us: i64, n: i64) -> i64 {
29 sys_write(1, label, bstrlen(label))
30 sys_write(1, "=" as *u8, 1)
31 let per: i64 = total_us / n
32 let buf: *u8 = sys_mmap(24)
33 var d: i64 = 0
34 if per == 0 { buf[0] = 48; d = 1 } else {
35 var x: i64 = per
36 var c: i64 = 0
37 while x > 0 { c = c + 1; x = x / 10 }
38 d = c
39 var i: i64 = d - 1
40 x = per
41 while i >= 0 { buf[i] = (48 + (x % 10)) as u8; x = x / 10; i = i - 1 }
42 }
43 sys_write(1, buf, d)
44 sys_write(1, " us/op N=" as *u8, 10)
45 // print n
46 let buf2: *u8 = sys_mmap(24)
47 var d2: i64 = 0
48 if n == 0 { buf2[0] = 48; d2 = 1 } else {
49 var x2: i64 = n
50 var c2: i64 = 0
51 while x2 > 0 { c2 = c2 + 1; x2 = x2 / 10 }
52 d2 = c2
53 var i2: i64 = d2 - 1
54 x2 = n
55 while i2 >= 0 { buf2[i2] = (48 + (x2 % 10)) as u8; x2 = x2 / 10; i2 = i2 - 1 }
56 }
57 sys_write(1, buf2, d2)
58 sys_write(1, "\n" as *u8, 1)
59 return 0
60}
61
62func main() -> i64 {
63 // ---- shared setup ----
64 let g: *P256Point = p256_point_alloc()
65 p256_point_load_g(g)
66 let table: *i64 = (sys_mmap(NX_P256_COMB_BYTES)) as *i64
67 p256_comb_build(table)
68
69 let k: *i64 = u256_alloc()
70 let be: *u8 = sys_mmap(32)
71 nx_csprng_fill(be, 32)
72 be[0] = 0 // keep scalar well below group order
73 u256_load_be(k, be)
74
75 let pout: *P256Point = p256_point_alloc()
76
77 var t0: i64 = 0
78 var i: i64 = 0
79
80 // ---- 1. generic k*G (pre-comb baseline) ----
81 // warmup
82 p256_scalar_mul(pout, k, g)
83 p256_scalar_mul(pout, k, g)
84 let NG: i64 = 60
85 t0 = sys_now_us()
86 i = 0
87 while i < NG { p256_scalar_mul(pout, k, g); i = i + 1 }
88 bprint("p256_kG_generic " as *u8, sys_now_us() - t0, NG)
89
90 // ---- 2. comb k*G (bits-up path) ----
91 p256_scalar_mul_base(pout, k, table) // warmup
92 p256_scalar_mul_base(pout, k, table)
93 let NC: i64 = 2000
94 t0 = sys_now_us()
95 i = 0
96 while i < NC { p256_scalar_mul_base(pout, k, table); i = i + 1 }
97 bprint("p256_kG_comb " as *u8, sys_now_us() - t0, NC)
98
99 // ---- 3 + 4. ECDSA sign + verify (need a real keypair/sig) ----
100 let dkey: *i64 = u256_alloc()
101 nx_csprng_fill(be, 32); be[0] = 0
102 u256_load_be(dkey, be)
103 let hash: *i64 = u256_alloc()
104 nx_csprng_fill(be, 32)
105 u256_load_be(hash, be)
106 let rr: *i64 = u256_alloc()
107 let ss: *i64 = u256_alloc()
108
109 nx_ecdsa_p256_sign(dkey, hash, rr, ss) // warmup + produce a real sig
110 let NS: i64 = 40
111 t0 = sys_now_us()
112 i = 0
113 while i < NS { nx_ecdsa_p256_sign(dkey, hash, rr, ss); i = i + 1 }
114 bprint("ecdsa_p256_sign " as *u8, sys_now_us() - t0, NS)
115
116 // public key Q = d*G for verify
117 let q: *P256Point = p256_point_alloc()
118 p256_scalar_mul(q, dkey, g)
119 p256_point_to_affine(q)
120
121 // sanity: verify the real signature once
122 let vv: i64 = nx_ecdsa_p256_verify(q.x, q.y, hash, rr, ss)
123 if vv != 1 {
124 sys_write(1, "VERIFY_SELFTEST_FAIL\n" as *u8, 21)
125 return 7
126 }
127 nx_ecdsa_p256_verify(q.x, q.y, hash, rr, ss) // warmup
128 let NV: i64 = 40
129 t0 = sys_now_us()
130 i = 0
131 while i < NV { nx_ecdsa_p256_verify(q.x, q.y, hash, rr, ss); i = i + 1 }
132 bprint("ecdsa_p256_verfy" as *u8, sys_now_us() - t0, NV)
133
134 // ---- 5. X25519 ECDH (variable-base) ----
135 let priv: *u8 = sys_mmap(32)
136 let pub2: *u8 = sys_mmap(32)
137 let secret: *u8 = sys_mmap(32)
138 let peerpriv: *u8 = sys_mmap(32)
139 nx_csprng_fill(priv, 32)
140 nx_csprng_fill(peerpriv, 32)
141 x25519_gen_keypair(peerpriv, pub2)
142 x25519_shared_secret(priv, pub2, secret) // warmup
143 x25519_shared_secret(priv, pub2, secret)
144 let NX: i64 = 1000
145 t0 = sys_now_us()
146 i = 0
147 while i < NX { x25519_shared_secret(priv, pub2, secret); i = i + 1 }
148 bprint("x25519_ecdh " as *u8, sys_now_us() - t0, NX)
149
150 sys_write(1, "BENCH_DONE\n" as *u8, 11)
151 return 0
152}