Skip to content

fix(aggregation_mode): hardcode image_id and vk_hash from solidity contract #1910

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
May 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -171,13 +171,13 @@ reset_last_aggregated_block:
@echo '{"last_aggregated_block":0}' > config-files/proof-aggregator.last_aggregated_block.json

start_proof_aggregator_dev: is_aggregator_set reset_last_aggregated_block ## Starts proof aggregator with mock proofs (DEV mode)
AGGREGATOR=$(AGGREGATOR) RISC0_DEV_MODE=1 cargo run --manifest-path ./aggregation_mode/Cargo.toml --release -- config-files/config-proof-aggregator-mock.yaml
AGGREGATOR=$(AGGREGATOR) RISC0_DEV_MODE=1 cargo run --manifest-path ./aggregation_mode/Cargo.toml --release --bin proof_aggregator -- config-files/config-proof-aggregator-mock.yaml

start_proof_aggregator: is_aggregator_set reset_last_aggregated_block ## Starts proof aggregator with proving activated
AGGREGATOR=$(AGGREGATOR) cargo run --manifest-path ./aggregation_mode/Cargo.toml --release --features prove -- config-files/config-proof-aggregator.yaml
AGGREGATOR=$(AGGREGATOR) cargo run --manifest-path ./aggregation_mode/Cargo.toml --release --features prove --bin proof_aggregator -- config-files/config-proof-aggregator.yaml

start_proof_aggregator_gpu: is_aggregator_set reset_last_aggregated_block ## Starts proof aggregator with proving + GPU acceleration (CUDA)
AGGREGATOR=$(AGGREGATOR) SP1_PROVER=cuda cargo run --manifest-path ./aggregation_mode/Cargo.toml --release --features prove,gpu -- config-files/config-proof-aggregator.yaml
AGGREGATOR=$(AGGREGATOR) SP1_PROVER=cuda cargo run --manifest-path ./aggregation_mode/Cargo.toml --release --features prove,gpu --bin proof_aggregator -- config-files/config-proof-aggregator.yaml

verify_aggregated_proof_sp1_holesky_stage:
@echo "Verifying SP1 in aggregated proofs on holesky..."
Expand All @@ -204,7 +204,11 @@ verify_aggregated_proof_risc0_holesky_stage:
--rpc_url https://ethereum-holesky-rpc.publicnode.com

install_aggregation_mode: ## Install the aggregation mode with proving enabled
cargo install --path aggregation_mode --features prove,gpu
cargo install --path aggregation_mode --features prove,gpu --bin proof_aggregator

agg_mode_write_program_ids: ## Write proof aggregator zkvm programs ids
@cd aggregation_mode && \
cargo run --release --bin write_program_image_id_vk_hash

_AGGREGATOR_:

Expand Down
9 changes: 8 additions & 1 deletion aggregation_mode/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ name = "proof_aggregator"
version = "0.1.0"
edition = "2021"


[dependencies]
serde = { version = "1.0.203", features = ["derive"] }
serde_json = "1.0.117"
Expand Down Expand Up @@ -41,3 +40,11 @@ opt-level = 3
default = []
prove = []
gpu = ["risc0-zkvm/cuda"]

[[bin]]
name = "proof_aggregator"
path = "./src/main.rs"

[[bin]]
name = "write_program_image_id_vk_hash"
path = "./bin/write_program_image_id_vk_hash.rs"
2 changes: 1 addition & 1 deletion aggregation_mode/abi/AlignedProofAggregationService.json

Large diffs are not rendered by default.

38 changes: 38 additions & 0 deletions aggregation_mode/bin/write_program_image_id_vk_hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use alloy::hex::hex;
use proof_aggregator::aggregators::{
risc0_aggregator::RISC0_AGGREGATOR_PROGRAM_ID_BYTES, sp1_aggregator,
};
use serde_json::json;
use sp1_sdk::HashableKey;
use std::{env, fs, path::Path};
use tracing::info;
use tracing_subscriber::FmtSubscriber;

const SP1_PROGRAM_ELF: &[u8] =
include_bytes!("../aggregation_programs/sp1/elf/sp1_aggregator_program");

include!(concat!(env!("OUT_DIR"), "/methods.rs"));

fn main() {
let subscriber = FmtSubscriber::builder().finish();
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");

info!("About to write sp1 programs vk hash bytes + risc0 programs image id bytes");
let sp1_vk_hash = sp1_aggregator::vk_from_elf(SP1_PROGRAM_ELF).bytes32_raw();
let risc0_image_id_bytes = RISC0_AGGREGATOR_PROGRAM_ID_BYTES;

let sp1_vk_hash_hex = hex::encode(sp1_vk_hash);
let risc0_image_id_hex = hex::encode(risc0_image_id_bytes);

let dest_path = Path::new("programs_ids.json");

let json_data = json!({
"sp1_vk_hash": format!("0x{}", sp1_vk_hash_hex),
"risc0_image_id": format!("0x{}", risc0_image_id_hex),
});

// Write to the file
fs::write(dest_path, serde_json::to_string_pretty(&json_data).unwrap()).unwrap();

info!("Program ids written to {:?}", dest_path);
}
4 changes: 4 additions & 0 deletions aggregation_mode/programs_ids.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"risc0_image_id": "0xa2966b3e63b5e73848dd3fb8ff1e03ac68ca10fa961ca0c0d8dbbb0a85b60acd",
"sp1_vk_hash": "0x00eb8139c8360fc371b9a6decdec55ba01aaae0f4739f68139e0b3d40397d1d6"
}
2 changes: 1 addition & 1 deletion aggregation_mode/src/aggregators/risc0_aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use risc0_zkvm::{default_prover, ExecutorEnv, ProverOpts, Receipt};
use sha3::{Digest, Keccak256};

/// Byte representation of the aggregator image_id, converted from `[u32; 8]` to `[u8; 32]`.
const RISC0_AGGREGATOR_PROGRAM_ID_BYTES: [u8; 32] = {
pub const RISC0_AGGREGATOR_PROGRAM_ID_BYTES: [u8; 32] = {
let mut res = [0u8; 32];
let mut i = 0;
while i < 8 {
Expand Down
3 changes: 0 additions & 3 deletions aggregation_mode/src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use config::Config;
use fetcher::{ProofsFetcher, ProofsFetcherError};
use merkle_tree::compute_proofs_merkle_root;
use risc0_ethereum_contracts::encode_seal;
use sp1_sdk::HashableKey;
use std::str::FromStr;
use tracing::{error, info, warn};
use types::{AlignedProofAggregationService, AlignedProofAggregationServiceContract};
Expand Down Expand Up @@ -154,7 +153,6 @@ impl ProofAggregator {
self.proof_aggregation_service
.verifySP1(
blob_versioned_hash.into(),
proof.vk().bytes32_raw().into(),
proof.proof_with_pub_values.public_values.to_vec().into(),
proof.proof_with_pub_values.bytes().into(),
)
Expand All @@ -170,7 +168,6 @@ impl ProofAggregator {
.verifyRisc0(
blob_versioned_hash.into(),
encoded_seal.into(),
proof.image_id.into(),
proof.receipt.journal.bytes.into(),
)
.sidecar(blob)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ contract AlignedProofAggregationServiceDeployer is Script {

address alignedAggregatorAddress = stdJson.readAddress(config_data, ".address.alignedAggregatorAddress");
address sp1VerifierAddress = stdJson.readAddress(config_data, ".address.sp1VerifierAddress");
bytes32 sp1AggregationProgramVKHash =
stdJson.readBytes32(config_data, ".programs_id.sp1AggregationProgramVKHash");
address risc0VerifierAddress = stdJson.readAddress(config_data, ".address.risc0VerifierAddress");
bytes32 risc0AggregationProgramImageId =
stdJson.readBytes32(config_data, ".programs_id.risc0AggregationProgramImageId");

address ownerAddress = stdJson.readAddress(config_data, ".permissions.owner");

Expand All @@ -23,11 +27,13 @@ contract AlignedProofAggregationServiceDeployer is Script {
ERC1967Proxy proxy = new ERC1967Proxy(
address(alignedProofAggregationService),
abi.encodeWithSignature(
"initialize(address,address,address,address)",
"initialize(address,address,address,address,bytes32,bytes32)",
ownerAddress,
alignedAggregatorAddress,
sp1VerifierAddress,
risc0VerifierAddress
risc0VerifierAddress,
risc0AggregationProgramImageId,
sp1AggregationProgramVKHash
)
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
"alignedAggregatorAddress": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720",
"alignedAggregatorAddressPrivateKey": "0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6"
},
"programs_id": {
"sp1AggregationProgramVKHash": "0x00eb8139c8360fc371b9a6decdec55ba01aaae0f4739f68139e0b3d40397d1d6",
"risc0AggregationProgramImageId": "0xa2966b3e63b5e73848dd3fb8ff1e03ac68ca10fa961ca0c0d8dbbb0a85b60acd"
},
"permissions": {
"owner": "0x14dC79964da2C08b23698B3D3cc7Ca32193d9955"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
"alignedAggregatorAddress": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720",
"alignedAggregatorAddressPrivateKey": "0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6"
},
"programs_id": {
"sp1AggregationProgramVKHash": "0x00eb8139c8360fc371b9a6decdec55ba01aaae0f4739f68139e0b3d40397d1d6",
"risc0AggregationProgramImageId": "0xa2966b3e63b5e73848dd3fb8ff1e03ac68ca10fa961ca0c0d8dbbb0a85b60acd"
},
"permissions": {
"owner": "0x14dC79964da2C08b23698B3D3cc7Ca32193d9955"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"risc0VerifierAddress": "0xf70aBAb028Eb6F4100A24B203E113D94E87DE93C",
"alignedAggregatorAddress": "0x9403dF48130621f87974a5A1d1d11d3aF1222A82"
},
"programs_id": {
"sp1AggregationProgramVKHash": "0x00eb8139c8360fc371b9a6decdec55ba01aaae0f4739f68139e0b3d40397d1d6",
"risc0AggregationProgramImageId": "0xa2966b3e63b5e73848dd3fb8ff1e03ac68ca10fa961ca0c0d8dbbb0a85b60acd"
},
"permissions": {
"owner": "0x97aEC5F28181abe5d2aD40dBe7FbaEe014529b7D"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"risc0VerifierAddress": "0xf70aBAb028Eb6F4100A24B203E113D94E87DE93C",
"alignedAggregatorAddress": "0x3595aa7d30f89f65933e7421dec77e4478d9fb01"
},
"programs_id": {
"sp1AggregationProgramVKHash": "0x00eb8139c8360fc371b9a6decdec55ba01aaae0f4739f68139e0b3d40397d1d6",
"risc0AggregationProgramImageId": "0xa2966b3e63b5e73848dd3fb8ff1e03ac68ca10fa961ca0c0d8dbbb0a85b60acd"
},
"permissions": {
"owner": "0xE3C695b73dbe27106aF4530b152de3e57456B385"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"risc0VerifierAddress": "0x8EaB2D97Dfce405A1692a21b3ff3A172d593D319",
"alignedAggregatorAddress": "<aligned_aggregator_address>"
},
"programs_id": {
"sp1AggregationProgramVKHash": "0x00eb8139c8360fc371b9a6decdec55ba01aaae0f4739f68139e0b3d40397d1d6",
"risc0AggregationProgramImageId": "0xa2966b3e63b5e73848dd3fb8ff1e03ac68ca10fa961ca0c0d8dbbb0a85b60acd"
},
"permissions": {
"owner": "<owner_address>"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"risc0VerifierAddress": "0x8EaB2D97Dfce405A1692a21b3ff3A172d593D319",
"alignedAggregatorAddress": "<aligned_aggregator_address>"
},
"programs_id": {
"sp1AggregationProgramVKHash": "0x00eb8139c8360fc371b9a6decdec55ba01aaae0f4739f68139e0b3d40397d1d6",
"risc0AggregationProgramImageId": "0xa2966b3e63b5e73848dd3fb8ff1e03ac68ca10fa961ca0c0d8dbbb0a85b60acd"
},
"permissions": {
"owner": "<owner_address>"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"risc0VerifierAddress": "0x925d8331ddc0a1F0d96E68CF073DFE1d92b69187",
"alignedAggregatorAddress": "<aligned_aggregator_address>"
},
"programs_id": {
"sp1AggregationProgramVKHash": "0x00eb8139c8360fc371b9a6decdec55ba01aaae0f4739f68139e0b3d40397d1d6",
"risc0AggregationProgramImageId": "0xa2966b3e63b5e73848dd3fb8ff1e03ac68ca10fa961ca0c0d8dbbb0a85b60acd"
},
"permissions": {
"owner": "<owner_address>"
}
Expand Down
17 changes: 17 additions & 0 deletions contracts/scripts/anvil/deploy_aligned_contracts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,23 @@ rm -f "script/output/devnet/alignedlayer_deployment_output.temp1.json"
rm -f "script/output/devnet/alignedlayer_deployment_output.temp2.json"


# Update Program IDs in anvil deployment
cd ..
make agg_mode_write_program_ids

# Copy new values to config file
jq '.programs_id.risc0AggregationProgramImageId = $input[0].risc0_image_id | .programs_id.sp1AggregationProgramVKHash = $input[0].sp1_vk_hash' \
--slurpfile input aggregation_mode/programs_ids.json \
contracts/script/deploy/config/devnet/proof-aggregator-service.devnet.config.json \
> temp.json && mv temp.json contracts/script/deploy/config/devnet/proof-aggregator-service.devnet.config.json

jq '.programs_id.risc0AggregationProgramImageId = $input[0].risc0_image_id | .programs_id.sp1AggregationProgramVKHash = $input[0].sp1_vk_hash' \
--slurpfile input aggregation_mode/programs_ids.json \
contracts/script/deploy/config/devnet/proof-aggregator-service.devnet.mock.config.json \
> temp.json && mv temp.json contracts/script/deploy/config/devnet/proof-aggregator-service.devnet.mock.config.json

cd contracts

# Deploy proof aggregation service contract with SP1 Verifier
forge script script/deploy/AlignedProofAggregationServiceDeployer.s.sol \
./script/deploy/config/devnet/proof-aggregator-service.devnet.config.json \
Expand Down

Large diffs are not rendered by default.

52 changes: 37 additions & 15 deletions contracts/src/core/AlignedProofAggregationService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ contract AlignedProofAggregationService is
/// if the sp1 verifier address is set to this address, then we skip verification
address public constant VERIFIER_MOCK_ADDRESS = address(0xFF);

/// The unique identifier (image ID) of the RISC Zero aggregator program.
/// This ensures that only proofs generated by a trusted Risc0 program can be verified.
bytes32 public risc0AggregatorProgramImageId;

/// The verification key hash for the SP1 aggregator program.
/// This ensures that only proofs generated by a trusted SP1 program can be verified.
bytes32 public sp1AggregatorProgramVKHash;

constructor() {
_disableInitializers();
}
Expand All @@ -44,45 +52,47 @@ contract AlignedProofAggregationService is
address newOwner,
address _alignedAggregatorAddress,
address _sp1VerifierAddress,
address _risc0VerifierAddress
address _risc0VerifierAddress,
bytes32 _risc0AggregatorProgramImageId,
bytes32 _sp1AggregatorProgramVKHash
) public initializer {
__Ownable_init();
__UUPSUpgradeable_init();
_transferOwnership(newOwner);
alignedAggregatorAddress = _alignedAggregatorAddress;
sp1VerifierAddress = _sp1VerifierAddress;
risc0VerifierAddress = _risc0VerifierAddress;
risc0AggregatorProgramImageId = _risc0AggregatorProgramImageId;
sp1AggregatorProgramVKHash = _sp1AggregatorProgramVKHash;
}

function verifySP1(
bytes32 blobVersionedHash,
bytes32 sp1ProgramVKey,
bytes calldata sp1PublicValues,
bytes calldata sp1ProofBytes
) public onlyAlignedAggregator {
function verifySP1(bytes32 blobVersionedHash, bytes calldata sp1PublicValues, bytes calldata sp1ProofBytes)
public
onlyAlignedAggregator
{
(bytes32 merkleRoot) = abi.decode(sp1PublicValues, (bytes32));

// In dev mode, poofs are mocked, so we skip the verification part
if (_isSP1VerificationEnabled()) {
ISP1Verifier(sp1VerifierAddress).verifyProof(sp1ProgramVKey, sp1PublicValues, sp1ProofBytes);
ISP1Verifier(sp1VerifierAddress).verifyProof(sp1AggregatorProgramVKHash, sp1PublicValues, sp1ProofBytes);
}

aggregatedProofs[merkleRoot] = true;
emit AggregatedProofVerified(merkleRoot, blobVersionedHash);
}

function verifyRisc0(
bytes32 blobVersionedHash,
bytes calldata risc0ReceiptSeal,
bytes32 risc0ImageId,
bytes calldata risc0JournalBytes
) public onlyAlignedAggregator {
function verifyRisc0(bytes32 blobVersionedHash, bytes calldata risc0ReceiptSeal, bytes calldata risc0JournalBytes)
public
onlyAlignedAggregator
{
(bytes32 merkleRoot) = abi.decode(risc0JournalBytes, (bytes32));

// In dev mode, poofs are mocked, so we skip the verification part
if (_isRisc0VerificationEnabled()) {
bytes32 risc0JournalDigest = sha256(risc0JournalBytes);
IRiscZeroVerifier(risc0VerifierAddress).verify(risc0ReceiptSeal, risc0ImageId, risc0JournalDigest);
IRiscZeroVerifier(risc0VerifierAddress).verify(
risc0ReceiptSeal, risc0AggregatorProgramImageId, risc0JournalDigest
);
}

aggregatedProofs[merkleRoot] = true;
Expand Down Expand Up @@ -115,4 +125,16 @@ contract AlignedProofAggregationService is
function setRisc0VerifierAddress(address _risc0VerifierAddress) external onlyOwner {
risc0VerifierAddress = _risc0VerifierAddress;
}

/// @notice Sets the image id of the Risc0 program
/// @param _risc0AggregatorProgramImageId The new imageid for the Risc0 aggregator program
function setRisc0AggregatorProgramImageId(bytes32 _risc0AggregatorProgramImageId) external onlyOwner {
risc0AggregatorProgramImageId = _risc0AggregatorProgramImageId;
}

/// @notice Sets the vk hash of the sp1 program
/// @param _sp1AggregatorProgramVKHash The new vk hash for the sp1 aggregator program
function setSP1AggregatorProgramVKHash(bytes32 _sp1AggregatorProgramVKHash) external onlyOwner {
sp1AggregatorProgramVKHash = _sp1AggregatorProgramVKHash;
}
}
17 changes: 4 additions & 13 deletions contracts/src/core/IAlignedProofAggregationService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,13 @@ interface IAlignedProofAggregationService {
/// @dev This function is called by the aligned proof aggregator after collecting the proofs and aggregating them
/// to be verified on-chain. We expect the blobTransactionHash to be called before
/// @param blobVersionedHash the versioned hash of the blob transaction that contains the leaves that compose the merkle root.
/// @param sp1ProgramVKey Public verifying key
/// @param sp1PublicValues Values used to perform the execution
/// @param sp1ProofBytes Groth16 proof
function verifySP1(
bytes32 blobVersionedHash,
bytes32 sp1ProgramVKey,
bytes calldata sp1PublicValues,
bytes calldata sp1ProofBytes
) external;
function verifySP1(bytes32 blobVersionedHash, bytes calldata sp1PublicValues, bytes calldata sp1ProofBytes)
external;

function verifyRisc0(
bytes32 blobVersionedHash,
bytes calldata risc0ReceiptSeal,
bytes32 risc0ImageId,
bytes calldata risc0JournalBytes
) external;
function verifyRisc0(bytes32 blobVersionedHash, bytes calldata risc0ReceiptSeal, bytes calldata risc0JournalBytes)
external;

/// @notice event that gets emitted after a successful aggregated proof verification
event AggregatedProofVerified(bytes32 indexed merkleRoot, bytes32 blobVersionedHash);
Expand Down
Loading