openvm_continuations/circuit/subair/merkle_tree/
air.rs1use std::array::from_fn;
2
3use openvm_circuit_primitives::{StructReflection, StructReflectionHelper, SubAir};
4use openvm_recursion_circuit::bus::{Poseidon2CompressBus, Poseidon2CompressMessage};
5use openvm_recursion_circuit_derive::AlignedBorrow;
6use openvm_stark_backend::interaction::InteractionBuilder;
7use openvm_stark_sdk::config::baby_bear_poseidon2::DIGEST_SIZE;
8use p3_air::AirBuilder;
9use p3_field::{Field, PrimeCharacteristicRing};
10
11use crate::{
12 circuit::{
13 deferral::{DEF_INTERNAL_TAG, DEF_LEAF_TAG},
14 subair::merkle_tree::bus::{
15 MerkleRootBus, MerkleRootMessage, MerkleTreeInternalBus, MerkleTreeInternalMessage,
16 },
17 },
18 utils::digests_to_poseidon2_input,
19};
20
21#[repr(C)]
22#[derive(AlignedBorrow, StructReflection, Copy, Clone, Debug)]
23pub struct MerkleTreeCols<T> {
24 pub row_idx: T,
25
26 pub send_type: T,
28 pub receive_type: T,
30
31 pub parent: [T; DIGEST_SIZE],
32 pub is_right_child: T,
33
34 pub left_child: [T; DIGEST_SIZE],
35 pub right_child: [T; DIGEST_SIZE],
36}
37
38#[derive(Clone, Debug, derive_new::new)]
40pub struct MerkleTreeSubAir {
41 pub poseidon2_bus: Poseidon2CompressBus,
42 pub merkle_root_bus: MerkleRootBus,
43 pub merkle_tree_internal_bus: MerkleTreeInternalBus,
44
45 pub idx: usize,
47 pub send_num_rows: bool,
50}
51
52impl<AB: AirBuilder + InteractionBuilder> SubAir<AB> for MerkleTreeSubAir {
53 type AirContext<'a>
54 = (
55 &'a MerkleTreeCols<AB::Var>,
56 &'a MerkleTreeCols<AB::Var>,
57 AB::Expr,
58 Option<&'a [AB::Var; DIGEST_SIZE]>,
59 )
60 where
61 AB: 'a,
62 AB::Var: 'a,
63 AB::Expr: 'a;
64
65 fn eval<'a>(&'a self, builder: &'a mut AB, ctx: Self::AirContext<'a>)
66 where
67 AB::Var: 'a,
68 AB::Expr: 'a,
69 {
70 let (local, next, num_rows, tagged_left_child) = ctx;
71
72 builder.when_first_row().assert_zero(local.row_idx);
77 builder
78 .when_transition()
79 .assert_eq(local.row_idx + AB::F::ONE, next.row_idx);
80 builder
81 .when_last_row()
82 .assert_eq(local.row_idx, num_rows.clone() - AB::F::ONE);
83
84 builder.when_first_row().assert_zero(local.is_right_child);
90 builder.assert_eq(local.is_right_child, AB::Expr::ONE - next.is_right_child);
91
92 builder.assert_tern(local.send_type);
99
100 builder
101 .when_first_row()
102 .assert_bool(local.send_type - AB::F::ONE);
103 builder
104 .when_transition()
105 .assert_bool(local.send_type - AB::F::ONE);
106 builder.when_last_row().assert_zero(local.send_type);
107 builder
108 .when_ne(local.send_type, AB::F::TWO)
109 .assert_bool(next.send_type - AB::F::ONE);
110 builder
111 .when_ne(local.send_type, AB::F::ZERO)
112 .when_ne(local.send_type, AB::F::ONE)
113 .assert_zero(next.send_type);
114
115 builder.assert_tern(local.receive_type);
123
124 builder.when_first_row().assert_one(local.receive_type);
125 builder
126 .when_transition()
127 .assert_bool(local.receive_type - AB::F::ONE);
128 builder.when_last_row().assert_zero(local.receive_type);
129
130 builder
131 .when_ne(local.receive_type, AB::F::ZERO)
132 .when_ne(local.receive_type, AB::F::ONE)
133 .assert_zero(next.receive_type * (next.receive_type - AB::F::TWO));
134
135 let half = AB::F::TWO.inverse();
142 let internal_send = local.send_type * (AB::Expr::TWO - local.send_type);
143 let internal_receive = local.receive_type * (local.receive_type - AB::F::ONE) * half;
144
145 self.merkle_tree_internal_bus.send(
146 builder,
147 MerkleTreeInternalMessage {
148 child_value: local.parent.map(Into::into),
149 is_right_child: local.is_right_child.into(),
150 parent_idx: (local.row_idx - local.is_right_child + num_rows.clone()) * half,
151 },
152 internal_send,
153 );
154
155 self.merkle_tree_internal_bus.receive(
156 builder,
157 MerkleTreeInternalMessage {
158 child_value: local.left_child.map(Into::into),
159 is_right_child: AB::Expr::ZERO,
160 parent_idx: local.row_idx.into(),
161 },
162 internal_receive.clone(),
163 );
164
165 self.merkle_tree_internal_bus.receive(
166 builder,
167 MerkleTreeInternalMessage {
168 child_value: local.right_child.map(Into::into),
169 is_right_child: AB::Expr::ONE,
170 parent_idx: local.row_idx.into(),
171 },
172 internal_receive,
173 );
174
175 let is_valid = local.send_type * (AB::Expr::from_u8(3) - local.send_type) * half;
183 let is_root = local.send_type * (local.send_type - AB::F::ONE) * half;
184
185 if let Some(tagged_left_child) = tagged_left_child {
186 let is_leaf = local.receive_type * (AB::Expr::TWO - local.receive_type);
187 let is_internal = local.receive_type * (local.receive_type - AB::F::ONE) * half;
188 let tag = from_fn(|i| {
189 is_leaf.clone() * AB::Expr::from_u8(DEF_LEAF_TAG[i])
190 + is_internal.clone() * AB::Expr::from_u8(DEF_INTERNAL_TAG[i])
191 });
192
193 self.poseidon2_bus.lookup_key(
194 builder,
195 Poseidon2CompressMessage {
196 input: digests_to_poseidon2_input(tag, local.left_child.map(Into::into)),
197 output: tagged_left_child.map(Into::into),
198 },
199 is_valid.clone(),
200 );
201 self.poseidon2_bus.lookup_key(
202 builder,
203 Poseidon2CompressMessage {
204 input: digests_to_poseidon2_input(
205 tagged_left_child.map(Into::into),
206 local.right_child.map(Into::into),
207 ),
208 output: local.parent.map(Into::into),
209 },
210 is_valid,
211 );
212 } else {
213 self.poseidon2_bus.lookup_key(
214 builder,
215 Poseidon2CompressMessage {
216 input: digests_to_poseidon2_input(local.left_child, local.right_child),
217 output: local.parent,
218 },
219 is_valid,
220 );
221 }
222
223 self.merkle_root_bus.send(
224 builder,
225 MerkleRootMessage {
226 merkle_root: local.parent.map(Into::into),
227 idx: AB::Expr::from_usize(self.idx),
228 num_rows_or_zero: if self.send_num_rows {
229 num_rows
230 } else {
231 AB::Expr::ZERO
232 },
233 },
234 is_root,
235 );
236 }
237}