Skip to content

Commit 5c2f763

Browse files
committed
Add EdwardsPoint::from_affine_coordinates (const)
Builds on #816. Resolves #817.
1 parent b70643a commit 5c2f763

File tree

6 files changed

+321
-214
lines changed

6 files changed

+321
-214
lines changed

curve25519-dalek/src/backend/serial/fiat_u32/field.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,20 @@ impl Zeroize for FieldElement2625 {
7070
}
7171
}
7272

73-
impl<'b> AddAssign<&'b FieldElement2625> for FieldElement2625 {
74-
fn add_assign(&mut self, rhs: &'b FieldElement2625) {
73+
impl FieldElement2625 {
74+
pub(crate) const fn const_add_assign(&mut self, _rhs: &FieldElement2625) -> FieldElement2625 {
7575
let mut result_loose = fiat_25519_loose_field_element([0; 10]);
7676
fiat_25519_add(&mut result_loose, &self.0, &rhs.0);
7777
fiat_25519_carry(&mut self.0, &result_loose);
7878
}
7979
}
8080

81+
impl<'b> AddAssign<&'b FieldElement2625> for FieldElement2625 {
82+
fn add_assign(&mut self, rhs: &'b FieldElement2625) {
83+
self.const_add_assign(rhs)
84+
}
85+
}
86+
8187
impl<'a, 'b> Add<&'b FieldElement2625> for &'a FieldElement2625 {
8288
type Output = FieldElement2625;
8389
fn add(self, rhs: &'b FieldElement2625) -> FieldElement2625 {
@@ -118,9 +124,8 @@ impl<'b> MulAssign<&'b FieldElement2625> for FieldElement2625 {
118124
}
119125
}
120126

121-
impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 {
122-
type Output = FieldElement2625;
123-
fn mul(self, rhs: &'b FieldElement2625) -> FieldElement2625 {
127+
impl FieldElement2625 {
128+
pub(crate) const fn const_mul(&self, rhs: &FieldElement2625) -> FieldElement2625 {
124129
let mut self_loose = fiat_25519_loose_field_element([0; 10]);
125130
fiat_25519_relax(&mut self_loose, &self.0);
126131
let mut rhs_loose = fiat_25519_loose_field_element([0; 10]);
@@ -131,6 +136,13 @@ impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 {
131136
}
132137
}
133138

139+
impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 {
140+
type Output = FieldElement2625;
141+
fn mul(self, rhs: &'b FieldElement2625) -> FieldElement2625 {
142+
self.const_mul(rhs)
143+
}
144+
}
145+
134146
impl<'a> Neg for &'a FieldElement2625 {
135147
type Output = FieldElement2625;
136148
fn neg(self) -> FieldElement2625 {

curve25519-dalek/src/backend/serial/fiat_u64/field.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,20 @@ impl Zeroize for FieldElement51 {
5959
}
6060
}
6161

62-
impl<'b> AddAssign<&'b FieldElement51> for FieldElement51 {
63-
fn add_assign(&mut self, rhs: &'b FieldElement51) {
62+
impl FieldElement51 {
63+
pub(crate) const fn const_add_assign(&mut self, rhs: &FieldElement51) {
6464
let mut result_loose = fiat_25519_loose_field_element([0; 5]);
6565
fiat_25519_add(&mut result_loose, &self.0, &rhs.0);
6666
fiat_25519_carry(&mut self.0, &result_loose);
6767
}
6868
}
6969

70+
impl<'b> AddAssign<&'b FieldElement51> for FieldElement51 {
71+
fn add_assign(&mut self, rhs: &'b FieldElement51) {
72+
self.const_add_assign(rhs)
73+
}
74+
}
75+
7076
impl<'a, 'b> Add<&'b FieldElement51> for &'a FieldElement51 {
7177
type Output = FieldElement51;
7278
fn add(self, rhs: &'b FieldElement51) -> FieldElement51 {
@@ -107,9 +113,8 @@ impl<'b> MulAssign<&'b FieldElement51> for FieldElement51 {
107113
}
108114
}
109115

110-
impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 {
111-
type Output = FieldElement51;
112-
fn mul(self, rhs: &'b FieldElement51) -> FieldElement51 {
116+
impl FieldElement51 {
117+
pub(crate) const fn const_mul(&self, rhs: &FieldElement51) -> FieldElement51 {
113118
let mut self_loose = fiat_25519_loose_field_element([0; 5]);
114119
fiat_25519_relax(&mut self_loose, &self.0);
115120
let mut rhs_loose = fiat_25519_loose_field_element([0; 5]);
@@ -120,6 +125,13 @@ impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 {
120125
}
121126
}
122127

128+
impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 {
129+
type Output = FieldElement51;
130+
fn mul(self, rhs: &'b FieldElement51) -> FieldElement51 {
131+
self.const_mul(rhs)
132+
}
133+
}
134+
123135
impl<'a> Neg for &'a FieldElement51 {
124136
type Output = FieldElement51;
125137
fn neg(self) -> FieldElement51 {

curve25519-dalek/src/backend/serial/u32/field.rs

Lines changed: 116 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,22 @@ impl Zeroize for FieldElement2625 {
6666
}
6767
}
6868

69-
impl<'b> AddAssign<&'b FieldElement2625> for FieldElement2625 {
70-
fn add_assign(&mut self, _rhs: &'b FieldElement2625) {
71-
for i in 0..10 {
69+
impl FieldElement2625 {
70+
pub(crate) const fn const_add_assign(&mut self, _rhs: &FieldElement2625) -> FieldElement2625 {
71+
let mut i = 0;
72+
while i < 10 {
7273
self.0[i] += _rhs.0[i];
74+
i += 1;
7375
}
7476
}
7577
}
7678

79+
impl<'b> AddAssign<&'b FieldElement2625> for FieldElement2625 {
80+
fn add_assign(&mut self, _rhs: &'b FieldElement2625) {
81+
self.const_add_assign(_rhs)
82+
}
83+
}
84+
7785
impl<'a, 'b> Add<&'b FieldElement2625> for &'a FieldElement2625 {
7886
type Output = FieldElement2625;
7987
fn add(self, _rhs: &'b FieldElement2625) -> FieldElement2625 {
@@ -121,109 +129,115 @@ impl<'b> MulAssign<&'b FieldElement2625> for FieldElement2625 {
121129
}
122130
}
123131

132+
impl FieldElement2625 {
133+
#[rustfmt::skip] // keep alignment of z* calculations
134+
pub(crate) const fn const_mul(&self, _rhs: & FieldElement2625) -> FieldElement2625 {
135+
/// Helper function to multiply two 32-bit integers with 64 bits
136+
/// of output.
137+
#[inline(always)]
138+
const fn m(x: u32, y: u32) -> u64 {
139+
(x as u64) * (y as u64)
140+
}
141+
142+
// Alias self, _rhs for more readable formulas
143+
let x: &[u32; 10] = &self.0;
144+
let y: &[u32; 10] = &_rhs.0;
145+
146+
// We assume that the input limbs x[i], y[i] are bounded by:
147+
//
148+
// x[i], y[i] < 2^(26 + b) if i even
149+
// x[i], y[i] < 2^(25 + b) if i odd
150+
//
151+
// where b is a (real) parameter representing the excess bits of
152+
// the limbs. We track the bitsizes of all variables through
153+
// the computation and solve at the end for the allowable
154+
// headroom bitsize b (which determines how many additions we
155+
// can perform between reductions or multiplications).
156+
157+
let y1_19 = 19 * y[1]; // This fits in a u32
158+
let y2_19 = 19 * y[2]; // iff 26 + b + lg(19) < 32
159+
let y3_19 = 19 * y[3]; // if b < 32 - 26 - 4.248 = 1.752
160+
let y4_19 = 19 * y[4];
161+
let y5_19 = 19 * y[5]; // below, b<2.5: this is a bottleneck,
162+
let y6_19 = 19 * y[6]; // could be avoided by promoting to
163+
let y7_19 = 19 * y[7]; // u64 here instead of in m()
164+
let y8_19 = 19 * y[8];
165+
let y9_19 = 19 * y[9];
166+
167+
// What happens when we multiply x[i] with y[j] and place the
168+
// result into the (i+j)-th limb?
169+
//
170+
// x[i] represents the value x[i]*2^ceil(i*51/2)
171+
// y[j] represents the value y[j]*2^ceil(j*51/2)
172+
// z[i+j] represents the value z[i+j]*2^ceil((i+j)*51/2)
173+
// x[i]*y[j] represents the value x[i]*y[i]*2^(ceil(i*51/2)+ceil(j*51/2))
174+
//
175+
// Since the radix is already accounted for, the result placed
176+
// into the (i+j)-th limb should be
177+
//
178+
// x[i]*y[i]*2^(ceil(i*51/2)+ceil(j*51/2) - ceil((i+j)*51/2)).
179+
//
180+
// The value of ceil(i*51/2)+ceil(j*51/2) - ceil((i+j)*51/2) is
181+
// 1 when both i and j are odd, and 0 otherwise. So we add
182+
//
183+
// x[i]*y[j] if either i or j is even
184+
// 2*x[i]*y[j] if i and j are both odd
185+
//
186+
// by using precomputed multiples of x[i] for odd i:
187+
188+
let x1_2 = 2 * x[1]; // This fits in a u32 iff 25 + b + 1 < 32
189+
let x3_2 = 2 * x[3]; // iff b < 6
190+
let x5_2 = 2 * x[5];
191+
let x7_2 = 2 * x[7];
192+
let x9_2 = 2 * x[9];
193+
194+
let z0 = m(x[0], y[0]) + m(x1_2, y9_19) + m(x[2], y8_19) + m(x3_2, y7_19) + m(x[4], y6_19) + m(x5_2, y5_19) + m(x[6], y4_19) + m(x7_2, y3_19) + m(x[8], y2_19) + m(x9_2, y1_19);
195+
let z1 = m(x[0], y[1]) + m(x[1], y[0]) + m(x[2], y9_19) + m(x[3], y8_19) + m(x[4], y7_19) + m(x[5], y6_19) + m(x[6], y5_19) + m(x[7], y4_19) + m(x[8], y3_19) + m(x[9], y2_19);
196+
let z2 = m(x[0], y[2]) + m(x1_2, y[1]) + m(x[2], y[0]) + m(x3_2, y9_19) + m(x[4], y8_19) + m(x5_2, y7_19) + m(x[6], y6_19) + m(x7_2, y5_19) + m(x[8], y4_19) + m(x9_2, y3_19);
197+
let z3 = m(x[0], y[3]) + m(x[1], y[2]) + m(x[2], y[1]) + m(x[3], y[0]) + m(x[4], y9_19) + m(x[5], y8_19) + m(x[6], y7_19) + m(x[7], y6_19) + m(x[8], y5_19) + m(x[9], y4_19);
198+
let z4 = m(x[0], y[4]) + m(x1_2, y[3]) + m(x[2], y[2]) + m(x3_2, y[1]) + m(x[4], y[0]) + m(x5_2, y9_19) + m(x[6], y8_19) + m(x7_2, y7_19) + m(x[8], y6_19) + m(x9_2, y5_19);
199+
let z5 = m(x[0], y[5]) + m(x[1], y[4]) + m(x[2], y[3]) + m(x[3], y[2]) + m(x[4], y[1]) + m(x[5], y[0]) + m(x[6], y9_19) + m(x[7], y8_19) + m(x[8], y7_19) + m(x[9], y6_19);
200+
let z6 = m(x[0], y[6]) + m(x1_2, y[5]) + m(x[2], y[4]) + m(x3_2, y[3]) + m(x[4], y[2]) + m(x5_2, y[1]) + m(x[6], y[0]) + m(x7_2, y9_19) + m(x[8], y8_19) + m(x9_2, y7_19);
201+
let z7 = m(x[0], y[7]) + m(x[1], y[6]) + m(x[2], y[5]) + m(x[3], y[4]) + m(x[4], y[3]) + m(x[5], y[2]) + m(x[6], y[1]) + m(x[7], y[0]) + m(x[8], y9_19) + m(x[9], y8_19);
202+
let z8 = m(x[0], y[8]) + m(x1_2, y[7]) + m(x[2], y[6]) + m(x3_2, y[5]) + m(x[4], y[4]) + m(x5_2, y[3]) + m(x[6], y[2]) + m(x7_2, y[1]) + m(x[8], y[0]) + m(x9_2, y9_19);
203+
let z9 = m(x[0], y[9]) + m(x[1], y[8]) + m(x[2], y[7]) + m(x[3], y[6]) + m(x[4], y[5]) + m(x[5], y[4]) + m(x[6], y[3]) + m(x[7], y[2]) + m(x[8], y[1]) + m(x[9], y[0]);
204+
205+
// How big is the contribution to z[i+j] from x[i], y[j]?
206+
//
207+
// Using the bounds above, we get:
208+
//
209+
// i even, j even: x[i]*y[j] < 2^(26+b)*2^(26+b) = 2*2^(51+2*b)
210+
// i odd, j even: x[i]*y[j] < 2^(25+b)*2^(26+b) = 1*2^(51+2*b)
211+
// i even, j odd: x[i]*y[j] < 2^(26+b)*2^(25+b) = 1*2^(51+2*b)
212+
// i odd, j odd: 2*x[i]*y[j] < 2*2^(25+b)*2^(25+b) = 1*2^(51+2*b)
213+
//
214+
// We perform inline reduction mod p by replacing 2^255 by 19
215+
// (since 2^255 - 19 = 0 mod p). This adds a factor of 19, so
216+
// we get the bounds (z0 is the biggest one, but calculated for
217+
// posterity here in case finer estimation is needed later):
218+
//
219+
// z0 < ( 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 249*2^(51 + 2*b)
220+
// z1 < ( 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 154*2^(51 + 2*b)
221+
// z2 < ( 2 + 1 + 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 195*2^(51 + 2*b)
222+
// z3 < ( 1 + 1 + 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 118*2^(51 + 2*b)
223+
// z4 < ( 2 + 1 + 2 + 1 + 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 141*2^(51 + 2*b)
224+
// z5 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 82*2^(51 + 2*b)
225+
// z6 < ( 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 87*2^(51 + 2*b)
226+
// z7 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1*19 + 1*19 )*2^(51 + 2b) = 46*2^(51 + 2*b)
227+
// z6 < ( 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1*19 )*2^(51 + 2b) = 33*2^(51 + 2*b)
228+
// z7 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 )*2^(51 + 2b) = 10*2^(51 + 2*b)
229+
//
230+
// So z[0] fits into a u64 if 51 + 2*b + lg(249) < 64
231+
// if b < 2.5.
232+
FieldElement2625::reduce([z0, z1, z2, z3, z4, z5, z6, z7, z8, z9])
233+
}
234+
}
235+
124236
impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 {
125237
type Output = FieldElement2625;
126238

127-
#[rustfmt::skip] // keep alignment of z* calculations
128239
fn mul(self, _rhs: &'b FieldElement2625) -> FieldElement2625 {
129-
/// Helper function to multiply two 32-bit integers with 64 bits
130-
/// of output.
131-
#[inline(always)]
132-
fn m(x: u32, y: u32) -> u64 {
133-
(x as u64) * (y as u64)
134-
}
135-
136-
// Alias self, _rhs for more readable formulas
137-
let x: &[u32; 10] = &self.0;
138-
let y: &[u32; 10] = &_rhs.0;
139-
140-
// We assume that the input limbs x[i], y[i] are bounded by:
141-
//
142-
// x[i], y[i] < 2^(26 + b) if i even
143-
// x[i], y[i] < 2^(25 + b) if i odd
144-
//
145-
// where b is a (real) parameter representing the excess bits of
146-
// the limbs. We track the bitsizes of all variables through
147-
// the computation and solve at the end for the allowable
148-
// headroom bitsize b (which determines how many additions we
149-
// can perform between reductions or multiplications).
150-
151-
let y1_19 = 19 * y[1]; // This fits in a u32
152-
let y2_19 = 19 * y[2]; // iff 26 + b + lg(19) < 32
153-
let y3_19 = 19 * y[3]; // if b < 32 - 26 - 4.248 = 1.752
154-
let y4_19 = 19 * y[4];
155-
let y5_19 = 19 * y[5]; // below, b<2.5: this is a bottleneck,
156-
let y6_19 = 19 * y[6]; // could be avoided by promoting to
157-
let y7_19 = 19 * y[7]; // u64 here instead of in m()
158-
let y8_19 = 19 * y[8];
159-
let y9_19 = 19 * y[9];
160-
161-
// What happens when we multiply x[i] with y[j] and place the
162-
// result into the (i+j)-th limb?
163-
//
164-
// x[i] represents the value x[i]*2^ceil(i*51/2)
165-
// y[j] represents the value y[j]*2^ceil(j*51/2)
166-
// z[i+j] represents the value z[i+j]*2^ceil((i+j)*51/2)
167-
// x[i]*y[j] represents the value x[i]*y[i]*2^(ceil(i*51/2)+ceil(j*51/2))
168-
//
169-
// Since the radix is already accounted for, the result placed
170-
// into the (i+j)-th limb should be
171-
//
172-
// x[i]*y[i]*2^(ceil(i*51/2)+ceil(j*51/2) - ceil((i+j)*51/2)).
173-
//
174-
// The value of ceil(i*51/2)+ceil(j*51/2) - ceil((i+j)*51/2) is
175-
// 1 when both i and j are odd, and 0 otherwise. So we add
176-
//
177-
// x[i]*y[j] if either i or j is even
178-
// 2*x[i]*y[j] if i and j are both odd
179-
//
180-
// by using precomputed multiples of x[i] for odd i:
181-
182-
let x1_2 = 2 * x[1]; // This fits in a u32 iff 25 + b + 1 < 32
183-
let x3_2 = 2 * x[3]; // iff b < 6
184-
let x5_2 = 2 * x[5];
185-
let x7_2 = 2 * x[7];
186-
let x9_2 = 2 * x[9];
187-
188-
let z0 = m(x[0], y[0]) + m(x1_2, y9_19) + m(x[2], y8_19) + m(x3_2, y7_19) + m(x[4], y6_19) + m(x5_2, y5_19) + m(x[6], y4_19) + m(x7_2, y3_19) + m(x[8], y2_19) + m(x9_2, y1_19);
189-
let z1 = m(x[0], y[1]) + m(x[1], y[0]) + m(x[2], y9_19) + m(x[3], y8_19) + m(x[4], y7_19) + m(x[5], y6_19) + m(x[6], y5_19) + m(x[7], y4_19) + m(x[8], y3_19) + m(x[9], y2_19);
190-
let z2 = m(x[0], y[2]) + m(x1_2, y[1]) + m(x[2], y[0]) + m(x3_2, y9_19) + m(x[4], y8_19) + m(x5_2, y7_19) + m(x[6], y6_19) + m(x7_2, y5_19) + m(x[8], y4_19) + m(x9_2, y3_19);
191-
let z3 = m(x[0], y[3]) + m(x[1], y[2]) + m(x[2], y[1]) + m(x[3], y[0]) + m(x[4], y9_19) + m(x[5], y8_19) + m(x[6], y7_19) + m(x[7], y6_19) + m(x[8], y5_19) + m(x[9], y4_19);
192-
let z4 = m(x[0], y[4]) + m(x1_2, y[3]) + m(x[2], y[2]) + m(x3_2, y[1]) + m(x[4], y[0]) + m(x5_2, y9_19) + m(x[6], y8_19) + m(x7_2, y7_19) + m(x[8], y6_19) + m(x9_2, y5_19);
193-
let z5 = m(x[0], y[5]) + m(x[1], y[4]) + m(x[2], y[3]) + m(x[3], y[2]) + m(x[4], y[1]) + m(x[5], y[0]) + m(x[6], y9_19) + m(x[7], y8_19) + m(x[8], y7_19) + m(x[9], y6_19);
194-
let z6 = m(x[0], y[6]) + m(x1_2, y[5]) + m(x[2], y[4]) + m(x3_2, y[3]) + m(x[4], y[2]) + m(x5_2, y[1]) + m(x[6], y[0]) + m(x7_2, y9_19) + m(x[8], y8_19) + m(x9_2, y7_19);
195-
let z7 = m(x[0], y[7]) + m(x[1], y[6]) + m(x[2], y[5]) + m(x[3], y[4]) + m(x[4], y[3]) + m(x[5], y[2]) + m(x[6], y[1]) + m(x[7], y[0]) + m(x[8], y9_19) + m(x[9], y8_19);
196-
let z8 = m(x[0], y[8]) + m(x1_2, y[7]) + m(x[2], y[6]) + m(x3_2, y[5]) + m(x[4], y[4]) + m(x5_2, y[3]) + m(x[6], y[2]) + m(x7_2, y[1]) + m(x[8], y[0]) + m(x9_2, y9_19);
197-
let z9 = m(x[0], y[9]) + m(x[1], y[8]) + m(x[2], y[7]) + m(x[3], y[6]) + m(x[4], y[5]) + m(x[5], y[4]) + m(x[6], y[3]) + m(x[7], y[2]) + m(x[8], y[1]) + m(x[9], y[0]);
198-
199-
// How big is the contribution to z[i+j] from x[i], y[j]?
200-
//
201-
// Using the bounds above, we get:
202-
//
203-
// i even, j even: x[i]*y[j] < 2^(26+b)*2^(26+b) = 2*2^(51+2*b)
204-
// i odd, j even: x[i]*y[j] < 2^(25+b)*2^(26+b) = 1*2^(51+2*b)
205-
// i even, j odd: x[i]*y[j] < 2^(26+b)*2^(25+b) = 1*2^(51+2*b)
206-
// i odd, j odd: 2*x[i]*y[j] < 2*2^(25+b)*2^(25+b) = 1*2^(51+2*b)
207-
//
208-
// We perform inline reduction mod p by replacing 2^255 by 19
209-
// (since 2^255 - 19 = 0 mod p). This adds a factor of 19, so
210-
// we get the bounds (z0 is the biggest one, but calculated for
211-
// posterity here in case finer estimation is needed later):
212-
//
213-
// z0 < ( 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 249*2^(51 + 2*b)
214-
// z1 < ( 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 154*2^(51 + 2*b)
215-
// z2 < ( 2 + 1 + 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 195*2^(51 + 2*b)
216-
// z3 < ( 1 + 1 + 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 118*2^(51 + 2*b)
217-
// z4 < ( 2 + 1 + 2 + 1 + 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 141*2^(51 + 2*b)
218-
// z5 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 82*2^(51 + 2*b)
219-
// z6 < ( 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 87*2^(51 + 2*b)
220-
// z7 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1*19 + 1*19 )*2^(51 + 2b) = 46*2^(51 + 2*b)
221-
// z6 < ( 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1*19 )*2^(51 + 2b) = 33*2^(51 + 2*b)
222-
// z7 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 )*2^(51 + 2b) = 10*2^(51 + 2*b)
223-
//
224-
// So z[0] fits into a u64 if 51 + 2*b + lg(249) < 64
225-
// if b < 2.5.
226-
FieldElement2625::reduce([z0, z1, z2, z3, z4, z5, z6, z7, z8, z9])
240+
self.const_mul(_rhs)
227241
}
228242
}
229243

0 commit comments

Comments
 (0)