mirror of
https://github.com/saymrwulf/pasta_curves-source.git
synced 2026-09-04 20:03:39 +00:00
commit
c052756831
8 changed files with 243 additions and 328 deletions
15
CHANGELOG.md
15
CHANGELOG.md
|
|
@ -6,6 +6,21 @@ and this project adheres to Rust's notion of
|
|||
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- `pasta_curves::arithmetic::SqrtRatio` trait, extending `ff::PrimeField` with
|
||||
square roots of ratios. This trait is likely to be moved into the `ff` crate
|
||||
in a future release (once we're satisfied with it).
|
||||
|
||||
### Removed
|
||||
- `pasta_curves::arithmetic`:
|
||||
- `Field` re-export (`pasta_curves::group::ff::Field` is equivalent).
|
||||
- `FieldExt::ROOT_OF_UNITY` (use `ff::PrimeField::root_of_unity` instead).
|
||||
- `FieldExt::{T_MINUS1_OVER2, pow_by_t_minus1_over2, get_lower_32, sqrt_alt,`
|
||||
`sqrt_ratio}` (moved to `SqrtRatio` trait).
|
||||
- `FieldExt::{RESCUE_ALPHA, RESCUE_INVALPHA}`
|
||||
- `FieldExt::from_u64` (use `From<u64> for ff::PrimeField` instead).
|
||||
- `FieldExt::{from_bytes, read, to_bytes, write}`
|
||||
(use `ff::PrimeField::{from_repr, to_repr}` instead).
|
||||
|
||||
## [0.2.1] - 2021-09-17
|
||||
### Changed
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@
|
|||
//! This module is temporary, and the extension traits defined here are expected to be
|
||||
//! upstreamed into the `ff` and `group` crates after some refactoring.
|
||||
|
||||
pub use ff::Field;
|
||||
|
||||
mod curves;
|
||||
mod fields;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ use super::{FieldExt, Group};
|
|||
#[cfg(feature = "std")]
|
||||
use std::{
|
||||
boxed::Box,
|
||||
cmp,
|
||||
io::{self, Read, Write},
|
||||
ops::{Add, Mul, Sub},
|
||||
};
|
||||
|
|
@ -28,8 +27,6 @@ pub trait CurveExt:
|
|||
PrimeCurve<Affine = <Self as CurveExt>::AffineExt>
|
||||
+ group::Group<Scalar = <Self as CurveExt>::ScalarExt>
|
||||
+ Default
|
||||
+ PartialEq
|
||||
+ cmp::Eq
|
||||
+ ConditionallySelectable
|
||||
+ ConstantTimeEq
|
||||
+ From<<Self as PrimeCurve>::Affine>
|
||||
|
|
|
|||
|
|
@ -4,106 +4,91 @@
|
|||
use core::mem::size_of;
|
||||
|
||||
use static_assertions::const_assert;
|
||||
use subtle::{Choice, CtOption};
|
||||
use subtle::Choice;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use subtle::CtOption;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use super::Group;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::{
|
||||
assert,
|
||||
boxed::Box,
|
||||
convert::TryInto,
|
||||
io::{self, Read, Write},
|
||||
marker::PhantomData,
|
||||
vec::Vec,
|
||||
};
|
||||
use std::{assert, boxed::Box, convert::TryInto, marker::PhantomData, vec::Vec};
|
||||
|
||||
const_assert!(size_of::<usize>() >= 4);
|
||||
|
||||
/// A trait that exposes additional operations related to calculating square roots of
|
||||
/// prime-order finite fields.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait SqrtRatio: ff::PrimeField {
|
||||
/// The value $(T-1)/2$ such that $2^S \cdot T = p - 1$ with $T$ odd.
|
||||
const T_MINUS1_OVER2: [u64; 4];
|
||||
|
||||
/// Raise this field element to the power [`Self::T_MINUS1_OVER2`].
|
||||
///
|
||||
/// Field implementations may override this to use an efficient addition chain.
|
||||
fn pow_by_t_minus1_over2(&self) -> Self {
|
||||
ff::Field::pow_vartime(&self, &Self::T_MINUS1_OVER2)
|
||||
}
|
||||
|
||||
/// Gets the lower 32 bits of this field element when expressed
|
||||
/// canonically.
|
||||
fn get_lower_32(&self) -> u32;
|
||||
|
||||
/// Computes:
|
||||
///
|
||||
/// - $(\textsf{true}, \sqrt{\textsf{num}/\textsf{div}})$, if $\textsf{num}$ and
|
||||
/// $\textsf{div}$ are nonzero and $\textsf{num}/\textsf{div}$ is a square in the
|
||||
/// field;
|
||||
/// - $(\textsf{true}, 0)$, if $\textsf{num}$ is zero;
|
||||
/// - $(\textsf{false}, 0)$, if $\textsf{num}$ is nonzero and $\textsf{div}$ is zero;
|
||||
/// - $(\textsf{false}, \sqrt{G_S \cdot \textsf{num}/\textsf{div}})$, if
|
||||
/// $\textsf{num}$ and $\textsf{div}$ are nonzero and $\textsf{num}/\textsf{div}$ is
|
||||
/// a nonsquare in the field;
|
||||
///
|
||||
/// where $G_S$ is a non-square.
|
||||
///
|
||||
/// For `pasta_curves`, $G_S$ is currently [`ff::PrimeField::root_of_unity`], a
|
||||
/// generator of the order $2^S$ subgroup. Users of this crate should not rely on this
|
||||
/// generator being fixed; it may be changed in future crate versions to simplify the
|
||||
/// implementation of the SSWU hash-to-curve algorithm.
|
||||
///
|
||||
/// The choice of root from sqrt is unspecified.
|
||||
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self);
|
||||
|
||||
/// Equivalent to `Self::sqrt_ratio(self, one())`.
|
||||
fn sqrt_alt(&self) -> (Choice, Self) {
|
||||
Self::sqrt_ratio(self, &Self::one())
|
||||
}
|
||||
}
|
||||
|
||||
/// This trait is a common interface for dealing with elements of a finite
|
||||
/// field.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait FieldExt: ff::PrimeField + From<bool> + Ord + Group<Scalar = Self> {
|
||||
pub trait FieldExt: SqrtRatio + From<bool> + Ord + Group<Scalar = Self> {
|
||||
/// Modulus of the field written as a string for display purposes
|
||||
const MODULUS: &'static str;
|
||||
|
||||
/// Generator of the $2^S$ multiplicative subgroup
|
||||
const ROOT_OF_UNITY: Self;
|
||||
|
||||
/// Inverse of `ROOT_OF_UNITY`
|
||||
/// Inverse of `PrimeField::root_of_unity()`
|
||||
const ROOT_OF_UNITY_INV: Self;
|
||||
|
||||
/// The value $(T-1)/2$ such that $2^S \cdot T = p - 1$ with $T$ odd.
|
||||
const T_MINUS1_OVER2: [u64; 4];
|
||||
|
||||
/// Generator of the $t-order$ multiplicative subgroup
|
||||
const DELTA: Self;
|
||||
|
||||
/// Inverse of $2$ in the field.
|
||||
const TWO_INV: Self;
|
||||
|
||||
/// Ideally the smallest prime $\alpha$ such that gcd($p - 1$, $\alpha$) = $1$
|
||||
const RESCUE_ALPHA: u64;
|
||||
|
||||
/// $RESCUE_INVALPHA \cdot RESCUE_ALPHA = 1 \mod p - 1$ such that
|
||||
/// `(a^RESCUE_ALPHA)^RESCUE_INVALPHA = a`.
|
||||
const RESCUE_INVALPHA: [u64; 4];
|
||||
|
||||
/// Element of multiplicative order $3$.
|
||||
const ZETA: Self;
|
||||
|
||||
/// Computes:
|
||||
///
|
||||
/// * (true, sqrt(num/div)), if num and div are nonzero and num/div is a square in the field;
|
||||
/// * (true, 0), if num is zero;
|
||||
/// * (false, 0), if num is nonzero and div is zero;
|
||||
/// * (false, sqrt(ROOT_OF_UNITY * num/div)), if num and div are nonzero and num/div is a nonsquare in the field;
|
||||
///
|
||||
/// where ROOT_OF_UNITY is a generator of the order 2^n subgroup (and therefore a nonsquare).
|
||||
///
|
||||
/// The choice of root from sqrt is unspecified.
|
||||
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self);
|
||||
|
||||
/// Equivalent to sqrt_ratio(self, one()).
|
||||
fn sqrt_alt(&self) -> (Choice, Self) {
|
||||
Self::sqrt_ratio(self, &Self::one())
|
||||
}
|
||||
|
||||
/// This computes a random element of the field using system randomness.
|
||||
fn rand() -> Self {
|
||||
Self::random(rand::rngs::OsRng)
|
||||
}
|
||||
|
||||
/// Obtains a field element congruent to the integer `v`.
|
||||
fn from_u64(v: u64) -> Self;
|
||||
|
||||
/// Obtains a field element congruent to the integer `v`.
|
||||
fn from_u128(v: u128) -> Self;
|
||||
|
||||
/// Converts this field element to its normalized, little endian byte
|
||||
/// representation.
|
||||
fn to_bytes(&self) -> [u8; 32];
|
||||
|
||||
/// Writes this element in its normalized, little endian form into a buffer.
|
||||
fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
|
||||
let compressed = self.to_bytes();
|
||||
writer.write_all(&compressed[..])
|
||||
}
|
||||
|
||||
/// Attempts to obtain a field element from its normalized, little endian
|
||||
/// byte representation.
|
||||
fn from_bytes(bytes: &[u8; 32]) -> CtOption<Self>;
|
||||
|
||||
/// Reads a normalized, little endian represented field element from a
|
||||
/// buffer.
|
||||
fn read<R: Read>(reader: &mut R) -> io::Result<Self> {
|
||||
let mut compressed = [0u8; 32];
|
||||
reader.read_exact(&mut compressed[..])?;
|
||||
Option::from(Self::from_bytes(&compressed))
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point encoding in proof"))
|
||||
}
|
||||
|
||||
/// Obtains a field element that is congruent to the provided little endian
|
||||
/// byte representation of an integer.
|
||||
fn from_bytes_wide(bytes: &[u8; 64]) -> Self;
|
||||
|
|
@ -126,16 +111,6 @@ pub trait FieldExt: ff::PrimeField + From<bool> + Ord + Group<Scalar = Self> {
|
|||
/// Gets the lower 128 bits of this field element when expressed
|
||||
/// canonically.
|
||||
fn get_lower_128(&self) -> u128;
|
||||
|
||||
/// Gets the lower 32 bits of this field element when expressed
|
||||
/// canonically.
|
||||
fn get_lower_32(&self) -> u32;
|
||||
|
||||
/// Raise this field element to the power T_MINUS1_OVER2.
|
||||
/// Field implementations may override this to use an efficient addition chain.
|
||||
fn pow_by_t_minus1_over2(&self) -> Self {
|
||||
ff::Field::pow_vartime(&self, &Self::T_MINUS1_OVER2)
|
||||
}
|
||||
}
|
||||
|
||||
/// Tonelli–Shanks' square-root algorithm for `p mod 16 = 1`.
|
||||
|
|
@ -233,7 +208,7 @@ impl<F: FieldExt> SqrtTables<F> {
|
|||
marker: PhantomData,
|
||||
};
|
||||
|
||||
let mut gtab = (0..4).scan(F::ROOT_OF_UNITY, |gi, _| {
|
||||
let mut gtab = (0..4).scan(F::root_of_unity(), |gi, _| {
|
||||
// gi == ROOT_OF_UNITY^(256^i)
|
||||
let gtab_i: Vec<F> = (0..256)
|
||||
.scan(F::one(), |acc, _| {
|
||||
|
|
@ -331,7 +306,7 @@ impl<F: FieldExt> SqrtTables<F> {
|
|||
|
||||
let sqdiv = res.square() * div;
|
||||
let is_square = (sqdiv - num).is_zero();
|
||||
let is_nonsquare = (sqdiv - F::ROOT_OF_UNITY * num).is_zero();
|
||||
let is_nonsquare = (sqdiv - F::root_of_unity() * num).is_zero();
|
||||
assert!(bool::from(
|
||||
num.is_zero() | div.is_zero() | (is_square ^ is_nonsquare)
|
||||
));
|
||||
|
|
@ -348,7 +323,7 @@ impl<F: FieldExt> SqrtTables<F> {
|
|||
|
||||
let sq = res.square();
|
||||
let is_square = (sq - u).is_zero();
|
||||
let is_nonsquare = (sq - F::ROOT_OF_UNITY * u).is_zero();
|
||||
let is_nonsquare = (sq - F::root_of_unity() * u).is_zero();
|
||||
assert!(bool::from(u.is_zero() | (is_square ^ is_nonsquare)));
|
||||
|
||||
(is_square, res)
|
||||
|
|
|
|||
|
|
@ -1100,7 +1100,7 @@ impl Ep {
|
|||
0x4000000000000000,
|
||||
]);
|
||||
|
||||
/// `(F::ROOT_OF_UNITY.invert().unwrap() * z).sqrt().unwrap()`
|
||||
/// `(F::root_of_unity().invert().unwrap() * z).sqrt().unwrap()`
|
||||
pub const THETA: Fp = Fp::from_raw([
|
||||
0xca330bcc09ac318e,
|
||||
0x51f64fc4dc888857,
|
||||
|
|
@ -1200,7 +1200,7 @@ impl Eq {
|
|||
0x4000000000000000,
|
||||
]);
|
||||
|
||||
/// `(F::ROOT_OF_UNITY.invert().unwrap() * z).sqrt().unwrap()`
|
||||
/// `(F::root_of_unity().invert().unwrap() * z).sqrt().unwrap()`
|
||||
pub const THETA: Fq = Fq::from_raw([
|
||||
0x632cae9872df1b5d,
|
||||
0x38578ccadf03ac27,
|
||||
|
|
|
|||
203
src/fields/fp.rs
203
src/fields/fp.rs
|
|
@ -15,7 +15,7 @@ use ff::{FieldBits, PrimeFieldBits};
|
|||
use crate::arithmetic::{adc, mac, sbb};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::arithmetic::{FieldExt, Group, SqrtTables};
|
||||
use crate::arithmetic::{FieldExt, Group, SqrtRatio, SqrtTables};
|
||||
|
||||
/// This represents an element of $\mathbb{F}_p$ where
|
||||
///
|
||||
|
|
@ -232,6 +232,14 @@ const DELTA: Fp = Fp::from_raw([
|
|||
0x0a757d0f0006ab6c,
|
||||
]);
|
||||
|
||||
/// `(t - 1) // 2` where t * 2^s + 1 = p with t odd.
|
||||
const T_MINUS1_OVER2: [u64; 4] = [
|
||||
0x04a6_7c8d_cc96_9876,
|
||||
0x0000_0000_1123_4c7e,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_2000_0000,
|
||||
];
|
||||
|
||||
impl Default for Fp {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
|
|
@ -513,15 +521,7 @@ impl ff::Field for Fp {
|
|||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
crate::arithmetic::sqrt_tonelli_shanks(
|
||||
self,
|
||||
&[
|
||||
0x04a6_7c8d_cc96_9876,
|
||||
0x0000_0000_1123_4c7e,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_2000_0000,
|
||||
],
|
||||
)
|
||||
crate::arithmetic::sqrt_tonelli_shanks(self, &T_MINUS1_OVER2)
|
||||
}
|
||||
|
||||
/// Computes the multiplicative inverse of this element,
|
||||
|
|
@ -627,7 +627,7 @@ impl PrimeFieldBits for Fp {
|
|||
type ReprBits = ReprBits;
|
||||
|
||||
fn to_le_bits(&self) -> FieldBits<Self::ReprBits> {
|
||||
let bytes = self.to_bytes();
|
||||
let bytes = self.to_repr();
|
||||
|
||||
#[cfg(not(target_pointer_width = "64"))]
|
||||
let limbs = [
|
||||
|
|
@ -670,94 +670,8 @@ lazy_static! {
|
|||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl FieldExt for Fp {
|
||||
const MODULUS: &'static str =
|
||||
"0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001";
|
||||
const ROOT_OF_UNITY: Self = ROOT_OF_UNITY;
|
||||
const ROOT_OF_UNITY_INV: Self = Fp::from_raw([
|
||||
0xf0b87c7db2ce91f6,
|
||||
0x84a0a1d8859f066f,
|
||||
0xb4ed8e647196dad1,
|
||||
0x2cd5282c53116b5c,
|
||||
]);
|
||||
const T_MINUS1_OVER2: [u64; 4] = [
|
||||
0x04a67c8dcc969876,
|
||||
0x0000000011234c7e,
|
||||
0x0000000000000000,
|
||||
0x20000000,
|
||||
];
|
||||
const DELTA: Self = DELTA;
|
||||
const TWO_INV: Self = Fp::from_raw([
|
||||
0xcc96987680000001,
|
||||
0x11234c7e04a67c8d,
|
||||
0x0000000000000000,
|
||||
0x2000000000000000,
|
||||
]);
|
||||
const RESCUE_ALPHA: u64 = 5;
|
||||
const RESCUE_INVALPHA: [u64; 4] = [
|
||||
0xe0f0f3f0cccccccd,
|
||||
0x4e9ee0c9a10a60e2,
|
||||
0x3333333333333333,
|
||||
0x3333333333333333,
|
||||
];
|
||||
const ZETA: Self = Fp::from_raw([
|
||||
0x1dad5ebdfdfe4ab9,
|
||||
0x1d1f8bd237ad3149,
|
||||
0x2caad5dc57aab1b0,
|
||||
0x12ccca834acdba71,
|
||||
]);
|
||||
|
||||
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
|
||||
FP_TABLES.sqrt_ratio(num, div)
|
||||
}
|
||||
|
||||
fn sqrt_alt(&self) -> (Choice, Self) {
|
||||
FP_TABLES.sqrt_alt(self)
|
||||
}
|
||||
|
||||
fn from_u64(v: u64) -> Self {
|
||||
Fp::from_raw([v as u64, 0, 0, 0])
|
||||
}
|
||||
|
||||
fn from_u128(v: u128) -> Self {
|
||||
Fp::from_raw([v as u64, (v >> 64) as u64, 0, 0])
|
||||
}
|
||||
|
||||
fn from_bytes(bytes: &[u8; 32]) -> CtOption<Fp> {
|
||||
<Self as ff::PrimeField>::from_repr(*bytes)
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> [u8; 32] {
|
||||
<Self as ff::PrimeField>::to_repr(self)
|
||||
}
|
||||
|
||||
/// Converts a 512-bit little endian integer into
|
||||
/// a `Fp` by reducing by the modulus.
|
||||
fn from_bytes_wide(bytes: &[u8; 64]) -> Fp {
|
||||
Fp::from_u512([
|
||||
u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[32..40].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
|
||||
])
|
||||
}
|
||||
|
||||
fn get_lower_128(&self) -> u128 {
|
||||
let tmp = Fp::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
|
||||
|
||||
u128::from(tmp.0[0]) | (u128::from(tmp.0[1]) << 64)
|
||||
}
|
||||
|
||||
fn get_lower_32(&self) -> u32 {
|
||||
// TODO: don't reduce, just hash the Montgomery form. (Requires rebuilding perfect hash table.)
|
||||
let tmp = Fp::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
|
||||
|
||||
tmp.0[0] as u32
|
||||
}
|
||||
impl SqrtRatio for Fp {
|
||||
const T_MINUS1_OVER2: [u64; 4] = T_MINUS1_OVER2;
|
||||
|
||||
fn pow_by_t_minus1_over2(&self) -> Self {
|
||||
let sqr = |x: Fp, i: u32| (0..i).fold(x, |x, _| x.square());
|
||||
|
|
@ -789,6 +703,71 @@ impl FieldExt for Fp {
|
|||
let rs = sqr(rr, 3) * r11;
|
||||
rs.square() // rt
|
||||
}
|
||||
|
||||
fn get_lower_32(&self) -> u32 {
|
||||
// TODO: don't reduce, just hash the Montgomery form. (Requires rebuilding perfect hash table.)
|
||||
let tmp = Fp::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
|
||||
|
||||
tmp.0[0] as u32
|
||||
}
|
||||
|
||||
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
|
||||
FP_TABLES.sqrt_ratio(num, div)
|
||||
}
|
||||
|
||||
fn sqrt_alt(&self) -> (Choice, Self) {
|
||||
FP_TABLES.sqrt_alt(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl FieldExt for Fp {
|
||||
const MODULUS: &'static str =
|
||||
"0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001";
|
||||
const ROOT_OF_UNITY_INV: Self = Fp::from_raw([
|
||||
0xf0b87c7db2ce91f6,
|
||||
0x84a0a1d8859f066f,
|
||||
0xb4ed8e647196dad1,
|
||||
0x2cd5282c53116b5c,
|
||||
]);
|
||||
const DELTA: Self = DELTA;
|
||||
const TWO_INV: Self = Fp::from_raw([
|
||||
0xcc96987680000001,
|
||||
0x11234c7e04a67c8d,
|
||||
0x0000000000000000,
|
||||
0x2000000000000000,
|
||||
]);
|
||||
const ZETA: Self = Fp::from_raw([
|
||||
0x1dad5ebdfdfe4ab9,
|
||||
0x1d1f8bd237ad3149,
|
||||
0x2caad5dc57aab1b0,
|
||||
0x12ccca834acdba71,
|
||||
]);
|
||||
|
||||
fn from_u128(v: u128) -> Self {
|
||||
Fp::from_raw([v as u64, (v >> 64) as u64, 0, 0])
|
||||
}
|
||||
|
||||
/// Converts a 512-bit little endian integer into
|
||||
/// a `Fp` by reducing by the modulus.
|
||||
fn from_bytes_wide(bytes: &[u8; 64]) -> Fp {
|
||||
Fp::from_u512([
|
||||
u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[32..40].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
|
||||
])
|
||||
}
|
||||
|
||||
fn get_lower_128(&self) -> u128 {
|
||||
let tmp = Fp::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
|
||||
|
||||
u128::from(tmp.0[0]) | (u128::from(tmp.0[1]) << 64)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "std"))]
|
||||
|
|
@ -809,18 +788,6 @@ fn test_inv() {
|
|||
assert_eq!(inv, INV);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn test_rescue() {
|
||||
// NB: TWO_INV is standing in as a "random" field element
|
||||
assert_eq!(
|
||||
Fp::TWO_INV
|
||||
.pow_vartime(&[Fp::RESCUE_ALPHA, 0, 0, 0])
|
||||
.pow_vartime(&Fp::RESCUE_INVALPHA),
|
||||
Fp::TWO_INV
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn test_sqrt() {
|
||||
|
|
@ -834,7 +801,7 @@ fn test_sqrt() {
|
|||
fn test_pow_by_t_minus1_over2() {
|
||||
// NB: TWO_INV is standing in as a "random" field element
|
||||
let v = (Fp::TWO_INV).pow_by_t_minus1_over2();
|
||||
assert!(v == ff::Field::pow_vartime(&Fp::TWO_INV, &Fp::T_MINUS1_OVER2));
|
||||
assert!(v == ff::Field::pow_vartime(&Fp::TWO_INV, &T_MINUS1_OVER2));
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
|
|
@ -842,9 +809,9 @@ fn test_pow_by_t_minus1_over2() {
|
|||
fn test_sqrt_ratio_and_alt() {
|
||||
// (true, sqrt(num/div)), if num and div are nonzero and num/div is a square in the field
|
||||
let num = (Fp::TWO_INV).square();
|
||||
let div = Fp::from_u64(25);
|
||||
let div = Fp::from(25);
|
||||
let div_inverse = div.invert().unwrap();
|
||||
let expected = Fp::TWO_INV * Fp::from_u64(5).invert().unwrap();
|
||||
let expected = Fp::TWO_INV * Fp::from(5).invert().unwrap();
|
||||
let (is_square, v) = Fp::sqrt_ratio(&num, &div);
|
||||
assert!(bool::from(is_square));
|
||||
assert!(v == expected || (-v) == expected);
|
||||
|
|
@ -854,8 +821,8 @@ fn test_sqrt_ratio_and_alt() {
|
|||
assert!(v_alt == v);
|
||||
|
||||
// (false, sqrt(ROOT_OF_UNITY * num/div)), if num and div are nonzero and num/div is a nonsquare in the field
|
||||
let num = num * Fp::ROOT_OF_UNITY;
|
||||
let expected = Fp::TWO_INV * Fp::ROOT_OF_UNITY * Fp::from_u64(5).invert().unwrap();
|
||||
let num = num * Fp::root_of_unity();
|
||||
let expected = Fp::TWO_INV * Fp::root_of_unity() * Fp::from(5).invert().unwrap();
|
||||
let (is_square, v) = Fp::sqrt_ratio(&num, &div);
|
||||
assert!(!bool::from(is_square));
|
||||
assert!(v == expected || (-v) == expected);
|
||||
|
|
@ -904,7 +871,7 @@ fn test_zeta() {
|
|||
#[test]
|
||||
fn test_root_of_unity() {
|
||||
assert_eq!(
|
||||
Fp::ROOT_OF_UNITY.pow_vartime(&[1 << Fp::S, 0, 0, 0]),
|
||||
Fp::root_of_unity().pow_vartime(&[1 << Fp::S, 0, 0, 0]),
|
||||
Fp::one()
|
||||
);
|
||||
}
|
||||
|
|
@ -912,7 +879,7 @@ fn test_root_of_unity() {
|
|||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn test_inv_root_of_unity() {
|
||||
assert_eq!(Fp::ROOT_OF_UNITY_INV, Fp::ROOT_OF_UNITY.invert().unwrap());
|
||||
assert_eq!(Fp::ROOT_OF_UNITY_INV, Fp::root_of_unity().invert().unwrap());
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
|
|
|
|||
203
src/fields/fq.rs
203
src/fields/fq.rs
|
|
@ -15,7 +15,7 @@ use ff::{FieldBits, PrimeFieldBits};
|
|||
use crate::arithmetic::{adc, mac, sbb};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::arithmetic::{FieldExt, Group, SqrtTables};
|
||||
use crate::arithmetic::{FieldExt, Group, SqrtRatio, SqrtTables};
|
||||
|
||||
/// This represents an element of $\mathbb{F}_q$ where
|
||||
///
|
||||
|
|
@ -232,6 +232,14 @@ const DELTA: Fq = Fq::from_raw([
|
|||
0x2237d54423724166,
|
||||
]);
|
||||
|
||||
/// `(t - 1) // 2` where t * 2^s + 1 = p with t odd.
|
||||
const T_MINUS1_OVER2: [u64; 4] = [
|
||||
0x04ca_546e_c623_7590,
|
||||
0x0000_0000_1123_4c7e,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_2000_0000,
|
||||
];
|
||||
|
||||
impl Default for Fq {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
|
|
@ -513,15 +521,7 @@ impl ff::Field for Fq {
|
|||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
crate::arithmetic::sqrt_tonelli_shanks(
|
||||
self,
|
||||
&[
|
||||
0x04ca_546e_c623_7590,
|
||||
0x0000_0000_1123_4c7e,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_2000_0000,
|
||||
],
|
||||
)
|
||||
crate::arithmetic::sqrt_tonelli_shanks(self, &T_MINUS1_OVER2)
|
||||
}
|
||||
|
||||
/// Computes the multiplicative inverse of this element,
|
||||
|
|
@ -627,7 +627,7 @@ impl PrimeFieldBits for Fq {
|
|||
type ReprBits = ReprBits;
|
||||
|
||||
fn to_le_bits(&self) -> FieldBits<Self::ReprBits> {
|
||||
let bytes = self.to_bytes();
|
||||
let bytes = self.to_repr();
|
||||
|
||||
#[cfg(not(target_pointer_width = "64"))]
|
||||
let limbs = [
|
||||
|
|
@ -670,94 +670,8 @@ lazy_static! {
|
|||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl FieldExt for Fq {
|
||||
const MODULUS: &'static str =
|
||||
"0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001";
|
||||
const ROOT_OF_UNITY: Self = ROOT_OF_UNITY;
|
||||
const ROOT_OF_UNITY_INV: Self = Fq::from_raw([
|
||||
0x57eecda0a84b6836,
|
||||
0x4ad38b9084b8a80c,
|
||||
0xf4c8f353124086c1,
|
||||
0x2235e1a7415bf936,
|
||||
]);
|
||||
const T_MINUS1_OVER2: [u64; 4] = [
|
||||
0x04ca546ec6237590,
|
||||
0x0000000011234c7e,
|
||||
0x0000000000000000,
|
||||
0x20000000,
|
||||
];
|
||||
const DELTA: Self = DELTA;
|
||||
const TWO_INV: Self = Fq::from_raw([
|
||||
0xc623759080000001,
|
||||
0x11234c7e04ca546e,
|
||||
0x0000000000000000,
|
||||
0x2000000000000000,
|
||||
]);
|
||||
const RESCUE_ALPHA: u64 = 5;
|
||||
const RESCUE_INVALPHA: [u64; 4] = [
|
||||
0xd69f2280cccccccd,
|
||||
0x4e9ee0c9a143ba4a,
|
||||
0x3333333333333333,
|
||||
0x3333333333333333,
|
||||
];
|
||||
const ZETA: Self = Fq::from_raw([
|
||||
0x2aa9d2e050aa0e4f,
|
||||
0x0fed467d47c033af,
|
||||
0x511db4d81cf70f5a,
|
||||
0x06819a58283e528e,
|
||||
]);
|
||||
|
||||
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
|
||||
FQ_TABLES.sqrt_ratio(num, div)
|
||||
}
|
||||
|
||||
fn sqrt_alt(&self) -> (Choice, Self) {
|
||||
FQ_TABLES.sqrt_alt(self)
|
||||
}
|
||||
|
||||
fn from_u64(v: u64) -> Self {
|
||||
Fq::from_raw([v as u64, 0, 0, 0])
|
||||
}
|
||||
|
||||
fn from_u128(v: u128) -> Self {
|
||||
Fq::from_raw([v as u64, (v >> 64) as u64, 0, 0])
|
||||
}
|
||||
|
||||
fn from_bytes(bytes: &[u8; 32]) -> CtOption<Fq> {
|
||||
<Self as ff::PrimeField>::from_repr(*bytes)
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> [u8; 32] {
|
||||
<Self as ff::PrimeField>::to_repr(self)
|
||||
}
|
||||
|
||||
/// Converts a 512-bit little endian integer into
|
||||
/// a `Fq` by reducing by the modulus.
|
||||
fn from_bytes_wide(bytes: &[u8; 64]) -> Fq {
|
||||
Fq::from_u512([
|
||||
u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[32..40].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
|
||||
])
|
||||
}
|
||||
|
||||
fn get_lower_128(&self) -> u128 {
|
||||
let tmp = Fq::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
|
||||
|
||||
u128::from(tmp.0[0]) | (u128::from(tmp.0[1]) << 64)
|
||||
}
|
||||
|
||||
fn get_lower_32(&self) -> u32 {
|
||||
// TODO: don't reduce, just hash the Montgomery form. (Requires rebuilding perfect hash table.)
|
||||
let tmp = Fq::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
|
||||
|
||||
tmp.0[0] as u32
|
||||
}
|
||||
impl SqrtRatio for Fq {
|
||||
const T_MINUS1_OVER2: [u64; 4] = T_MINUS1_OVER2;
|
||||
|
||||
fn pow_by_t_minus1_over2(&self) -> Self {
|
||||
let sqr = |x: Fq, i: u32| (0..i).fold(x, |x, _| x.square());
|
||||
|
|
@ -789,6 +703,71 @@ impl FieldExt for Fq {
|
|||
let ss = sqr(sr, 3) * self;
|
||||
sqr(ss, 4) // st
|
||||
}
|
||||
|
||||
fn get_lower_32(&self) -> u32 {
|
||||
// TODO: don't reduce, just hash the Montgomery form. (Requires rebuilding perfect hash table.)
|
||||
let tmp = Fq::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
|
||||
|
||||
tmp.0[0] as u32
|
||||
}
|
||||
|
||||
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
|
||||
FQ_TABLES.sqrt_ratio(num, div)
|
||||
}
|
||||
|
||||
fn sqrt_alt(&self) -> (Choice, Self) {
|
||||
FQ_TABLES.sqrt_alt(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl FieldExt for Fq {
|
||||
const MODULUS: &'static str =
|
||||
"0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001";
|
||||
const ROOT_OF_UNITY_INV: Self = Fq::from_raw([
|
||||
0x57eecda0a84b6836,
|
||||
0x4ad38b9084b8a80c,
|
||||
0xf4c8f353124086c1,
|
||||
0x2235e1a7415bf936,
|
||||
]);
|
||||
const DELTA: Self = DELTA;
|
||||
const TWO_INV: Self = Fq::from_raw([
|
||||
0xc623759080000001,
|
||||
0x11234c7e04ca546e,
|
||||
0x0000000000000000,
|
||||
0x2000000000000000,
|
||||
]);
|
||||
const ZETA: Self = Fq::from_raw([
|
||||
0x2aa9d2e050aa0e4f,
|
||||
0x0fed467d47c033af,
|
||||
0x511db4d81cf70f5a,
|
||||
0x06819a58283e528e,
|
||||
]);
|
||||
|
||||
fn from_u128(v: u128) -> Self {
|
||||
Fq::from_raw([v as u64, (v >> 64) as u64, 0, 0])
|
||||
}
|
||||
|
||||
/// Converts a 512-bit little endian integer into
|
||||
/// a `Fq` by reducing by the modulus.
|
||||
fn from_bytes_wide(bytes: &[u8; 64]) -> Fq {
|
||||
Fq::from_u512([
|
||||
u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[32..40].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
|
||||
])
|
||||
}
|
||||
|
||||
fn get_lower_128(&self) -> u128 {
|
||||
let tmp = Fq::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
|
||||
|
||||
u128::from(tmp.0[0]) | (u128::from(tmp.0[1]) << 64)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "std"))]
|
||||
|
|
@ -809,18 +788,6 @@ fn test_inv() {
|
|||
assert_eq!(inv, INV);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn test_rescue() {
|
||||
// NB: TWO_INV is standing in as a "random" field element
|
||||
assert_eq!(
|
||||
Fq::TWO_INV
|
||||
.pow_vartime(&[Fq::RESCUE_ALPHA, 0, 0, 0])
|
||||
.pow_vartime(&Fq::RESCUE_INVALPHA),
|
||||
Fq::TWO_INV
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn test_sqrt() {
|
||||
|
|
@ -834,7 +801,7 @@ fn test_sqrt() {
|
|||
fn test_pow_by_t_minus1_over2() {
|
||||
// NB: TWO_INV is standing in as a "random" field element
|
||||
let v = (Fq::TWO_INV).pow_by_t_minus1_over2();
|
||||
assert!(v == ff::Field::pow_vartime(&Fq::TWO_INV, &Fq::T_MINUS1_OVER2));
|
||||
assert!(v == ff::Field::pow_vartime(&Fq::TWO_INV, &T_MINUS1_OVER2));
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
|
|
@ -842,9 +809,9 @@ fn test_pow_by_t_minus1_over2() {
|
|||
fn test_sqrt_ratio_and_alt() {
|
||||
// (true, sqrt(num/div)), if num and div are nonzero and num/div is a square in the field
|
||||
let num = (Fq::TWO_INV).square();
|
||||
let div = Fq::from_u64(25);
|
||||
let div = Fq::from(25);
|
||||
let div_inverse = div.invert().unwrap();
|
||||
let expected = Fq::TWO_INV * Fq::from_u64(5).invert().unwrap();
|
||||
let expected = Fq::TWO_INV * Fq::from(5).invert().unwrap();
|
||||
let (is_square, v) = Fq::sqrt_ratio(&num, &div);
|
||||
assert!(bool::from(is_square));
|
||||
assert!(v == expected || (-v) == expected);
|
||||
|
|
@ -854,8 +821,8 @@ fn test_sqrt_ratio_and_alt() {
|
|||
assert!(v_alt == v);
|
||||
|
||||
// (false, sqrt(ROOT_OF_UNITY * num/div)), if num and div are nonzero and num/div is a nonsquare in the field
|
||||
let num = num * Fq::ROOT_OF_UNITY;
|
||||
let expected = Fq::TWO_INV * Fq::ROOT_OF_UNITY * Fq::from_u64(5).invert().unwrap();
|
||||
let num = num * Fq::root_of_unity();
|
||||
let expected = Fq::TWO_INV * Fq::root_of_unity() * Fq::from(5).invert().unwrap();
|
||||
let (is_square, v) = Fq::sqrt_ratio(&num, &div);
|
||||
assert!(!bool::from(is_square));
|
||||
assert!(v == expected || (-v) == expected);
|
||||
|
|
@ -903,7 +870,7 @@ fn test_zeta() {
|
|||
#[test]
|
||||
fn test_root_of_unity() {
|
||||
assert_eq!(
|
||||
Fq::ROOT_OF_UNITY.pow_vartime(&[1 << Fq::S, 0, 0, 0]),
|
||||
Fq::root_of_unity().pow_vartime(&[1 << Fq::S, 0, 0, 0]),
|
||||
Fq::one()
|
||||
);
|
||||
}
|
||||
|
|
@ -911,7 +878,7 @@ fn test_root_of_unity() {
|
|||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn test_inv_root_of_unity() {
|
||||
assert_eq!(Fq::ROOT_OF_UNITY_INV, Fq::ROOT_OF_UNITY.invert().unwrap());
|
||||
assert_eq!(Fq::ROOT_OF_UNITY_INV, Fq::root_of_unity().invert().unwrap());
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
|
|
|
|||
|
|
@ -171,11 +171,7 @@ pub fn map_to_curve_simple_swu<F: FieldExt, C: CurveExt<Base = F>, I: CurveExt<B
|
|||
let y = F::conditional_select(&y2, &y1, gx1_square);
|
||||
|
||||
// 9. If sgn0(u) != sgn0(y), set y = -y
|
||||
let y = F::conditional_select(
|
||||
&(-y),
|
||||
&y,
|
||||
(u.get_lower_32() % 2).ct_eq(&(y.get_lower_32() % 2)),
|
||||
);
|
||||
let y = F::conditional_select(&(-y), &y, u.is_odd().ct_eq(&y.is_odd()));
|
||||
|
||||
I::new_jacobian(num_x * div, y * div3, div).unwrap()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue