1use elliptic_curve::bigint::{Limb, U256, modular::ConstMontyParams};
4
5const MODULUS: &[Limb; 4] = super::FieldParams::PARAMS.modulus().as_ref().as_limbs();
6
7pub(super) const fn add(a: &U256, b: &U256) -> U256 {
8 let a = a.as_limbs();
9 let b = b.as_limbs();
10
11 let (w0, carry) = a[0].carrying_add(b[0], Limb::ZERO);
13 let (w1, carry) = a[1].carrying_add(b[1], carry);
14 let (w2, carry) = a[2].carrying_add(b[2], carry);
15 let (w3, w4) = a[3].carrying_add(b[3], carry);
16
17 let (result, _) = sub_inner(
19 [w0, w1, w2, w3, w4],
20 [MODULUS[0], MODULUS[1], MODULUS[2], MODULUS[3], Limb::ZERO],
21 );
22 U256::new([result[0], result[1], result[2], result[3]])
23}
24
25pub(super) const fn sub(a: &U256, b: &U256) -> U256 {
26 let a = a.as_limbs();
27 let b = b.as_limbs();
28
29 let (result, _) = sub_inner(
30 [a[0], a[1], a[2], a[3], Limb::ZERO],
31 [b[0], b[1], b[2], b[3], Limb::ZERO],
32 );
33 U256::new([result[0], result[1], result[2], result[3]])
34}
35
36#[inline]
37pub(super) const fn to_canonical(a: &U256) -> U256 {
38 montgomery_reduce(a, &U256::ZERO)
39}
40
41#[inline]
82#[allow(clippy::too_many_arguments)]
83pub(super) const fn montgomery_reduce(lo: &U256, hi: &U256) -> U256 {
84 let lo = lo.as_limbs();
85 let hi = hi.as_limbs();
86
87 let a0 = lo[0];
88 let a1 = lo[1];
89 let a2 = lo[2];
90 let a3 = lo[3];
91 let a4 = hi[0];
92 let a5 = hi[1];
93 let a6 = hi[2];
94 let a7 = hi[3];
95
96 let (a1, carry) = a0.carrying_mul_add(MODULUS[1], a1, a0);
97 let (a2, carry) = a2.carrying_add(Limb::ZERO, carry);
98 let (a3, carry) = a0.carrying_mul_add(MODULUS[3], a3, carry);
99 let (a4, carry2) = a4.carrying_add(Limb::ZERO, carry);
100
101 let (a2, carry) = a1.carrying_mul_add(MODULUS[1], a2, a1);
102 let (a3, carry) = a3.carrying_add(Limb::ZERO, carry);
103 let (a4, carry) = a1.carrying_mul_add(MODULUS[3], a4, carry);
104 let (a5, carry2) = a5.carrying_add(carry2, carry);
105
106 let (a3, carry) = a2.carrying_mul_add(MODULUS[1], a3, a2);
107 let (a4, carry) = a4.carrying_add(Limb::ZERO, carry);
108 let (a5, carry) = a2.carrying_mul_add(MODULUS[3], a5, carry);
109 let (a6, carry2) = a6.carrying_add(carry2, carry);
110
111 let (a4, carry) = a3.carrying_mul_add(MODULUS[1], a4, a3);
112 let (a5, carry) = a5.carrying_add(Limb::ZERO, carry);
113 let (a6, carry) = a3.carrying_mul_add(MODULUS[3], a6, carry);
114 let (a7, a8) = a7.carrying_add(carry2, carry);
115
116 let (result, _) = sub_inner(
118 [a4, a5, a6, a7, a8],
119 [MODULUS[0], MODULUS[1], MODULUS[2], MODULUS[3], Limb::ZERO],
120 );
121
122 U256::new([result[0], result[1], result[2], result[3]])
123}
124
125#[inline]
126#[allow(clippy::too_many_arguments)]
127const fn sub_inner(l: [Limb; 5], r: [Limb; 5]) -> ([Limb; 4], Limb) {
128 let (w0, borrow) = l[0].borrowing_sub(r[0], Limb::ZERO);
129 let (w1, borrow) = l[1].borrowing_sub(r[1], borrow);
130 let (w2, borrow) = l[2].borrowing_sub(r[2], borrow);
131 let (w3, borrow) = l[3].borrowing_sub(r[3], borrow);
132 let (_, borrow) = l[4].borrowing_sub(r[4], borrow);
133
134 let (w0, carry) = w0.carrying_add(MODULUS[0].bitand(borrow), Limb::ZERO);
139 let (w1, carry) = w1.carrying_add(MODULUS[1].bitand(borrow), carry);
140 let (w2, carry) = w2.carrying_add(MODULUS[2].bitand(borrow), carry);
141 let (w3, _) = w3.carrying_add(MODULUS[3].bitand(borrow), carry);
142
143 ([w0, w1, w2, w3], borrow)
144}