openvm_verify_stark_host/
deferral.rs1use openvm_circuit::{
2 arch::instructions::DEFERRAL_AS, system::memory::dimensions::MemoryDimensions,
3};
4use openvm_stark_backend::codec::{DecodableConfig, EncodableConfig};
5use openvm_stark_sdk::config::baby_bear_poseidon2::{
6 poseidon2_compress_with_capacity, BabyBearPoseidon2Config as SC, DIGEST_SIZE, F,
7};
8use p3_field::PrimeCharacteristicRing;
9
10use crate::error::VerifyStarkError;
11
12#[derive(Clone, Debug)]
18pub struct DeferralMerkleProofs<F> {
19 pub initial_merkle_proof: Vec<[F; DIGEST_SIZE]>,
20 pub final_merkle_proof: Vec<[F; DIGEST_SIZE]>,
21}
22
23impl DeferralMerkleProofs<F> {
24 pub fn encode<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
25 SC::encode_digest_slice(&self.initial_merkle_proof, writer)?;
26 SC::encode_digest_slice(&self.final_merkle_proof, writer)?;
27 Ok(())
28 }
29
30 pub fn decode<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
31 let initial_merkle_proof = SC::decode_digest_vec(reader)?;
32 let final_merkle_proof = SC::decode_digest_vec(reader)?;
33 Ok(Self {
34 initial_merkle_proof,
35 final_merkle_proof,
36 })
37 }
38
39 pub fn verify(
46 &self,
47 memory_dimensions: MemoryDimensions,
48 initial_root: [F; DIGEST_SIZE],
49 final_root: [F; DIGEST_SIZE],
50 initial_acc_hash: [F; DIGEST_SIZE],
51 final_acc_hash: [F; DIGEST_SIZE],
52 depth: usize,
53 ) -> Result<(), VerifyStarkError> {
54 let overall_height = memory_dimensions.overall_height();
55 if self.initial_merkle_proof.len() != overall_height {
56 return Err(VerifyStarkError::DeferralMerkleProofLengthMismatch {
57 expected: overall_height,
58 actual: self.initial_merkle_proof.len(),
59 });
60 }
61 if self.final_merkle_proof.len() != overall_height {
62 return Err(VerifyStarkError::DeferralMerkleProofLengthMismatch {
63 expected: overall_height,
64 actual: self.final_merkle_proof.len(),
65 });
66 }
67
68 if depth > memory_dimensions.address_height {
69 return Err(VerifyStarkError::DeferralDepthTooLarge {
70 depth,
71 address_height: memory_dimensions.address_height,
72 });
73 }
74
75 for i in 0..memory_dimensions.address_height {
76 if self.initial_merkle_proof[i] != self.final_merkle_proof[i] {
77 return Err(VerifyStarkError::DeferralMerkleProofSiblingMismatch {
78 depth: i,
79 initial: self.initial_merkle_proof[i],
80 final_: self.final_merkle_proof[i],
81 });
82 }
83 }
84
85 let is_unset = depth == 0;
86 let idx_prefix =
87 usize::try_from(memory_dimensions.label_to_index((DEFERRAL_AS, 0))).unwrap();
88
89 let initial_leaf = if is_unset {
91 poseidon2_compress_with_capacity(initial_acc_hash, [F::ZERO; DIGEST_SIZE]).0
92 } else {
93 initial_acc_hash
94 };
95 let final_leaf = if is_unset {
96 poseidon2_compress_with_capacity(final_acc_hash, [F::ZERO; DIGEST_SIZE]).0
97 } else {
98 final_acc_hash
99 };
100
101 let computed_initial_root =
102 merkle_path_root(initial_leaf, &self.initial_merkle_proof, idx_prefix, depth);
103 if computed_initial_root != initial_root {
104 return Err(VerifyStarkError::DeferralInitialRootMismatch {
105 expected: initial_root,
106 actual: computed_initial_root,
107 });
108 }
109
110 let computed_final_root =
111 merkle_path_root(final_leaf, &self.final_merkle_proof, idx_prefix, depth);
112 if computed_final_root != final_root {
113 return Err(VerifyStarkError::DeferralFinalRootMismatch {
114 expected: final_root,
115 actual: computed_final_root,
116 });
117 }
118
119 Ok(())
120 }
121}
122
123fn merkle_path_root(
127 leaf: [F; DIGEST_SIZE],
128 proof: &[[F; DIGEST_SIZE]],
129 idx_prefix: usize,
130 depth: usize,
131) -> [F; DIGEST_SIZE] {
132 let mut node = leaf;
133 for (i, sibling) in proof.iter().enumerate() {
134 if i < depth {
135 continue;
136 }
137 let is_right = (depth == 0 && i == 0) || (idx_prefix >> i) & 1 == 1;
138 node = if is_right {
139 poseidon2_compress_with_capacity(*sibling, node).0
140 } else {
141 poseidon2_compress_with_capacity(node, *sibling).0
142 };
143 }
144 node
145}