Skip to content

Commit d0a6aa8

Browse files
committed
feat(stm): implement 'SnarkVerifierSetup' in unsafe helpers
1 parent 933f562 commit d0a6aa8

3 files changed

Lines changed: 96 additions & 9 deletions

File tree

mithril-stm/src/proof_system/halo2_snark/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub use proof::SnarkProof;
1919
pub(crate) use proof::SnarkProver;
2020
pub(crate) use signer::SnarkProofSigner;
2121
pub(crate) use single_signature::SingleSignatureForSnark;
22-
pub(crate) use unsafe_helpers::SnarkSetup;
22+
pub(crate) use unsafe_helpers::{SnarkSetup, SnarkVerifierSetup};
2323

2424
/// Fixed merkle tree depth used of the merkle tree
2525
/// of signers for the SNARK proof. It is used to compute

mithril-stm/src/proof_system/halo2_snark/proof.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::{
2222
},
2323
};
2424

25-
use super::{SnarkClerk, SnarkSetup};
25+
use super::{SnarkClerk, SnarkSetup, SnarkVerifierSetup};
2626

2727
/// `SnarkProof` contains a proof generated by the certificate circuit represented as a vector of
2828
/// bytes. It can be verified using verifier parameters derived from the srs, the circuit verification key
@@ -65,9 +65,9 @@ impl<D: MembershipDigest> SnarkProof<D> {
6565
/// Verify a SNARK proof given a message, an aggregate verification key for snark
6666
/// and a circuit verification key
6767
///
68-
/// For now, we generate a temporary SnarkSetup inside the function to get access
69-
/// to the srs and generate the verifier parameters. This part will be removed once
70-
/// the circuit is stable and the srs is stored and available.
68+
/// The KZG verifier params are loaded from a hard-coded constant derived from the
69+
/// deterministic unsafe SNARK setup (seed 42), so verification does not need to load
70+
/// or regenerate the full SRS.
7171
///
7272
/// This proof verifies that there exists a witness such that:
7373
/// * each signatures in the witness is valid for the given message
@@ -81,14 +81,14 @@ impl<D: MembershipDigest> SnarkProof<D> {
8181
message: &[u8],
8282
aggregate_verification_key_for_snark: &AggregateVerificationKeyForSnark<D>,
8383
) -> StmResult<()> {
84-
let snark_setup = SnarkSetup::try_new(&self.params, MERKLE_TREE_DEPTH_FOR_SNARK)?;
84+
let verifier_setup = SnarkVerifierSetup::try_new()?;
8585

8686
let merkle_root = &aggregate_verification_key_for_snark.get_merkle_tree_commitment().root;
8787
let proof_message = build_snark_message(merkle_root, message)?;
8888
let proof_instance = (proof_message[0].into(), proof_message[1].into());
8989

9090
let verify_result = zk::verify::<StmCertificateCircuit, PoseidonState<CircuitBase>>(
91-
&snark_setup.srs.verifier_params(),
91+
&verifier_setup.verifier_params,
9292
&self.circuit_verification_key.get_midnight_vk(),
9393
&proof_instance,
9494
None,

mithril-stm/src/proof_system/halo2_snark/unsafe_helpers.rs

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ use std::{
1313

1414
use anyhow::{Context, anyhow};
1515
use 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+
};
1720
use midnight_zk_stdlib::{self as zk, MidnightCircuit, MidnightPK, MidnightVK};
1821
use rand_chacha::ChaCha20Rng;
1922
use 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

Comments
 (0)