sp1_verifier/compressed/
internal.rs1use alloc::vec::Vec;
4use core::borrow::Borrow;
5
6use slop_algebra::{AbstractField, PrimeField32};
7use slop_symmetric::CryptographicHasher;
8use sp1_hypercube::{
9 verify_merkle_proof, HashableKey, InnerSC, MachineVerifier, MachineVerifierError,
10 SP1RecursionProof, ShardVerifier, DIGEST_SIZE, PROOF_MAX_NUM_PVS,
11};
12use sp1_primitives::{fri_params::recursion_fri_config, poseidon2_hasher, SP1Field};
13use sp1_recursion_executor::{RecursionPublicValues, NUM_PV_ELMS_TO_HASH};
14
15use super::CompressedError;
16use crate::{
17 blake3_hash,
18 compressed::{RECURSION_LOG_STACKING_HEIGHT, RECURSION_MAX_LOG_ROW_COUNT},
19};
20
21type GC = sp1_primitives::SP1GlobalContext;
23type C = sp1_hypercube::SP1PcsProofInner;
25
26pub const COMPRESS_DEGREE: usize = 3;
28
29pub type CompressAir<SP1Field> = sp1_recursion_machine::RecursionAir<SP1Field, COMPRESS_DEGREE, 2>;
30
31pub struct SP1CompressedVerifier {
36 verifier: MachineVerifier<GC, InnerSC<CompressAir<SP1Field>>>,
37 vk_merkle_root: [SP1Field; DIGEST_SIZE],
38}
39
40impl Default for SP1CompressedVerifier {
41 fn default() -> Self {
42 let compress_log_stacking_height = RECURSION_LOG_STACKING_HEIGHT;
43 let compress_max_log_row_count = RECURSION_MAX_LOG_ROW_COUNT;
44
45 let machine = CompressAir::<SP1Field>::compress_machine();
46 let recursion_shard_verifier = ShardVerifier::from_basefold_parameters(
47 recursion_fri_config(),
48 compress_log_stacking_height,
49 compress_max_log_row_count,
50 machine.clone(),
51 );
52
53 let verifier = MachineVerifier::new(recursion_shard_verifier);
54 let vk_merkle_root = crate::VerifierRecursionVks::default().root();
55 Self { verifier, vk_merkle_root }
56 }
57}
58
59impl SP1CompressedVerifier {
60 pub fn new() -> Self {
61 Self::default()
62 }
63
64 pub fn recursion_public_values_digest(
66 &self,
67 public_values: &RecursionPublicValues<SP1Field>,
68 ) -> [SP1Field; 8] {
69 let hasher = poseidon2_hasher();
70 hasher.hash_slice(&public_values.as_array()[0..NUM_PV_ELMS_TO_HASH])
71 }
72
73 pub fn is_recursion_public_values_valid(
75 &self,
76 public_values: &RecursionPublicValues<SP1Field>,
77 ) -> bool {
78 let expected_digest = self.recursion_public_values_digest(public_values);
79 public_values.digest.iter().copied().eq(expected_digest)
80 }
81
82 pub fn verify_compressed(
84 &self,
85 proof: &SP1RecursionProof<GC, C>,
86 vkey_hash: &[SP1Field; 8],
87 ) -> Result<(), CompressedError> {
88 let SP1RecursionProof { vk: compress_vk, proof, vk_merkle_proof } = proof;
89
90 let mut challenger = self.verifier.challenger();
91 compress_vk.observe_into(&mut challenger);
92
93 self.verifier
95 .verify_shard(compress_vk, proof, &mut challenger)
96 .map_err(MachineVerifierError::InvalidShardProof)?;
97
98 if proof.public_values.len() != PROOF_MAX_NUM_PVS {
100 return Err(MachineVerifierError::InvalidPublicValues("invalid public values length"))?;
101 }
102
103 let public_values: &RecursionPublicValues<_> = proof.public_values.as_slice().borrow();
105
106 if !self.is_recursion_public_values_valid(public_values) {
108 return Err(MachineVerifierError::InvalidPublicValues(
109 "recursion public values are invalid",
110 )
111 .into());
112 }
113
114 verify_merkle_proof(vk_merkle_proof, compress_vk.hash_koalabear(), self.vk_merkle_root)
116 .map_err(CompressedError::InvalidVkey)?;
117
118 if public_values.vk_root != self.vk_merkle_root {
120 return Err(MachineVerifierError::InvalidPublicValues("vk merkle root mismatch"))?;
121 }
122
123 if public_values.is_complete != SP1Field::one() {
125 return Err(MachineVerifierError::InvalidPublicValues("is_complete is not 1").into());
126 }
127
128 if public_values.sp1_vk_digest != *vkey_hash {
130 return Err(MachineVerifierError::InvalidPublicValues("sp1 vk hash mismatch").into());
131 }
132
133 Ok(())
134 }
135
136 pub fn verify_compressed_with_public_values(
138 &self,
139 proof: &SP1RecursionProof<GC, C>,
140 sp1_public_inputs: &[u8],
141 vkey_hash: &[SP1Field; 8],
142 ) -> Result<(), CompressedError> {
143 self.verify_compressed(proof, vkey_hash)?;
145
146 let SP1RecursionProof { proof, .. } = proof;
150
151 let public_values: &RecursionPublicValues<_> = proof.public_values.as_slice().borrow();
153
154 let committed_value_digest_bytes = public_values
156 .committed_value_digest
157 .iter()
158 .flat_map(|w| w.iter().map(|x| x.as_canonical_u32() as u8))
159 .collect::<Vec<_>>();
160
161 let sha256_digest = crate::sha256_hash(sp1_public_inputs);
165 let blake3_digest = blake3_hash(sp1_public_inputs);
166 if committed_value_digest_bytes.as_slice() != sha256_digest.as_slice()
167 && committed_value_digest_bytes.as_slice() != blake3_digest.as_slice()
168 {
169 return Err(CompressedError::PublicValuesMismatch);
170 }
171 Ok(())
172 }
173}