@@ -13,7 +13,10 @@ use std::{
1313
1414use anyhow:: { Context , anyhow} ;
1515use midnight_curves:: Bls12 ;
16- use midnight_proofs:: { poly:: kzg:: params:: ParamsKZG , utils:: SerdeFormat } ;
16+ use midnight_proofs:: {
17+ poly:: kzg:: params:: { ParamsKZG , ParamsVerifierKZG } ,
18+ utils:: SerdeFormat ,
19+ } ;
1720use midnight_zk_stdlib:: { self as zk, MidnightCircuit , MidnightPK , MidnightVK } ;
1821use rand_chacha:: ChaCha20Rng ;
1922use rand_core:: SeedableRng ;
@@ -98,6 +101,71 @@ impl SnarkSetup {
98101 }
99102}
100103
104+ /// Bundles the minimal setup artifacts needed to verify SNARK proofs.
105+ ///
106+ /// Only the KZG verifier parameters are required for verification, and they depend solely on the
107+ /// toxic secret `s = Fq::random(ChaCha20Rng::seed_from_u64(42))`. That secret is independent of
108+ /// the circuit degree `k`, so a single hard-coded serialization of `s_g2` suffices for every
109+ /// circuit produced by the deterministic unsafe setup.
110+ pub ( crate ) struct SnarkVerifierSetup {
111+ /// KZG verifier parameters derived from `s_g2`.
112+ pub ( crate ) verifier_params : ParamsVerifierKZG < Bls12 > ,
113+ }
114+
115+ /// Serialized `s_g2` (the only material the KZG verifier needs) for the deterministic SNARK setup
116+ /// seeded with `ChaCha20Rng::seed_from_u64(42)`.
117+ ///
118+ /// Regenerate by running the `golden_snark_verifier_params_bytes` test and copying its printed
119+ /// decimal byte sequence.
120+ const SNARK_VERIFIER_PARAMS_BYTES : [ u8 ; 192 ] = [
121+ 9 , 133 , 52 , 70 , 100 , 186 , 221 , 42 , 162 , 210 , 65 , 103 , 250 , 71 , 142 , 192 , 58 , 111 , 199 , 110 ,
122+ 176 , 91 , 161 , 195 , 250 , 201 , 221 , 136 , 183 , 74 , 68 , 204 , 221 , 93 , 8 , 139 , 182 , 151 , 92 , 6 , 168 ,
123+ 223 , 75 , 16 , 6 , 248 , 229 , 53 , 10 , 219 , 248 , 43 , 58 , 117 , 134 , 19 , 245 , 109 , 69 , 25 , 218 , 98 ,
124+ 249 , 7 , 90 , 223 , 221 , 136 , 43 , 53 , 243 , 90 , 85 , 245 , 50 , 71 , 17 , 145 , 52 , 137 , 36 , 165 , 195 ,
125+ 133 , 133 , 41 , 248 , 60 , 251 , 3 , 44 , 200 , 150 , 47 , 121 , 34 , 9 , 231 , 248 , 39 , 163 , 121 , 37 , 113 ,
126+ 212 , 227 , 126 , 233 , 45 , 198 , 96 , 170 , 240 , 47 , 77 , 250 , 32 , 66 , 193 , 18 , 103 , 251 , 89 , 161 ,
127+ 202 , 162 , 45 , 89 , 203 , 163 , 70 , 170 , 27 , 1 , 80 , 237 , 9 , 87 , 173 , 20 , 38 , 94 , 11 , 146 , 14 , 217 ,
128+ 151 , 197 , 170 , 203 , 108 , 179 , 227 , 90 , 187 , 9 , 128 , 97 , 0 , 213 , 149 , 128 , 132 , 129 , 179 , 255 ,
129+ 247 , 26 , 178 , 177 , 112 , 81 , 142 , 4 , 53 , 235 , 114 , 223 , 242 , 209 , 244 , 23 , 177 , 150 , 185 , 252 ,
130+ 175 , 141 , 204 , 205 , 242 , 78 ,
131+ ] ;
132+
133+ impl SnarkVerifierSetup {
134+ /// Build the verifier setup from the embedded constant verifier params bytes.
135+ pub ( crate ) fn try_new ( ) -> StmResult < Self > {
136+ let verifier_params = ParamsVerifierKZG :: < Bls12 > :: read (
137+ & mut & SNARK_VERIFIER_PARAMS_BYTES [ ..] ,
138+ SerdeFormat :: RawBytesUnchecked ,
139+ )
140+ . with_context ( || "Failed to read embedded SNARK verifier params bytes" ) ?;
141+
142+ Ok ( Self { verifier_params } )
143+ }
144+ }
145+
146+ /// Compute the deterministic verifier params bytes for the unsafe SNARK setup seeded with
147+ /// `ChaCha20Rng::seed_from_u64(42)`.
148+ ///
149+ /// Kept available so the embedded `SNARK_VERIFIER_PARAMS_BYTES` constant can be regenerated by
150+ /// running the `golden_snark_verifier_params_bytes` test.
151+ #[ cfg( test) ]
152+ fn compute_snark_verifier_params_bytes ( ) -> StmResult < Vec < u8 > > {
153+ use ff:: Field ;
154+ use group:: Group ;
155+ use midnight_curves:: { Fq , G2Projective } ;
156+ use midnight_proofs:: utils:: helpers:: ProcessedSerdeObject ;
157+
158+ let mut rng = ChaCha20Rng :: seed_from_u64 ( 42 ) ;
159+ let s = Fq :: random ( & mut rng) ;
160+ let s_g2 = G2Projective :: generator ( ) * s;
161+
162+ let mut buf = Vec :: new ( ) ;
163+ s_g2. write ( & mut buf, SerdeFormat :: RawBytesUnchecked )
164+ . with_context ( || "Failed to serialize s_g2" ) ?;
165+
166+ Ok ( buf)
167+ }
168+
101169/// Load the KZG SRS from `path`, or generate one with an unsafe deterministic seed
102170/// if the file does not exist. When generated, the result is persisted to `path` so
103171/// subsequent calls can load it quickly.
@@ -183,7 +251,11 @@ mod test {
183251 proof_system:: halo2_snark:: SnarkSetup ,
184252 } ;
185253
186- use super :: { SnarkSetupCacheKey , get_or_build_snark_keys, load_or_generate_srs, persist_srs} ;
254+ use super :: {
255+ SNARK_VERIFIER_PARAMS_BYTES , SnarkSetupCacheKey , SnarkVerifierSetup ,
256+ compute_snark_verifier_params_bytes, get_or_build_snark_keys, load_or_generate_srs,
257+ persist_srs,
258+ } ;
187259
188260 fn small_srs ( ) -> ParamsKZG < Bls12 > {
189261 ParamsKZG :: unsafe_setup ( 3 , ChaCha20Rng :: seed_from_u64 ( 42 ) )
@@ -328,4 +400,19 @@ mod test {
328400 "same parameters must produce the same verification key"
329401 ) ;
330402 }
403+
404+ #[ test]
405+ fn golden_snark_verifier_params_bytes ( ) {
406+ let bytes = compute_snark_verifier_params_bytes ( ) . unwrap ( ) ;
407+ println ! ( "SNARK_VERIFIER_PARAMS_BYTES len = {}" , bytes. len( ) ) ;
408+ println ! ( "SNARK_VERIFIER_PARAMS_BYTES hex = {}" , hex:: encode( & bytes) ) ;
409+
410+ assert_eq ! (
411+ bytes. as_slice( ) ,
412+ & SNARK_VERIFIER_PARAMS_BYTES ,
413+ "computed verifier params bytes do not match the hard-coded constant"
414+ ) ;
415+
416+ let _ = SnarkVerifierSetup :: try_new ( ) . expect ( "verifier setup must build from constant" ) ;
417+ }
331418}
0 commit comments