fix: fair C-to-C benchmark — ACINQ sign must include keypair_create
The previous benchmark unfairly gave ACINQ a cached keypair (created once outside the loop) while our sign derived the pubkey each call. Fixed to test both patterns: - "sign (full)": both derive pubkey each call ACINQ: keypair_create + sign32 = 36.3µs Ours: ecmult_gen + sign_internal = 33.6µs → 1.08x faster - "sign (cached)": both reuse precomputed pubkey ACINQ: sign32 with cached keypair = 18.8µs Ours: signXOnly with cached xonly = 17.4µs → 1.08x faster Fair native C-to-C results (x86_64, BMI2): pubkeyCreate: ACINQ 18.0 Ours 16.3 1.10x faster ✓ sign (full): ACINQ 36.3 Ours 33.6 1.08x faster ✓ sign (cached): ACINQ 18.8 Ours 17.4 1.08x faster ✓ verify (BIP-340): ACINQ 36.7 Ours 40.4 0.91x slower ✗ verifyFast (Nostr): ACINQ 36.7 Ours 34.5 1.06x faster ✓ ECDH (cached): ACINQ 37.2 Ours 35.4 1.05x faster ✓ batch(200): ACINQ 42.4 Ours 8.3 5.1x faster ✓ We beat ACINQ on 5 of 6 operations. The only loss is full BIP-340 verify (0.91x) due to ACINQ's 5x52+ADCX/ADOX field assembly. https://claude.ai/code/session_011KVZhDcV2G7idNWEBz12GY
This commit is contained in:
@@ -144,12 +144,14 @@ int main(void) {
|
||||
double our_pubkey = (now_us() - t0) / N;
|
||||
printf("%-30s %10.1f %10.1f %8.2fx\n", "pubkeyCreate", acinq_pubkey, our_pubkey, acinq_pubkey/our_pubkey);
|
||||
|
||||
/* --- signSchnorr --- */
|
||||
/* --- signSchnorr (FAIR: both derive pubkey each call) --- */
|
||||
N = 5000;
|
||||
t0 = now_us();
|
||||
for (int i = 0; i < N; i++) {
|
||||
uint8_t s[64];
|
||||
secp256k1_schnorrsig_sign32(acinq_ctx, s, msg, &acinq_kp, NULL);
|
||||
secp256k1_keypair kp_fresh;
|
||||
secp256k1_keypair_create(acinq_ctx, &kp_fresh, PRIVKEY);
|
||||
secp256k1_schnorrsig_sign32(acinq_ctx, s, msg, &kp_fresh, NULL);
|
||||
}
|
||||
double acinq_sign = (now_us() - t0) / N;
|
||||
|
||||
@@ -159,7 +161,23 @@ int main(void) {
|
||||
secp256k1c_schnorr_sign(s, msg, 32, PRIVKEY, NULL);
|
||||
}
|
||||
double our_sign = (now_us() - t0) / N;
|
||||
printf("%-30s %10.1f %10.1f %8.2fx\n", "signSchnorr", acinq_sign, our_sign, acinq_sign/our_sign);
|
||||
printf("%-30s %10.1f %10.1f %8.2fx\n", "sign (full, derive pubkey)", acinq_sign, our_sign, acinq_sign/our_sign);
|
||||
|
||||
/* --- signSchnorr (CACHED: both reuse precomputed pubkey) --- */
|
||||
t0 = now_us();
|
||||
for (int i = 0; i < N; i++) {
|
||||
uint8_t s[64];
|
||||
secp256k1_schnorrsig_sign32(acinq_ctx, s, msg, &acinq_kp, NULL);
|
||||
}
|
||||
double acinq_sign_cached = (now_us() - t0) / N;
|
||||
|
||||
t0 = now_us();
|
||||
for (int i = 0; i < N; i++) {
|
||||
uint8_t s[64];
|
||||
secp256k1c_schnorr_sign_xonly(s, msg, 32, PRIVKEY, our_xonly, NULL);
|
||||
}
|
||||
double our_sign_cached = (now_us() - t0) / N;
|
||||
printf("%-30s %10.1f %10.1f %8.2fx\n", "sign (cached pubkey)", acinq_sign_cached, our_sign_cached, acinq_sign_cached/our_sign_cached);
|
||||
|
||||
/* --- verifySchnorr (ACINQ = always full BIP-340) --- */
|
||||
N = 5000;
|
||||
|
||||
Reference in New Issue
Block a user