Skip to main content

class_groups/crypto_bigint/
uint.rs

1#![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}