Skip to main content

twenty_first/math/
bfield_codec.rs

1use std::cmp::Ordering;
2use std::error::Error;
3use std::fmt::Debug;
4use std::fmt::Display;
5use std::marker::PhantomData;
6use std::slice::Iter;
7
8// Re-export the derive macro so that it can be used in other crates without having to add
9// an explicit dependency on `bfieldcodec_derive` to their Cargo.toml.
10pub use bfieldcodec_derive::BFieldCodec;
11use num_traits::ConstOne;
12use num_traits::ConstZero;
13use thiserror::Error;
14
15use super::b_field_element::BFieldElement;
16use super::polynomial::Polynomial;
17use super::traits::FiniteField;
18use crate::bfe;
19use crate::bfe_vec;
20
21/// This trait provides functions for encoding to and decoding from a Vec of
22/// [BFieldElement]s. This encoding does not record the size of objects nor
23/// their type information; this is the responsibility of the decoder.
24///
25/// ### Dyn-Compatibility
26///
27/// This trait is _not_ [dyn-compatible] (previously known as “object safe”).
28///
29/// [dyn-compatible]: https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility
30pub trait BFieldCodec {
31    type Error: Into<Box<dyn Error + Send + Sync>> + Debug + Display;
32
33    fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error>;
34    fn encode(&self) -> Vec<BFieldElement>;
35
36    /// Returns the length in number of [BFieldElement]s if it is known at compile-time.
37    /// Otherwise, None.
38    fn static_length() -> Option<usize>;
39}
40
41#[derive(Debug, Error)]
42#[non_exhaustive]
43pub enum BFieldCodecError {
44    #[error("empty sequence")]
45    EmptySequence,
46
47    #[error("sequence too short")]
48    SequenceTooShort,
49
50    #[error("sequence too long")]
51    SequenceTooLong,
52
53    #[error("element out of range")]
54    ElementOutOfRange,
55
56    #[error("missing length indicator")]
57    MissingLengthIndicator,
58
59    #[error("invalid length indicator")]
60    InvalidLengthIndicator,
61
62    #[error(transparent)]
63    TryFromIntError(#[from] std::num::TryFromIntError),
64
65    #[error("inner decoding error: {0}")]
66    InnerDecodingFailure(#[from] Box<dyn Error + Send + Sync>),
67}
68
69// The type underlying BFieldElement is u64. A single u64 does not fit in one BFieldElement.
70// Therefore, deriving the BFieldCodec for BFieldElement using the derive macro will result in a
71// BFieldCodec implementation that encodes a single BFieldElement as two BFieldElements.
72// This is not desired. Hence, BFieldCodec is implemented manually for BFieldElement.
73impl BFieldCodec for BFieldElement {
74    type Error = BFieldCodecError;
75
76    fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error> {
77        if sequence.is_empty() {
78            return Err(Self::Error::EmptySequence);
79        }
80        if sequence.len() > 1 {
81            return Err(Self::Error::SequenceTooLong);
82        }
83        Ok(Box::new(sequence[0]))
84    }
85
86    fn encode(&self) -> Vec<BFieldElement> {
87        [*self].to_vec()
88    }
89
90    fn static_length() -> Option<usize> {
91        Some(1)
92    }
93}
94
95macro_rules! impl_bfield_codec_for_big_primitive_uint {
96    ($ty:ty, $size:literal) => {
97        impl BFieldCodec for $ty {
98            type Error = BFieldCodecError;
99
100            fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error> {
101                if sequence.is_empty() {
102                    return Err(Self::Error::EmptySequence);
103                }
104                if sequence.len() < $size {
105                    return Err(Self::Error::SequenceTooShort);
106                }
107                if sequence.len() > $size {
108                    return Err(Self::Error::SequenceTooLong);
109                }
110                if sequence.iter().any(|s| s.value() > u32::MAX.into()) {
111                    return Err(Self::Error::ElementOutOfRange);
112                }
113
114                let element = sequence
115                    .iter()
116                    .enumerate()
117                    .map(|(i, s)| Self::from(s) << (i * 32))
118                    .sum();
119                Ok(Box::new(element))
120            }
121
122            fn encode(&self) -> Vec<BFieldElement> {
123                const LOW_BIT_MASK: $ty = u32::MAX as $ty;
124
125                (0..$size)
126                    .map(|i| bfe!((*self >> (i * 32)) & LOW_BIT_MASK))
127                    .collect()
128            }
129
130            fn static_length() -> Option<usize> {
131                Some($size)
132            }
133        }
134    };
135}
136
137impl_bfield_codec_for_big_primitive_uint!(u64, 2);
138impl_bfield_codec_for_big_primitive_uint!(u128, 4);
139
140macro_rules! impl_bfield_codec_for_signed_int {
141    ($iint:ty, using $uint:ty) => {
142        impl BFieldCodec for $iint {
143            type Error = <$uint as BFieldCodec>::Error;
144
145            fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error> {
146                <$uint>::decode(sequence).map(|v| Box::new(*v as Self))
147            }
148
149            fn encode(&self) -> Vec<BFieldElement> {
150                (*self as $uint).encode()
151            }
152
153            fn static_length() -> Option<usize> {
154                <$uint>::static_length()
155            }
156        }
157    };
158}
159
160impl_bfield_codec_for_signed_int!(i8, using u8);
161impl_bfield_codec_for_signed_int!(i16, using u16);
162impl_bfield_codec_for_signed_int!(i32, using u32);
163impl_bfield_codec_for_signed_int!(i64, using u64);
164impl_bfield_codec_for_signed_int!(i128, using u128);
165
166impl BFieldCodec for bool {
167    type Error = BFieldCodecError;
168
169    fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error> {
170        if sequence.is_empty() {
171            return Err(Self::Error::EmptySequence);
172        }
173        if sequence.len() > 1 {
174            return Err(Self::Error::SequenceTooLong);
175        }
176
177        let element = match sequence[0].value() {
178            0 => false,
179            1 => true,
180            _ => return Err(Self::Error::ElementOutOfRange),
181        };
182        Ok(Box::new(element))
183    }
184
185    fn encode(&self) -> Vec<BFieldElement> {
186        vec![BFieldElement::new(*self as u64)]
187    }
188
189    fn static_length() -> Option<usize> {
190        Some(1)
191    }
192}
193
194macro_rules! impl_bfield_codec_for_small_primitive_uint {
195    ($($t:ident),+ $(,)?) => {$(
196        impl BFieldCodec for $t {
197            type Error = BFieldCodecError;
198
199            fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error> {
200                if sequence.is_empty() {
201                    return Err(Self::Error::EmptySequence);
202                }
203                let [first] = sequence[..] else {
204                    return Err(Self::Error::SequenceTooLong);
205                };
206                let element = $t::try_from(first.value())
207                    .map_err(|_| Self::Error::ElementOutOfRange)?;
208
209                Ok(Box::new(element))
210            }
211
212            fn encode(&self) -> Vec<BFieldElement> {
213                bfe_vec![*self]
214            }
215
216            fn static_length() -> Option<usize> {
217                Some(1)
218            }
219        }
220    )+};
221}
222
223impl_bfield_codec_for_small_primitive_uint!(u8, u16, u32);
224
225impl<T: BFieldCodec> BFieldCodec for Box<T> {
226    type Error = T::Error;
227
228    fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error> {
229        T::decode(sequence).map(Box::new)
230    }
231
232    fn encode(&self) -> Vec<BFieldElement> {
233        self.as_ref().encode()
234    }
235
236    fn static_length() -> Option<usize> {
237        T::static_length()
238    }
239}
240
241macro_rules! impl_bfield_codec_for_tuple {
242    // entrypoint: introduce marker tokens to start reversing token sequence
243    ($($forward:ident),+) => {
244        impl_bfield_codec_for_tuple!(@>@ $($forward)+ @rev@);
245    };
246
247    // general case: reversing in progress, move marker token `@>@`
248    ($($a:ident)* @>@ $b:ident $($c:ident)* @rev@ $($reverse:ident)*) => {
249        impl_bfield_codec_for_tuple!($($a)* $b @>@ $($c)* @rev@ $b $($reverse)*);
250    };
251
252    // base case: reversing is done
253    //
254    // Use token sequence in “forward” mode to
255    //  - declare the tuple type,
256    //  - construct the tuple after successful decoding, and
257    //  - pattern-match-deconstruct `self` to prepare encoding.
258    // Use token sequence in “reverse” mode to en/decode in reverse order from type
259    // declaration.
260    //
261    // Because it is impossible to construct tuple accessors (like the 0 in
262    // `my_tuple.0`) in a declarative macro, pattern matching is used to
263    // deconstruct `self`. This requires identifiers. The current design uses the
264    // type identifiers for this purpose. While these identifiers don't follow the
265    // guidelines for variable identifiers, this is deemed acceptable in macro code.
266    ($($f:ident)+ @>@ @rev@ $($r:ident)+) => {
267        impl <$($f),+> BFieldCodec for ($($f),+ ,)
268        where $($f: BFieldCodec),+
269        {
270            type Error = BFieldCodecError;
271
272            fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error> {
273                $(
274                if $r::static_length().is_none() && sequence.first().is_none() {
275                    return Err(Self::Error::MissingLengthIndicator);
276                }
277                let (length, sequence) = $r::static_length()
278                    .map(|length| (Ok(length), sequence))
279                    .unwrap_or_else(|| (sequence[0].try_into(), &sequence[1..]));
280                let length = length?;
281                if sequence.len() < length {
282                    return Err(Self::Error::SequenceTooShort);
283                }
284                let (sequence_for_ty, sequence) = sequence.split_at(length);
285                #[allow(non_snake_case)]
286                let $r = *$r::decode(sequence_for_ty).map_err(|err| err.into())?;
287                )+
288
289                if !sequence.is_empty() {
290                    return Err(Self::Error::SequenceTooLong);
291                }
292                Ok(Box::new(($($f),+ ,)))
293            }
294
295            fn encode(&self) -> Vec<BFieldElement> {
296                #[allow(non_snake_case)]
297                let ($($f),+ ,) = self;
298                let mut sequence = vec![];
299
300                $(
301                let encoding = $r.encode();
302                if $r::static_length().is_none() {
303                    sequence.push(encoding.len().into());
304                }
305                sequence.extend(encoding);
306                )+
307
308                sequence
309            }
310
311            fn static_length() -> Option<usize> {
312                // Token `+` cannot be used as macro repetition separator. As a workaround, use
313                // it inside macro repetition, and make last emitted `+` syntactic by adding 0.
314                Some($($f::static_length()? +)+ 0)
315            }
316        }
317    };
318}
319
320impl_bfield_codec_for_tuple!(A);
321impl_bfield_codec_for_tuple!(A, B);
322impl_bfield_codec_for_tuple!(A, B, C);
323impl_bfield_codec_for_tuple!(A, B, C, D);
324impl_bfield_codec_for_tuple!(A, B, C, D, E);
325impl_bfield_codec_for_tuple!(A, B, C, D, E, F);
326impl_bfield_codec_for_tuple!(A, B, C, D, E, F, G);
327impl_bfield_codec_for_tuple!(A, B, C, D, E, F, G, H);
328impl_bfield_codec_for_tuple!(A, B, C, D, E, F, G, H, I);
329impl_bfield_codec_for_tuple!(A, B, C, D, E, F, G, H, I, J);
330impl_bfield_codec_for_tuple!(A, B, C, D, E, F, G, H, I, J, K);
331impl_bfield_codec_for_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
332
333impl<T: BFieldCodec> BFieldCodec for Option<T> {
334    type Error = BFieldCodecError;
335
336    fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error> {
337        if sequence.is_empty() {
338            return Err(Self::Error::EmptySequence);
339        }
340        let is_some = *bool::decode(&sequence[0..1])?;
341        let sequence = &sequence[1..];
342        let maybe_result = is_some.then(|| T::decode(sequence).map_err(|e| e.into()));
343        let element = maybe_result.transpose()?.map(|boxed_self| *boxed_self);
344
345        if !is_some && !sequence.is_empty() {
346            return Err(Self::Error::SequenceTooLong);
347        }
348        Ok(Box::new(element))
349    }
350
351    fn encode(&self) -> Vec<BFieldElement> {
352        match self {
353            None => vec![BFieldElement::ZERO],
354            Some(t) => [vec![BFieldElement::ONE], t.encode()].concat(),
355        }
356    }
357
358    fn static_length() -> Option<usize> {
359        None
360    }
361}
362
363impl<T: BFieldCodec, const N: usize> BFieldCodec for [T; N] {
364    type Error = BFieldCodecError;
365
366    fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error> {
367        if N > 0 && sequence.is_empty() {
368            return Err(Self::Error::EmptySequence);
369        }
370
371        let vec_t = bfield_codec_decode_list(N, sequence)?;
372        let array = vec_t.try_into().map_err(|_| {
373            Self::Error::InnerDecodingFailure(format!("cannot convert Vec<T> into [T; {N}]").into())
374        })?;
375        Ok(Box::new(array))
376    }
377
378    fn encode(&self) -> Vec<BFieldElement> {
379        bfield_codec_encode_list(self.iter())
380    }
381
382    fn static_length() -> Option<usize> {
383        T::static_length().map(|len| len * N)
384    }
385}
386
387impl<T: BFieldCodec> BFieldCodec for Vec<T> {
388    type Error = BFieldCodecError;
389
390    fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error> {
391        if sequence.is_empty() {
392            return Err(Self::Error::EmptySequence);
393        }
394
395        let vec_length = sequence[0].try_into()?;
396        let vec = bfield_codec_decode_list(vec_length, &sequence[1..])?;
397        Ok(Box::new(vec))
398    }
399
400    fn encode(&self) -> Vec<BFieldElement> {
401        let mut encoding = bfe_vec![self.len()];
402        encoding.extend(bfield_codec_encode_list(self.iter()));
403        encoding
404    }
405
406    fn static_length() -> Option<usize> {
407        None
408    }
409}
410
411#[derive(Debug, Error)]
412pub enum PolynomialBFieldCodecError {
413    /// A polynomial with leading zero-coefficients, corresponding to an encoding
414    /// with trailing zeros, is a waste of space. More importantly, it allows for
415    /// non-canonical encodings of the same underlying polynomial, which is
416    /// confusing and can lead to errors.
417    ///
418    /// A note on “leading” vs “trailing”:
419    /// The polynomial 0·x³ + 2x² + 42 has a spuriuous _leading_ zero, which
420    /// translates into a spurious _trailing_ zero in its encoding.
421    #[error("trailing zeros in polynomial-encoding")]
422    TrailingZerosInPolynomialEncoding,
423
424    #[error(transparent)]
425    Other(#[from] BFieldCodecError),
426}
427
428impl<T> BFieldCodec for Polynomial<'_, T>
429where
430    T: BFieldCodec + FiniteField + 'static,
431{
432    type Error = PolynomialBFieldCodecError;
433
434    fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error> {
435        if sequence.is_empty() {
436            return Err(Self::Error::Other(BFieldCodecError::EmptySequence));
437        }
438
439        let coefficients_field_length_indicator: Result<usize, _> = sequence[0].value().try_into();
440        let Ok(coefficients_field_length_indicator) = coefficients_field_length_indicator else {
441            return Err(Self::Error::Other(BFieldCodecError::InvalidLengthIndicator));
442        };
443
444        // Indicated sequence length is 1 + field size, as the size indicator takes up 1 word.
445        let indicated_sequence_length = coefficients_field_length_indicator + 1;
446        let decoded_vec = match sequence.len().cmp(&indicated_sequence_length) {
447            Ordering::Equal => Vec::<T>::decode(&sequence[1..]),
448            Ordering::Less => Err(BFieldCodecError::SequenceTooShort),
449            Ordering::Greater => Err(BFieldCodecError::SequenceTooLong),
450        }?;
451
452        let encoding_contains_trailing_zeros = decoded_vec
453            .last()
454            .is_some_and(|last_coeff| last_coeff.is_zero());
455        if encoding_contains_trailing_zeros {
456            return Err(PolynomialBFieldCodecError::TrailingZerosInPolynomialEncoding);
457        }
458
459        Ok(Box::new(Polynomial::new(*decoded_vec)))
460    }
461
462    fn encode(&self) -> Vec<BFieldElement> {
463        // The length of the coefficients field is prepended to the encoding to make the
464        // encoding consistent with a hypothetical derived implementation.
465        let coefficients_encoded = self.coefficients().to_owned().encode();
466        [bfe_vec!(coefficients_encoded.len()), coefficients_encoded].concat()
467    }
468
469    fn static_length() -> Option<usize> {
470        None
471    }
472}
473
474/// The core of the [`BFieldCodec`] decoding logic for `Vec<T>` and `[T; N]`.
475/// Decoding the length-prepending must be handled by the caller (if necessary).
476fn bfield_codec_decode_list<T: BFieldCodec>(
477    indicated_num_items: usize,
478    sequence: &[BFieldElement],
479) -> Result<Vec<T>, BFieldCodecError> {
480    let vec = if T::static_length().is_some() {
481        bfield_codec_decode_list_with_statically_sized_items(indicated_num_items, sequence)?
482    } else {
483        bfield_codec_decode_list_with_dynamically_sized_items(indicated_num_items, sequence)?
484    };
485    Ok(vec)
486}
487
488fn bfield_codec_decode_list_with_statically_sized_items<T: BFieldCodec>(
489    num_items: usize,
490    sequence: &[BFieldElement],
491) -> Result<Vec<T>, BFieldCodecError> {
492    let item_length = T::static_length().unwrap();
493    let maybe_vector_size = num_items.checked_mul(item_length);
494    let Some(vector_size) = maybe_vector_size else {
495        return Err(BFieldCodecError::InvalidLengthIndicator);
496    };
497    if sequence.len() < vector_size {
498        return Err(BFieldCodecError::SequenceTooShort);
499    }
500    if sequence.len() > vector_size {
501        return Err(BFieldCodecError::SequenceTooLong);
502    }
503
504    // `chunks_exact` panics on argument 0
505    if item_length == 0 {
506        let vec = (0..num_items).map(|_| *T::decode(&[]).unwrap()).collect();
507        return Ok(vec);
508    }
509
510    // Initializing the vector with the indicated capacity allows a DOS.
511    let mut vec = Vec::new();
512    for raw_item in sequence.chunks_exact(item_length) {
513        let item = *T::decode(raw_item).map_err(|e| e.into())?;
514        vec.push(item);
515    }
516    Ok(vec)
517}
518
519fn bfield_codec_decode_list_with_dynamically_sized_items<T: BFieldCodec>(
520    num_items: usize,
521    sequence: &[BFieldElement],
522) -> Result<Vec<T>, BFieldCodecError> {
523    // Initializing the vector with the indicated capacity potentially allows a DOS.
524    let mut vec = vec![];
525    let mut sequence_index = 0;
526    for _ in 0..num_items {
527        let item_length = sequence
528            .get(sequence_index)
529            .ok_or(BFieldCodecError::MissingLengthIndicator)?;
530        let item_length = usize::try_from(item_length)?;
531        sequence_index += 1;
532        if sequence.len() < sequence_index + item_length {
533            return Err(BFieldCodecError::SequenceTooShort);
534        }
535        let item = *T::decode(&sequence[sequence_index..sequence_index + item_length])
536            .map_err(|e| e.into())?;
537        sequence_index += item_length;
538        vec.push(item);
539    }
540    if sequence.len() != sequence_index {
541        return Err(BFieldCodecError::SequenceTooLong);
542    }
543    Ok(vec)
544}
545
546/// The core of the [`BFieldCodec`] encoding logic for `Vec<T>` and `[T; N]`.
547/// Encoding the length-prepending must be handled by the caller (if necessary).
548fn bfield_codec_encode_list<T: BFieldCodec>(elements: Iter<T>) -> Vec<BFieldElement> {
549    if T::static_length().is_some() {
550        return elements.flat_map(|elem| elem.encode()).collect();
551    }
552
553    let mut encoding = vec![];
554    for element in elements {
555        let element_encoded = element.encode();
556        encoding.push(element_encoded.len().into());
557        encoding.extend(element_encoded);
558    }
559    encoding
560}
561
562impl BFieldCodec for () {
563    type Error = BFieldCodecError;
564
565    fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error> {
566        sequence
567            .is_empty()
568            .then(|| Box::new(()))
569            .ok_or_else(|| BFieldCodecError::SequenceTooLong)
570    }
571
572    fn encode(&self) -> Vec<BFieldElement> {
573        Vec::new()
574    }
575
576    fn static_length() -> Option<usize> {
577        Some(0)
578    }
579}
580
581impl<T> BFieldCodec for PhantomData<T> {
582    type Error = BFieldCodecError;
583
584    fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error> {
585        sequence
586            .is_empty()
587            .then(|| Box::new(PhantomData))
588            .ok_or_else(|| BFieldCodecError::SequenceTooLong)
589    }
590
591    fn encode(&self) -> Vec<BFieldElement> {
592        Vec::new()
593    }
594
595    fn static_length() -> Option<usize> {
596        Some(0)
597    }
598}
599
600#[cfg(test)]
601#[cfg_attr(coverage_nightly, coverage(off))]
602mod tests {
603    use num_traits::ConstZero;
604    use num_traits::Zero;
605    use proptest::collection::size_range;
606    use proptest::collection::vec;
607    use proptest::prelude::*;
608    use proptest::test_runner::TestCaseResult;
609    use proptest_arbitrary_adapter::arb;
610
611    use super::*;
612    use crate::prelude::*;
613    use crate::tests::proptest;
614    use crate::tests::test;
615
616    #[derive(Debug, PartialEq, Eq, test_strategy::Arbitrary)]
617    struct BFieldCodecPropertyTestData<T>
618    where
619        T: 'static + BFieldCodec + Eq + Debug + Clone + for<'a> arbitrary::Arbitrary<'a>,
620    {
621        #[strategy(arb())]
622        value: T,
623
624        #[strategy(Just(#value.encode()))]
625        encoding: Vec<BFieldElement>,
626
627        #[strategy(vec(arb(), #encoding.len()))]
628        #[filter(#encoding.iter().zip(#random_encoding.iter()).all(|(a, b)| a != b))]
629        random_encoding: Vec<BFieldElement>,
630
631        #[any(size_range(1..128).lift())]
632        encoding_lengthener: Vec<BFieldElement>,
633
634        #[strategy(0..=#encoding.len())]
635        length_of_too_short_sequence: usize,
636    }
637
638    impl<T> BFieldCodecPropertyTestData<T>
639    where
640        T: 'static + BFieldCodec + Eq + Debug + Clone + for<'a> arbitrary::Arbitrary<'a>,
641    {
642        fn assert_bfield_codec_properties(&self) -> TestCaseResult {
643            self.assert_static_length_is_equal_to_encoded_length()?;
644            self.assert_decoded_encoding_is_self()?;
645            self.assert_decoding_too_long_encoding_fails()?;
646            self.assert_decoding_too_short_encoding_fails()?;
647            self.modify_each_element_and_assert_decoding_failure()?;
648            self.assert_decoding_random_too_short_encoding_fails_gracefully()?;
649            Ok(())
650        }
651
652        fn assert_static_length_is_equal_to_encoded_length(&self) -> TestCaseResult {
653            if let Some(static_len) = T::static_length() {
654                prop_assert_eq!(static_len, self.encoding.len());
655            }
656            Ok(())
657        }
658
659        fn assert_decoded_encoding_is_self(&self) -> TestCaseResult {
660            let Ok(decoding) = T::decode(&self.encoding) else {
661                let err = TestCaseError::Fail("decoding canonical encoding must not fail".into());
662                return Err(err);
663            };
664            prop_assert_eq!(&self.value, &*decoding);
665            Ok(())
666        }
667
668        fn assert_decoding_too_long_encoding_fails(&self) -> TestCaseResult {
669            let mut too_long_encoding = self.encoding.to_owned();
670            too_long_encoding.extend(self.encoding_lengthener.to_owned());
671            prop_assert!(T::decode(&too_long_encoding).is_err());
672            Ok(())
673        }
674
675        fn assert_decoding_too_short_encoding_fails(&self) -> TestCaseResult {
676            if self.failure_assertions_for_decoding_too_short_sequence_is_not_meaningful() {
677                return Ok(());
678            }
679            let mut encoded = self.encoding.to_owned();
680            encoded.pop();
681            prop_assert!(T::decode(&encoded).is_err());
682            Ok(())
683        }
684
685        fn modify_each_element_and_assert_decoding_failure(&self) -> TestCaseResult {
686            let mut encoding = self.encoding.to_owned();
687            for i in 0..encoding.len() {
688                let original_value = encoding[i];
689                encoding[i] = self.random_encoding[i];
690                let decoding = T::decode(&encoding);
691                if decoding.is_ok_and(|d| *d == self.value) {
692                    return Err(TestCaseError::Fail(format!("failing index: {i}").into()));
693                }
694                encoding[i] = original_value;
695            }
696            Ok(())
697        }
698
699        fn assert_decoding_random_too_short_encoding_fails_gracefully(&self) -> TestCaseResult {
700            if self.failure_assertions_for_decoding_too_short_sequence_is_not_meaningful() {
701                return Ok(());
702            }
703
704            let random_encoding =
705                self.random_encoding[..self.length_of_too_short_sequence].to_vec();
706            let decoding_result = T::decode(&random_encoding);
707            if decoding_result.is_ok_and(|d| *d == self.value) {
708                return Err(TestCaseError::Fail("randomness mustn't be `self`".into()));
709            }
710            Ok(())
711        }
712
713        fn failure_assertions_for_decoding_too_short_sequence_is_not_meaningful(&self) -> bool {
714            self.encoding.is_empty()
715        }
716    }
717
718    macro_rules! test_case {
719        (fn $fn_name:ident for $t:ty: $static_len:expr) => {
720            #[macro_rules_attr::apply(proptest)]
721            fn $fn_name(test_data: BFieldCodecPropertyTestData<$t>) {
722                prop_assert_eq!($static_len, <$t as BFieldCodec>::static_length());
723                test_data.assert_bfield_codec_properties()?;
724            }
725        };
726    }
727
728    macro_rules! neg_test_case {
729        (fn $fn_name:ident for $t:ty) => {
730            #[macro_rules_attr::apply(proptest)]
731            fn $fn_name(random_encoding: Vec<BFieldElement>) {
732                let decoding = <$t as BFieldCodec>::decode(&random_encoding);
733                prop_assert!(decoding.is_err());
734            }
735        };
736    }
737
738    test_case! { fn test_u8 for u8: Some(1) }
739    test_case! { fn test_i8 for i8: Some(1) }
740    test_case! { fn test_u16 for u16: Some(1) }
741    test_case! { fn test_i16 for i16: Some(1) }
742    test_case! { fn test_u32 for u32: Some(1) }
743    test_case! { fn test_i32 for i32: Some(1) }
744    test_case! { fn test_u64 for u64: Some(2) }
745    test_case! { fn test_i64 for i64: Some(2) }
746    test_case! { fn test_u128 for u128: Some(4) }
747    test_case! { fn test_i128 for i128: Some(4) }
748    test_case! { fn bfieldelement for BFieldElement: Some(1) }
749    test_case! { fn xfieldelement for XFieldElement: Some(3) }
750    test_case! { fn digest for Digest: Some(5) }
751    test_case! { fn vec_of_bfieldelement for Vec<BFieldElement>: None }
752    test_case! { fn vec_of_xfieldelement for Vec<XFieldElement>: None }
753    test_case! { fn vec_of_digest for Vec<Digest>: None }
754    test_case! { fn vec_of_vec_of_bfieldelement for Vec<Vec<BFieldElement>>: None }
755    test_case! { fn vec_of_vec_of_xfieldelement for Vec<Vec<XFieldElement>>: None }
756    test_case! { fn vec_of_vec_of_digest for Vec<Vec<Digest>>: None }
757    test_case! { fn poly_bfe for Polynomial<'static, BFieldElement>: None }
758    test_case! { fn poly_xfe for Polynomial<'static, XFieldElement>: None }
759    test_case! { fn tuples_static_static_size_0 for (Digest, u128): Some(9) }
760    test_case! { fn tuples_static_static_size_1 for (Digest, u64): Some(7) }
761    test_case! { fn tuples_static_static_size_2 for (BFieldElement, BFieldElement): Some(2) }
762    test_case! { fn tuples_static_static_size_3 for (BFieldElement, XFieldElement): Some(4) }
763    test_case! { fn tuples_static_static_size_4 for (XFieldElement, BFieldElement): Some(4) }
764    test_case! { fn tuples_static_static_size_5 for (XFieldElement, Digest): Some(8) }
765    test_case! { fn tuples_static_static_size_6 for (u8, u16, u32, u64): Some(5) }
766    test_case! { fn tuples_static_static_size_7 for (u8,): Some(1) }
767    test_case! { fn tuples_static_dynamic_size_0 for (u32, Vec<u32>): None }
768    test_case! { fn tuples_static_dynamic_size_1 for (u32, Vec<u64>): None }
769    test_case! { fn tuples_static_dynamic_size_2 for (Digest, Vec<BFieldElement>): None }
770    test_case! { fn tuples_static_dynamic_size_3 for (Vec<BFieldElement>,): None }
771    test_case! { fn tuples_dynamic_static_size for (Vec<XFieldElement>, Digest): None }
772    test_case! { fn tuples_dynamic_dynamic_size for (Vec<XFieldElement>, Vec<Digest>): None }
773    test_case! { fn unit for (): Some(0) }
774    test_case! { fn phantom_data for PhantomData<Tip5>: Some(0) }
775    test_case! { fn boxed_u32s for Box<u32>: Some(1) }
776    test_case! { fn tuple_with_boxed_bfe for (u64, Box<BFieldElement>): Some(3) }
777    test_case! { fn tuple_with_boxed_digest for (u128, Box<Digest>): Some(9) }
778    test_case! { fn vec_of_boxed_tuple_of_u128_and_bfe for Vec<(u128, Box<BFieldElement>)>: None }
779    test_case! { fn vec_option_xfieldelement for Vec<Option<XFieldElement>>: None }
780    test_case! { fn array_with_static_element_size for [u64; 14]: Some(28) }
781    test_case! { fn array_with_dynamic_element_size for [Vec<Digest>; 19]: None }
782
783    neg_test_case! { fn vec_of_bfield_element_neg for Vec<BFieldElement> }
784    neg_test_case! { fn vec_of_xfield_elements_neg for Vec<XFieldElement> }
785    neg_test_case! { fn vec_of_digests_neg for Vec<Digest> }
786    neg_test_case! { fn vec_of_vec_of_bfield_elements_neg for Vec<Vec<BFieldElement>> }
787    neg_test_case! { fn vec_of_vec_of_xfield_elements_neg for Vec<Vec<XFieldElement>> }
788    neg_test_case! { fn poly_of_bfe_neg for Polynomial<BFieldElement> }
789    neg_test_case! { fn poly_of_xfe_neg for Polynomial<XFieldElement> }
790
791    #[macro_rules_attr::apply(test)]
792    fn encoding_tuple_puts_fields_in_expected_order() {
793        let encoding = (1_u8, 2_u16, 3_u32, 4_u64, true).encode();
794        let expected = bfe_vec![1, 4, 0, 3, 2, 1];
795        assert_eq!(expected, encoding);
796    }
797
798    #[macro_rules_attr::apply(test)]
799    fn leading_zero_coefficient_have_no_effect_on_encoding_empty_poly_bfe() {
800        let empty_poly = Polynomial::<BFieldElement>::new(vec![]);
801        assert_eq!(empty_poly.encode(), Polynomial::new(bfe_vec![0]).encode());
802    }
803
804    #[macro_rules_attr::apply(test)]
805    fn leading_zero_coefficients_have_no_effect_on_encoding_empty_poly_xfe() {
806        let empty_poly = Polynomial::<XFieldElement>::new(vec![]);
807        assert_eq!(empty_poly.encode(), Polynomial::new(xfe_vec![0]).encode());
808    }
809
810    #[macro_rules_attr::apply(proptest)]
811    fn leading_zero_coefficients_have_no_effect_on_encoding_poly_bfe_pbt(
812        polynomial: Polynomial<'static, BFieldElement>,
813        #[strategy(0usize..30)] num_leading_zeros: usize,
814    ) {
815        let encoded = polynomial.encode();
816
817        let mut coefficients = polynomial.into_coefficients();
818        coefficients.extend(vec![BFieldElement::ZERO; num_leading_zeros]);
819        let poly_w_leading_zeros = Polynomial::new(coefficients);
820
821        prop_assert_eq!(encoded, poly_w_leading_zeros.encode());
822    }
823
824    #[macro_rules_attr::apply(proptest)]
825    fn leading_zero_coefficients_have_no_effect_on_encoding_poly_xfe_pbt(
826        polynomial: Polynomial<'static, XFieldElement>,
827        #[strategy(0usize..30)] num_leading_zeros: usize,
828    ) {
829        let encoded = polynomial.encode();
830
831        let mut coefficients = polynomial.into_coefficients();
832        coefficients.extend(vec![XFieldElement::ZERO; num_leading_zeros]);
833        let poly_w_leading_zeros = Polynomial::new(coefficients);
834
835        prop_assert_eq!(encoded, poly_w_leading_zeros.encode());
836    }
837
838    fn disallow_trailing_zeros_in_poly_encoding_prop<FF>(
839        polynomial: Polynomial<FF>,
840        leading_coefficient: FF,
841        num_leading_zeros: usize,
842    ) -> TestCaseResult
843    where
844        FF: FiniteField + BFieldCodec + 'static,
845    {
846        let mut polynomial_coefficients = polynomial.into_coefficients();
847        polynomial_coefficients.push(leading_coefficient);
848        let actual_polynomial = Polynomial::new(polynomial_coefficients.clone());
849        let vec_encoding = actual_polynomial.coefficients().to_vec().encode();
850        let poly_encoding = actual_polynomial.encode();
851        prop_assert_eq!(
852            [bfe_vec!(vec_encoding.len()), vec_encoding].concat(),
853            poly_encoding,
854            "This test expects similarity of Vec and Polynomial encoding"
855        );
856
857        polynomial_coefficients.extend(vec![FF::ZERO; num_leading_zeros]);
858        let coefficient_encoding = polynomial_coefficients.encode();
859        let poly_encoding_with_leading_zeros =
860            [bfe_vec!(coefficient_encoding.len()), coefficient_encoding].concat();
861        let decoding_result = Polynomial::<FF>::decode(&poly_encoding_with_leading_zeros);
862        prop_assert!(matches!(
863            decoding_result.unwrap_err(),
864            PolynomialBFieldCodecError::TrailingZerosInPolynomialEncoding
865        ));
866
867        Ok(())
868    }
869
870    #[macro_rules_attr::apply(proptest)]
871    fn disallow_trailing_zeros_in_poly_encoding_bfe(
872        polynomial: Polynomial<'static, BFieldElement>,
873        #[filter(!#leading_coefficient.is_zero())] leading_coefficient: BFieldElement,
874        #[strategy(1usize..30)] num_leading_zeros: usize,
875    ) {
876        disallow_trailing_zeros_in_poly_encoding_prop(
877            polynomial,
878            leading_coefficient,
879            num_leading_zeros,
880        )?
881    }
882
883    #[macro_rules_attr::apply(proptest)]
884    fn disallow_trailing_zeros_in_poly_encoding_xfe(
885        polynomial: Polynomial<'static, XFieldElement>,
886        #[filter(!#leading_coefficient.is_zero())] leading_coefficient: XFieldElement,
887        #[strategy(1usize..30)] num_leading_zeros: usize,
888    ) {
889        disallow_trailing_zeros_in_poly_encoding_prop(
890            polynomial,
891            leading_coefficient,
892            num_leading_zeros,
893        )?
894    }
895
896    /// Depending on the test helper [`BFieldCodecPropertyTestData`] in the bfieldcodec_derive crate
897    /// would introduce an almost-cyclic dependency.[^1] This would make publishing to crates.io
898    /// quite difficult. Hence, integration tests in the bfieldcodec_derive crate are also off the
899    /// table. Consequently, we test the derive macro here.
900    ///
901    /// See also: https://github.com/rust-lang/cargo/issues/8379#issuecomment-1261970561
902    ///
903    /// [^1]: almost-cyclic because the dependency would be a dev-dependency
904    pub mod derive {
905        use arbitrary::Arbitrary;
906        use num_traits::Zero;
907
908        use super::*;
909        use crate::math::x_field_element::XFieldElement;
910        use crate::tests::proptest;
911        use crate::tests::test;
912        use crate::tip5::Digest;
913        use crate::tip5::Tip5;
914        use crate::util_types::mmr::mmr_accumulator::MmrAccumulator;
915        use crate::util_types::mmr::mmr_membership_proof::MmrMembershipProof;
916
917        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
918        struct UnitStruct;
919
920        test_case! { fn unit_struct for UnitStruct: Some(0) }
921
922        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
923        struct StructWithUnitStruct {
924            a: UnitStruct,
925        }
926
927        test_case! { fn struct_with_unit_struct for StructWithUnitStruct: Some(0) }
928
929        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
930        enum EnumWithUnitStruct {
931            A(UnitStruct),
932            B,
933        }
934
935        test_case! { fn enum_with_unit_struct for EnumWithUnitStruct: Some(1) }
936
937        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
938        struct DeriveTestStructA {
939            field_a: u64,
940            field_b: u64,
941            field_c: u64,
942        }
943
944        test_case! { fn struct_a for DeriveTestStructA: Some(6) }
945
946        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
947        struct DeriveTestStructB(u128);
948
949        test_case! { fn struct_b for DeriveTestStructB: Some(4) }
950
951        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
952        struct DeriveTestStructC(u128, u64, u32);
953
954        test_case! { fn struct_c for DeriveTestStructC: Some(7) }
955
956        // Struct containing Vec<T> where T is BFieldCodec
957        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
958        struct DeriveTestStructD(Vec<u128>);
959
960        test_case! { fn struct_d for DeriveTestStructD: None }
961
962        // Structs containing Polynomial<T> where T is BFieldCodec
963        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
964        struct DeriveTestStructWithBfePolynomialField(Polynomial<'static, BFieldElement>);
965
966        test_case! {
967            fn struct_with_bfe_poly_field for DeriveTestStructWithBfePolynomialField: None
968        }
969
970        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
971        struct DeriveTestStructWithXfePolynomialField(Polynomial<'static, XFieldElement>);
972
973        test_case! {
974            fn struct_with_xfe_poly_field for DeriveTestStructWithXfePolynomialField: None
975        }
976
977        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
978        enum EnumWithVariantWithPolyField {
979            Bee,
980            BooBoo(Polynomial<'static, BFieldElement>),
981            Bop(Polynomial<'static, XFieldElement>),
982        }
983
984        test_case! { fn enum_with_variant_with_poly_field for EnumWithVariantWithPolyField: None }
985        neg_test_case! { fn enum_with_variant_with_poly_field_neg for EnumWithVariantWithPolyField }
986
987        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
988        struct DeriveTestStructE(Vec<u128>, u128, u64, Vec<bool>, u32, Vec<u128>);
989
990        test_case! { fn struct_e for DeriveTestStructE: None }
991
992        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
993        struct DeriveTestStructF {
994            field_a: Vec<u64>,
995            field_b: bool,
996            field_c: u32,
997            field_d: Vec<bool>,
998            field_e: Vec<BFieldElement>,
999            field_f: Vec<BFieldElement>,
1000        }
1001
1002        test_case! { fn struct_f for DeriveTestStructF: None }
1003
1004        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1005        struct WithPhantomData<FF: FiniteField> {
1006            a_field: u128,
1007            #[bfield_codec(ignore)]
1008            _phantom_data: PhantomData<FF>,
1009            another_field: Vec<u64>,
1010        }
1011
1012        test_case! { fn with_phantom_data for WithPhantomData<BFieldElement>: None }
1013
1014        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1015        struct WithNestedPhantomData<FF: FiniteField> {
1016            a_field: u128,
1017            #[bfield_codec(ignore)]
1018            _phantom_data: PhantomData<FF>,
1019            another_field: Vec<u64>,
1020            a_third_field: Vec<WithPhantomData<FF>>,
1021            a_fourth_field: WithPhantomData<BFieldElement>,
1022        }
1023
1024        test_case! { fn with_nested_phantom_data for WithNestedPhantomData<XFieldElement>: None }
1025
1026        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1027        struct WithNestedVec {
1028            a_field: Vec<Vec<u64>>,
1029        }
1030
1031        test_case! { fn with_nested_vec for WithNestedVec: None }
1032
1033        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1034        struct VecWithZst(Vec<()>);
1035
1036        /// Because Zero-Sized Types don't take up space in the encoding,
1037        /// many of the usual checks are nonsensical.
1038        #[macro_rules_attr::apply(proptest)]
1039        fn vec_with_zst(test_data: BFieldCodecPropertyTestData<VecWithZst>) {
1040            prop_assert!(VecWithZst::static_length().is_none());
1041            test_data.assert_decoding_too_long_encoding_fails()?;
1042            test_data.assert_decoded_encoding_is_self()?;
1043        }
1044
1045        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1046        struct EmptyStruct {}
1047
1048        test_case! { fn empty_struct for EmptyStruct: Some(0) }
1049
1050        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1051        struct StructWithEmptyStruct {
1052            a: EmptyStruct,
1053        }
1054
1055        test_case! { fn struct_with_empty_struct for StructWithEmptyStruct: Some(0) }
1056
1057        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1058        struct StructWithTwoEmptyStructs {
1059            a: EmptyStruct,
1060            b: EmptyStruct,
1061        }
1062
1063        test_case! { fn struct_with_two_empty_structs for StructWithTwoEmptyStructs: Some(0) }
1064
1065        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1066        struct BigStructWithEmptyStructs {
1067            a: EmptyStruct,
1068            b: EmptyStruct,
1069            c: StructWithTwoEmptyStructs,
1070            d: StructWithEmptyStruct,
1071            e: EmptyStruct,
1072        }
1073
1074        test_case! { fn big_struct_with_empty_structs for BigStructWithEmptyStructs: Some(0) }
1075
1076        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1077        enum EnumWithEmptyStruct {
1078            A(EmptyStruct),
1079            B,
1080            C(EmptyStruct),
1081        }
1082
1083        test_case! { fn enum_with_empty_struct for EnumWithEmptyStruct: Some(1) }
1084
1085        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1086        struct MuchNesting {
1087            a: Vec<Vec<Vec<Vec<BFieldElement>>>>,
1088            #[bfield_codec(ignore)]
1089            b: PhantomData<Tip5>,
1090            #[bfield_codec(ignore)]
1091            c: PhantomData<Tip5>,
1092        }
1093
1094        test_case! { fn much_nesting for MuchNesting: None }
1095
1096        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1097        struct SmallArrayStructUnnamedFields([u128; 1]);
1098
1099        test_case! {
1100            fn small_array_struct_unnamed_fields for SmallArrayStructUnnamedFields: Some(4)
1101        }
1102
1103        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1104        struct SmallArrayStructNamedFields {
1105            a: [u128; 1],
1106        }
1107
1108        test_case! { fn small_array_struct_named_fields for SmallArrayStructNamedFields: Some(4) }
1109
1110        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1111        struct BigArrayStructUnnamedFields([u128; 150]);
1112
1113        test_case! {
1114            fn big_array_struct_unnamed_fields for BigArrayStructUnnamedFields: Some(4 * 150)
1115        }
1116
1117        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1118        struct BigArrayStructNamedFields {
1119            a: [XFieldElement; 150],
1120            b: XFieldElement,
1121            c: u64,
1122        }
1123
1124        test_case! {
1125            fn big_array_struct_named_fields for BigArrayStructNamedFields: Some(3 * 150 + 3 + 2)
1126        }
1127
1128        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1129        struct ArrayStructDynamicallySizedElementsUnnamedFields([Vec<u128>; 7]);
1130
1131        test_case! {
1132            fn array_struct_dyn_sized_elements_unnamed_fields
1133            for ArrayStructDynamicallySizedElementsUnnamedFields: None
1134        }
1135
1136        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1137        struct ArrayStructDynamicallySizedElementsNamedFields {
1138            a: [Vec<u128>; 7],
1139        }
1140
1141        test_case! {
1142            fn array_struct_dyn_sized_elements_named_fields
1143            for ArrayStructDynamicallySizedElementsNamedFields: None
1144        }
1145
1146        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1147        struct StructWithTupleField {
1148            a: (Digest, Vec<Digest>),
1149        }
1150
1151        test_case! { fn struct_with_tuple_field for StructWithTupleField: None }
1152
1153        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1154        struct StructWithTupleFieldTwoElements {
1155            a: ([Digest; 2], XFieldElement),
1156        }
1157
1158        test_case! {
1159            fn struct_with_tuple_field_two_elements for StructWithTupleFieldTwoElements: Some(13)
1160        }
1161
1162        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1163        struct StructWithNestedTupleField {
1164            a: (([Digest; 2], Vec<XFieldElement>), (XFieldElement, u64)),
1165        }
1166
1167        test_case! { fn struct_with_nested_tuple_field for StructWithNestedTupleField: None }
1168
1169        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1170        struct MsMembershipProof {
1171            sender_randomness: Digest,
1172            receiver_preimage: Digest,
1173            auth_path_aocl: MmrMembershipProof,
1174        }
1175
1176        test_case! { fn ms_membership_proof for MsMembershipProof: None }
1177        test_case! { fn mmr_accumulator for MmrAccumulator: None }
1178
1179        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1180        struct UnsupportedFields {
1181            a: u64,
1182            #[bfield_codec(ignore)]
1183            b: usize,
1184        }
1185
1186        #[macro_rules_attr::apply(proptest)]
1187        fn unsupported_fields_can_be_ignored_test(#[strategy(arb())] my_struct: UnsupportedFields) {
1188            let encoded = my_struct.encode();
1189            let decoded = UnsupportedFields::decode(&encoded).unwrap();
1190            prop_assert_eq!(my_struct.a, decoded.a);
1191            prop_assert_eq!(usize::default(), decoded.b);
1192        }
1193
1194        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1195        struct OneFixedLenField {
1196            some_digest: Digest,
1197        }
1198
1199        test_case! { fn one_fixed_len_field for OneFixedLenField: Some(5) }
1200
1201        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1202        pub struct TwoFixedLenFields {
1203            pub some_digest: Digest,
1204            pub some_u64: u64,
1205        }
1206
1207        test_case! { fn two_fixed_len_fields for TwoFixedLenFields: Some(7) }
1208
1209        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1210        pub struct TwoFixedLenUnnamedFields(Digest, u64);
1211
1212        test_case! { fn two_fixed_len_unnamed_fields for TwoFixedLenUnnamedFields: Some(7) }
1213
1214        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1215        pub struct FixAndVarLenFields {
1216            pub some_digest: Digest,
1217            pub some_vec: Vec<u64>,
1218        }
1219
1220        test_case! { fn fix_and_var_len_fields for FixAndVarLenFields: None }
1221
1222        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1223        struct FixAndVarLenUnnamedFields(Digest, Vec<u64>);
1224
1225        test_case! { fn fix_and_var_len_unnamed_fields for FixAndVarLenUnnamedFields: None }
1226
1227        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1228        struct QuiteAFewFixAndVarLenFields {
1229            some_digest: Digest,
1230            some_vec: Vec<u64>,
1231            some_u64: u64,
1232            other_vec: Vec<u32>,
1233            other_digest: Digest,
1234            yet_another_vec: Vec<u32>,
1235            and_another_vec: Vec<u64>,
1236            more_fixed_len: u64,
1237            even_more_fixed_len: u64,
1238        }
1239
1240        test_case! { fn quite_a_few_fix_and_var_len_fields for QuiteAFewFixAndVarLenFields: None }
1241
1242        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1243        struct SimpleStructA {
1244            a: BFieldElement,
1245            b: XFieldElement,
1246        }
1247
1248        test_case! { fn simple_struct_a for SimpleStructA: Some(4) }
1249
1250        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1251        struct SimpleStructB(u32, u64);
1252
1253        test_case! { fn simple_struct_b for SimpleStructB: Some(3) }
1254
1255        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1256        struct StructWithBox {
1257            a: Box<u64>,
1258        }
1259
1260        test_case! { fn struct_with_box for StructWithBox: Some(2) }
1261
1262        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1263        struct TupleStructWithBox(Box<u64>);
1264
1265        test_case! { fn tuple_struct_with_box for TupleStructWithBox: Some(2) }
1266
1267        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1268        struct StructWithBoxContainingStructWithBox {
1269            a: Box<StructWithBox>,
1270            b: Box<TupleStructWithBox>,
1271        }
1272
1273        test_case! {
1274            fn struct_with_box_containing_struct_with_box
1275            for StructWithBoxContainingStructWithBox: Some(4)
1276        }
1277
1278        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1279        enum SimpleEnum {
1280            A,
1281            B(u32),
1282            C(BFieldElement, u32, u32),
1283        }
1284
1285        test_case! { fn simple_enum for SimpleEnum: None }
1286
1287        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1288        enum ComplexEnum {
1289            A,
1290            B(u32),
1291            C(BFieldElement, XFieldElement, u32),
1292            D(Vec<BFieldElement>, Digest),
1293            E(Option<bool>),
1294        }
1295
1296        test_case! { fn complex_enum for ComplexEnum: None }
1297
1298        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1299        enum EnumWithUniformDataSize {
1300            A(Digest),
1301            B(Digest),
1302            C(Digest),
1303        }
1304
1305        test_case! { fn enum_with_uniform_data_size for EnumWithUniformDataSize: Some(6) }
1306
1307        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1308        enum EnumWithIrregularDataSize {
1309            A(u32),
1310            B,
1311            C(Digest),
1312            D(Vec<XFieldElement>),
1313        }
1314
1315        test_case! { fn enum_with_irregular_data_size for EnumWithIrregularDataSize: None }
1316
1317        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1318        enum EnumWithGenerics<I: Into<u64>> {
1319            A(I),
1320            B(I, I),
1321        }
1322
1323        test_case! { fn enum_with_generics for EnumWithGenerics<u32>: None }
1324
1325        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1326        enum EnumWithGenericsAndWhereClause<I: Into<u64>>
1327        where
1328            I: Debug + Copy + Eq,
1329        {
1330            A,
1331            B(I),
1332            C(I, I),
1333        }
1334
1335        test_case! {
1336            fn enum_with_generics_and_where_clause for EnumWithGenericsAndWhereClause<u32>: None
1337        }
1338
1339        #[macro_rules_attr::apply(test)]
1340        fn enums_bfield_codec_discriminant_can_be_accessed() {
1341            let a = EnumWithGenericsAndWhereClause::<u32>::A;
1342            let b = EnumWithGenericsAndWhereClause::<u32>::B(1);
1343            let c = EnumWithGenericsAndWhereClause::<u32>::C(1, 2);
1344            assert_eq!(0, a.bfield_codec_discriminant());
1345            assert_eq!(1, b.bfield_codec_discriminant());
1346            assert_eq!(2, c.bfield_codec_discriminant());
1347        }
1348
1349        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1350        enum EnumWithBoxedVariant {
1351            A(Box<u64>),
1352            B(Box<u64>, Box<u64>),
1353        }
1354
1355        test_case! { fn enum_with_boxed_variant for EnumWithBoxedVariant: None }
1356
1357        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1358        enum EnumWithBoxedVariantAndBoxedStruct {
1359            A(Box<StructWithBox>),
1360            B(Box<StructWithBox>, Box<TupleStructWithBox>),
1361        }
1362
1363        test_case! {
1364            fn enum_with_boxed_variant_and_boxed_struct for EnumWithBoxedVariantAndBoxedStruct: None
1365        }
1366
1367        #[derive(Debug, Clone, PartialEq, Eq, BFieldCodec, Arbitrary)]
1368        struct DummyPolynomial<T: FiniteField + BFieldCodec> {
1369            coefficients: Vec<T>,
1370        }
1371
1372        #[macro_rules_attr::apply(proptest)]
1373        fn manual_poly_encoding_implementation_is_consistent_with_derived_bfe(
1374            #[strategy(arb())] coefficients: Vec<BFieldElement>,
1375        ) {
1376            manual_poly_encoding_implementation_is_consistent_with_derived(coefficients)?;
1377        }
1378
1379        #[macro_rules_attr::apply(proptest)]
1380        fn manual_poly_encoding_implementation_is_consistent_with_derived_xfe(
1381            #[strategy(arb())] coefficients: Vec<XFieldElement>,
1382        ) {
1383            manual_poly_encoding_implementation_is_consistent_with_derived(coefficients)?;
1384        }
1385
1386        fn manual_poly_encoding_implementation_is_consistent_with_derived<FF>(
1387            coefficients: Vec<FF>,
1388        ) -> TestCaseResult
1389        where
1390            FF: FiniteField + BFieldCodec + 'static,
1391        {
1392            if coefficients.last().is_some_and(Zero::is_zero) {
1393                let rsn = "`DummyPolynomial::encode` only works for non-zero leading coefficients";
1394                return Err(TestCaseError::Reject(rsn.into()));
1395            }
1396
1397            let polynomial = Polynomial::new(coefficients.clone());
1398            let dummy_polynomial = DummyPolynomial { coefficients };
1399            prop_assert_eq!(dummy_polynomial.encode(), polynomial.encode());
1400            Ok(())
1401        }
1402    }
1403}