354 lines
12 KiB
Rust
354 lines
12 KiB
Rust
// Copyright (c) Facebook, Inc. and its affiliates.
|
||
//
|
||
// This source code is licensed under the MIT license found in the
|
||
// LICENSE file in the root directory of this source tree.
|
||
#![allow(clippy::let_and_return)]
|
||
|
||
//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(64\\)-bit
|
||
//! limbs with \\(128\\)-bit products.
|
||
|
||
use core::fmt::Debug;
|
||
use core::ops::Neg;
|
||
use core::ops::{Add, AddAssign};
|
||
use core::ops::{Mul, MulAssign};
|
||
|
||
use subtle::Choice;
|
||
use subtle::ConditionallyNegatable;
|
||
use subtle::ConditionallySelectable;
|
||
use subtle::ConstantTimeEq;
|
||
|
||
use zeroize::Zeroize;
|
||
|
||
use fiat_crypto::curve25519_64::*;
|
||
|
||
/// A `FieldElement51` represents an element of the field
|
||
/// \\( \mathbb Z / (2\^{255} - 19)\\).
|
||
///
|
||
/// In the 64-bit implementation, a `FieldElement` is represented in
|
||
/// radix \\(2\^{51}\\) as five `u64`s; the coefficients are allowed to
|
||
/// grow up to \\(2\^{54}\\) between reductions modulo \\(p\\).
|
||
///
|
||
/// # Note
|
||
///
|
||
/// The `curve25519_dalek::field` module provides a type alias
|
||
/// `curve25519_dalek::field::FieldElement` to either `FieldElement51`
|
||
/// or `FieldElement2625`.
|
||
///
|
||
/// The backend-specific type `FieldElement51` should not be used
|
||
/// outside of the `curve25519_dalek::field` module.
|
||
#[derive(Copy, Clone)]
|
||
pub struct FieldElement51(pub(crate) [u64; 5]);
|
||
|
||
impl Debug for FieldElement51 {
|
||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||
write!(f, "FieldElement51({:?})", &self.0[..])
|
||
}
|
||
}
|
||
|
||
impl Zeroize for FieldElement51 {
|
||
fn zeroize(&mut self) {
|
||
self.0.zeroize();
|
||
}
|
||
}
|
||
|
||
impl ConstantTimeEq for FieldElement51 {
|
||
/// Test equality between two `FieldElement`s. Since the
|
||
/// internal representation is not canonical, the field elements
|
||
/// are normalized to wire format before comparison.
|
||
fn ct_eq(&self, other: &FieldElement51) -> Choice {
|
||
self.to_bytes().ct_eq(&other.to_bytes())
|
||
}
|
||
}
|
||
|
||
impl<'b> AddAssign<&'b FieldElement51> for FieldElement51 {
|
||
fn add_assign(&mut self, _rhs: &'b FieldElement51) {
|
||
let input = self.0;
|
||
fiat_25519_add(&mut self.0, &input, &_rhs.0);
|
||
let input = self.0;
|
||
fiat_25519_carry(&mut self.0, &input);
|
||
}
|
||
}
|
||
|
||
impl<'a, 'b> Add<&'b FieldElement51> for &'a FieldElement51 {
|
||
type Output = FieldElement51;
|
||
fn add(self, _rhs: &'b FieldElement51) -> FieldElement51 {
|
||
let mut output = *self;
|
||
fiat_25519_add(&mut output.0, &self.0, &_rhs.0);
|
||
let input = output.0;
|
||
fiat_25519_carry(&mut output.0, &input);
|
||
output
|
||
}
|
||
}
|
||
|
||
impl<'b> MulAssign<&'b FieldElement51> for FieldElement51 {
|
||
fn mul_assign(&mut self, _rhs: &'b FieldElement51) {
|
||
let input = self.0;
|
||
fiat_25519_carry_mul(&mut self.0, &input, &_rhs.0);
|
||
}
|
||
}
|
||
|
||
impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 {
|
||
type Output = FieldElement51;
|
||
fn mul(self, _rhs: &'b FieldElement51) -> FieldElement51 {
|
||
let mut output = *self;
|
||
fiat_25519_carry_mul(&mut output.0, &self.0, &_rhs.0);
|
||
output
|
||
}
|
||
}
|
||
|
||
impl<'a> Neg for &'a FieldElement51 {
|
||
type Output = FieldElement51;
|
||
fn neg(self) -> FieldElement51 {
|
||
let mut output = *self;
|
||
fiat_25519_opp(&mut output.0, &self.0);
|
||
let input = output.0;
|
||
fiat_25519_carry(&mut output.0, &input);
|
||
output
|
||
}
|
||
}
|
||
|
||
impl ConditionallySelectable for FieldElement51 {
|
||
fn conditional_select(
|
||
a: &FieldElement51,
|
||
b: &FieldElement51,
|
||
choice: Choice,
|
||
) -> FieldElement51 {
|
||
let mut output = [0u64; 5];
|
||
fiat_25519_selectznz(&mut output, choice.unwrap_u8() as fiat_25519_u1, &a.0, &b.0);
|
||
FieldElement51(output)
|
||
}
|
||
|
||
fn conditional_swap(a: &mut FieldElement51, b: &mut FieldElement51, choice: Choice) {
|
||
u64::conditional_swap(&mut a.0[0], &mut b.0[0], choice);
|
||
u64::conditional_swap(&mut a.0[1], &mut b.0[1], choice);
|
||
u64::conditional_swap(&mut a.0[2], &mut b.0[2], choice);
|
||
u64::conditional_swap(&mut a.0[3], &mut b.0[3], choice);
|
||
u64::conditional_swap(&mut a.0[4], &mut b.0[4], choice);
|
||
}
|
||
|
||
fn conditional_assign(&mut self, _rhs: &FieldElement51, choice: Choice) {
|
||
let mut output = [0u64; 5];
|
||
let choicebit = choice.unwrap_u8() as fiat_25519_u1;
|
||
fiat_25519_cmovznz_u64(&mut output[0], choicebit, self.0[0], _rhs.0[0]);
|
||
fiat_25519_cmovznz_u64(&mut output[1], choicebit, self.0[1], _rhs.0[1]);
|
||
fiat_25519_cmovznz_u64(&mut output[2], choicebit, self.0[2], _rhs.0[2]);
|
||
fiat_25519_cmovznz_u64(&mut output[3], choicebit, self.0[3], _rhs.0[3]);
|
||
fiat_25519_cmovznz_u64(&mut output[4], choicebit, self.0[4], _rhs.0[4]);
|
||
*self = FieldElement51(output);
|
||
}
|
||
}
|
||
|
||
impl FieldElement51 {
|
||
/// Construct zero.
|
||
pub fn zero() -> FieldElement51 {
|
||
FieldElement51([0, 0, 0, 0, 0])
|
||
}
|
||
|
||
/// Construct one.
|
||
pub fn one() -> FieldElement51 {
|
||
FieldElement51([1, 0, 0, 0, 0])
|
||
}
|
||
|
||
pub fn is_negative(&self) -> Choice {
|
||
let bytes = self.to_bytes();
|
||
(bytes[0] & 1).into()
|
||
}
|
||
|
||
/// Raise this field element to the power (p-5)/8 = 2^252 -3.
|
||
fn pow_p58(&self) -> FieldElement51 {
|
||
// The bits of (p-5)/8 are 101111.....11.
|
||
//
|
||
// nonzero bits of exponent
|
||
let (t19, _) = self.pow22501(); // 249..0
|
||
let t20 = t19.pow2k(2); // 251..2
|
||
let t21 = self * &t20; // 251..2,0
|
||
|
||
t21
|
||
}
|
||
|
||
/// Given a nonzero field element, compute its inverse.
|
||
///
|
||
/// The inverse is computed as self^(p-2), since
|
||
/// x^(p-2)x = x^(p-1) = 1 (mod p).
|
||
///
|
||
/// This function returns zero on input zero.
|
||
pub fn invert(&self) -> FieldElement51 {
|
||
// The bits of p-2 = 2^255 -19 -2 are 11010111111...11.
|
||
//
|
||
// nonzero bits of exponent
|
||
let (t19, t3) = self.pow22501(); // t19: 249..0 ; t3: 3,1,0
|
||
let t20 = t19.pow2k(5); // 254..5
|
||
let t21 = &t20 * &t3; // 254..5,3,1,0
|
||
|
||
t21
|
||
}
|
||
|
||
/// Compute (self^(2^250-1), self^11), used as a helper function
|
||
/// within invert() and pow22523().
|
||
fn pow22501(&self) -> (FieldElement51, FieldElement51) {
|
||
// Instead of managing which temporary variables are used
|
||
// for what, we define as many as we need and leave stack
|
||
// allocation to the compiler
|
||
//
|
||
// Each temporary variable t_i is of the form (self)^e_i.
|
||
// Squaring t_i corresponds to multiplying e_i by 2,
|
||
// so the pow2k function shifts e_i left by k places.
|
||
// Multiplying t_i and t_j corresponds to adding e_i + e_j.
|
||
//
|
||
// Temporary t_i Nonzero bits of e_i
|
||
//
|
||
let t0 = self.square(); // 1 e_0 = 2^1
|
||
let t1 = t0.square().square(); // 3 e_1 = 2^3
|
||
let t2 = self * &t1; // 3,0 e_2 = 2^3 + 2^0
|
||
let t3 = &t0 * &t2; // 3,1,0
|
||
let t4 = t3.square(); // 4,2,1
|
||
let t5 = &t2 * &t4; // 4,3,2,1,0
|
||
let t6 = t5.pow2k(5); // 9,8,7,6,5
|
||
let t7 = &t6 * &t5; // 9,8,7,6,5,4,3,2,1,0
|
||
let t8 = t7.pow2k(10); // 19..10
|
||
let t9 = &t8 * &t7; // 19..0
|
||
let t10 = t9.pow2k(20); // 39..20
|
||
let t11 = &t10 * &t9; // 39..0
|
||
let t12 = t11.pow2k(10); // 49..10
|
||
let t13 = &t12 * &t7; // 49..0
|
||
let t14 = t13.pow2k(50); // 99..50
|
||
let t15 = &t14 * &t13; // 99..0
|
||
let t16 = t15.pow2k(100); // 199..100
|
||
let t17 = &t16 * &t15; // 199..0
|
||
let t18 = t17.pow2k(50); // 249..50
|
||
let t19 = &t18 * &t13; // 249..0
|
||
|
||
(t19, t3)
|
||
}
|
||
|
||
/// Load a `FieldElement51` from the low 255 bits of a 256-bit
|
||
/// input.
|
||
///
|
||
/// # Warning
|
||
///
|
||
/// This function does not check that the input used the canonical
|
||
/// representative. It masks the high bit, but it will happily
|
||
/// decode 2^255 - 18 to 1. Applications that require a canonical
|
||
/// encoding of every field element should decode, re-encode to
|
||
/// the canonical encoding, and check that the input was
|
||
/// canonical.
|
||
///
|
||
pub fn from_bytes(bytes: &[u8; 32]) -> FieldElement51 {
|
||
let mut temp = [0u8; 32];
|
||
temp.copy_from_slice(bytes);
|
||
temp[31] &= 127u8;
|
||
let mut output = [0u64; 5];
|
||
fiat_25519_from_bytes(&mut output, &temp);
|
||
FieldElement51(output)
|
||
}
|
||
|
||
/// Serialize this `FieldElement51` to a 32-byte array. The
|
||
/// encoding is canonical.
|
||
pub fn to_bytes(&self) -> [u8; 32] {
|
||
let mut bytes = [0u8; 32];
|
||
fiat_25519_to_bytes(&mut bytes, &self.0);
|
||
bytes
|
||
}
|
||
|
||
/// Given `k > 0`, return `self^(2^k)`.
|
||
pub fn pow2k(&self, mut k: u32) -> FieldElement51 {
|
||
let mut output = *self;
|
||
loop {
|
||
let input = output.0;
|
||
fiat_25519_carry_square(&mut output.0, &input);
|
||
k -= 1;
|
||
if k == 0 {
|
||
return output;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Given `FieldElements` `u` and `v`, compute either `sqrt(u/v)`
|
||
/// or `sqrt(i*u/v)` in constant time.
|
||
///
|
||
/// This function always returns the nonnegative square root.
|
||
///
|
||
/// # Return
|
||
///
|
||
/// - `(Choice(1), +sqrt(u/v)) ` if `v` is nonzero and `u/v` is square;
|
||
/// - `(Choice(1), zero) ` if `u` is zero;
|
||
/// - `(Choice(0), zero) ` if `v` is zero and `u` is nonzero;
|
||
/// - `(Choice(0), +sqrt(i*u/v))` if `u/v` is nonsquare (so `i*u/v` is square).
|
||
///
|
||
pub fn sqrt_ratio_i(u: &FieldElement51, v: &FieldElement51) -> (Choice, FieldElement51) {
|
||
// Using the same trick as in ed25519 decoding, we merge the
|
||
// inversion, the square root, and the square test as follows.
|
||
//
|
||
// To compute sqrt(α), we can compute β = α^((p+3)/8).
|
||
// Then β^2 = ±α, so multiplying β by sqrt(-1) if necessary
|
||
// gives sqrt(α).
|
||
//
|
||
// To compute 1/sqrt(α), we observe that
|
||
// 1/β = α^(p-1 - (p+3)/8) = α^((7p-11)/8)
|
||
// = α^3 * (α^7)^((p-5)/8).
|
||
//
|
||
// We can therefore compute sqrt(u/v) = sqrt(u)/sqrt(v)
|
||
// by first computing
|
||
// r = u^((p+3)/8) v^(p-1-(p+3)/8)
|
||
// = u u^((p-5)/8) v^3 (v^7)^((p-5)/8)
|
||
// = (uv^3) (uv^7)^((p-5)/8).
|
||
//
|
||
// If v is nonzero and u/v is square, then r^2 = ±u/v,
|
||
// so vr^2 = ±u.
|
||
// If vr^2 = u, then sqrt(u/v) = r.
|
||
// If vr^2 = -u, then sqrt(u/v) = r*sqrt(-1).
|
||
//
|
||
// If v is zero, r is also zero.
|
||
|
||
let v3 = &v.square() * v;
|
||
let v7 = &v3.square() * v;
|
||
let mut r = &(u * &v3) * &(u * &v7).pow_p58();
|
||
let check = v * &r.square();
|
||
|
||
let i = &SQRT_M1;
|
||
|
||
let correct_sign_sqrt = check.ct_eq(u);
|
||
let flipped_sign_sqrt = check.ct_eq(&(-u));
|
||
let flipped_sign_sqrt_i = check.ct_eq(&(&(-u) * i));
|
||
|
||
let r_prime = &SQRT_M1 * &r;
|
||
r.conditional_assign(&r_prime, flipped_sign_sqrt | flipped_sign_sqrt_i);
|
||
|
||
// Choose the nonnegative square root.
|
||
let r_is_negative = r.is_negative();
|
||
r.conditional_negate(r_is_negative);
|
||
|
||
let was_nonzero_square = correct_sign_sqrt | flipped_sign_sqrt;
|
||
|
||
(was_nonzero_square, r)
|
||
}
|
||
|
||
/// Returns the square of this field element.
|
||
pub fn square(&self) -> FieldElement51 {
|
||
let mut output = *self;
|
||
fiat_25519_carry_square(&mut output.0, &self.0);
|
||
output
|
||
}
|
||
|
||
/// Returns 2 times the square of this field element.
|
||
pub fn square2(&self) -> FieldElement51 {
|
||
let mut output = *self;
|
||
let mut temp = *self;
|
||
// Void vs return type, measure cost of copying self
|
||
fiat_25519_carry_square(&mut temp.0, &self.0);
|
||
fiat_25519_add(&mut output.0, &temp.0, &temp.0);
|
||
let input = output.0;
|
||
fiat_25519_carry(&mut output.0, &input);
|
||
output
|
||
}
|
||
}
|
||
|
||
/// Precomputed value of one of the square roots of -1 (mod p)
|
||
pub(crate) const SQRT_M1: FieldElement51 = FieldElement51([
|
||
1718705420411056,
|
||
234908883556509,
|
||
2233514472574048,
|
||
2117202627021982,
|
||
765476049583133,
|
||
]);
|