1use alloc::vec::Vec;
42
43use p3_challenger::CanObserve;
44use p3_challenger::fs::{TranscriptError, TranscriptField, TypeTag};
45
46use crate::{
47 BinaryField8, BinaryField16, BinaryField32, BinaryField64, BinaryField128, Poly64, TowerLevel,
48};
49
50macro_rules! impl_transcript_field {
58 ($name:ty, $repr:ty, $bits:literal, |$degree:ident, $basis:ident| $tag:expr) => {
59 impl TranscriptField for $name {
60 fn algebra_tag($degree: usize, $basis: [u8; 32]) -> TypeTag {
61 $tag
62 }
63
64 fn observe_seed<C: CanObserve<Self>>(challenger: &mut C, bytes: &[u8]) {
65 const WIDTH: usize = $bits / 8;
67
68 let element = |chunk: &[u8]| {
73 let mut padded = [0u8; WIDTH];
74 padded[..chunk.len()].copy_from_slice(chunk);
75 <$name>::from_repr(<$repr>::from_le_bytes(padded))
76 };
77
78 for chunk in (bytes.len() as u64).to_le_bytes().chunks(WIDTH) {
83 challenger.observe(element(chunk));
84 }
85
86 for chunk in bytes.chunks(WIDTH) {
88 challenger.observe(element(chunk));
89 }
90 }
91
92 fn wire_len() -> usize {
93 $bits / 8
94 }
95
96 fn encode(value: &Self, out: &mut Vec<u8>) {
97 out.extend_from_slice(&value.to_repr().to_be_bytes());
98 }
99
100 fn decode(bytes: &[u8]) -> Result<Self, TranscriptError> {
101 let prefix = bytes
102 .get(..$bits / 8)
103 .ok_or(TranscriptError::BadProofShape {
104 reason: "not enough bytes for a canonical binary field encoding",
105 })?;
106 Ok(Self::from_repr(<$repr>::from_be_bytes(
108 prefix.try_into().unwrap(),
109 )))
110 }
111 }
112 };
113}
114
115impl_transcript_field!(BinaryField8, u8, 8, |degree, basis| TypeTag::BinaryTower {
116 bits: 8,
117 degree,
118 basis,
119});
120impl_transcript_field!(BinaryField16, u16, 16, |degree, basis| {
121 TypeTag::BinaryTower {
122 bits: 16,
123 degree,
124 basis,
125 }
126});
127impl_transcript_field!(BinaryField32, u32, 32, |degree, basis| {
128 TypeTag::BinaryTower {
129 bits: 32,
130 degree,
131 basis,
132 }
133});
134impl_transcript_field!(BinaryField64, u64, 64, |degree, basis| {
135 TypeTag::BinaryTower {
136 bits: 64,
137 degree,
138 basis,
139 }
140});
141impl_transcript_field!(BinaryField128, u128, 128, |degree, basis| {
142 TypeTag::BinaryTower {
143 bits: 128,
144 degree,
145 basis,
146 }
147});
148impl_transcript_field!(Poly64, u64, 64, |degree, basis| TypeTag::BinaryPolynomial {
149 bits: 64,
150 modulus: 0x1b,
151 degree,
152 basis,
153});
154
155#[cfg(test)]
156mod tests {
157 use alloc::vec;
158 use alloc::vec::Vec;
159
160 use p3_challenger::testing::Recorder;
161
162 use super::*;
163
164 const SEED_LEN_BYTES: usize = 8;
166
167 fn packed<F: TranscriptField>(bytes: &[u8]) -> Vec<F> {
169 let mut recorder = Recorder::default();
170 F::observe_seed(&mut recorder, bytes);
171 recorder.into_absorbed()
172 }
173
174 #[test]
175 fn a_seed_carries_its_length_ahead_of_its_bytes() {
176 let seen = packed::<BinaryField8>(&[1, 2, 3]);
181
182 assert_eq!(seen.len(), SEED_LEN_BYTES + 3);
183 assert_eq!(seen[0], BinaryField8::from_repr(3));
184 assert_eq!(&seen[SEED_LEN_BYTES..], &packed_bytes(&[1, 2, 3])[..]);
185 }
186
187 fn packed_bytes(bytes: &[u8]) -> Vec<BinaryField8> {
189 bytes.iter().map(|&b| BinaryField8::from_repr(b)).collect()
190 }
191
192 #[test]
193 fn a_shorter_string_is_never_a_prefix_of_a_longer_one() {
194 assert_ne!(
199 packed::<BinaryField8>(&[1]),
200 packed::<BinaryField8>(&[1, 0])
201 );
202 assert_ne!(
203 packed::<BinaryField16>(&[1]),
204 packed::<BinaryField16>(&[1, 0])
205 );
206 assert_ne!(
207 packed::<BinaryField32>(&[1]),
208 packed::<BinaryField32>(&[1, 0])
209 );
210 assert_ne!(
211 packed::<BinaryField64>(&[1]),
212 packed::<BinaryField64>(&[1, 0])
213 );
214 assert_ne!(
215 packed::<BinaryField128>(&[1]),
216 packed::<BinaryField128>(&[1, 0])
217 );
218 }
219
220 #[test]
221 fn the_widest_level_packs_a_seed_by_the_same_rule_as_the_narrow_ones() {
222 let bytes: Vec<u8> = (0..20).collect();
230 let seen = packed::<BinaryField128>(&bytes);
231
232 assert_eq!(seen.len(), 3);
233 assert_eq!(seen[0], BinaryField128::from_repr(20));
234
235 let mut first = [0u8; 16];
237 first.copy_from_slice(&bytes[..16]);
238 assert_eq!(
239 seen[1],
240 BinaryField128::from_repr(u128::from_le_bytes(first))
241 );
242
243 let mut last = [0u8; 16];
244 last[..4].copy_from_slice(&bytes[16..]);
245 assert_eq!(
246 seen[2],
247 BinaryField128::from_repr(u128::from_le_bytes(last))
248 );
249 }
250
251 #[test]
252 fn a_wire_encoding_round_trips_at_every_level() {
253 let mut out = Vec::new();
255 BinaryField8::encode(&BinaryField8::from_repr(0xA5), &mut out);
256 assert_eq!(out, vec![0xA5]);
257 assert_eq!(
258 BinaryField8::decode(&out).unwrap(),
259 BinaryField8::from_repr(0xA5)
260 );
261
262 let mut out = Vec::new();
263 BinaryField16::encode(&BinaryField16::from_repr(0xA5C3), &mut out);
264 assert_eq!(out, vec![0xA5, 0xC3]);
265 assert_eq!(
266 BinaryField16::decode(&out).unwrap(),
267 BinaryField16::from_repr(0xA5C3)
268 );
269
270 let mut out = Vec::new();
271 BinaryField32::encode(&BinaryField32::from_repr(0x0123_4567), &mut out);
272 assert_eq!(
273 BinaryField32::decode(&out).unwrap(),
274 BinaryField32::from_repr(0x0123_4567)
275 );
276
277 let mut out = Vec::new();
278 BinaryField64::encode(&BinaryField64::from_repr(0x0123_4567_89AB_CDEF), &mut out);
279 assert_eq!(
280 BinaryField64::decode(&out).unwrap(),
281 BinaryField64::from_repr(0x0123_4567_89AB_CDEF)
282 );
283
284 let mut out = Vec::new();
285 Poly64::encode(&Poly64::new(0xFEDC_BA98_7654_3210), &mut out);
286 assert_eq!(
287 Poly64::decode(&out).unwrap(),
288 Poly64::new(0xFEDC_BA98_7654_3210)
289 );
290 }
291
292 #[test]
293 fn a_short_wire_encoding_is_rejected() {
294 assert!(BinaryField64::decode(&[0; 7]).is_err());
296 assert!(BinaryField32::decode(&[0; 3]).is_err());
297 assert!(BinaryField16::decode(&[0; 1]).is_err());
298 assert!(BinaryField8::decode(&[]).is_err());
299 assert!(Poly64::decode(&[0; 7]).is_err());
300 }
301
302 #[test]
303 fn each_level_names_its_own_width() {
304 assert_eq!(
306 BinaryField8::algebra_tag(1, [0; 32]),
307 TypeTag::BinaryTower {
308 bits: 8,
309 degree: 1,
310 basis: [0; 32]
311 }
312 );
313 assert_ne!(
314 BinaryField8::algebra_tag(1, [0; 32]),
315 BinaryField16::algebra_tag(1, [0; 32])
316 );
317 assert_ne!(
318 BinaryField32::algebra_tag(1, [0; 32]),
319 BinaryField64::algebra_tag(1, [0; 32])
320 );
321 assert_ne!(
322 BinaryField64::algebra_tag(1, [0; 32]),
323 BinaryField128::algebra_tag(1, [0; 32])
324 );
325 assert_ne!(
326 BinaryField64::algebra_tag(1, [0; 32]),
327 Poly64::algebra_tag(1, [0; 32])
328 );
329 }
330}