1use std::{marker::PhantomData, mem::size_of};
6
7use binius_core::word::Word;
8use binius_field::BinaryField;
9use binius_ip::channel::{
10 IPVerifierChannel, WordIPVerifierChannel, pack_words_concrete, select_word, subset_sum_word,
11};
12use binius_utils::serialization::FixedSizeSerializeBytes;
13
14use crate::{
15 channel::grinding::GrindingVerifierChannel,
16 merkle_channel::{Error, MerkleIPVerifierChannel},
17 merkle_tree::MerkleTreeScheme,
18};
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub struct CommittedShape {
25 leaf_size: usize,
27 depth: usize,
29}
30
31pub struct SizeTrackingChannel<'a, F, MerkleScheme_> {
43 scheme: &'a MerkleScheme_,
44 proof_size: usize,
45 _field_marker: PhantomData<F>,
46}
47
48impl<'a, F, MerkleScheme_> SizeTrackingChannel<'a, F, MerkleScheme_> {
49 pub const fn new(scheme: &'a MerkleScheme_) -> Self {
51 Self {
52 scheme,
53 proof_size: 0,
54 _field_marker: PhantomData,
55 }
56 }
57
58 pub const fn proof_size(&self) -> usize {
60 self.proof_size
61 }
62}
63
64impl<F, MerkleScheme_> IPVerifierChannel<F> for SizeTrackingChannel<'_, F, MerkleScheme_>
65where
66 F: BinaryField + FixedSizeSerializeBytes,
67 MerkleScheme_: MerkleTreeScheme<F>,
68{
69 type Elem = F;
73
74 fn recv_one(&mut self) -> Result<F, binius_ip::channel::Error> {
75 self.proof_size += F::BYTE_SIZE;
76 Ok(F::ZERO)
77 }
78
79 fn recv_many(&mut self, n: usize) -> Result<Vec<F>, binius_ip::channel::Error> {
80 self.proof_size += n * F::BYTE_SIZE;
81 Ok(vec![F::ZERO; n])
82 }
83
84 fn recv_array<const N: usize>(&mut self) -> Result<[F; N], binius_ip::channel::Error> {
85 self.proof_size += N * F::BYTE_SIZE;
86 Ok([F::ZERO; N])
87 }
88
89 fn sample(&mut self) -> F {
90 F::ZERO
91 }
92
93 fn observe_one(&mut self, _val: F) -> F {
94 F::ZERO
95 }
96
97 fn observe_many(&mut self, vals: &[F]) -> Vec<F> {
98 vec![F::ZERO; vals.len()]
99 }
100
101 fn assert_zero(&mut self, _val: F) -> Result<(), binius_ip::channel::Error> {
102 Ok(())
103 }
104}
105
106impl<F, MerkleScheme_> WordIPVerifierChannel<F> for SizeTrackingChannel<'_, F, MerkleScheme_>
107where
108 F: BinaryField + FixedSizeSerializeBytes,
109 MerkleScheme_: MerkleTreeScheme<F>,
110{
111 type Word = Word;
112
113 fn observe_words(&mut self, words: &[Word]) -> Vec<Word> {
115 words.to_vec()
116 }
117
118 fn subset_sum(&mut self, elems: &[F], word: &Word) -> F {
119 subset_sum_word(elems, *word)
120 }
121
122 fn select(&mut self, elems: &[F], word: &Word) -> F {
123 select_word(elems, *word)
124 }
125
126 fn sample_bits(&mut self, _bits: usize) -> Word {
128 Word::ZERO
129 }
130
131 fn pack_words(&mut self, words: &[Word]) -> Vec<F> {
132 pack_words_concrete::<F, F>(words)
133 }
134}
135
136impl<F, MerkleScheme_> GrindingVerifierChannel for SizeTrackingChannel<'_, F, MerkleScheme_> {
137 fn verify_grind(&mut self, bits: usize) -> Result<(), binius_transcript::Error> {
138 if bits == 0 {
140 return Ok(());
141 }
142 self.proof_size += size_of::<u64>();
144 Ok(())
145 }
146}
147
148impl<F, MerkleScheme_> MerkleIPVerifierChannel<F> for SizeTrackingChannel<'_, F, MerkleScheme_>
149where
150 F: BinaryField + FixedSizeSerializeBytes,
151 MerkleScheme_: MerkleTreeScheme<F>,
152{
153 type Commitment = CommittedShape;
154
155 fn recv_merkle_commitment(
156 &mut self,
157 leaf_size: usize,
158 depth: usize,
159 ) -> Result<Self::Commitment, Error> {
160 self.proof_size += size_of::<MerkleScheme_::Digest>();
162 Ok(CommittedShape { leaf_size, depth })
163 }
164
165 fn recv_openings(
166 &mut self,
167 commitment: &Self::Commitment,
168 indices: &[Word],
169 ) -> Result<Vec<F>, Error> {
170 let layer_depth = self
173 .scheme
174 .optimal_verify_layer(indices.len(), commitment.depth);
175 self.proof_size +=
176 self.scheme
177 .proof_size(1 << commitment.depth, indices.len(), layer_depth);
178
179 let n_values = indices.len() * commitment.leaf_size;
181 self.proof_size += n_values * F::BYTE_SIZE;
182 Ok(vec![F::ZERO; n_values])
183 }
184
185 fn recv_committed_vector(&mut self, commitment: &Self::Commitment) -> Result<Vec<F>, Error> {
186 let len = commitment.leaf_size << commitment.depth;
188 self.proof_size += len * F::BYTE_SIZE;
189 Ok(vec![F::ZERO; len])
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use binius_field::Ghash128b as B128;
196 use binius_hash::StdHashSuite;
197
198 use super::*;
199 use crate::merkle_tree::BinaryMerkleTreeScheme;
200
201 #[test]
202 fn a_grind_is_charged_one_nonce_and_a_zero_bit_one_is_charged_nothing() {
203 let scheme = BinaryMerkleTreeScheme::<B128, StdHashSuite>::new();
209 let mut channel = SizeTrackingChannel::<B128, _>::new(&scheme);
210 assert_eq!(channel.proof_size(), 0);
211
212 channel
213 .verify_grind(0)
214 .expect("a zero-bit grind cannot fail");
215 assert_eq!(channel.proof_size(), 0);
216
217 for bits in [1, 8, 32] {
218 channel.verify_grind(bits).expect("nothing here can fail");
219 }
220 assert_eq!(channel.proof_size(), 3 * size_of::<u64>());
221 }
222}