Skip to content

Commit 4fa59f4

Browse files
committed
feat: sign transaction + merkle root computation
1 parent 554abb1 commit 4fa59f4

File tree

5 files changed

+71
-27
lines changed

5 files changed

+71
-27
lines changed

aggregation-mode/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aggregation-mode/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ tracing-subscriber = { version = "0.3.0", features = ["env-filter"] }
1414
alloy = { version = "0.11", features = [] }
1515
bincode = "1.3.3"
1616
tokio = { version = "1", features = ["time"]}
17+
sha3 = "0.10.8"
1718

1819
[build-dependencies]
1920
sp1-build = { version = "4.1.3" }
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use crate::zk::Proof;
2+
use sha3::{Digest, Keccak256};
3+
4+
pub fn combine_hashes(hash_a: &[u8; 32], hash_b: &[u8; 32]) -> [u8; 32] {
5+
let mut hasher = Keccak256::new();
6+
hasher.update(hash_a);
7+
hasher.update(hash_b);
8+
hasher.finalize().into()
9+
}
10+
11+
/// Returns (merkle_root, leaves)
12+
pub fn compute_proofs_merkle_root(proofs: &[Proof]) -> ([u8; 32], Vec<[u8; 32]>) {
13+
let leaves: Vec<[u8; 32]> = proofs
14+
.chunks(2)
15+
.map(|chunk| match chunk {
16+
[a, b] => combine_hashes(&a.hash(), &b.hash()),
17+
[a] => combine_hashes(&a.hash(), &a.hash()),
18+
_ => panic!("Unexpected chunk leaves"),
19+
})
20+
.collect();
21+
22+
let mut root = leaves.clone();
23+
24+
while root.len() > 1 {
25+
root = root
26+
.chunks(2)
27+
.map(|chunk| match chunk {
28+
[a, b] => combine_hashes(&a, &b),
29+
[a] => combine_hashes(&a, &a),
30+
_ => panic!("Unexpected chunk size in leaves"),
31+
})
32+
.collect()
33+
}
34+
35+
(root[0], leaves)
36+
}

aggregation-mode/src/backend/mod.rs

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,30 @@
11
use std::time::Duration;
22

33
use alloy::{
4+
network::EthereumWallet,
45
primitives::Address,
56
providers::{PendingTransactionError, ProviderBuilder},
67
rpc::types::TransactionReceipt,
8+
signers::local::PrivateKeySigner,
79
};
10+
use merkle_tree::compute_proofs_merkle_root;
811
use sp1_sdk::HashableKey;
912
use tracing::{error, info};
1013
use types::{AlignedProofAggregationService, AlignedProofAggregationServiceContract};
1114

1215
use crate::zk::{
1316
aggregator::{self, AggregatedProof, ProgramInput, ProofAggregationError},
14-
Proof, ZKVMEngine,
17+
backends::sp1::SP1AggregationInput,
18+
Proof, VerificationError, ZKVMEngine,
1519
};
1620

21+
mod merkle_tree;
1722
mod types;
1823

1924
#[derive(Debug)]
2025
pub enum ProofQueueError {
2126
QueueMaxCapacity,
22-
InvalidProof,
27+
InvalidProof(VerificationError),
2328
}
2429

2530
#[derive(Debug)]
@@ -42,7 +47,9 @@ impl ProofAggregator {
4247
// TODO read .yaml config file
4348
pub fn new(rpc_url: &str) -> Self {
4449
let rpc_url = rpc_url.parse().expect("correct url");
45-
let provider = ProviderBuilder::new().on_http(rpc_url);
50+
let signer = PrivateKeySigner::random();
51+
let wallet = EthereumWallet::from(signer);
52+
let provider = ProviderBuilder::new().wallet(wallet).on_http(rpc_url);
4653
let proof_aggregation_service =
4754
AlignedProofAggregationService::new(Address::default(), provider);
4855

@@ -77,9 +84,9 @@ impl ProofAggregator {
7784
}
7885
}
7986

80-
pub fn add_proof(&mut self, proof: Proof) -> Result<(), ProofQueueError> {
81-
if proof.verify().is_err() {
82-
return Err(ProofQueueError::InvalidProof);
87+
pub fn add_proof(&mut self, proof: Proof, elf: &[u8]) -> Result<(), ProofQueueError> {
88+
if let Err(err) = proof.verify(elf) {
89+
return Err(ProofQueueError::InvalidProof(err));
8390
};
8491

8592
if self.proofs_queue.len() as u16 >= self.max_proofs_in_queue {
@@ -94,34 +101,26 @@ impl ProofAggregator {
94101
async fn aggregate_and_submit_proofs_on_chain(
95102
&mut self,
96103
) -> Result<(), AggregatedProofSubmissionError> {
97-
// TODO build merkle tree and pass as input
98-
99104
let proofs = self
100105
.proofs_queue
101106
.drain(0..self.proofs_queue.len())
102107
.collect::<Vec<_>>();
103108

104-
let leaves: Vec<[u8; 32]> = vec![];
105-
let merkle_root = [0u8; 32];
106-
109+
let (merkle_root, leaves) = compute_proofs_merkle_root(&proofs);
107110
let output = match self.engine {
108111
ZKVMEngine::SP1 => {
109-
// convert proofs to sp1 input format
112+
// only SP1 compressed proofs are supported
110113
let proofs = proofs
111-
.iter()
112-
.map(|proof| match proof {
113-
Proof::SP1(proof) => sp1_aggregator::Proof::SP1Compressed(
114-
sp1_aggregator::SP1CompressedProof {
115-
public_inputs: proof.proof.public_values.to_vec(),
116-
vk: proof.verifying_key().bytes32().as_bytes().to_vec(),
117-
},
118-
),
114+
.into_iter()
115+
.filter_map(|proof| match proof {
116+
Proof::SP1(proof) => Some(proof),
119117
})
120118
.collect();
121-
let input = sp1_aggregator::Input { proofs };
122119

123-
// clean proof queue
124-
self.proofs_queue = vec![];
120+
let input = SP1AggregationInput {
121+
proofs,
122+
merkle_root,
123+
};
125124

126125
aggregator::aggregate_proofs(ProgramInput::SP1(input))
127126
.map_err(AggregatedProofSubmissionError::Aggregation)?
@@ -135,7 +134,6 @@ impl ProofAggregator {
135134
Ok(())
136135
}
137136

138-
// TODO send blob + contract transaction
139137
async fn send_proof_to_verify_on_chain(
140138
&self,
141139
blob_tx_hash: &[u8; 32],
@@ -152,6 +150,7 @@ impl ProofAggregator {
152150
proof.proof.bytes().into(),
153151
)
154152
.send()
153+
// sign with aggregator wallet
155154
.await
156155
.map_err(
157156
AggregatedProofSubmissionError::SendVerifyAggregatedProofTransaction,

aggregation-mode/src/backend/types.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
use alloy::{
2+
network::EthereumWallet,
23
providers::{
3-
fillers::{BlobGasFiller, ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller},
4+
fillers::{
5+
BlobGasFiller, ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller,
6+
WalletFiller,
7+
},
48
Identity, RootProvider,
59
},
610
sol,
@@ -17,8 +21,11 @@ pub type AlignedProofAggregationServiceContract = AlignedProofAggregationService
1721
(),
1822
FillProvider<
1923
JoinFill<
20-
Identity,
21-
JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>,
24+
JoinFill<
25+
Identity,
26+
JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>,
27+
>,
28+
WalletFiller<EthereumWallet>,
2229
>,
2330
RootProvider,
2431
>,

0 commit comments

Comments
 (0)