55/// - `file_table`: kind points are pre-computed in `kind_table.json`; the circuit
66/// resolves them via a table lookup, skipping `hash_to_curve`.
77///
8+ /// Each configuration is benchmarked with 1, 2, 4, and 8 consumed/created
9+ /// resources to measure scaling behaviour.
10+ ///
811/// # Running on CPU
912///
1013/// ```sh
2730/// ```
2831use anoma_rm_risc0:: compliance:: { ComplianceWitness , INITIAL_ROOT } ;
2932use anoma_rm_risc0:: constants:: { global_kind_table, init_kind_table_from_file} ;
30- use anoma_rm_risc0:: merkle_path:: MerklePath ;
3133use anoma_rm_risc0:: nullifier_key:: NullifierKey ;
32- use anoma_rm_risc0:: resource:: Resource ;
34+ use anoma_rm_risc0:: resource:: { ConsumedResourceWitness , Resource } ;
3335use compliance_methods:: COMPLIANCE_GUEST_ELF ;
34- use criterion:: { criterion_group, criterion_main, Criterion } ;
36+ use criterion:: { criterion_group, criterion_main, BenchmarkId , Criterion } ;
3537use risc0_zkvm:: { default_prover, Digest , ExecutorEnv , ProverOpts } ;
3638use std:: time:: Duration ;
3739
40+ const RESOURCE_COUNTS : & [ usize ] = & [ 1 , 2 , 4 , 8 ] ;
41+
3842fn do_prove ( witness : & ComplianceWitness ) {
3943 let env = ExecutorEnv :: builder ( )
4044 . write ( witness)
@@ -46,32 +50,54 @@ fn do_prove(witness: &ComplianceWitness) {
4650 . unwrap ( ) ;
4751}
4852
49- /// Build a compliance witness whose resources use `logic_ref` and `label_ref`,
50- /// pulling the current global kind table into the witness .
51- fn make_witness ( logic_ref : Digest , label_ref : Digest ) -> ComplianceWitness {
53+ /// Build a compliance witness with `count` consumed/created resources.
54+ /// Each consumed resource gets a unique nonce via its index in the last byte .
55+ fn make_witness ( logic_ref : Digest , label_ref : Digest , count : usize ) -> ComplianceWitness {
5256 let nf_key = NullifierKey :: default ( ) ;
53- let consumed_resource = Resource {
54- logic_ref,
55- label_ref,
56- quantity : 1 ,
57- value_ref : Digest :: default ( ) ,
58- is_ephemeral : false ,
59- nonce : [ 0u8 ; 32 ] ,
60- nk_commitment : nf_key. commit ( ) ,
61- rand_seed : [ 0u8 ; 32 ] ,
62- } ;
63- let nf = consumed_resource. nullifier ( & nf_key) . unwrap ( ) ;
64- let created_resource = Resource {
65- nonce : nf. as_bytes ( ) . try_into ( ) . unwrap ( ) ,
66- ..consumed_resource
67- } ;
57+
58+ let consumed_data: Vec < ConsumedResourceWitness > = ( 0 ..count)
59+ . map ( |i| {
60+ let mut nonce = [ 0u8 ; 32 ] ;
61+ nonce[ 31 ] = i as u8 ;
62+ let resource = Resource {
63+ logic_ref,
64+ label_ref,
65+ quantity : 1 ,
66+ value_ref : Digest :: default ( ) ,
67+ is_ephemeral : false ,
68+ nonce,
69+ nk_commitment : nf_key. commit ( ) ,
70+ rand_seed : [ 0u8 ; 32 ] ,
71+ } ;
72+ ConsumedResourceWitness :: from_resource ( resource, nf_key. clone ( ) )
73+ } )
74+ . collect ( ) ;
75+
76+ let nullifiers: Vec < Digest > = consumed_data
77+ . iter ( )
78+ . map ( |w| w. resource . nullifier ( & nf_key) . unwrap ( ) )
79+ . collect ( ) ;
80+
81+ let created_resources: Vec < Resource > = ( 0 ..count)
82+ . map ( |i| {
83+ let nonce = Resource :: derive_nonce_from_nullifiers ( i as u32 , & nullifiers) . unwrap ( ) ;
84+ Resource {
85+ logic_ref,
86+ label_ref,
87+ quantity : 1 ,
88+ value_ref : Digest :: default ( ) ,
89+ is_ephemeral : false ,
90+ nonce,
91+ nk_commitment : nf_key. commit ( ) ,
92+ rand_seed : [ 0u8 ; 32 ] ,
93+ }
94+ } )
95+ . collect ( ) ;
96+
6897 ComplianceWitness {
69- consumed_resource ,
70- merkle_path : MerklePath :: default ( ) ,
98+ consumed_data ,
99+ created_resources ,
71100 ephemeral_root : * INITIAL_ROOT ,
72- nf_key,
73- created_resource,
74- // Scalar::ONE encoded as big-endian 32 bytes
75101 rcv : [ vec ! [ 0u8 ; 31 ] , vec ! [ 1u8 ] ] . concat ( ) ,
76102 kind_table : global_kind_table ( ) . to_vec ( ) ,
77103 }
@@ -84,17 +110,21 @@ fn bench_empty_table(c: &mut Criterion) {
84110 group. warm_up_time ( Duration :: from_secs ( 1 ) ) ;
85111 group. measurement_time ( Duration :: from_secs ( 1 ) ) ;
86112
87- group. bench_function ( "prove" , |b| {
88- b. iter_with_setup ( ComplianceWitness :: default, |witness| do_prove ( & witness) ) ;
89- } ) ;
113+ for & count in RESOURCE_COUNTS {
114+ group. bench_with_input ( BenchmarkId :: new ( "prove" , count) , & count, |b, & count| {
115+ b. iter_with_setup (
116+ || make_witness ( Digest :: default ( ) , Digest :: default ( ) , count) ,
117+ |witness| do_prove ( & witness) ,
118+ ) ;
119+ } ) ;
120+ }
90121
91122 group. finish ( ) ;
92123}
93124
94125/// Precomputed kind table from file: the circuit resolves kind points via table
95126/// lookup, skipping `hash_to_curve`. The witness uses the `logic_ref` and
96- /// `label_ref` of the first entry in the loaded table so both consumed and
97- /// created resources are guaranteed to hit the table.
127+ /// `label_ref` of the first entry in the loaded table so all resources hit the table.
98128fn bench_file_table ( c : & mut Criterion ) {
99129 let kind_table_path =
100130 std:: path:: PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) . join ( "../../arm/kind_table.json" ) ;
@@ -109,12 +139,14 @@ fn bench_file_table(c: &mut Criterion) {
109139 group. warm_up_time ( Duration :: from_secs ( 1 ) ) ;
110140 group. measurement_time ( Duration :: from_secs ( 1 ) ) ;
111141
112- group. bench_function ( "prove" , |b| {
113- b. iter_with_setup (
114- || make_witness ( logic_ref, label_ref) ,
115- |witness| do_prove ( & witness) ,
116- ) ;
117- } ) ;
142+ for & count in RESOURCE_COUNTS {
143+ group. bench_with_input ( BenchmarkId :: new ( "prove" , count) , & count, |b, & count| {
144+ b. iter_with_setup (
145+ || make_witness ( logic_ref, label_ref, count) ,
146+ |witness| do_prove ( & witness) ,
147+ ) ;
148+ } ) ;
149+ }
118150
119151 group. finish ( ) ;
120152}
0 commit comments