Skip to content

Commit

Permalink
feat: automatic solidity verifier adjustments (#1496)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattstam authored Sep 12, 2024
1 parent ef09ebb commit 6f67afd
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 6 deletions.
59 changes: 59 additions & 0 deletions crates/recursion/gnark-ffi/assets/SP1VerifierGroth16.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {ISP1Verifier, ISP1VerifierWithHash} from "../ISP1Verifier.sol";
import {Groth16Verifier} from "./Groth16Verifier.sol";

/// @title SP1 Verifier
/// @author Succinct Labs
/// @notice This contracts implements a solidity verifier for SP1.
contract SP1Verifier is Groth16Verifier, ISP1VerifierWithHash {
/// @notice Thrown when the verifier selector from this proof does not match the one in this
/// verifier. This indicates that this proof was sent to the wrong verifier.
/// @param received The verifier selector from the first 4 bytes of the proof.
/// @param expected The verifier selector from the first 4 bytes of the VERIFIER_HASH().
error WrongVerifierSelector(bytes4 received, bytes4 expected);

/// @notice Thrown when the proof is invalid.
error InvalidProof();

function VERSION() external pure returns (string memory) {
return "{SP1_CIRCUIT_VERSION}";
}

/// @inheritdoc ISP1VerifierWithHash
function VERIFIER_HASH() public pure returns (bytes32) {
return {VERIFIER_HASH};
}

/// @notice Hashes the public values to a field elements inside Bn254.
/// @param publicValues The public values.
function hashPublicValues(
bytes calldata publicValues
) public pure returns (bytes32) {
return sha256(publicValues) & bytes32(uint256((1 << 253) - 1));
}

/// @notice Verifies a proof with given public values and vkey.
/// @param programVKey The verification key for the RISC-V program.
/// @param publicValues The public values encoded as bytes.
/// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes.
function verifyProof(
bytes32 programVKey,
bytes calldata publicValues,
bytes calldata proofBytes
) external view {
bytes4 receivedSelector = bytes4(proofBytes[:4]);
bytes4 expectedSelector = bytes4(VERIFIER_HASH());
if (receivedSelector != expectedSelector) {
revert WrongVerifierSelector(receivedSelector, expectedSelector);
}

bytes32 publicValuesDigest = hashPublicValues(publicValues);
uint256[2] memory inputs;
inputs[0] = uint256(programVKey);
inputs[1] = uint256(publicValuesDigest);
uint256[8] memory proof = abi.decode(proofBytes[4:], (uint256[8]));
this.Verify(proof, inputs);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
pragma solidity ^0.8.20;

import {ISP1Verifier, ISP1VerifierWithHash} from "../ISP1Verifier.sol";
import {{PROOF_SYSTEM}Verifier} from "./{PROOF_SYSTEM}Verifier.sol";
import {PlonkVerifier} from "./PlonkVerifier.sol";

/// @title SP1 Verifier
/// @author Succinct Labs
/// @notice This contracts implements a solidity verifier for SP1.
contract SP1Verifier is {PROOF_SYSTEM}Verifier, ISP1VerifierWithHash {
contract SP1Verifier is PlonkVerifier, ISP1VerifierWithHash {
/// @notice Thrown when the verifier selector from this proof does not match the one in this
/// verifier. This indicates that this proof was sent to the wrong verifier.
/// @param received The verifier selector from the first 4 bytes of the proof.
Expand Down
21 changes: 19 additions & 2 deletions crates/recursion/gnark-ffi/src/groth16_bn254.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{
fs::File,
io::Write,
io::{Read, Write},
path::{Path, PathBuf},
};

Expand Down Expand Up @@ -76,12 +76,15 @@ impl Groth16Bn254Prover {
// Write the corresponding asset files to the build dir.
let sp1_verifier_path = build_dir.join("SP1VerifierGroth16.sol");
let vkey_hash = Self::get_vkey_hash(&build_dir);
let sp1_verifier_str = include_str!("../assets/SP1Verifier.txt")
let sp1_verifier_str = include_str!("../assets/SP1VerifierGroth16.txt")
.replace("{SP1_CIRCUIT_VERSION}", SP1_CIRCUIT_VERSION)
.replace("{VERIFIER_HASH}", format!("0x{}", hex::encode(vkey_hash)).as_str())
.replace("{PROOF_SYSTEM}", "Groth16");
let mut sp1_verifier_file = File::create(sp1_verifier_path).unwrap();
sp1_verifier_file.write_all(sp1_verifier_str.as_bytes()).unwrap();

let groth16_verifier_path = build_dir.join("Groth16Verifier.sol");
Self::modify_groth16_verifier(&groth16_verifier_path);
}

/// Generates a Groth16 proof given a witness.
Expand Down Expand Up @@ -120,6 +123,20 @@ impl Groth16Bn254Prover {
)
.expect("failed to verify proof")
}

/// Modify the Groth16Verifier so that it works with the SP1Verifier.
fn modify_groth16_verifier(file_path: &Path) {
let mut content = String::new();
File::open(file_path).unwrap().read_to_string(&mut content).unwrap();

content = content
.replace("pragma solidity ^0.8.0;", "pragma solidity ^0.8.20;")
.replace("contract Verifier {", "contract Groth16Verifier {")
.replace("function verifyProof(", "function Verify(");

let mut file = File::create(file_path).unwrap();
file.write_all(content.as_bytes()).unwrap();
}
}

impl Default for Groth16Bn254Prover {
Expand Down
18 changes: 16 additions & 2 deletions crates/recursion/gnark-ffi/src/plonk_bn254.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{
fs::File,
io::Write,
io::{Read, Write},
path::{Path, PathBuf},
};

Expand Down Expand Up @@ -75,12 +75,15 @@ impl PlonkBn254Prover {
// Write the corresponding asset files to the build dir.
let sp1_verifier_path = build_dir.join("SP1VerifierPlonk.sol");
let vkey_hash = Self::get_vkey_hash(&build_dir);
let sp1_verifier_str = include_str!("../assets/SP1Verifier.txt")
let sp1_verifier_str = include_str!("../assets/SP1VerifierPlonk.txt")
.replace("{SP1_CIRCUIT_VERSION}", SP1_CIRCUIT_VERSION)
.replace("{VERIFIER_HASH}", format!("0x{}", hex::encode(vkey_hash)).as_str())
.replace("{PROOF_SYSTEM}", "Plonk");
let mut sp1_verifier_file = File::create(sp1_verifier_path).unwrap();
sp1_verifier_file.write_all(sp1_verifier_str.as_bytes()).unwrap();

let plonk_verifier_path = build_dir.join("PlonkVerifier.sol");
Self::modify_plonk_verifier(&plonk_verifier_path);
}

/// Generates a PLONK proof given a witness.
Expand Down Expand Up @@ -119,6 +122,17 @@ impl PlonkBn254Prover {
)
.expect("failed to verify proof")
}

/// Modify the PlonkVerifier so that it works with the SP1Verifier.
fn modify_plonk_verifier(file_path: &Path) {
let mut content = String::new();
File::open(file_path).unwrap().read_to_string(&mut content).unwrap();

content = content.replace("pragma solidity ^0.8.19;", "pragma solidity ^0.8.20;");

let mut file = File::create(file_path).unwrap();
file.write_all(content.as_bytes()).unwrap();
}
}

impl Default for PlonkBn254Prover {
Expand Down

0 comments on commit 6f67afd

Please sign in to comment.