class_groups/crypto_bigint/
uint.rs1#![expect(clippy::inline_always)]
2
3use crypto_bigint::{Choice, CtEq as _, Encoding, Concat, SplitEven, One as _, NonZero, Uint};
4
5impl<const LIMBS: usize, const WIDE_LIMBS: usize> super::c::Limbs for Uint<LIMBS>
6where
7 Self: Concat<LIMBS, Output = Uint<WIDE_LIMBS>>,
8 Uint<WIDE_LIMBS>: SplitEven<Output = Self>,
9{
10 #[inline(always)]
11 fn widening_square(&self) -> (Self, Self) {
12 Uint::<LIMBS>::widening_square(self)
13 }
14 #[inline(always)]
15 fn wrapping_div(num: (Self, Self), denom: &Self) -> Self {
16 let concatenated = num.0.concat(&num.1);
17 let quotient = concatenated / *denom;
18 quotient.split().0
19 }
20 #[inline(always)]
21 fn rem(num: Self, denom: &Self) -> Self {
22 num.div_rem(&NonZero::new(*denom).unwrap()).1
23 }
24}
25
26impl<const LIMBS: usize> super::reduction::Limbs for Uint<LIMBS> {
27 #[inline(always)]
28 fn like_zero(&self) -> Self {
29 Self::ZERO
30 }
31}
32
33impl<const LIMBS: usize, const WIDE_LIMBS: usize> super::composition::Limbs for Uint<LIMBS>
34where
35 Self: Concat<LIMBS, Output = Uint<WIDE_LIMBS>>,
36 Uint<WIDE_LIMBS>: SplitEven<Output = Self>,
37{
38 type Wide = <Self as Concat<LIMBS>>::Output;
39 #[expect(private_interfaces)]
40 fn xgcd(self, other: Self) -> super::composition::Xgcd<Self> {
41 let xgcd = Uint::xgcd(&self, &other);
42 super::composition::Xgcd {
43 d: xgcd.gcd,
44 u: (xgcd.x.is_positive(), xgcd.x.abs()),
45 v: (xgcd.y.is_positive(), xgcd.y.abs()),
46 }
47 }
48 #[inline(always)]
49 fn div(self, denom: &Self) -> Self {
50 self.div_rem(&NonZero::new(*denom).unwrap()).0
51 }
52 #[inline(always)]
53 fn mul_mod(&self, other: &Self, modulus: &Self) -> Self {
54 self.mul_mod(other, &NonZero::new(*modulus).unwrap())
55 }
56 #[inline(always)]
57 fn mul(&self, other: &Self) -> Self::Wide {
58 self.concatenating_mul(other)
59 }
60 #[inline(always)]
61 fn square(&self) -> Self::Wide {
62 self.concatenating_square()
63 }
64}
65
66impl<const LIMBS: usize, const WIDE_LIMBS: usize>
67 super::composition::WideLimbs<<Self as SplitEven>::Output> for Uint<WIDE_LIMBS>
68where
69 Uint<WIDE_LIMBS>: SplitEven<Output = Uint<LIMBS>>,
70{
71 #[inline(always)]
72 fn rem(self, denom: &<Self as SplitEven>::Output) -> <Self as SplitEven>::Output {
73 self.div_rem(&NonZero::new(*denom).unwrap()).1
74 }
75}
76
77struct StitchedBytes<const WIDE_LIMBS: usize>
78where
79 Uint<WIDE_LIMBS>: Encoding,
80{
81 buf: <Uint<WIDE_LIMBS> as Encoding>::Repr,
82 len: usize,
83}
84
85impl<const WIDE_LIMBS: usize> AsRef<[u8]> for StitchedBytes<WIDE_LIMBS>
86where
87 Uint<WIDE_LIMBS>: Encoding,
88{
89 fn as_ref(&self) -> &[u8] {
90 &self.buf.as_ref()[.. self.len]
91 }
92}
93
94impl<const LIMBS: usize, const WIDE_LIMBS: usize> super::encoding::Limbs for Uint<LIMBS>
95where
96 Self: Concat<LIMBS, Output = Uint<WIDE_LIMBS>>,
97 Uint<WIDE_LIMBS>: SplitEven<Output = Self>,
98{
99 fn wide_div_rem_thin(wide: Self::Wide, thin: &NonZero<Self>) -> (Self::Wide, Self) {
100 wide.div_rem(thin)
101 }
102
103 fn coprime(a: Self, b_abs: Self, c: Self::Wide) -> Choice {
104 a.gcd(&b_abs).concat(&Self::ZERO).gcd(&c).is_one()
105 }
106}
107
108impl<const LIMBS: usize, const WIDE_LIMBS: usize> super::element::Limbs for Uint<LIMBS>
109where
110 Self: Encoding<Repr: Default> + Concat<LIMBS, Output = Uint<WIDE_LIMBS>>,
111 Uint<WIDE_LIMBS>: Encoding<Repr: Default> + SplitEven<Output = Self> + super::c::Limbs,
112{
113 type Bytes = crypto_bigint::EncodedUint<LIMBS>;
114
115 #[inline(always)]
116 fn max_bits() -> Option<u32> {
117 Some(Self::BITS)
118 }
119
120 #[inline(always)]
121 fn truncate(wide: Self::Wide, _bits: u32) -> Self {
122 wide.split().0
123 }
124 #[inline(always)]
125 fn widen(thin: Self, _wide_bits: u32) -> Self::Wide {
126 thin.concat(&Uint::ZERO)
127 }
128
129 #[inline(always)]
130 fn to_le_bytes(self) -> Self::Bytes {
131 Self::to_le_bytes(&self)
132 }
133 #[inline(always)]
134 fn wide_to_le_bytes(wide: Self::Wide) -> impl AsRef<[u8]> {
135 Self::Wide::to_le_bytes(&wide)
136 }
137
138 #[inline(always)]
139 fn from_le_slice(bytes: &[u8], max_bits: u32) -> Self {
140 assert!(max_bits <= Self::BITS);
141
142 let mut fixed_bytes = <Self as Encoding>::Repr::default();
143 {
144 let fixed_bytes = fixed_bytes.as_mut();
145 let mutual_len = fixed_bytes.len().min(bytes.len());
146 for b in bytes.iter().skip(mutual_len) {
147 assert!(bool::from(b.ct_eq(&0)));
148 }
149 fixed_bytes[.. mutual_len].copy_from_slice(&bytes[.. mutual_len]);
150 }
151
152 Self::from_le_bytes(fixed_bytes)
153 }
154 #[inline(always)]
155 fn wide_from_le_slice(bytes: &[u8], max_bits: u32) -> Self::Wide {
156 assert!(max_bits <= Self::Wide::BITS);
157
158 let mut fixed_bytes = <Uint<WIDE_LIMBS> as Encoding>::Repr::default();
159 {
160 let fixed_bytes = fixed_bytes.as_mut();
161 let mutual_len = fixed_bytes.len().min(bytes.len());
162 for b in bytes.iter().skip(mutual_len) {
163 assert!(bool::from(b.ct_eq(&0)));
164 }
165 fixed_bytes[.. mutual_len].copy_from_slice(&bytes[.. mutual_len]);
166 }
167
168 Self::Wide::from_le_bytes(fixed_bytes)
169 }
170
171 fn stitch(first: Self::Bytes, second: Self::Bytes, bytes_per_element: usize) -> impl AsRef<[u8]> {
172 let mut buf = <Self::Wide as Encoding>::Repr::default();
173 buf.as_mut()[.. bytes_per_element].copy_from_slice(&first.as_ref()[.. bytes_per_element]);
174 buf.as_mut()[bytes_per_element .. (2 * bytes_per_element)]
175 .copy_from_slice(&second.as_ref()[.. bytes_per_element]);
176 StitchedBytes::<WIDE_LIMBS> { buf, len: 2 * bytes_per_element }
177 }
178}