Merge pull request #20 from zcash/refactor

Refactor the crate APIs
This commit is contained in:
str4d 2021-10-01 06:07:38 +13:00 committed by GitHub
commit c052756831
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 243 additions and 328 deletions

View file

@ -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

View file

@ -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;

View file

@ -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>

View file

@ -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)
}
}
/// TonelliShanks' 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)

View file

@ -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,

View file

@ -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")]

View file

@ -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")]

View file

@ -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()
}