356int main(
int argc,
char** argv) {
357 int parse_exit_code = -1;
358 std::optional<BenchConfig> config = parse_args(argc, argv, parse_exit_code);
359 if (!config.has_value()) {
360 return parse_exit_code < 0 ? 1 : parse_exit_code;
363 warn_if_not_release();
365 std::optional<PurifyBenchCase> bench_case = make_case();
366 if (!bench_case.has_value()) {
369 std::array<unsigned char, 32> experimental_nonce{};
370 for (std::size_t i = 0; i < experimental_nonce.size(); ++i) {
371 experimental_nonce[i] =
static_cast<unsigned char>(i + 17);
375 std::size_t circuit_bytes = estimate_bytes(bench_case->circuit);
377 bench_case->proven_signature.serialize(bench_case->secp_context.get());
378 if (!proven_signature_bytes.
has_value()) {
379 std::cerr << proven_signature_bytes.
error().message() <<
"\n";
383 bench_case->proven_signature_plusplus.serialize(bench_case->secp_context.get());
384 if (!proven_signature_plusplus_bytes.
has_value()) {
385 std::cerr << proven_signature_plusplus_bytes.
error().message() <<
"\n";
389 std::cout <<
"purify benchmark setup\n";
390 std::cout <<
"proof_system=legacy_bp_and_bppp_with_puresign_legacy_and_plusplus\n";
391 std::cout <<
"message_bytes=" << bench_case->message.size() <<
"\n";
392 std::cout <<
"gates=" << bench_case->circuit.n_gates <<
"\n";
393 std::cout <<
"constraints=" << bench_case->circuit.c.size() <<
"\n";
394 std::cout <<
"commitments=" << bench_case->circuit.n_commitments <<
"\n";
395 std::cout <<
"circuit_size_bytes=" << circuit_bytes <<
"\n";
396 std::cout <<
"cache_eval_input_bytes=" << bench_case->message_proof_cache.eval_input.size() <<
"\n";
397 std::cout <<
"experimental_proof_size_bytes=" << bench_case->experimental_proof.proof.size() <<
"\n";
398 std::cout <<
"experimental_bppp_proof_size_bytes=" << bench_case->experimental_bppp_proof.proof.size() <<
"\n";
399 std::cout <<
"norm_arg_n_vec_len=" << bench_case->norm_arg_inputs.n_vec.size() <<
"\n";
400 std::cout <<
"norm_arg_l_vec_len=" << bench_case->norm_arg_inputs.l_vec.size() <<
"\n";
401 std::cout <<
"norm_arg_c_vec_len=" << bench_case->norm_arg_inputs.c_vec.size() <<
"\n";
402 std::cout <<
"norm_arg_proof_size_bytes=" << bench_case->norm_arg_proof.proof.size() <<
"\n";
403 std::cout <<
"puresign_signature_size_bytes=" << bench_case->signature.bytes.size() <<
"\n";
404 std::cout <<
"puresign_legacy_proven_signature_size_bytes=" << proven_signature_bytes->size() <<
"\n";
405 std::cout <<
"puresign_plusplus_proven_signature_size_bytes=" << proven_signature_plusplus_bytes->size() <<
"\n";
407 auto build_bench = make_bench(*config,
"circuit");
408 build_bench.run(
"verifier_circuit.native.build", [&] {
411 assert(built.
has_value() &&
"benchmark verifier circuit build should succeed");
412 ankerl::nanobench::doNotOptimizeAway(built->c.size());
415 auto instantiate_bench = make_bench(*config,
"circuit");
416 instantiate_bench.run(
"verifier_circuit.template.instantiate_native", [&] {
418 bench_case->circuit_template.instantiate(bench_case->witness.public_key);
419 assert(built.
has_value() &&
"benchmark verifier circuit template instantiation should succeed");
420 ankerl::nanobench::doNotOptimizeAway(built->c.size());
423 auto instantiate_packed_bench = make_bench(*config,
"circuit");
424 instantiate_packed_bench.run(
"verifier_circuit.template.instantiate_packed", [&] {
426 bench_case->circuit_template.instantiate_packed(bench_case->witness.public_key);
427 assert(built.
has_value() &&
"benchmark packed verifier circuit template instantiation should succeed");
428 ankerl::nanobench::doNotOptimizeAway(built->constraint_count());
431 auto template_build_bench = make_bench(*config,
"template");
432 template_build_bench.run(
"verifier_circuit.template.build", [&] {
435 assert(built.
has_value() &&
"benchmark verifier circuit template build should succeed");
436 ankerl::nanobench::doNotOptimizeAway(&*built);
439 auto partial_eval_bench = make_bench(*config,
"evaluation");
440 partial_eval_bench.run(
"verifier_circuit.template.evaluate_partial", [&] {
441 purify::Result<bool> ok = bench_case->circuit_template.partial_evaluate(bench_case->witness.assignment);
442 assert(ok.
has_value() && *ok &&
"benchmark circuit template partial evaluation should succeed");
443 ankerl::nanobench::doNotOptimizeAway(*ok);
446 auto final_eval_bench = make_bench(*config,
"evaluation");
447 final_eval_bench.run(
"verifier_circuit.template.evaluate_final", [&] {
449 bench_case->circuit_template.final_evaluate(bench_case->witness.assignment, bench_case->witness.public_key);
450 assert(ok.
has_value() && *ok &&
"benchmark circuit template final evaluation should succeed");
451 ankerl::nanobench::doNotOptimizeAway(*ok);
454 auto proof_cache_build_bench = make_bench(*config,
"cache");
455 proof_cache_build_bench.run(
"puresign_legacy.message_proof_cache.build", [&] {
458 assert(built.
has_value() &&
"benchmark message proof cache build should succeed");
459 ankerl::nanobench::doNotOptimizeAway(built->eval_input.data());
462 auto experimental_prove_bench = make_bench(*config,
"proof");
463 experimental_prove_bench.run(
"experimental_circuit.legacy_bp.prove", [&] {
468 bench_case->secp_context.get(),
469 experimental_binding, std::nullopt,
470 &bench_case->experimental_bulletproof_cache);
471 assert(proof.
has_value() &&
"benchmark experimental circuit proof should succeed");
472 ankerl::nanobench::doNotOptimizeAway(proof->proof.data());
473 ankerl::nanobench::doNotOptimizeAway(proof->proof.size());
476 auto experimental_verify_bench = make_bench(*config,
"proof");
477 experimental_verify_bench.run(
"experimental_circuit.legacy_bp.verify", [&] {
481 bench_case->secp_context.get(), experimental_binding,
482 &bench_case->experimental_bulletproof_cache);
483 assert(ok.
has_value() && *ok &&
"benchmark experimental circuit verification should succeed");
484 ankerl::nanobench::doNotOptimizeAway(*ok);
487 auto experimental_bppp_prove_bench = make_bench(*config,
"proof");
488 experimental_bppp_prove_bench.run(
"experimental_circuit.bppp_zk_norm_arg.prove", [&] {
491 bench_case->circuit, bench_case->witness.assignment, experimental_nonce,
492 bench_case->secp_context.get(), experimental_bppp_binding, &bench_case->experimental_bppp_cache);
493 assert(proof.
has_value() &&
"benchmark experimental zk BPPP circuit proof should succeed");
494 ankerl::nanobench::doNotOptimizeAway(proof->proof.data());
495 ankerl::nanobench::doNotOptimizeAway(proof->proof.size());
498 auto experimental_bppp_verify_bench = make_bench(*config,
"proof");
499 experimental_bppp_verify_bench.run(
"experimental_circuit.bppp_zk_norm_arg.verify", [&] {
502 bench_case->circuit, bench_case->experimental_bppp_proof, bench_case->secp_context.get(),
503 experimental_bppp_binding,
504 &bench_case->experimental_bppp_cache);
505 assert(ok.
has_value() && *ok &&
"benchmark experimental zk BPPP circuit verification should succeed");
506 ankerl::nanobench::doNotOptimizeAway(*ok);
509 auto prove_bench = make_bench(*config,
"proof");
510 prove_bench.run(
"bppp.norm_arg.prove", [&] {
513 assert(proof.
has_value() &&
"benchmark norm-arg prove should succeed");
514 ankerl::nanobench::doNotOptimizeAway(proof->proof.data());
515 ankerl::nanobench::doNotOptimizeAway(proof->proof.size());
518 auto verify_bench = make_bench(*config,
"proof");
519 verify_bench.run(
"bppp.norm_arg.verify", [&] {
521 assert(ok &&
"benchmark verification should succeed");
522 ankerl::nanobench::doNotOptimizeAway(ok);
525 auto experimental_backend_bench = make_bench(*config,
"resource_set");
526 experimental_backend_bench.run(
"experimental_circuit.legacy_bp_backend_resources.create", [&] {
529 assert(resources !=
nullptr &&
"benchmark experimental backend resource creation should succeed");
530 ankerl::nanobench::doNotOptimizeAway(resources);
534 auto prepare_nonce_bench = make_bench(*config,
"nonce");
535 prepare_nonce_bench.run(
"puresign_legacy.nonce.prepare", [&] {
537 bench_case->key_pair->prepare_message_nonce(bench_case->message, bench_case->secp_context.get());
538 assert(prepared.
has_value() &&
"benchmark PureSign nonce preparation should succeed");
539 ankerl::nanobench::doNotOptimizeAway(prepared->public_nonce().xonly.data());
542 auto prepare_nonce_with_proof_bench = make_bench(*config,
"nonce");
543 prepare_nonce_with_proof_bench.run(
"puresign_legacy.nonce.prepare_with_proof", [&] {
545 bench_case->key_pair->prepare_message_nonce_with_proof(bench_case->message,
546 bench_case->secp_context.get());
547 assert(prepared.
has_value() &&
"benchmark PureSign nonce proof preparation should succeed");
548 ankerl::nanobench::doNotOptimizeAway(prepared->proof().proof.proof.data());
551 auto prepare_nonce_with_cached_proof_bench = make_bench(*config,
"nonce");
552 prepare_nonce_with_cached_proof_bench.run(
"puresign_legacy.nonce.prepare_with_proof_cached_template", [&] {
554 bench_case->key_pair->prepare_message_nonce_with_proof(bench_case->message_proof_cache,
555 bench_case->secp_context.get());
556 assert(prepared.
has_value() &&
"benchmark cached PureSign nonce proof preparation should succeed");
557 ankerl::nanobench::doNotOptimizeAway(prepared->proof().proof.proof.data());
560 auto prepare_nonce_with_proof_plusplus_bench = make_bench(*config,
"nonce");
561 prepare_nonce_with_proof_plusplus_bench.run(
"puresign_plusplus.nonce.prepare_with_proof", [&] {
563 bench_case->key_pair_plusplus->prepare_message_nonce_with_proof(
564 bench_case->message, bench_case->secp_context.get(), &bench_case->puresign_plusplus_cache);
565 assert(prepared.
has_value() &&
"benchmark PureSign++ nonce proof preparation should succeed");
566 ankerl::nanobench::doNotOptimizeAway(prepared->proof().proof.proof.data());
569 auto prepare_nonce_with_cached_proof_plusplus_bench = make_bench(*config,
"nonce");
570 prepare_nonce_with_cached_proof_plusplus_bench.run(
571 "puresign_plusplus.nonce.prepare_with_proof_cached_template", [&] {
574 bench_case->key_pair_plusplus->prepare_message_nonce_with_proof(
575 bench_case->message_proof_cache_plusplus, bench_case->secp_context.get());
576 assert(prepared.
has_value() &&
"benchmark cached PureSign++ nonce proof preparation should succeed");
577 ankerl::nanobench::doNotOptimizeAway(prepared->proof().proof.proof.data());
580 auto verify_nonce_with_proof_bench = make_bench(*config,
"nonce");
581 verify_nonce_with_proof_bench.run(
"puresign_legacy.nonce.verify_proof", [&] {
583 bench_case->public_key.verify_message_nonce_proof(bench_case->message,
584 bench_case->proven_signature.nonce_proof,
585 bench_case->secp_context.get());
586 assert(ok.
has_value() && *ok &&
"benchmark PureSign nonce proof verification should succeed");
587 ankerl::nanobench::doNotOptimizeAway(*ok);
590 auto verify_nonce_with_cached_proof_bench = make_bench(*config,
"nonce");
591 verify_nonce_with_cached_proof_bench.run(
"puresign_legacy.nonce.verify_proof_cached_template", [&] {
593 bench_case->public_key.verify_message_nonce_proof(bench_case->message_proof_cache,
594 bench_case->proven_signature.nonce_proof,
595 bench_case->secp_context.get());
596 assert(ok.
has_value() && *ok &&
"benchmark cached PureSign nonce proof verification should succeed");
597 ankerl::nanobench::doNotOptimizeAway(*ok);
600 auto verify_nonce_with_proof_plusplus_bench = make_bench(*config,
"nonce");
601 verify_nonce_with_proof_plusplus_bench.run(
"puresign_plusplus.nonce.verify_proof", [&] {
603 bench_case->public_key_plusplus.verify_message_nonce_proof(
604 bench_case->message, bench_case->proven_signature_plusplus.nonce_proof,
605 bench_case->secp_context.get(), &bench_case->puresign_plusplus_cache);
606 assert(ok.
has_value() && *ok &&
"benchmark PureSign++ nonce proof verification should succeed");
607 ankerl::nanobench::doNotOptimizeAway(*ok);
610 auto verify_nonce_with_cached_proof_plusplus_bench = make_bench(*config,
"nonce");
611 verify_nonce_with_cached_proof_plusplus_bench.run(
612 "puresign_plusplus.nonce.verify_proof_cached_template", [&] {
614 bench_case->public_key_plusplus.verify_message_nonce_proof(
615 bench_case->message_proof_cache_plusplus, bench_case->proven_signature_plusplus.nonce_proof,
616 bench_case->secp_context.get());
617 assert(ok.
has_value() && *ok &&
"benchmark cached PureSign++ nonce proof verification should succeed");
618 ankerl::nanobench::doNotOptimizeAway(*ok);
621 auto sign_bench = make_bench(*config,
"signature");
622 sign_bench.run(
"puresign_legacy.signature.sign", [&] {
624 bench_case->key_pair->sign_message(bench_case->message, bench_case->secp_context.get());
625 assert(signature.
has_value() &&
"benchmark PureSign signing should succeed");
626 ankerl::nanobench::doNotOptimizeAway(signature->bytes.data());
629 auto sign_with_proof_bench = make_bench(*config,
"signature");
630 sign_with_proof_bench.run(
"puresign_legacy.signature.sign_with_proof", [&] {
632 bench_case->key_pair->sign_message_with_proof(bench_case->message, bench_case->secp_context.get());
633 assert(signature.
has_value() &&
"benchmark PureSign proof signing should succeed");
634 ankerl::nanobench::doNotOptimizeAway(signature->signature.bytes.data());
637 auto sign_with_cached_proof_bench = make_bench(*config,
"signature");
638 sign_with_cached_proof_bench.run(
"puresign_legacy.signature.sign_with_proof_cached_template", [&] {
640 bench_case->key_pair->sign_message_with_proof(bench_case->message_proof_cache,
641 bench_case->secp_context.get());
642 assert(signature.
has_value() &&
"benchmark cached PureSign proof signing should succeed");
643 ankerl::nanobench::doNotOptimizeAway(signature->signature.bytes.data());
646 auto sign_with_proof_plusplus_bench = make_bench(*config,
"signature");
647 sign_with_proof_plusplus_bench.run(
"puresign_plusplus.signature.sign_with_proof", [&] {
649 bench_case->key_pair_plusplus->sign_message_with_proof(bench_case->message,
650 bench_case->secp_context.get(),
651 &bench_case->puresign_plusplus_cache);
652 assert(signature.
has_value() &&
"benchmark PureSign++ proof signing should succeed");
653 ankerl::nanobench::doNotOptimizeAway(signature->signature.bytes.data());
656 auto sign_with_cached_proof_plusplus_bench = make_bench(*config,
"signature");
657 sign_with_cached_proof_plusplus_bench.run(
"puresign_plusplus.signature.sign_with_proof_cached_template", [&] {
659 bench_case->key_pair_plusplus->sign_message_with_proof(bench_case->message_proof_cache_plusplus,
660 bench_case->secp_context.get());
661 assert(signature.
has_value() &&
"benchmark cached PureSign++ proof signing should succeed");
662 ankerl::nanobench::doNotOptimizeAway(signature->signature.bytes.data());
665 auto verify_signature_bench = make_bench(*config,
"signature");
666 verify_signature_bench.run(
"puresign_legacy.signature.verify", [&] {
668 bench_case->public_key.verify_signature(bench_case->message, bench_case->signature,
669 bench_case->secp_context.get());
670 assert(ok.
has_value() && *ok &&
"benchmark PureSign signature verification should succeed");
671 ankerl::nanobench::doNotOptimizeAway(*ok);
674 auto verify_with_proof_bench = make_bench(*config,
"signature");
675 verify_with_proof_bench.run(
"puresign_legacy.signature.verify_with_proof", [&] {
677 bench_case->public_key.verify_message_signature_with_proof(bench_case->message,
678 bench_case->proven_signature,
679 bench_case->secp_context.get());
680 assert(ok.
has_value() && *ok &&
"benchmark PureSign proof verification should succeed");
681 ankerl::nanobench::doNotOptimizeAway(*ok);
684 auto verify_signature_with_cached_proof_bench = make_bench(*config,
"signature");
685 verify_signature_with_cached_proof_bench.run(
"puresign_legacy.signature.verify_with_proof_cached_template", [&] {
687 bench_case->public_key.verify_message_signature_with_proof(bench_case->message_proof_cache,
688 bench_case->proven_signature,
689 bench_case->secp_context.get());
690 assert(ok.
has_value() && *ok &&
"benchmark cached PureSign proof verification should succeed");
691 ankerl::nanobench::doNotOptimizeAway(*ok);
694 auto verify_with_proof_plusplus_bench = make_bench(*config,
"signature");
695 verify_with_proof_plusplus_bench.run(
"puresign_plusplus.signature.verify_with_proof", [&] {
697 bench_case->public_key_plusplus.verify_message_signature_with_proof(
698 bench_case->message, bench_case->proven_signature_plusplus, bench_case->secp_context.get(),
699 &bench_case->puresign_plusplus_cache);
700 assert(ok.
has_value() && *ok &&
"benchmark PureSign++ proof verification should succeed");
701 ankerl::nanobench::doNotOptimizeAway(*ok);
704 auto verify_signature_with_cached_proof_plusplus_bench = make_bench(*config,
"signature");
705 verify_signature_with_cached_proof_plusplus_bench.run(
706 "puresign_plusplus.signature.verify_with_proof_cached_template", [&] {
708 bench_case->public_key_plusplus.verify_message_signature_with_proof(
709 bench_case->message_proof_cache_plusplus, bench_case->proven_signature_plusplus,
710 bench_case->secp_context.get());
711 assert(ok.
has_value() && *ok &&
"benchmark cached PureSign++ proof verification should succeed");
712 ankerl::nanobench::doNotOptimizeAway(*ok);