Skip to content

Conversation

0xernesto
Copy link
Contributor

@0xernesto 0xernesto commented Sep 17, 2025

Motivation

Proofs fail during recursion when an incorrect amount of deferred proofs are passed or when verification fails.

Solution

Instead of just throwing a warning or panicking, stop execution and throw an error that we can catch in the prover network and display in the explorer.

Example Logs

UnverifiedDeferredProofs

Thrown when the user never calls verify_sp1_proof, or when the user only called it for some of the proofs.

2025-09-18T22:28:57.503034Z  INFO aggregate the proofs:execute:verify: close time.busy=60.4ms time.idle=1.00µs
2025-09-18T22:28:57.506112Z ERROR aggregate the proofs:execute: Not all proofs were verified. Expected to verify 3 proofs, but only 2 were verified. Make sure you're passing the correct number of proofs and that you're calling verify_sp1_proof for all proofs.
2025-09-18T22:28:57.506681Z  INFO aggregate the proofs:execute: close time.busy=131ms time.idle=541ns

thread 'main' panicked at aggregation/script/src/main.rs:80:73:
execution failed: unverified deferred proofs: verified=2, expected=3

InsufficientDeferredProofs

Thrown when the user tries to verify more proofs than passed.

2025-09-18T23:04:09.684238Z  INFO aggregate the proofs:execute:verify: close time.busy=60.0ms time.idle=791ns

thread 'main' panicked at /Users/ernestoramirez/Dev/sp1/crates/core/executor/src/syscalls/verify.rs:31:17:
Not enough proofs were written to the runtime.
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
2025-09-18T23:04:09.687518Z ERROR aggregate the proofs:execute: Insufficient deferred proofs: unable to verify proof at index 3 because only 3 proofs were provided. Make sure you're passing the correct number of proofs and that you're calling verify_sp1_proof for all proofs.
2025-09-18T23:04:09.688125Z  INFO aggregate the proofs:execute: close time.busy=195ms time.idle=250ns

thread 'main' panicked at aggregation/script/src/main.rs:80:73:
execution failed: insufficient deferred proofs: unable to verify proof at index 3

DeferredProofVerificationFailed

Thrown when proof verification fails.

2025-09-18T23:09:12.920686Z  INFO aggregate the proofs:execute: clk = 0 pc = 0x204360

thread 'main' panicked at /Users/ernestoramirez/Dev/sp1/crates/core/executor/src/syscalls/verify.rs:41:25:
Failed to verify proof 0 with digest d0abd303eefe48a35a09197c8840467029bde2832f61695991207d60fb6a2354: Invalid public values: vk hash from syscall does not match vkey from input
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
2025-09-18T23:09:12.921329Z ERROR aggregate the proofs:execute: Failed to verify deferred proof at index 0.
2025-09-18T23:09:12.921912Z  INFO aggregate the proofs:execute: close time.busy=2.78ms time.idle=166ns

thread 'main' panicked at aggregation/script/src/main.rs:80:73:
execution failed: deferred proof verification failed: Failed to verify proof 0 with digest d0abd303eefe48a35a09197c8840467029bde2832f61695991207d60fb6a2354: Invalid public values: vk hash from syscall does not match vkey from input

@0xernesto 0xernesto requested a review from ctian1 September 17, 2025 21:53
Copy link
Contributor

github-actions bot commented Sep 17, 2025

Test Old New Diff
curve25519_dalek_test_zero_mul 197103 197103 0.0000 %
curve25519_dalek_test_zero_msm 213024 213024 0.0000 %
p256_test_recover_rand_lte_100 7284547 7247340 -0.5108 %
bls12_381_tests_test_inverse_fp_100 1375050 1375050 0.0000 %
rust_crypto_rsa_test_pkcs_verify_100 101811087 102228816 0.4103 %
secp256k1_program_test_verify_v0_30_0_rand_lte_100 46860266 46721429 -0.2963 %
rustcrypto_bigint_test_bigint_mul_mod_special 2315020 2315020 0.0000 %
bn_test_bn_test_fq_inverse_100 766356 766356 0.0000 %
bls12_381_tests_test_bls_add_100 15763438 15763438 0.0000 %
sha_test_sha2_v0_9_9_expected_digest_lte_100_times 1491803 1490173 -0.1093 %
sha_test_sha2_v0_10_8_expected_digest_lte_100_times 1731180 1730189 -0.0572 %
curve25519_dalek_test_decompressed_noncanonical 9169 9169 0.0000 %
keccack_test_expected_digest_lte_100 2036746 2035878 -0.0426 %
p256_test_verify_rand_lte_100 24851251 24870838 0.0788 %
bls12_381_tests_test_bls_double_100 9218745 9218745 0.0000 %
curve25519_dalek_test_decompressed_expected_value 15537521 15688660 0.9727 %
rustcrypto_bigint_test_bigint_mul_add_residue 2253569 2253569 0.0000 %
k256_test_recover_high_hash_high_recid 2439640 2993211 22.6907 %
curve25519_dalek_ng_test_zero_mul 197063 197063 0.0000 %
bn_test_bn_test_g1_double_100 648048 648027 -0.0032 %
bls12_381_tests_test_inverse_fp2_100 3083020 3083020 0.0000 %
curve25519_dalek_ng_test_decompressed_noncanonical 206954 206954 0.0000 %
k256_test_verify_rand_lte_100 24856837 24780072 -0.3088 %
bn_test_bn_test_g1_add_100 846331 846338 0.0008 %
sha_test_sha2_v0_10_6_expected_digest_lte_100_times 1734367 1731135 -0.1864 %
curve25519_dalek_test_ed25519_verify 32348550 32349942 0.0043 %
bn_test_bn_test_fr_inverse_100 796856 796856 0.0000 %
p256_test_recover_high_hash_high_recid 3513663 3404474 -3.1076 %
bn_test_bn_test_fq_sqrt_100 763356 763356 0.0000 %
k256_test_recover_pubkey_infinity 124534 124534 0.0000 %
sha_test_sha3_expected_digest_lte_100_times 1668648 1668908 0.0156 %
curve25519_dalek_test_add_then_multiply 7934238 6538668 -17.5892 %
k256_test_schnorr_verify 7029116 7025261 -0.0548 %
secp256k1_program_test_recover_rand_lte_100 6600945 6598042 -0.0440 %
bls12_381_tests_test_sqrt_fp2_100 2008721 1986056 -1.1283 %
p256_test_recover_pubkey_infinity 143003 143003 0.0000 %
curve25519_dalek_ng_test_zero_msm 216592 216592 0.0000 %
bls12_381_tests_test_sqrt_fp_100 1006880 916867 -8.9398 %
secp256k1_program_test_recover_v0_30_0_rand_lte_100 6634928 6647814 0.1942 %
secp256k1_program_test_verify_rand_lte_100 46745666 46881782 0.2912 %
k256_test_recover_rand_lte_100 5618667 5612358 -0.1123 %
curve25519_dalek_ng_test_add_then_multiply 8450604 6375828 -24.5518 %

UnconstrainedCycleLimitExceeded(u64),

/// Not all deferred proofs were verified during execution.
#[error("unverified deferred proofs: verified={actual}, expected={expected}")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "unverified" is a bit misleading. Maybe "not enough"?

let res = syscall_impl.execute(&mut precompile_rt, syscall, b, c);
let res = if syscall == SyscallCode::VERIFY_SP1_PROOF {
// Catch panics for VERIFY_SP1_PROOF to provide better error messages.
match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's kind of bad that we need to use this and have syscall-specific branch here, ideally execute fn should just return a Result

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants