I am working on a smart contract that uses Risc Zero to verify proofs generated from a Rust program. I have successfully generated the seal, imageID, and journalDigest from the Risc Zero Rust program. The proof can be verified off-chain using a Rust script, but I encounter an error when trying to verify it on-chain.
Steps to Reproduce
- Generate the proof (seal, imageID, and journalDigest) using the Risc Zero Rust program.
- Verify the proof off-chain using a Rust script (successful).
- Deploy the RiscZeroGroth16Verifier contract on a local testnet and Binance Smart Chain testnet.
- Submit the seal, imageID, and journalDigest to the on-chain verifier contract.
Expected Behavior
The proof should be verified successfully on-chain, just as it is verified off-chain.
Actual Behavior
The transaction reverts with the following error:
call to RiscZeroGroth16Verifier.verify errored: Error occurred: revert.
revert
The transaction has been reverted to the initial state.
Error provided by the contract:
VerificationFailed : Error raised when cryptographic verification of the zero-knowledge proof fails.
Parameters:
{}
Additional Information
- I am using the exact source code from the RiscZeroGroth16Verifier contract deployed on Ethereum by Risc Zero.
- The proof verification works off-chain with the same seal, imageID, and journalDigest.
- I have tried increasing the gas limit, but the issue persists.
Code Snippets
Smart Contract Code (simplified):
function _verifyIntegrity(bytes calldata seal, bytes32 claimDigest) internal view {
// Check that the seal has a matching selector. Mismatch generally indicates that the
// prover and this verifier are using different parameters, and so the verification
// will not succeed.
if (SELECTOR != bytes4(seal[:4])) {
revert SelectorMismatch({received: bytes4(seal[:4]), expected: SELECTOR});
}
// Run the Groth16 verify procedure.
(bytes16 claim0, bytes16 claim1) = splitDigest(claimDigest);
Seal memory decodedSeal = abi.decode(seal[4:], (Seal));
bool verified = this.verifyProof(
decodedSeal.a,
decodedSeal.b,
decodedSeal.c,
[
uint256(uint128(CONTROL_ROOT_0)),
uint256(uint128(CONTROL_ROOT_1)),
uint256(uint128(claim0)),
uint256(uint128(claim1)),
uint256(BN254_CONTROL_ID)
]
);
// Revert is verification failed.
if (!verified) {
revert VerificationFailed();
}
}
function verify(bytes calldata seal, bytes32 imageId, bytes32 journalDigest) external view {
_verifyIntegrity(seal, ReceiptClaimLib.ok(imageId, journalDigest).digest());
}
Verifier Parameters Used During Deployment
control_root (bytes32): 0x8cdad9242664be3112aba377c5425a4df735eb1c6966472b561d2855932c0469
bn254_control_id (bytes32): 0x04446e66d300eb7fb45c9726bb53c793dda407a62e9601618bb43c5c14657ac0
Transaction Details:
call to RiscZeroGroth16Verifier.verify errored: Error occurred: revert.
revert
The transaction has been reverted to the initial state.
Error provided by the contract:
VerificationFailed : Error raised when cryptographic verification of the zero-knowledge proof fails.
Parameters:
{}
If the transaction failed for not having enough gas, try increasing the gas limit gently.
Environment
- Solidity Version: 0.8.26+commit.8a97fa7a
- Ethereum Testnet Contract:
- Binance Smart Chain Testnet:
Question
Why does the proof verification fail on-chain but succeed off-chain? What could be the potential issues, and how can I resolve them?
Are there additional parameters (e.g., public inputs, verification keys) that need to be set before calling the verify function?
Are there differences in how verifier parameters should be configured on-chain vs. off-chain?
I am working on a smart contract that uses Risc Zero to verify proofs generated from a Rust program. I have successfully generated the seal, imageID, and journalDigest from the Risc Zero Rust program. The proof can be verified off-chain using a Rust script, but I encounter an error when trying to verify it on-chain.
Steps to Reproduce
- Generate the proof (seal, imageID, and journalDigest) using the Risc Zero Rust program.
- Verify the proof off-chain using a Rust script (successful).
- Deploy the RiscZeroGroth16Verifier contract on a local testnet and Binance Smart Chain testnet.
- Submit the seal, imageID, and journalDigest to the on-chain verifier contract.
Expected Behavior
The proof should be verified successfully on-chain, just as it is verified off-chain.
Actual Behavior
The transaction reverts with the following error:
call to RiscZeroGroth16Verifier.verify errored: Error occurred: revert.
revert
The transaction has been reverted to the initial state.
Error provided by the contract:
VerificationFailed : Error raised when cryptographic verification of the zero-knowledge proof fails.
Parameters:
{}
Additional Information
- I am using the exact source code from the RiscZeroGroth16Verifier contract deployed on Ethereum by Risc Zero.
- The proof verification works off-chain with the same seal, imageID, and journalDigest.
- I have tried increasing the gas limit, but the issue persists.
Code Snippets
Smart Contract Code (simplified):
function _verifyIntegrity(bytes calldata seal, bytes32 claimDigest) internal view {
// Check that the seal has a matching selector. Mismatch generally indicates that the
// prover and this verifier are using different parameters, and so the verification
// will not succeed.
if (SELECTOR != bytes4(seal[:4])) {
revert SelectorMismatch({received: bytes4(seal[:4]), expected: SELECTOR});
}
// Run the Groth16 verify procedure.
(bytes16 claim0, bytes16 claim1) = splitDigest(claimDigest);
Seal memory decodedSeal = abi.decode(seal[4:], (Seal));
bool verified = this.verifyProof(
decodedSeal.a,
decodedSeal.b,
decodedSeal.c,
[
uint256(uint128(CONTROL_ROOT_0)),
uint256(uint128(CONTROL_ROOT_1)),
uint256(uint128(claim0)),
uint256(uint128(claim1)),
uint256(BN254_CONTROL_ID)
]
);
// Revert is verification failed.
if (!verified) {
revert VerificationFailed();
}
}
function verify(bytes calldata seal, bytes32 imageId, bytes32 journalDigest) external view {
_verifyIntegrity(seal, ReceiptClaimLib.ok(imageId, journalDigest).digest());
}
Verifier Parameters Used During Deployment
control_root (bytes32): 0x8cdad9242664be3112aba377c5425a4df735eb1c6966472b561d2855932c0469
bn254_control_id (bytes32): 0x04446e66d300eb7fb45c9726bb53c793dda407a62e9601618bb43c5c14657ac0
Transaction Details:
call to RiscZeroGroth16Verifier.verify errored: Error occurred: revert.
revert
The transaction has been reverted to the initial state.
Error provided by the contract:
VerificationFailed : Error raised when cryptographic verification of the zero-knowledge proof fails.
Parameters:
{}
If the transaction failed for not having enough gas, try increasing the gas limit gently.
Environment
- Solidity Version: 0.8.26+commit.8a97fa7a
- Ethereum Testnet Contract: https://etherscan.io/address/0xAC292cF957Dd5BA174cdA13b05C16aFC71700327
- Binance Smart Chain Testnet: https://testnet.bscscan/address/0x21ee758fe996c8b6bef57cf81b35fe9f4057e037
Question
Why does the proof verification fail on-chain but succeed off-chain? What could be the potential issues, and how can I resolve them?
Are there additional parameters (e.g., public inputs, verification keys) that need to be set before calling the verify function?
Are there differences in how verifier parameters should be configured on-chain vs. off-chain?
- FYI, Ethereum has a separate Stack Exchange site – Charles Duffy Commented Mar 18 at 19:08
1 Answer
Reset to default 0I have few suggestions for it. Here are some potential causes and troubleshooting steps:
Case -1
Proof Size and Gas Limitations: On-chain verification requires sufficient gas to process the proof. If the proof size is large, it might exceed the block gas limit, causing the transaction to revert. Ensure that the gas limit for the transaction is adequately set to accommodate the proof verification process.
Contract Compatibility: Verify that the deployed
RiscZeroGroth16Verifier
contract on-chain matches the version used during off-chain verification. Discrepancies between contract versions can lead to verification failures.Proof Integrity: Confirm that the proof (
seal
),imageID
, andjournalDigest
submitted on-chain are identical to those verified off-chain. Any alteration or corruption during the submission process can result in verification errors.Blockchain Specifics: Different blockchains may have varying implementations of cryptographic primitives. Ensure that the verifier contract is compatible with the specific blockchain's environment where it's deployed.
Debugging Reverts: Utilize debugging tools provided by the blockchain platform to trace the exact reason for the transaction revert. This can offer insights into whether the failure is due to gas issues, contract logic errors, or other factors.
Case - 2:
Possible Causes and Solutions:
Smart Contract Constraints:
Gas Limitations: On-chain verification is resource-intensive and may exceed gas limits, leading to transaction reverts.
Arithmetic Precision: Smart contracts operate with fixed-size integers, which might not accommodate the precision required for cryptographic operations.
Solution: Optimize the verification algorithm to be more gas-efficient and ensure it operates within the arithmetic constraints of the blockchain environment.
Data Encoding and Transmission:
Serialization Differences: Discrepancies in how data is serialized/deserialized between off-chain and on-chain environments can cause verification failures.
Data Integrity: Ensure that the proof data isn't altered during transmission to the smart contract.
Solution: Standardize data encoding methods across both environments and implement checks to verify data integrity upon receipt.
Library and Dependency Compatibility:
- Cryptographic Libraries: Differences in cryptographic libraries or versions between off-chain and on-chain environments can lead to inconsistencies.
Solution: Ensure that the cryptographic functions used off-chain are compatible with those available on-chain, or implement equivalent functions within the smart contract.
Environmental Differences:
- Execution Context: The execution environment of smart contracts is constrained compared to off-chain environments, potentially leading to unexpected behaviors.
Solution: Conduct thorough testing in a simulated on-chain environment to identify and address discrepancies.
Source
Thanks
Anuj