1use crypto_bigint::{BitOps, BoxedUint, Word};
6use crypto_primitives::{
7 ConstIntSemiring, PrimeField, WORD_FACTOR, boolean::Boolean, crypto_bigint_int::Int,
8 crypto_bigint_uint::Uint,
9};
10use itertools::Itertools;
11use zinc_primality::PrimalityTest;
12use zinc_utils::{add, from_ref::FromRef, mul};
13
14pub trait GenTranscribable: Sized {
17 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self;
21
22 fn write_transcription_bytes_exact(&self, buf: &mut [u8]);
25}
26
27pub trait Transcribable: GenTranscribable {
30 const LENGTH_NUM_BYTES: usize = u32::NUM_BYTES;
35
36 fn read_num_bytes(bytes: &[u8]) -> usize {
41 usize::try_from(u32::read_transcription_bytes_exact(bytes))
42 .expect("num_bytes must fit into usize")
43 }
44
45 fn get_num_bytes(&self) -> usize;
49
50 fn read_transcription_bytes_subset(bytes: &[u8]) -> (Self, &[u8]) {
53 let (bytes_num_bytes, bytes_rem) = bytes.split_at(Self::LENGTH_NUM_BYTES);
54 let num_bytes = Self::read_num_bytes(bytes_num_bytes);
55 assert!(
57 bytes_rem.len() >= num_bytes,
58 "Byte slice length is not sufficient for reading Transcribable"
59 );
60 let (bytes_data, bytes_rem) = bytes_rem.split_at(num_bytes);
61 (Self::read_transcription_bytes_exact(bytes_data), bytes_rem)
62 }
63
64 fn write_transcription_bytes_subset<'a>(&self, mut buf: &'a mut [u8]) -> &'a mut [u8] {
67 let num_bytes = self.get_num_bytes();
68 if Self::LENGTH_NUM_BYTES > 0 {
69 buf[0..Self::LENGTH_NUM_BYTES]
70 .copy_from_slice(&num_bytes.to_le_bytes()[..Self::LENGTH_NUM_BYTES]);
71 buf = &mut buf[Self::LENGTH_NUM_BYTES..];
72 };
73 let (buf, rest) = buf.split_at_mut(num_bytes);
74 self.write_transcription_bytes_exact(buf);
75 rest
76 }
77}
78
79pub trait ConstTranscribable: GenTranscribable {
82 const NUM_BYTES: usize;
84 const NUM_BITS: usize = Self::NUM_BYTES * 8;
86}
87
88impl<T: ConstTranscribable> Transcribable for T {
89 const LENGTH_NUM_BYTES: usize = 0;
90
91 fn read_num_bytes(bytes: &[u8]) -> usize {
92 assert_eq!(bytes.len(), 0);
93 Self::NUM_BYTES
94 }
95
96 fn get_num_bytes(&self) -> usize {
97 Self::NUM_BYTES
98 }
99
100 fn read_transcription_bytes_subset(bytes: &[u8]) -> (Self, &[u8]) {
101 assert!(
102 bytes.len() >= Self::NUM_BYTES,
103 "Byte slice length is not sufficient for reading Transcribable"
104 );
105 let (bytes_data, bytes_rem) = bytes.split_at(Self::NUM_BYTES);
106 (Self::read_transcription_bytes_exact(bytes_data), bytes_rem)
107 }
108}
109
110#[macro_export]
113macro_rules! delegate_gen_transcribable {
114 ($wrapper:ident { $field:tt : $inner_ty:ty }) => {
115 impl $crate::traits::GenTranscribable for $wrapper {
116 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
117 Self {
118 $field: <$inner_ty as $crate::traits::GenTranscribable>::read_transcription_bytes_exact(bytes),
119 }
120 }
121
122 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
123 $crate::traits::GenTranscribable::write_transcription_bytes_exact(&self.$field, buf)
124 }
125 }
126 };
127 ($wrapper:ident <$($gen:tt),+> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
128 impl<$($gen),+> $crate::traits::GenTranscribable for $wrapper<$($gen),+>
129 $(where $($bounds)+)?
130 {
131 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
132 Self {
133 $field: <$inner_ty as $crate::traits::GenTranscribable>::read_transcription_bytes_exact(bytes),
134 }
135 }
136
137 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
138 $crate::traits::GenTranscribable::write_transcription_bytes_exact(&self.$field, buf)
139 }
140 }
141 };
142 ($wrapper:ident <const $cg_name:ident : $cg_ty:ty> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
143 impl<const $cg_name: $cg_ty> $crate::traits::GenTranscribable for $wrapper<$cg_name>
144 $(where $($bounds)+)?
145 {
146 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
147 Self {
148 $field: <$inner_ty as $crate::traits::GenTranscribable>::read_transcription_bytes_exact(bytes),
149 }
150 }
151
152 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
153 $crate::traits::GenTranscribable::write_transcription_bytes_exact(&self.$field, buf)
154 }
155 }
156 };
157 ($wrapper:ident <$($gen:tt),+, const $cg_name:ident : $cg_ty:ty> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
158 impl<$($gen),+, const $cg_name: $cg_ty> $crate::traits::GenTranscribable for $wrapper<$($gen),+, $cg_name>
159 $(where $($bounds)+)?
160 {
161 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
162 Self {
163 $field: <$inner_ty as $crate::traits::GenTranscribable>::read_transcription_bytes_exact(bytes),
164 }
165 }
166
167 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
168 $crate::traits::GenTranscribable::write_transcription_bytes_exact(&self.$field, buf)
169 }
170 }
171 };
172}
173
174#[macro_export]
187macro_rules! delegate_transcribable {
188 ($wrapper:ident ($inner_ty:ty)) => {
189 $crate::delegate_transcribable!($wrapper { 0: $inner_ty });
190 };
191 ($wrapper:ident { $field:tt : $inner_ty:ty }) => {
192 $crate::delegate_gen_transcribable!($wrapper { $field: $inner_ty });
193 impl $crate::traits::Transcribable for $wrapper {
194 const LENGTH_NUM_BYTES: usize =
195 <$inner_ty as $crate::traits::Transcribable>::LENGTH_NUM_BYTES;
196
197 fn read_num_bytes(bytes: &[u8]) -> usize {
198 <$inner_ty as $crate::traits::Transcribable>::read_num_bytes(bytes)
199 }
200
201 fn get_num_bytes(&self) -> usize {
202 <$inner_ty as $crate::traits::Transcribable>::get_num_bytes(&self.$field)
203 }
204 }
205 };
206 ($wrapper:ident <$($gen:tt),+> ($inner_ty:ty) $(where $($bounds:tt)+)?) => {
207 $crate::delegate_transcribable!($wrapper <$($gen),+> { 0: $inner_ty } $(where $($bounds)+)?);
208 };
209 ($wrapper:ident <$($gen:tt),+> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
210 $crate::delegate_gen_transcribable!($wrapper <$($gen),+> { $field: $inner_ty } $(where $($bounds)+)?);
211 impl<$($gen),+> $crate::traits::Transcribable for $wrapper<$($gen),+>
212 $(where $($bounds)+)?
213 {
214 const LENGTH_NUM_BYTES: usize =
215 <$inner_ty as $crate::traits::Transcribable>::LENGTH_NUM_BYTES;
216
217 fn read_num_bytes(bytes: &[u8]) -> usize {
218 <$inner_ty as $crate::traits::Transcribable>::read_num_bytes(bytes)
219 }
220
221 fn get_num_bytes(&self) -> usize {
222 <$inner_ty as $crate::traits::Transcribable>::get_num_bytes(&self.$field)
223 }
224 }
225 };
226 ($wrapper:ident <const $cg_name:ident : $cg_ty:ty> ($inner_ty:ty) $(where $($bounds:tt)+)?) => {
227 $crate::delegate_transcribable!($wrapper <const $cg_name : $cg_ty> { 0: $inner_ty } $(where $($bounds)+)?);
228 };
229 ($wrapper:ident <const $cg_name:ident : $cg_ty:ty> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
230 $crate::delegate_gen_transcribable!($wrapper <const $cg_name : $cg_ty> { $field: $inner_ty } $(where $($bounds)+)?);
231 impl<const $cg_name: $cg_ty> $crate::traits::Transcribable for $wrapper<$cg_name>
232 $(where $($bounds)+)?
233 {
234 const LENGTH_NUM_BYTES: usize =
235 <$inner_ty as $crate::traits::Transcribable>::LENGTH_NUM_BYTES;
236
237 fn read_num_bytes(bytes: &[u8]) -> usize {
238 <$inner_ty as $crate::traits::Transcribable>::read_num_bytes(bytes)
239 }
240
241 fn get_num_bytes(&self) -> usize {
242 <$inner_ty as $crate::traits::Transcribable>::get_num_bytes(&self.$field)
243 }
244 }
245 };
246 ($wrapper:ident <$($gen:tt),+, const $cg_name:ident : $cg_ty:ty> ($inner_ty:ty) $(where $($bounds:tt)+)?) => {
247 $crate::delegate_transcribable!($wrapper <$($gen),+, const $cg_name : $cg_ty> { 0: $inner_ty } $(where $($bounds)+)?);
248 };
249 ($wrapper:ident <$($gen:tt),+, const $cg_name:ident : $cg_ty:ty> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
250 $crate::delegate_gen_transcribable!($wrapper <$($gen),+, const $cg_name : $cg_ty> { $field: $inner_ty } $(where $($bounds)+)?);
251 impl<$($gen),+, const $cg_name: $cg_ty> $crate::traits::Transcribable for $wrapper<$($gen),+, $cg_name>
252 $(where $($bounds)+)?
253 {
254 const LENGTH_NUM_BYTES: usize =
255 <$inner_ty as $crate::traits::Transcribable>::LENGTH_NUM_BYTES;
256
257 fn read_num_bytes(bytes: &[u8]) -> usize {
258 <$inner_ty as $crate::traits::Transcribable>::read_num_bytes(bytes)
259 }
260
261 fn get_num_bytes(&self) -> usize {
262 <$inner_ty as $crate::traits::Transcribable>::get_num_bytes(&self.$field)
263 }
264 }
265 };
266}
267
268#[macro_export]
280macro_rules! delegate_const_transcribable {
281 ($wrapper:ident ($inner_ty:ty)) => {
282 $crate::delegate_const_transcribable!($wrapper { 0: $inner_ty });
283 };
284 ($wrapper:ident { $field:tt : $inner_ty:ty }) => {
285 $crate::delegate_gen_transcribable!($wrapper { $field: $inner_ty });
286 impl $crate::traits::ConstTranscribable for $wrapper {
287 const NUM_BYTES: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BYTES;
288 const NUM_BITS: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BITS;
289 }
290 };
291 ($wrapper:ident <$($gen:tt),+> ($inner_ty:ty) $(where $($bounds:tt)+)?) => {
292 $crate::delegate_const_transcribable!($wrapper <$($gen),+> { 0: $inner_ty } $(where $($bounds)+)?);
293 };
294 ($wrapper:ident <$($gen:tt),+> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
295 $crate::delegate_gen_transcribable!($wrapper <$($gen),+> { $field: $inner_ty } $(where $($bounds)+)?);
296 impl<$($gen),+> $crate::traits::ConstTranscribable for $wrapper<$($gen),+>
297 $(where $($bounds)+)?
298 {
299 const NUM_BYTES: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BYTES;
300 const NUM_BITS: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BITS;
301 }
302 };
303 ($wrapper:ident <const $cg_name:ident : $cg_ty:ty> ($inner_ty:ty) $(where $($bounds:tt)+)?) => {
304 $crate::delegate_const_transcribable!($wrapper <const $cg_name : $cg_ty> { 0: $inner_ty } $(where $($bounds)+)?);
305 };
306 ($wrapper:ident <const $cg_name:ident : $cg_ty:ty> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
307 $crate::delegate_gen_transcribable!($wrapper <const $cg_name : $cg_ty> { $field: $inner_ty } $(where $($bounds)+)?);
308 impl<const $cg_name: $cg_ty> $crate::traits::ConstTranscribable for $wrapper<$cg_name>
309 $(where $($bounds)+)?
310 {
311 const NUM_BYTES: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BYTES;
312 const NUM_BITS: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BITS;
313 }
314 };
315 ($wrapper:ident <$($gen:tt),+, const $cg_name:ident : $cg_ty:ty> ($inner_ty:ty) $(where $($bounds:tt)+)?) => {
316 $crate::delegate_const_transcribable!($wrapper <$($gen),+, const $cg_name : $cg_ty> { 0: $inner_ty } $(where $($bounds)+)?);
317 };
318 ($wrapper:ident <$($gen:tt),+, const $cg_name:ident : $cg_ty:ty> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
319 $crate::delegate_gen_transcribable!($wrapper <$($gen),+, const $cg_name : $cg_ty> { $field: $inner_ty } $(where $($bounds)+)?);
320 impl<$($gen),+, const $cg_name: $cg_ty> $crate::traits::ConstTranscribable for $wrapper<$($gen),+, $cg_name>
321 $(where $($bounds)+)?
322 {
323 const NUM_BYTES: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BYTES;
324 const NUM_BITS: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BITS;
325 }
326 };
327}
328
329pub trait Transcript {
330 fn get_challenge<T: ConstTranscribable>(&mut self) -> T;
333
334 fn get_field_challenge<F: PrimeField>(&mut self, cfg: &F::Config) -> F
335 where
336 F::Inner: ConstTranscribable,
337 {
338 let random_inner = self.get_challenge();
339
340 F::new_with_cfg(random_inner, cfg)
341 }
342
343 fn get_field_challenges<F: PrimeField>(&mut self, n: usize, cfg: &F::Config) -> Vec<F>
350 where
351 F::Inner: ConstTranscribable,
352 {
353 (0..n).map(|_| self.get_field_challenge(cfg)).collect()
354 }
355
356 fn get_challenges<T: ConstTranscribable>(&mut self, n: usize) -> Vec<T> {
359 (0..n).map(|_| self.get_challenge()).collect()
360 }
361
362 fn get_prime<R: ConstIntSemiring + ConstTranscribable, T: PrimalityTest<R>>(&mut self) -> R;
363
364 fn get_random_field_cfg<F, FMod, T>(&mut self) -> F::Config
365 where
366 F: PrimeField,
367 FMod: ConstTranscribable + ConstIntSemiring,
368 F::Modulus: FromRef<FMod>,
369 T: PrimalityTest<FMod>,
370 {
371 let prime = self.get_prime::<FMod, T>();
372
373 F::make_cfg(&F::Modulus::from_ref(&prime)).expect("prime is guaranteed to be prime")
374 }
375
376 fn absorb_inner(&mut self, v: &[u8]);
380
381 fn absorb_slice(&mut self, buf: &[u8]) {
383 self.absorb_inner(&[0x6]);
384 self.absorb_inner(buf);
385 self.absorb_inner(&[0x7]);
386 }
387
388 fn absorb_random_field<F>(&mut self, v: &F, buf: &mut [u8])
394 where
395 F: PrimeField,
396 F::Inner: Transcribable,
397 F::Modulus: Transcribable,
398 {
399 debug_assert_eq!(F::Inner::LENGTH_NUM_BYTES, F::Modulus::LENGTH_NUM_BYTES);
400 debug_assert_eq!(
401 F::Inner::get_num_bytes(v.inner()),
402 F::Modulus::get_num_bytes(&v.modulus())
403 );
404 self.absorb_inner(&[0x3]);
405 v.modulus().write_transcription_bytes_exact(buf);
406 self.absorb_inner(buf);
407 self.absorb_inner(&[0x5]);
408
409 self.absorb_inner(&[0x1]);
410 v.inner().write_transcription_bytes_exact(buf);
411 self.absorb_inner(buf);
412 self.absorb_inner(&[0x3])
413 }
414
415 fn absorb_random_field_slice<F>(&mut self, v: &[F], buf: &mut [u8])
419 where
420 F: PrimeField,
421 F::Inner: Transcribable,
422 F::Modulus: Transcribable,
423 {
424 v.iter().for_each(|x| self.absorb_random_field(x, buf));
425 }
426}
427
428macro_rules! impl_transcribable_for_primitives {
433 ($($type:ty),+) => {
434 $(
435 impl GenTranscribable for $type {
436 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
437 Self::from_le_bytes(bytes.try_into().expect("Invalid byte slice length"))
438 }
439
440 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
441 debug_assert_eq!(buf.len(), Self::NUM_BYTES);
442 buf.copy_from_slice(&self.to_le_bytes());
443 }
444 }
445
446 impl ConstTranscribable for $type {
447 const NUM_BYTES: usize = std::mem::size_of::<$type>();
448 }
449 )+
450 };
451}
452
453impl_transcribable_for_primitives!(u8, u16, u32, u64, u128);
454impl_transcribable_for_primitives!(i8, i16, i32, i64, i128);
455
456impl GenTranscribable for Boolean {
457 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
458 (bytes[0] != 0).into()
459 }
460
461 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
462 buf[0] = self.to_u8();
463 }
464}
465
466impl ConstTranscribable for Boolean {
467 const NUM_BYTES: usize = 1;
468 const NUM_BITS: usize = 1;
469}
470
471impl<const LIMBS: usize> GenTranscribable for Uint<LIMBS> {
472 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
473 let (chunked, rem) = bytes.as_chunks::<{ 8 / WORD_FACTOR }>();
477 assert!(rem.is_empty(), "Invalid byte slice length for Uint");
478 let words = chunked
479 .iter()
480 .map(|chunk| Word::from_le_bytes(*chunk))
481 .collect_array::<LIMBS>()
482 .expect("Invalid length for Uint");
483 Uint::<LIMBS>::from_words(words)
484 }
485
486 #[allow(clippy::arithmetic_side_effects)]
487 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
488 assert_eq!(buf.len(), Self::NUM_BYTES, "Buffer size mismatch for Uint");
492 const W_SIZE: usize = size_of::<Word>();
493 for (i, w) in self.as_words().iter().enumerate() {
494 buf[(i * W_SIZE)..(i * W_SIZE + W_SIZE)].copy_from_slice(w.to_le_bytes().as_ref());
497 }
498 }
499}
500
501impl<const LIMBS: usize> ConstTranscribable for Uint<LIMBS> {
502 const NUM_BYTES: usize = 8 * LIMBS / WORD_FACTOR;
503}
504
505impl<const LIMBS: usize> GenTranscribable for Int<LIMBS> {
506 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
507 *Uint::<LIMBS>::read_transcription_bytes_exact(bytes).as_int()
508 }
509
510 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
511 self.as_uint().write_transcription_bytes_exact(buf)
512 }
513}
514
515impl<const LIMBS: usize> ConstTranscribable for Int<LIMBS> {
516 const NUM_BYTES: usize = Uint::<LIMBS>::NUM_BYTES;
517}
518
519impl GenTranscribable for BoxedUint {
520 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
521 let (chunked, rem) = bytes.as_chunks::<{ 8 / WORD_FACTOR }>();
525 assert!(rem.is_empty(), "Invalid byte slice length for BoxedUint");
526 let words = chunked
527 .iter()
528 .map(|chunk| Word::from_le_bytes(*chunk))
529 .collect_vec();
530 BoxedUint::from_words(words)
531 }
532
533 #[allow(clippy::arithmetic_side_effects)]
534 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
535 assert_eq!(
539 buf.len(),
540 self.bytes_precision(),
541 "Buffer size mismatch for BoxedUint"
542 );
543 const W_SIZE: usize = size_of::<Word>();
544 for (i, w) in self.as_words().iter().enumerate() {
545 buf[(i * W_SIZE)..(i * W_SIZE + W_SIZE)].copy_from_slice(w.to_le_bytes().as_ref());
548 }
549 }
550}
551
552impl Transcribable for BoxedUint {
553 const LENGTH_NUM_BYTES: usize = 1;
555
556 fn read_num_bytes(bytes: &[u8]) -> usize {
557 assert_eq!(bytes.len(), Self::LENGTH_NUM_BYTES);
558 usize::from(bytes[0])
559 }
560
561 fn get_num_bytes(&self) -> usize {
562 usize::from(u8::try_from(self.bytes_precision()).expect("BoxedUint size must fit into u8"))
563 }
564}
565
566impl<F> GenTranscribable for Vec<F>
567where
568 F: PrimeField,
569 F::Inner: ConstTranscribable,
570 F::Modulus: ConstTranscribable,
571{
572 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
573 if bytes.is_empty() {
574 return Vec::new();
575 }
576 let mod_size = F::Modulus::NUM_BYTES;
577 let cfg = super::read_field_cfg::<F>(&bytes[..mod_size]);
578 super::read_field_vec_with_cfg(&bytes[mod_size..], &cfg)
579 }
580
581 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
582 if self.is_empty() {
583 return;
584 }
585 let buf = super::append_field_cfg::<F>(buf, &self[0].modulus());
586 let buf = super::append_field_vec_inner(buf, self);
587 assert!(
588 buf.is_empty(),
589 "Buffer size mismatch for Vec<F> transcription"
590 );
591 }
592}
593
594impl<F> Transcribable for Vec<F>
595where
596 F: PrimeField,
597 F::Inner: ConstTranscribable,
598 F::Modulus: ConstTranscribable,
599{
600 fn get_num_bytes(&self) -> usize {
601 if self.is_empty() {
602 0
603 } else {
604 add!(F::Modulus::NUM_BYTES, mul!(self.len(), F::Inner::NUM_BYTES))
605 }
606 }
607}