mirror of
https://github.com/saymrwulf/risc0-curve25519-dalek-source.git
synced 2026-09-09 20:50:40 +00:00
Use parallel carry-ins and carry-outs in FieldElement64::reduce()
This commit is contained in:
parent
d8d235fb48
commit
ec50ec96f7
1 changed files with 43 additions and 19 deletions
|
|
@ -78,8 +78,7 @@ impl<'a, 'b> Sub<&'b FieldElement64> for &'a FieldElement64 {
|
||||||
// just bigger than _rhs and avoid having to do a reduction.
|
// just bigger than _rhs and avoid having to do a reduction.
|
||||||
//
|
//
|
||||||
// Since we don't yet have type-level integers to do this, we
|
// Since we don't yet have type-level integers to do this, we
|
||||||
// have to add an explicit reduction call here, which is a
|
// have to add an explicit reduction call here.
|
||||||
// somewhat significant cost.
|
|
||||||
FieldElement64::reduce([
|
FieldElement64::reduce([
|
||||||
(self.0[0] + 36028797018963664u64) - _rhs.0[0],
|
(self.0[0] + 36028797018963664u64) - _rhs.0[0],
|
||||||
(self.0[1] + 36028797018963952u64) - _rhs.0[1],
|
(self.0[1] + 36028797018963952u64) - _rhs.0[1],
|
||||||
|
|
@ -200,20 +199,39 @@ impl FieldElement64 {
|
||||||
FieldElement64([2251799813685228, 2251799813685247, 2251799813685247, 2251799813685247, 2251799813685247])
|
FieldElement64([2251799813685228, 2251799813685247, 2251799813685247, 2251799813685247, 2251799813685247])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given 64-bit limbs, reduce to enforce the bound c_i < 2^51.
|
/// Given 64-bit input limbs, reduce to enforce the bound 2^(51 + eps).
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn reduce(mut limbs: [u64; 5]) -> FieldElement64 {
|
fn reduce(mut limbs: [u64; 5]) -> FieldElement64 {
|
||||||
let low_51_bit_mask = (1u64 << 51) - 1;
|
const LOW_51_BIT_MASK: u64 = (1u64 << 51) - 1;
|
||||||
limbs[1] += limbs[0] >> 51;
|
|
||||||
limbs[0] = limbs[0] & low_51_bit_mask;
|
// Since the input limbs are bounded by 2^64, the biggest
|
||||||
limbs[2] += limbs[1] >> 51;
|
// carry-out is bounded by 2^13.
|
||||||
limbs[1] = limbs[1] & low_51_bit_mask;
|
//
|
||||||
limbs[3] += limbs[2] >> 51;
|
// The biggest carry-in is c4 * 19, resulting in
|
||||||
limbs[2] = limbs[2] & low_51_bit_mask;
|
//
|
||||||
limbs[4] += limbs[3] >> 51;
|
// 2^51 + 19*2^13 < 2^51.0000000001
|
||||||
limbs[3] = limbs[3] & low_51_bit_mask;
|
//
|
||||||
limbs[0] += (limbs[4] >> 51) * 19;
|
// Because we don't need to canonicalize, only to reduce the
|
||||||
limbs[4] = limbs[4] & low_51_bit_mask;
|
// limb sizes, it's OK to do a "weak reduction", where we
|
||||||
|
// compute the carry-outs in parallel.
|
||||||
|
|
||||||
|
let c0 = limbs[0] >> 51;
|
||||||
|
let c1 = limbs[1] >> 51;
|
||||||
|
let c2 = limbs[2] >> 51;
|
||||||
|
let c3 = limbs[3] >> 51;
|
||||||
|
let c4 = limbs[4] >> 51;
|
||||||
|
|
||||||
|
limbs[0] &= LOW_51_BIT_MASK;
|
||||||
|
limbs[1] &= LOW_51_BIT_MASK;
|
||||||
|
limbs[2] &= LOW_51_BIT_MASK;
|
||||||
|
limbs[3] &= LOW_51_BIT_MASK;
|
||||||
|
limbs[4] &= LOW_51_BIT_MASK;
|
||||||
|
|
||||||
|
limbs[0] += c4 * 19;
|
||||||
|
limbs[1] += c0;
|
||||||
|
limbs[2] += c1;
|
||||||
|
limbs[3] += c2;
|
||||||
|
limbs[4] += c3;
|
||||||
|
|
||||||
FieldElement64(limbs)
|
FieldElement64(limbs)
|
||||||
}
|
}
|
||||||
|
|
@ -260,18 +278,24 @@ impl FieldElement64 {
|
||||||
/// Serialize this `FieldElement64` to a 32-byte array. The
|
/// Serialize this `FieldElement64` to a 32-byte array. The
|
||||||
/// encoding is canonical.
|
/// encoding is canonical.
|
||||||
pub fn to_bytes(&self) -> [u8; 32] {
|
pub fn to_bytes(&self) -> [u8; 32] {
|
||||||
// This reduces to the range [0,2^255), but we need [0,2^255-19).
|
|
||||||
let mut limbs = FieldElement64::reduce(self.0).0;
|
|
||||||
|
|
||||||
// Let h = limbs[0] + limbs[1]*2^51 + ... + limbs[4]*2^204.
|
// Let h = limbs[0] + limbs[1]*2^51 + ... + limbs[4]*2^204.
|
||||||
//
|
//
|
||||||
// Write h = pq + r with 0 <= r < p. We want to compute r = h mod p.
|
// Write h = pq + r with 0 <= r < p.
|
||||||
//
|
//
|
||||||
// Since h < 2^255, q = 0 or 1, with q = 0 when h < p and q = 1 when h >= p.
|
// We want to compute r = h mod p.
|
||||||
|
//
|
||||||
|
// If h < 2*p = 2^256 - 38,
|
||||||
|
// then q = 0 or 1,
|
||||||
|
//
|
||||||
|
// with q = 0 when h < p
|
||||||
|
// and q = 1 when h >= p.
|
||||||
//
|
//
|
||||||
// Notice that h >= p <==> h + 19 >= p + 19 <==> h + 19 >= 2^255.
|
// Notice that h >= p <==> h + 19 >= p + 19 <==> h + 19 >= 2^255.
|
||||||
// Therefore q can be computed as the carry bit of h + 19.
|
// Therefore q can be computed as the carry bit of h + 19.
|
||||||
|
|
||||||
|
// First, reduce the limbs to ensure h < 2*p.
|
||||||
|
let mut limbs = FieldElement64::reduce(self.0).0;
|
||||||
|
|
||||||
let mut q = (limbs[0] + 19) >> 51;
|
let mut q = (limbs[0] + 19) >> 51;
|
||||||
q = (limbs[1] + q) >> 51;
|
q = (limbs[1] + q) >> 51;
|
||||||
q = (limbs[2] + q) >> 51;
|
q = (limbs[2] + q) >> 51;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue