zinc_utils/field/
const_monty.rs1use crypto_bigint::modular::{ConstMontyForm, ConstMontyParams};
2use crypto_primitives::{
3 FixedConfig, Wrapper, crypto_bigint_const_monty::ConstMontyField, crypto_bigint_int::Int,
4 crypto_bigint_uint::Uint,
5};
6
7use crate::{
8 from_ref::FromRef, mul_by_scalar::MulByScalar, projectable_to_field::ProjectableToField,
9};
10
11impl<Mod: ConstMontyParams<LIMBS>, const LIMBS: usize> MulByScalar<ConstMontyField<Mod, LIMBS>>
12 for ConstMontyField<Mod, LIMBS>
13{
14 #[allow(clippy::arithmetic_side_effects)] fn mul_by_scalar<const CHECK: bool>(
16 self,
17 rhs: &ConstMontyField<Mod, LIMBS>,
18 ) -> Option<ConstMontyField<Mod, LIMBS>> {
19 Some(self * rhs)
21 }
22}
23
24macro_rules! impl_from_primitive_ref {
25 ($($t:ty),* $(,)?) => {
26 $(
27 impl<Mod: ConstMontyParams<LIMBS>, const LIMBS: usize> FromRef<$t> for ConstMontyField<Mod, LIMBS> {
28 #![allow(clippy::arithmetic_side_effects)]
29 fn from_ref(value: &$t) -> Self {
30 Self::from(*value)
31 }
32 }
33 )*
34 };
35}
36impl_from_primitive_ref!(u8, u16, u32, u64, u128);
37
38impl<Mod: ConstMontyParams<LIMBS>, const LIMBS: usize> FromRef<Uint<LIMBS>>
39 for ConstMontyForm<Mod, LIMBS>
40{
41 fn from_ref(value: &Uint<LIMBS>) -> Self {
42 ConstMontyForm::new(value.inner())
43 }
44}
45
46impl<Mod: ConstMontyParams<LIMBS>, const LIMBS: usize> FromRef<Self>
47 for ConstMontyField<Mod, LIMBS>
48{
49 fn from_ref(value: &Self) -> Self {
50 *value
51 }
52}
53
54impl<Mod: ConstMontyParams<LIMBS>, const LIMBS: usize, const LIMBS2: usize>
56 ProjectableToField<FixedConfig<ConstMontyField<Mod, LIMBS>>> for Int<LIMBS2>
57{
58 fn prepare_projection(
59 _cfg: &FixedConfig<ConstMontyField<Mod, LIMBS>>,
60 _sampled_value: &ConstMontyField<Mod, LIMBS>,
61 ) -> impl Fn(&Self) -> ConstMontyField<Mod, LIMBS> {
62 |value: &Int<LIMBS2>| value.into()
64 }
65}
66
67#[cfg(test)]
68#[allow(
69 clippy::arithmetic_side_effects,
70 clippy::cast_possible_truncation,
71 clippy::cast_possible_wrap
72)]
73mod tests {
74 use crate::projectable_to_field::ProjectableToField;
75
76 use super::*;
77
78 use crypto_bigint::{U128, U256, const_monty_params};
79 use crypto_primitives::{crypto_bigint_const_monty::F256, crypto_bigint_int::Int};
80 use num_traits::{One, Zero};
81 use proptest::prelude::*;
82
83 const_monty_params!(
84 ModQ,
85 U256,
86 "00dca94d8a1ecce3b6e8755d8999787d0524d8ca1ea755e7af84fb646fa31f27"
87 );
88 type F = F256<ModQ>;
89
90 #[test]
91 fn prepare_projection_for_int() {
92 let sampled = F::from(5_u64);
94
95 let cfg = FixedConfig::default();
96 let projection_fn = Int::<{ U128::LIMBS }>::prepare_projection(&cfg, &sampled);
97
98 let int_value = Int::<{ U128::LIMBS }>::from(10_i64);
99 let result = projection_fn(&int_value);
100 assert_eq!(result, F::from(&int_value));
101 assert_eq!(result, F::from(10_u64));
102
103 let int_value = Int::<{ U128::LIMBS }>::from(-7_i64);
104 let result = projection_fn(&int_value);
105 assert_eq!(result, F::from(&int_value));
106 assert_eq!(result + F::from(7_u64), F::zero());
107 }
108
109 fn any_u128() -> impl Strategy<Value = u128> {
110 any::<u128>()
111 }
112 fn any_i128() -> impl Strategy<Value = i128> {
113 any::<i128>()
114 }
115 fn any_bool() -> impl Strategy<Value = bool> {
116 any::<bool>()
117 }
118
119 proptest! {
120 #[test]
121 #[cfg_attr(miri, ignore)] fn prop_from_unsigned_matches_sum_of_bits(x in any_u128()) {
123 let f = F::from(x);
124 let mut acc = F::zero();
125 for i in 0..128 {
126 if (x >> i) & 1 == 1 { acc += F::from(1u64) * F::from(1u64 << i.min(63)); }
127 }
128 let u = Uint::<{ U256::LIMBS }>::from(x);
129 let g2: F = F::from(u);
130 prop_assert_eq!(f, g2);
131 }
132
133 #[test]
134 #[cfg_attr(miri, ignore)] fn prop_from_signed_is_neg_of_abs_when_negative(x in any_i128()) {
136 let f = F::from(x);
137 let abs = x.unsigned_abs();
138 let g_abs = F::from(abs);
139 if x < 0 {
140 prop_assert_eq!(f + g_abs, F::zero());
141 } else {
142 prop_assert_eq!(f, g_abs);
143 }
144 }
145
146 #[test]
147 #[cfg_attr(miri, ignore)] fn prop_from_bool_is_identity(b in any_bool()) {
149 let f = F::from(b);
150 prop_assert_eq!(f, if b { F::one() } else { F::zero() });
151 }
152
153 #[test]
154 #[cfg_attr(miri, ignore)] fn prop_from_uint_roundtrip_through_uint(x in any_u128()) {
156 let u: Uint<{ U256::LIMBS }> = Uint::from(x);
157 let g_from_uint: F = u.into();
158 let g_direct: F = F::from(x);
159 prop_assert_eq!(g_from_uint, g_direct);
160 }
161
162 #[test]
163 #[cfg_attr(miri, ignore)] fn prop_from_ref_generic_matches_owned(x in any::<u64>()) {
165 let a: F = F::from(x);
166 let b: F = F::from(&x);
167 prop_assert_eq!(a, b);
168 }
169 }
170}