nx_p256_comb_bench.nx source
↩ module page · 68 lines · 3263 B
1// nx_p256_comb_bench.nx -- does the fixed-base comb (p256_scalar_mul_base, precomputed G-table) beat
2// generic double-and-add (p256_scalar_mul) enough to justify wiring it into the ECDSA verify's u1*G?
3// Table built ONCE (amortized, as it would be cached live). Dependent-chain (DCE/hoist-proof).
4// Correctness pre-check: comb == generic for the same scalar (the nx_p256_comb_test guarantee, re-run
5// here on the bench scalars). expect_exit: 0 license_tier: ORIGINAL
6import "nx_syscalls.nx"
7import "nx_p256_comb.nx"
8import "nx_p256_scalar_mul.nx"
9const N_MAGIC_1000000000: i64 = 1000000000
10
11const N_ITER: i64 = 2000
12
13func bp(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
14func bn(v: i64) -> i64 {
15 let t: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
16 let b: *u8 = sys_mmap(28); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 }
17 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
18 var i: i64 = 0; while i < k { b[i] = t[k-1-i]; i = i + 1 } sys_write(1, b, k); return 0
19}
20func now_ns(ts: *i64) -> i64 { __syscall(SYS_CLOCK_GETTIME, 1, ts as i64, 0, 0, 0, 0); return ts[0] * N_MAGIC_1000000000 + ts[1] }
21
22func main() -> i64 {
23 let table: *i64 = (sys_mmap(NX_P256_COMB_BYTES)) as *i64
24 p256_comb_build(table)
25 let g: *P256Point = p256_point_alloc()
26 p256_point_load_g(g)
27 let k: *i64 = u256_alloc()
28 let r1: *P256Point = p256_point_alloc()
29 let r2: *P256Point = p256_point_alloc()
30 let ts: *i64 = sys_mmap(32) as *i64
31
32 // correctness pre-check: comb == generic over a few scalars
33 var bad: i64 = 0
34 var s: i64 = 0
35 while s < 64 {
36 var j: i64 = 0; while j < 4 { k[j] = (0x9e3779b97f4a7c15 * (s + 1) * (j + 1)) & 0xffffffffffffffff; j = j + 1 }
37 p256_scalar_mul_base(r1, k, table)
38 p256_scalar_mul(r2, k, g)
39 if p256_point_eq(r1, r2) == 0 { bad = bad + 1 }
40 s = s + 1
41 }
42 bp("=== nx_p256_comb_bench: fixed-base comb k*G vs generic double-and-add ===\n" as *u8)
43 if bad != 0 { bp("CORRECTNESS FAIL bad=" as *u8); bn(bad); bp("\n" as *u8); sys_exit(1); return 1 }
44 bp("correctness: comb == generic over 64 scalars (GREEN)\n" as *u8)
45
46 var j2: i64 = 0; while j2 < 4 { k[j2] = (0xdeadbeefcafebabe * (j2 + 7)) & 0xffffffffffffffff; j2 = j2 + 1 }
47
48 // generic k*G
49 var accg: i64 = 0
50 let t0: i64 = now_ns(ts)
51 var i: i64 = 0
52 while i < N_ITER { k[0] = (k[0] ^ accg) & 0xffffffffffffffff; p256_scalar_mul(r2, k, g); accg = accg ^ r2.x[0]; i = i + 1 }
53 let gen_ns: i64 = now_ns(ts) - t0
54
55 k[0] = (0xdeadbeefcafebabe * 7) & 0xffffffffffffffff
56 // comb k*G
57 var accc: i64 = 0
58 let t2: i64 = now_ns(ts)
59 i = 0
60 while i < N_ITER { k[0] = (k[0] ^ accc) & 0xffffffffffffffff; p256_scalar_mul_base(r1, k, table); accc = accc ^ r1.x[0]; i = i + 1 }
61 let comb_ns: i64 = now_ns(ts) - t2
62
63 bn(N_ITER); bp(" iters\n" as *u8)
64 bp("generic_kG = " as *u8); bn(gen_ns / N_ITER); bp(" ns/op\n" as *u8)
65 bp("comb_kG = " as *u8); bn(comb_ns / N_ITER); bp(" ns/op\n" as *u8)
66 if comb_ns > 0 { bp("speedup_x100 = " as *u8); bn(gen_ns * 100 / comb_ns); bp(" (100=parity, >100=comb faster)\n" as *u8) }
67 return 0
68}