code wiki / (root) / nx_p256_comb_bench.nx

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}