1- pub mod lib;
21pub mod risc0_aggregator;
32pub mod sp1_aggregator;
43
54use std:: fmt:: Display ;
65
7- use risc0_aggregator:: { AlignedRisc0VerificationError , Risc0ProofReceiptAndImageId } ;
8- use sp1_aggregator:: { AlignedSP1VerificationError , SP1ProofWithPubValuesAndElf } ;
6+ use risc0_aggregator:: {
7+ AlignedRisc0VerificationError , Risc0AggregationError , Risc0ProofReceiptAndImageId ,
8+ } ;
9+ use sp1_aggregator:: {
10+ AlignedSP1VerificationError , SP1AggregationError , SP1ProofWithPubValuesAndElf ,
11+ } ;
912
1013#[ derive( Clone , Debug ) ]
1114pub enum ZKVMEngine {
@@ -22,6 +25,13 @@ impl Display for ZKVMEngine {
2225 }
2326}
2427
28+ #[ derive( Debug ) ]
29+ pub enum ProofAggregationError {
30+ SP1Aggregation ( SP1AggregationError ) ,
31+ Risc0Aggregation ( Risc0AggregationError ) ,
32+ PublicInputsDeserialization ,
33+ }
34+
2535impl ZKVMEngine {
2636 pub fn from_env ( ) -> Option < Self > {
2737 let key = "AGGREGATOR" ;
@@ -34,6 +44,69 @@ impl ZKVMEngine {
3444
3545 Some ( engine)
3646 }
47+
48+ /// Aggregates a list of [`AlignedProof`]s into a single [`AlignedProof`].
49+ ///
50+ /// Returns a tuple containing:
51+ /// - The aggregated [`AlignedProof`], representing the combined proof
52+ /// - The Merkle root computed within the ZKVM, exposed as a public input
53+ ///
54+ /// This function performs proof aggregation and ensures the resulting Merkle root
55+ /// can be independently verified by external systems.
56+ pub fn aggregate_proofs (
57+ & self ,
58+ proofs : Vec < AlignedProof > ,
59+ ) -> Result < ( AlignedProof , [ u8 ; 32 ] ) , ProofAggregationError > {
60+ let res = match self {
61+ ZKVMEngine :: SP1 => {
62+ let proofs = proofs
63+ . into_iter ( )
64+ // Fetcher already filtered for SP1
65+ // We do this for type casting, as to avoid using generics
66+ // or macros in this function
67+ . filter_map ( |proof| match proof {
68+ AlignedProof :: SP1 ( proof) => Some ( * proof) ,
69+ _ => None ,
70+ } )
71+ . collect ( ) ;
72+
73+ let mut agg_proof = sp1_aggregator:: aggregate_proofs ( proofs)
74+ . map_err ( ProofAggregationError :: SP1Aggregation ) ?;
75+
76+ let merkle_root: [ u8 ; 32 ] = agg_proof
77+ . proof_with_pub_values
78+ . public_values
79+ . read :: < [ u8 ; 32 ] > ( ) ;
80+
81+ ( AlignedProof :: SP1 ( agg_proof. into ( ) ) , merkle_root)
82+ }
83+ ZKVMEngine :: RISC0 => {
84+ let proofs = proofs
85+ . into_iter ( )
86+ // Fetcher already filtered for Risc0
87+ // We do this for type casting, as to avoid using generics
88+ // or macros in this function
89+ . filter_map ( |proof| match proof {
90+ AlignedProof :: Risc0 ( proof) => Some ( * proof) ,
91+ _ => None ,
92+ } )
93+ . collect ( ) ;
94+
95+ let agg_proof = risc0_aggregator:: aggregate_proofs ( proofs)
96+ . map_err ( ProofAggregationError :: Risc0Aggregation ) ?;
97+
98+ // Note: journal.decode() won't work here as risc0 deserializer works under u32 words
99+ let public_input_bytes = agg_proof. receipt . journal . as_ref ( ) ;
100+ let merkle_root: [ u8 ; 32 ] = public_input_bytes
101+ . try_into ( )
102+ . map_err ( |_| ProofAggregationError :: PublicInputsDeserialization ) ?;
103+
104+ ( AlignedProof :: Risc0 ( agg_proof. into ( ) ) , merkle_root)
105+ }
106+ } ;
107+
108+ Ok ( res)
109+ }
37110}
38111
39112pub enum AlignedProof {
@@ -42,7 +115,7 @@ pub enum AlignedProof {
42115}
43116
44117impl AlignedProof {
45- pub fn hash ( & self ) -> [ u8 ; 32 ] {
118+ pub fn commitment ( & self ) -> [ u8 ; 32 ] {
46119 match self {
47120 AlignedProof :: SP1 ( proof) => proof. hash_vk_and_pub_inputs ( ) ,
48121 AlignedProof :: Risc0 ( proof) => proof. hash_image_id_and_public_inputs ( ) ,
0 commit comments