Skip to main content

zinc_utils/field/
boxed_monty.rs

1use crate::{from_ref::FromRef, projectable_to_field::ProjectableToField};
2use crypto_primitives::{
3    ProjectElementWithConfig, SetConfig, Wrapper,
4    crypto_bigint_boxed_monty::{BoxedMontyField, BoxedMontyFieldElement},
5    crypto_bigint_boxed_uint::BoxedUint,
6    crypto_bigint_uint::Uint,
7};
8
9impl FromRef<Self> for BoxedMontyFieldElement {
10    fn from_ref(value: &Self) -> Self {
11        value.clone()
12    }
13}
14
15impl<const LIMBS: usize> FromRef<Uint<LIMBS>> for BoxedUint {
16    #[inline]
17    fn from_ref(value: &Uint<LIMBS>) -> Self {
18        value.inner().into()
19    }
20}
21
22impl<T> ProjectableToField<BoxedMontyField> for T
23where
24    BoxedMontyField: ProjectElementWithConfig<T>,
25{
26    fn prepare_projection(
27        cfg: &BoxedMontyField,
28        _sampled_value: &<BoxedMontyField as SetConfig>::Element,
29    ) -> impl Fn(&Self) -> <BoxedMontyField as SetConfig>::Element {
30        let cfg = cfg.clone();
31        move |value: &T| cfg.project(value)
32    }
33}
34
35#[cfg(test)]
36#[allow(
37    clippy::arithmetic_side_effects,
38    clippy::cast_possible_truncation,
39    clippy::cast_possible_wrap
40)]
41mod prop_tests {
42    use crypto_primitives::{
43        BaseFieldConfig, ProjectElementWithConfig, SemiringConfig,
44        crypto_bigint_boxed_monty::BoxedMontyField,
45        crypto_bigint_boxed_uint::BoxedUint,
46        crypto_bigint_uint::{U256, Uint},
47    };
48    use proptest::prelude::*;
49    use std::str::FromStr;
50
51    const MODULUS: &str = "00dca94d8a1ecce3b6e8755d8999787d0524d8ca1ea755e7af84fb646fa31f27";
52
53    fn get_dyn_config(hex_modulus: &str) -> BoxedMontyField {
54        let modulus =
55            BoxedUint::from_str(&format!("0x{hex_modulus}")).expect("Invalid modulus hex string");
56        BoxedMontyField::new(&modulus).expect("Failed to create field config")
57    }
58
59    fn any_u128() -> impl Strategy<Value = u128> {
60        any::<u128>()
61    }
62    fn any_i128() -> impl Strategy<Value = i128> {
63        any::<i128>()
64    }
65    fn any_bool() -> impl Strategy<Value = bool> {
66        any::<bool>()
67    }
68
69    proptest! {
70        #[test]
71        #[cfg_attr(miri, ignore)] // long running
72        fn prop_from_unsigned_matches_sum_of_bits(x in any_u128()) {
73            let cfg = get_dyn_config(MODULUS);
74            let f = cfg.project(&x);
75            let mut acc = cfg.zero();
76            for i in 0..128 {
77                if (x >> i) & 1 == 1 {
78                    let bit = cfg.mul(&cfg.project(&1u64), &cfg.project(&(1u64 << i.min(63))));
79                    cfg.add_assign(&mut acc, &bit);
80                }
81            }
82            let u = Uint::<{ U256::LIMBS }>::from(x);
83            let g2 = cfg.project(&u);
84            prop_assert_eq!(f, g2);
85        }
86
87        #[test]
88        #[cfg_attr(miri, ignore)] // long running
89        fn prop_from_signed_is_neg_of_abs_when_negative(x in any_i128()) {
90            let cfg = get_dyn_config(MODULUS);
91            let f = cfg.project(&x);
92            let abs = x.unsigned_abs();
93            let g_abs = cfg.project(&abs);
94            if x < 0 {
95                prop_assert_eq!(cfg.add(&f, &g_abs), cfg.zero());
96            } else {
97                prop_assert_eq!(f, g_abs);
98            }
99        }
100
101        #[test]
102        #[cfg_attr(miri, ignore)] // long running
103        fn prop_from_bool_is_identity(b in any_bool()) {
104            let cfg = get_dyn_config(MODULUS);
105            let f = cfg.project(&b);
106            prop_assert_eq!(f, if b { cfg.one() } else { cfg.zero() });
107        }
108
109        #[test]
110        #[cfg_attr(miri, ignore)] // long running
111        fn prop_from_uint_roundtrip_through_uint(x in any_u128()) {
112            let cfg = get_dyn_config(MODULUS);
113            let u = BoxedUint::from(x).resize(cfg.bits_precision());
114            let g_from_uint = cfg.project(&u);
115            let g_direct = cfg.project(&x);
116            prop_assert_eq!(g_from_uint, g_direct);
117        }
118    }
119}