Skip to content

Commit e39ed67

Browse files
committed
fix: aggregated proofs commitment for the second layer
1 parent 4059b2c commit e39ed67

File tree

7 files changed

+86
-85
lines changed

7 files changed

+86
-85
lines changed

aggregation_mode/aggregation_programs/risc0/src/lib.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,25 @@ pub struct Risc0ImageIdAndPubInputs {
88
}
99

1010
impl Risc0ImageIdAndPubInputs {
11-
pub fn commitment(&self) -> [u8; 32] {
12-
let mut hasher = Keccak::v256();
13-
for &word in &self.image_id {
14-
hasher.update(&word.to_be_bytes());
15-
}
16-
hasher.update(&self.public_inputs);
11+
pub fn commitment(&self, is_aggregated_chunk: bool) -> [u8; 32] {
12+
if is_aggregated_chunk {
13+
self.public_inputs.clone().try_into().unwrap()
14+
} else {
15+
let mut hasher = Keccak::v256();
16+
for &word in &self.image_id {
17+
hasher.update(&word.to_be_bytes());
18+
}
19+
hasher.update(&self.public_inputs);
1720

18-
let mut hash = [0u8; 32];
19-
hasher.finalize(&mut hash);
20-
hash
21+
let mut hash = [0u8; 32];
22+
hasher.finalize(&mut hash);
23+
hash
24+
}
2125
}
2226
}
2327

2428
#[derive(Serialize, Deserialize)]
2529
pub struct Input {
2630
pub proofs_image_id_and_pub_inputs: Vec<Risc0ImageIdAndPubInputs>,
31+
pub is_aggregated_chunk: bool,
2732
}

aggregation_mode/aggregation_programs/risc0/src/main.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,18 @@ fn combine_hashes(hash_a: &[u8; 32], hash_b: &[u8; 32]) -> [u8; 32] {
1717
}
1818

1919
/// Computes the merkle root for the given proofs
20-
fn compute_merkle_root(proofs: &[Risc0ImageIdAndPubInputs]) -> [u8; 32] {
20+
fn compute_merkle_root(proofs: &[Risc0ImageIdAndPubInputs], is_aggregated_chunk: bool) -> [u8; 32] {
2121
let mut leaves: Vec<[u8; 32]> = proofs
2222
.chunks(2)
2323
.map(|chunk| match chunk {
24-
[a, b] => combine_hashes(&a.commitment(), &b.commitment()),
25-
[a] => combine_hashes(&a.commitment(), &a.commitment()),
24+
[a, b] => combine_hashes(
25+
&a.commitment(is_aggregated_chunk),
26+
&b.commitment(is_aggregated_chunk),
27+
),
28+
[a] => combine_hashes(
29+
&a.commitment(is_aggregated_chunk),
30+
&a.commitment(is_aggregated_chunk),
31+
),
2632
_ => panic!("Unexpected chunk leaves"),
2733
})
2834
.collect();
@@ -52,7 +58,10 @@ fn main() {
5258
env::verify(image_id.clone(), &public_inputs).expect("proof to be verified correctly");
5359
}
5460

55-
let merkle_root = compute_merkle_root(&input.proofs_image_id_and_pub_inputs);
61+
let merkle_root = compute_merkle_root(
62+
&input.proofs_image_id_and_pub_inputs,
63+
input.is_aggregated_chunk,
64+
);
5665

5766
env::commit_slice(&merkle_root);
5867
}

aggregation_mode/aggregation_programs/sp1/src/lib.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,22 @@ pub struct SP1VkAndPubInputs {
88
}
99

1010
impl SP1VkAndPubInputs {
11-
pub fn hash(&self) -> [u8; 32] {
12-
let mut hasher = Keccak256::new();
13-
for &word in &self.vk {
14-
hasher.update(word.to_be_bytes());
11+
pub fn commitment(&self, is_aggregated_chunk: bool) -> [u8; 32] {
12+
if is_aggregated_chunk {
13+
self.public_inputs.clone().try_into().unwrap()
14+
} else {
15+
let mut hasher = Keccak256::new();
16+
for &word in &self.vk {
17+
hasher.update(word.to_be_bytes());
18+
}
19+
hasher.update(&self.public_inputs);
20+
hasher.finalize().into()
1521
}
16-
hasher.update(&self.public_inputs);
17-
hasher.finalize().into()
1822
}
1923
}
2024

2125
#[derive(Serialize, Deserialize)]
2226
pub struct Input {
2327
pub proofs_vk_and_pub_inputs: Vec<SP1VkAndPubInputs>,
28+
pub is_aggregated_chunk: bool,
2429
}

aggregation_mode/aggregation_programs/sp1/src/main.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,18 @@ fn combine_hashes(hash_a: &[u8; 32], hash_b: &[u8; 32]) -> [u8; 32] {
1313
}
1414

1515
/// Computes the merkle root for the given proofs using the vk
16-
fn compute_merkle_root(proofs: &[SP1VkAndPubInputs]) -> [u8; 32] {
16+
fn compute_merkle_root(proofs: &[SP1VkAndPubInputs], is_aggregated_chunk: bool) -> [u8; 32] {
1717
let mut leaves: Vec<[u8; 32]> = proofs
1818
.chunks(2)
1919
.map(|chunk| match chunk {
20-
[a, b] => combine_hashes(&a.hash(), &b.hash()),
21-
[a] => combine_hashes(&a.hash(), &a.hash()),
20+
[a, b] => combine_hashes(
21+
&a.commitment(is_aggregated_chunk),
22+
&b.commitment(is_aggregated_chunk),
23+
),
24+
[a] => combine_hashes(
25+
&a.commitment(is_aggregated_chunk),
26+
&a.commitment(is_aggregated_chunk),
27+
),
2228
_ => panic!("Unexpected chunk leaves"),
2329
})
2430
.collect();
@@ -48,7 +54,8 @@ pub fn main() {
4854
sp1_zkvm::lib::verify::verify_sp1_proof(&vkey, &public_values_digest.into());
4955
}
5056

51-
let merkle_root = compute_merkle_root(&input.proofs_vk_and_pub_inputs);
57+
let merkle_root =
58+
compute_merkle_root(&input.proofs_vk_and_pub_inputs, input.is_aggregated_chunk);
5259

5360
sp1_zkvm::io::commit_slice(&merkle_root);
5461
}

aggregation_mode/src/aggregators/mod.rs

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use std::fmt::Display;
55

66
use risc0_aggregator::{
77
AlignedRisc0VerificationError, Risc0AggregationError, Risc0ProofReceiptAndImageId,
8-
Risc0ProofType,
98
};
109
use sp1_aggregator::{
11-
AlignedSP1VerificationError, SP1AggregationError, SP1ProofType, SP1ProofWithPubValuesAndElf,
10+
AlignedSP1VerificationError, SP1AggregationError, SP1ProofWithPubValuesAndElf,
1211
};
1312

13+
const AGG_PROOF_CHUNKS: usize = 512;
14+
1415
#[derive(Clone, Debug)]
1516
pub enum ZKVMEngine {
1617
SP1,
@@ -68,29 +69,21 @@ impl ZKVMEngine {
6869
})
6970
.collect();
7071

71-
// we run the aggregator in chunks of 512 proofs
72-
let chunks = proofs.chunks(512);
73-
let mut agg_proofs: Vec<SP1ProofWithPubValuesAndElf> = vec![];
74-
75-
let agg_chunks_type = if chunks.len() == 1 {
76-
SP1ProofType::Groth16
77-
} else {
78-
SP1ProofType::Compressed
79-
};
80-
81-
for chunk in chunks {
82-
let agg_proof =
83-
sp1_aggregator::aggregate_proofs(chunk, agg_chunks_type.clone())
72+
let mut agg_proof = if proofs.len() > AGG_PROOF_CHUNKS {
73+
let chunks = proofs.chunks(AGG_PROOF_CHUNKS);
74+
let mut agg_proofs: Vec<SP1ProofWithPubValuesAndElf> = vec![];
75+
for chunk in chunks {
76+
let agg_proof = sp1_aggregator::aggregate_proofs(chunk, false, false)
8477
.map_err(ProofAggregationError::SP1Aggregation)?;
8578

86-
agg_proofs.push(agg_proof);
87-
}
79+
agg_proofs.push(agg_proof);
80+
}
8881

89-
let mut agg_proof = if agg_proofs.len() > 1 {
90-
sp1_aggregator::aggregate_proofs(&agg_proofs, SP1ProofType::Groth16)
82+
sp1_aggregator::aggregate_proofs(&agg_proofs, true, true)
9183
.map_err(ProofAggregationError::SP1Aggregation)?
9284
} else {
93-
agg_proofs.pop().unwrap()
85+
sp1_aggregator::aggregate_proofs(&proofs, false, true)
86+
.map_err(ProofAggregationError::SP1Aggregation)?
9487
};
9588

9689
let merkle_root: [u8; 32] = agg_proof
@@ -109,28 +102,20 @@ impl ZKVMEngine {
109102
})
110103
.collect();
111104

112-
let chunks = proofs.chunks(512);
113-
let mut agg_proofs: Vec<Risc0ProofReceiptAndImageId> = vec![];
114-
115-
let agg_chunks_type = if chunks.len() == 1 {
116-
Risc0ProofType::Groth16
117-
} else {
118-
Risc0ProofType::Composite
119-
};
120-
121-
for chunk in chunks {
122-
let agg_proof =
123-
risc0_aggregator::aggregate_proofs(chunk, agg_chunks_type.clone())
105+
let agg_proof = if proofs.len() > AGG_PROOF_CHUNKS {
106+
let chunks = proofs.chunks(AGG_PROOF_CHUNKS);
107+
let mut agg_proofs: Vec<Risc0ProofReceiptAndImageId> = vec![];
108+
for chunk in chunks {
109+
let agg_proof = risc0_aggregator::aggregate_proofs(chunk, false, false)
124110
.map_err(ProofAggregationError::Risc0Aggregation)?;
111+
agg_proofs.push(agg_proof);
112+
}
125113

126-
agg_proofs.push(agg_proof);
127-
}
128-
129-
let agg_proof = if agg_proofs.len() > 1 {
130-
risc0_aggregator::aggregate_proofs(&agg_proofs, Risc0ProofType::Groth16)
114+
risc0_aggregator::aggregate_proofs(&agg_proofs, true, true)
131115
.map_err(ProofAggregationError::Risc0Aggregation)?
132116
} else {
133-
agg_proofs.pop().unwrap()
117+
risc0_aggregator::aggregate_proofs(&proofs, false, true)
118+
.map_err(ProofAggregationError::Risc0Aggregation)?
134119
};
135120

136121
// Note: journal.decode() won't work here as risc0 deserializer works under u32 words

aggregation_mode/src/aggregators/risc0_aggregator.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,10 @@ pub enum Risc0AggregationError {
4646
Verification(String),
4747
}
4848

49-
#[derive(Debug, Clone)]
50-
pub enum Risc0ProofType {
51-
Groth16,
52-
Composite,
53-
Succinct,
54-
}
55-
5649
pub(crate) fn aggregate_proofs(
5750
proofs: &[Risc0ProofReceiptAndImageId],
58-
to_proof_type: Risc0ProofType,
51+
is_aggregated_chunk: bool,
52+
should_wrap_to_groth16: bool,
5953
) -> Result<Risc0ProofReceiptAndImageId, Risc0AggregationError> {
6054
let mut env_builder = ExecutorEnv::builder();
6155

@@ -72,6 +66,7 @@ pub(crate) fn aggregate_proofs(
7266
// write input data
7367
let input = risc0_aggregation_program::Input {
7468
proofs_image_id_and_pub_inputs,
69+
is_aggregated_chunk,
7570
};
7671
env_builder
7772
.write(&input)
@@ -83,10 +78,10 @@ pub(crate) fn aggregate_proofs(
8378

8479
let prover = default_prover();
8580

86-
let opts = match to_proof_type {
87-
Risc0ProofType::Groth16 => ProverOpts::groth16(),
88-
Risc0ProofType::Composite => ProverOpts::composite(),
89-
Risc0ProofType::Succinct => ProverOpts::succinct(),
81+
let opts = if should_wrap_to_groth16 {
82+
ProverOpts::groth16()
83+
} else {
84+
ProverOpts::composite()
9085
};
9186

9287
let receipt = prover

aggregation_mode/src/aggregators/sp1_aggregator.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,16 @@ pub enum SP1AggregationError {
3838
UnsupportedProof,
3939
}
4040

41-
#[derive(Debug, Clone)]
42-
pub enum SP1ProofType {
43-
Groth16,
44-
Compressed,
45-
Core,
46-
}
47-
4841
pub(crate) fn aggregate_proofs(
4942
proofs: &[SP1ProofWithPubValuesAndElf],
50-
to_proof_type: SP1ProofType,
43+
is_aggregated_chunk: bool,
44+
should_wrap_to_groth16: bool,
5145
) -> Result<SP1ProofWithPubValuesAndElf, SP1AggregationError> {
5246
let mut stdin = SP1Stdin::new();
5347

5448
let mut program_input = sp1_aggregation_program::Input {
5549
proofs_vk_and_pub_inputs: vec![],
50+
is_aggregated_chunk,
5651
};
5752

5853
// write vk + public inputs
@@ -85,10 +80,10 @@ pub(crate) fn aggregate_proofs(
8580

8681
let (pk, vk) = client.setup(PROGRAM_ELF);
8782
let proof_builder = client.prove(&pk, &stdin);
88-
let proof_builder = match to_proof_type {
89-
SP1ProofType::Groth16 => proof_builder.groth16(),
90-
SP1ProofType::Compressed => proof_builder.compressed(),
91-
SP1ProofType::Core => proof_builder.core(),
83+
let proof_builder = if should_wrap_to_groth16 {
84+
proof_builder.groth16()
85+
} else {
86+
proof_builder.compressed()
9287
};
9388

9489
let proof = proof_builder

0 commit comments

Comments
 (0)