1use crypto_bigint::{Word, modular::ConstMontyParams};
6use crypto_primitives::{
7 BaseFieldConfig, ConstBaseField, ConstIntSemiring, FieldConfig, LiftElementWithConfig,
8 ProjectElementWithConfig, Semiring, boolean::Boolean, crypto_bigint_boxed_uint::BoxedUint,
9 crypto_bigint_const_monty::ConstMontyField, crypto_bigint_int::Int,
10 crypto_bigint_monty::MontyFieldElement, crypto_bigint_uint::Uint,
11};
12use itertools::Itertools;
13use zinc_primality::PrimalityTest;
14use zinc_utils::{from_ref::FromRef, mul};
15
16pub trait GenTranscribable: Sized {
19 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self;
23
24 fn write_transcription_bytes_exact(&self, buf: &mut [u8]);
27}
28
29pub trait Transcribable: GenTranscribable {
32 const LENGTH_NUM_BYTES: usize = u32::NUM_BYTES;
37
38 fn read_num_bytes(bytes: &[u8]) -> usize {
43 usize::try_from(u32::read_transcription_bytes_exact(bytes))
44 .expect("num_bytes must fit into usize")
45 }
46
47 fn get_num_bytes(&self) -> usize;
51
52 fn read_transcription_bytes_subset(bytes: &[u8]) -> (Self, &[u8]) {
55 let (bytes_num_bytes, bytes_rem) = bytes.split_at(Self::LENGTH_NUM_BYTES);
56 let num_bytes = Self::read_num_bytes(bytes_num_bytes);
57 assert!(
59 bytes_rem.len() >= num_bytes,
60 "Byte slice length is not sufficient for reading Transcribable"
61 );
62 let (bytes_data, bytes_rem) = bytes_rem.split_at(num_bytes);
63 (Self::read_transcription_bytes_exact(bytes_data), bytes_rem)
64 }
65
66 fn write_transcription_bytes_subset<'a>(&self, mut buf: &'a mut [u8]) -> &'a mut [u8] {
69 let num_bytes = self.get_num_bytes();
70 if Self::LENGTH_NUM_BYTES > 0 {
71 buf[0..Self::LENGTH_NUM_BYTES]
72 .copy_from_slice(&num_bytes.to_le_bytes()[..Self::LENGTH_NUM_BYTES]);
73 buf = &mut buf[Self::LENGTH_NUM_BYTES..];
74 };
75 let (buf, rest) = buf.split_at_mut(num_bytes);
76 self.write_transcription_bytes_exact(buf);
77 rest
78 }
79}
80
81pub trait ConstTranscribable: GenTranscribable {
84 const NUM_BYTES: usize;
86 const NUM_BITS: usize = Self::NUM_BYTES * 8;
88}
89
90impl<T: ConstTranscribable> Transcribable for T {
91 const LENGTH_NUM_BYTES: usize = 0;
92
93 fn read_num_bytes(bytes: &[u8]) -> usize {
94 assert_eq!(bytes.len(), 0);
95 Self::NUM_BYTES
96 }
97
98 fn get_num_bytes(&self) -> usize {
99 Self::NUM_BYTES
100 }
101
102 fn read_transcription_bytes_subset(bytes: &[u8]) -> (Self, &[u8]) {
103 assert!(
104 bytes.len() >= Self::NUM_BYTES,
105 "Byte slice length is not sufficient for reading Transcribable"
106 );
107 let (bytes_data, bytes_rem) = bytes.split_at(Self::NUM_BYTES);
108 (Self::read_transcription_bytes_exact(bytes_data), bytes_rem)
109 }
110}
111
112#[macro_export]
115macro_rules! delegate_gen_transcribable {
116 ($wrapper:ident { $field:tt : $inner_ty:ty }) => {
117 impl $crate::traits::GenTranscribable for $wrapper {
118 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
119 Self {
120 $field: <$inner_ty as $crate::traits::GenTranscribable>::read_transcription_bytes_exact(bytes),
121 }
122 }
123
124 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
125 $crate::traits::GenTranscribable::write_transcription_bytes_exact(&self.$field, buf)
126 }
127 }
128 };
129 ($wrapper:ident <$($gen:tt),+> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
130 impl<$($gen),+> $crate::traits::GenTranscribable for $wrapper<$($gen),+>
131 $(where $($bounds)+)?
132 {
133 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
134 Self {
135 $field: <$inner_ty as $crate::traits::GenTranscribable>::read_transcription_bytes_exact(bytes),
136 }
137 }
138
139 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
140 $crate::traits::GenTranscribable::write_transcription_bytes_exact(&self.$field, buf)
141 }
142 }
143 };
144 ($wrapper:ident <const $cg_name:ident : $cg_ty:ty> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
145 impl<const $cg_name: $cg_ty> $crate::traits::GenTranscribable for $wrapper<$cg_name>
146 $(where $($bounds)+)?
147 {
148 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
149 Self {
150 $field: <$inner_ty as $crate::traits::GenTranscribable>::read_transcription_bytes_exact(bytes),
151 }
152 }
153
154 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
155 $crate::traits::GenTranscribable::write_transcription_bytes_exact(&self.$field, buf)
156 }
157 }
158 };
159 ($wrapper:ident <$($gen:tt),+, const $cg_name:ident : $cg_ty:ty> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
160 impl<$($gen),+, const $cg_name: $cg_ty> $crate::traits::GenTranscribable for $wrapper<$($gen),+, $cg_name>
161 $(where $($bounds)+)?
162 {
163 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
164 Self {
165 $field: <$inner_ty as $crate::traits::GenTranscribable>::read_transcription_bytes_exact(bytes),
166 }
167 }
168
169 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
170 $crate::traits::GenTranscribable::write_transcription_bytes_exact(&self.$field, buf)
171 }
172 }
173 };
174}
175
176#[macro_export]
189macro_rules! delegate_transcribable {
190 ($wrapper:ident ($inner_ty:ty)) => {
191 $crate::delegate_transcribable!($wrapper { 0: $inner_ty });
192 };
193 ($wrapper:ident { $field:tt : $inner_ty:ty }) => {
194 $crate::delegate_gen_transcribable!($wrapper { $field: $inner_ty });
195 impl $crate::traits::Transcribable for $wrapper {
196 const LENGTH_NUM_BYTES: usize =
197 <$inner_ty as $crate::traits::Transcribable>::LENGTH_NUM_BYTES;
198
199 fn read_num_bytes(bytes: &[u8]) -> usize {
200 <$inner_ty as $crate::traits::Transcribable>::read_num_bytes(bytes)
201 }
202
203 fn get_num_bytes(&self) -> usize {
204 <$inner_ty as $crate::traits::Transcribable>::get_num_bytes(&self.$field)
205 }
206 }
207 };
208 ($wrapper:ident <$($gen:tt),+> ($inner_ty:ty) $(where $($bounds:tt)+)?) => {
209 $crate::delegate_transcribable!($wrapper <$($gen),+> { 0: $inner_ty } $(where $($bounds)+)?);
210 };
211 ($wrapper:ident <$($gen:tt),+> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
212 $crate::delegate_gen_transcribable!($wrapper <$($gen),+> { $field: $inner_ty } $(where $($bounds)+)?);
213 impl<$($gen),+> $crate::traits::Transcribable for $wrapper<$($gen),+>
214 $(where $($bounds)+)?
215 {
216 const LENGTH_NUM_BYTES: usize =
217 <$inner_ty as $crate::traits::Transcribable>::LENGTH_NUM_BYTES;
218
219 fn read_num_bytes(bytes: &[u8]) -> usize {
220 <$inner_ty as $crate::traits::Transcribable>::read_num_bytes(bytes)
221 }
222
223 fn get_num_bytes(&self) -> usize {
224 <$inner_ty as $crate::traits::Transcribable>::get_num_bytes(&self.$field)
225 }
226 }
227 };
228 ($wrapper:ident <const $cg_name:ident : $cg_ty:ty> ($inner_ty:ty) $(where $($bounds:tt)+)?) => {
229 $crate::delegate_transcribable!($wrapper <const $cg_name : $cg_ty> { 0: $inner_ty } $(where $($bounds)+)?);
230 };
231 ($wrapper:ident <const $cg_name:ident : $cg_ty:ty> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
232 $crate::delegate_gen_transcribable!($wrapper <const $cg_name : $cg_ty> { $field: $inner_ty } $(where $($bounds)+)?);
233 impl<const $cg_name: $cg_ty> $crate::traits::Transcribable for $wrapper<$cg_name>
234 $(where $($bounds)+)?
235 {
236 const LENGTH_NUM_BYTES: usize =
237 <$inner_ty as $crate::traits::Transcribable>::LENGTH_NUM_BYTES;
238
239 fn read_num_bytes(bytes: &[u8]) -> usize {
240 <$inner_ty as $crate::traits::Transcribable>::read_num_bytes(bytes)
241 }
242
243 fn get_num_bytes(&self) -> usize {
244 <$inner_ty as $crate::traits::Transcribable>::get_num_bytes(&self.$field)
245 }
246 }
247 };
248 ($wrapper:ident <$($gen:tt),+, const $cg_name:ident : $cg_ty:ty> ($inner_ty:ty) $(where $($bounds:tt)+)?) => {
249 $crate::delegate_transcribable!($wrapper <$($gen),+, const $cg_name : $cg_ty> { 0: $inner_ty } $(where $($bounds)+)?);
250 };
251 ($wrapper:ident <$($gen:tt),+, const $cg_name:ident : $cg_ty:ty> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
252 $crate::delegate_gen_transcribable!($wrapper <$($gen),+, const $cg_name : $cg_ty> { $field: $inner_ty } $(where $($bounds)+)?);
253 impl<$($gen),+, const $cg_name: $cg_ty> $crate::traits::Transcribable for $wrapper<$($gen),+, $cg_name>
254 $(where $($bounds)+)?
255 {
256 const LENGTH_NUM_BYTES: usize =
257 <$inner_ty as $crate::traits::Transcribable>::LENGTH_NUM_BYTES;
258
259 fn read_num_bytes(bytes: &[u8]) -> usize {
260 <$inner_ty as $crate::traits::Transcribable>::read_num_bytes(bytes)
261 }
262
263 fn get_num_bytes(&self) -> usize {
264 <$inner_ty as $crate::traits::Transcribable>::get_num_bytes(&self.$field)
265 }
266 }
267 };
268}
269
270#[macro_export]
282macro_rules! delegate_const_transcribable {
283 ($wrapper:ident ($inner_ty:ty)) => {
284 $crate::delegate_const_transcribable!($wrapper { 0: $inner_ty });
285 };
286 ($wrapper:ident { $field:tt : $inner_ty:ty }) => {
287 $crate::delegate_gen_transcribable!($wrapper { $field: $inner_ty });
288 impl $crate::traits::ConstTranscribable for $wrapper {
289 const NUM_BYTES: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BYTES;
290 const NUM_BITS: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BITS;
291 }
292 };
293 ($wrapper:ident <$($gen:tt),+> ($inner_ty:ty) $(where $($bounds:tt)+)?) => {
294 $crate::delegate_const_transcribable!($wrapper <$($gen),+> { 0: $inner_ty } $(where $($bounds)+)?);
295 };
296 ($wrapper:ident <$($gen:tt),+> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
297 $crate::delegate_gen_transcribable!($wrapper <$($gen),+> { $field: $inner_ty } $(where $($bounds)+)?);
298 impl<$($gen),+> $crate::traits::ConstTranscribable for $wrapper<$($gen),+>
299 $(where $($bounds)+)?
300 {
301 const NUM_BYTES: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BYTES;
302 const NUM_BITS: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BITS;
303 }
304 };
305 ($wrapper:ident <const $cg_name:ident : $cg_ty:ty> ($inner_ty:ty) $(where $($bounds:tt)+)?) => {
306 $crate::delegate_const_transcribable!($wrapper <const $cg_name : $cg_ty> { 0: $inner_ty } $(where $($bounds)+)?);
307 };
308 ($wrapper:ident <const $cg_name:ident : $cg_ty:ty> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
309 $crate::delegate_gen_transcribable!($wrapper <const $cg_name : $cg_ty> { $field: $inner_ty } $(where $($bounds)+)?);
310 impl<const $cg_name: $cg_ty> $crate::traits::ConstTranscribable for $wrapper<$cg_name>
311 $(where $($bounds)+)?
312 {
313 const NUM_BYTES: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BYTES;
314 const NUM_BITS: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BITS;
315 }
316 };
317 ($wrapper:ident <$($gen:tt),+, const $cg_name:ident : $cg_ty:ty> ($inner_ty:ty) $(where $($bounds:tt)+)?) => {
318 $crate::delegate_const_transcribable!($wrapper <$($gen),+, const $cg_name : $cg_ty> { 0: $inner_ty } $(where $($bounds)+)?);
319 };
320 ($wrapper:ident <$($gen:tt),+, const $cg_name:ident : $cg_ty:ty> { $field:tt : $inner_ty:ty } $(where $($bounds:tt)+)?) => {
321 $crate::delegate_gen_transcribable!($wrapper <$($gen),+, const $cg_name : $cg_ty> { $field: $inner_ty } $(where $($bounds)+)?);
322 impl<$($gen),+, const $cg_name: $cg_ty> $crate::traits::ConstTranscribable for $wrapper<$($gen),+, $cg_name>
323 $(where $($bounds)+)?
324 {
325 const NUM_BYTES: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BYTES;
326 const NUM_BITS: usize = <$inner_ty as $crate::traits::ConstTranscribable>::NUM_BITS;
327 }
328 };
329}
330
331pub trait Transcript {
332 fn get_challenge<T: ConstTranscribable>(&mut self) -> T;
335
336 fn get_field_challenge<C>(&mut self, cfg: &C) -> C::Element
337 where
338 C: FieldConfig + ProjectElementWithConfig<C::Integer>,
339 C::Integer: ConstTranscribable,
340 {
341 let random_integer: C::Integer = self.get_challenge();
342 cfg.project(&random_integer)
343 }
344
345 fn get_field_challenges<C>(&mut self, n: usize, cfg: &C) -> Vec<C::Element>
352 where
353 C: FieldConfig + ProjectElementWithConfig<C::Integer>,
354 C::Integer: ConstTranscribable,
355 {
356 (0..n).map(|_| self.get_field_challenge(cfg)).collect()
357 }
358
359 fn get_challenges<T: ConstTranscribable>(&mut self, n: usize) -> Vec<T> {
362 (0..n).map(|_| self.get_challenge()).collect()
363 }
364
365 fn get_prime<R: ConstIntSemiring + ConstTranscribable, T: PrimalityTest<R>>(&mut self) -> R;
366
367 fn get_random_field_cfg<C, FMod, T>(&mut self) -> C
368 where
369 C: BaseFieldConfig,
370 C::Integer: FromRef<FMod>,
371 FMod: ConstTranscribable + ConstIntSemiring,
372 T: PrimalityTest<FMod>,
373 {
374 let prime = self.get_prime::<FMod, T>();
375
376 C::new(&C::Integer::from_ref(&prime)).expect("prime is guaranteed to be prime")
377 }
378
379 fn absorb_inner(&mut self, v: &[u8]);
383
384 fn absorb_bytes(&mut self, buf: &[u8]) {
387 self.absorb_inner(&[0x06]);
388 self.absorb_inner(buf);
389 self.absorb_inner(&[0x07]);
390 }
391
392 fn absorb_field_element<C, I>(&mut self, cfg: &C, v: &C::Element, buf: &mut [u8])
398 where
399 C: FieldConfig + LiftElementWithConfig<I>,
400 I: Semiring + Transcribable,
401 {
402 self.absorb_int(&cfg.lift(v), buf);
403 }
404
405 fn absorb_field_element_slice<C, I>(&mut self, cfg: &C, v: &[C::Element], buf: &mut [u8])
407 where
408 C: FieldConfig + LiftElementWithConfig<I>,
409 I: Semiring + Transcribable,
410 {
411 v.iter()
412 .for_each(|x| self.absorb_field_element(cfg, x, buf));
413 }
414
415 fn absorb_int<S>(&mut self, v: &S, buf: &mut [u8])
417 where
418 S: Semiring + Transcribable,
419 {
420 v.write_transcription_bytes_exact(buf);
421 self.absorb_bytes(buf);
422 }
423
424 fn absorb_int_slice<S>(&mut self, v: &[S], buf: &mut [u8])
426 where
427 S: Semiring + Transcribable,
428 {
429 v.iter().for_each(|x| self.absorb_int(x, buf));
430 }
431}
432
433macro_rules! impl_transcribable_for_primitives {
438 ($($type:ty),+) => {
439 $(
440 impl GenTranscribable for $type {
441 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
442 Self::from_le_bytes(bytes.try_into().expect("Invalid byte slice length"))
443 }
444
445 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
446 debug_assert_eq!(buf.len(), Self::NUM_BYTES);
447 buf.copy_from_slice(&self.to_le_bytes());
448 }
449 }
450
451 impl ConstTranscribable for $type {
452 const NUM_BYTES: usize = std::mem::size_of::<$type>();
453 }
454 )+
455 };
456}
457
458impl_transcribable_for_primitives!(u8, u16, u32, u64, u128);
459impl_transcribable_for_primitives!(i8, i16, i32, i64, i128);
460
461impl GenTranscribable for Boolean {
462 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
463 (bytes[0] != 0).into()
464 }
465
466 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
467 buf[0] = self.to_u8();
468 }
469}
470
471impl ConstTranscribable for Boolean {
472 const NUM_BYTES: usize = 1;
473 const NUM_BITS: usize = 1;
474}
475
476impl<const LIMBS: usize> GenTranscribable for Uint<LIMBS> {
477 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
478 let (chunked, rem) = bytes.as_chunks::<{ Word::NUM_BYTES }>();
482 assert!(rem.is_empty(), "Invalid byte slice length for Uint");
483 let words = chunked
484 .iter()
485 .map(|chunk| Word::from_le_bytes(*chunk))
486 .collect_array::<LIMBS>()
487 .expect("Invalid length for Uint");
488 Uint::<LIMBS>::from_words(words)
489 }
490
491 #[allow(clippy::arithmetic_side_effects)]
492 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
493 assert_eq!(buf.len(), Self::NUM_BYTES, "Buffer size mismatch for Uint");
497 const W_SIZE: usize = size_of::<Word>();
498 for (i, w) in self.as_words().iter().enumerate() {
499 buf[(i * W_SIZE)..(i * W_SIZE + W_SIZE)].copy_from_slice(w.to_le_bytes().as_ref());
502 }
503 }
504}
505
506impl<const LIMBS: usize> ConstTranscribable for Uint<LIMBS> {
507 const NUM_BYTES: usize = LIMBS * Word::NUM_BYTES;
508}
509
510impl<const LIMBS: usize> GenTranscribable for Int<LIMBS> {
511 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
512 *Uint::<LIMBS>::read_transcription_bytes_exact(bytes).as_int()
513 }
514
515 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
516 self.as_uint().write_transcription_bytes_exact(buf)
517 }
518}
519
520impl<const LIMBS: usize> ConstTranscribable for Int<LIMBS> {
521 const NUM_BYTES: usize = Uint::<LIMBS>::NUM_BYTES;
522}
523
524impl GenTranscribable for BoxedUint {
525 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
526 let (chunked, rem) = bytes.as_chunks::<{ Word::NUM_BYTES }>();
530 assert!(rem.is_empty(), "Invalid byte slice length for BoxedUint");
531 let words = chunked
532 .iter()
533 .map(|chunk| Word::from_le_bytes(*chunk))
534 .collect_vec();
535 BoxedUint::from_words(words)
536 }
537
538 #[allow(clippy::arithmetic_side_effects)]
539 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
540 assert_eq!(
544 buf.len(),
545 self.bytes_precision(),
546 "Buffer size mismatch for BoxedUint"
547 );
548 const W_SIZE: usize = size_of::<Word>();
549 for (i, w) in self.as_words().iter().enumerate() {
550 buf[(i * W_SIZE)..(i * W_SIZE + W_SIZE)].copy_from_slice(w.to_le_bytes().as_ref());
553 }
554 }
555}
556
557impl Transcribable for BoxedUint {
558 const LENGTH_NUM_BYTES: usize = 1;
560
561 fn read_num_bytes(bytes: &[u8]) -> usize {
562 assert_eq!(bytes.len(), Self::LENGTH_NUM_BYTES);
563 usize::from(bytes[0])
564 }
565
566 fn get_num_bytes(&self) -> usize {
567 usize::from(u8::try_from(self.bytes_precision()).expect("BoxedUint size must fit into u8"))
568 }
569}
570
571impl<const LIMBS: usize> GenTranscribable for MontyFieldElement<LIMBS> {
583 fn read_transcription_bytes_exact(_bytes: &[u8]) -> Self {
584 panic!("MontyFieldElement cannot be deserialized without a field config");
585 }
586
587 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
588 self.0.write_transcription_bytes_exact(buf)
589 }
590}
591
592impl<Mod: ConstMontyParams<LIMBS>, const LIMBS: usize> GenTranscribable
593 for ConstMontyField<Mod, LIMBS>
594{
595 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
596 let int = Uint::<LIMBS>::read_transcription_bytes_exact(bytes);
597 assert!(
598 int < <Self as ConstBaseField>::MODULUS,
599 "non-canonical field element: lifted integer >= modulus"
600 );
601 Self::new(int)
602 }
603
604 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
605 self.retrieve().write_transcription_bytes_exact(buf)
606 }
607}
608
609impl<Mod: ConstMontyParams<LIMBS>, const LIMBS: usize> ConstTranscribable
610 for ConstMontyField<Mod, LIMBS>
611{
612 const NUM_BYTES: usize = Uint::<LIMBS>::NUM_BYTES;
613}
614
615impl<T> GenTranscribable for Vec<T>
616where
617 T: ConstTranscribable,
618{
619 fn read_transcription_bytes_exact(bytes: &[u8]) -> Self {
620 let chunks = bytes.chunks_exact(T::NUM_BYTES);
621 assert!(
622 chunks.remainder().is_empty(),
623 "Invalid byte slice length for Vec transcription"
624 );
625 chunks.map(T::read_transcription_bytes_exact).collect()
626 }
627
628 fn write_transcription_bytes_exact(&self, buf: &mut [u8]) {
629 assert_eq!(
630 buf.len(),
631 mul!(self.len(), T::NUM_BYTES),
632 "Buffer size mismatch for Vec transcription"
633 );
634 for (elem, chunk) in self.iter().zip(buf.chunks_exact_mut(T::NUM_BYTES)) {
635 elem.write_transcription_bytes_exact(chunk);
636 }
637 }
638}
639
640impl<T> Transcribable for Vec<T>
641where
642 T: ConstTranscribable,
643{
644 fn get_num_bytes(&self) -> usize {
645 mul!(self.len(), T::NUM_BYTES)
646 }
647}