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