mirror of
https://github.com/saymrwulf/pasta_curves-source.git
synced 2026-09-04 20:03:39 +00:00
Move square-root operations from FieldExt into a separate trait
This commit is contained in:
parent
0c58a40a98
commit
1b2f581ac1
4 changed files with 155 additions and 139 deletions
|
|
@ -6,10 +6,17 @@ 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, sqrt_alt, sqrt_ratio}`
|
||||
(moved to `SqrtRatio` trait).
|
||||
|
||||
## [0.2.1] - 2021-09-17
|
||||
### Changed
|
||||
|
|
|
|||
|
|
@ -21,19 +21,53 @@ use std::{
|
|||
|
||||
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)
|
||||
}
|
||||
|
||||
/// 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$ ([`ff::PrimeField::root_of_unity`]) is a generator of the order $2^S$
|
||||
/// subgroup (and therefore a nonsquare).
|
||||
///
|
||||
/// 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;
|
||||
|
||||
/// 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;
|
||||
|
||||
|
|
@ -50,23 +84,6 @@ pub trait FieldExt: ff::PrimeField + From<bool> + Ord + Group<Scalar = Self> {
|
|||
/// 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)
|
||||
|
|
@ -127,12 +144,6 @@ pub trait FieldExt: ff::PrimeField + From<bool> + Ord + Group<Scalar = Self> {
|
|||
/// 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`.
|
||||
|
|
|
|||
111
src/fields/fp.rs
111
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,
|
||||
|
|
@ -669,6 +669,50 @@ lazy_static! {
|
|||
static ref FP_TABLES: SqrtTables<Fp> = SqrtTables::new(0x11BE, 1098);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
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());
|
||||
|
||||
let r10 = self.square();
|
||||
let r11 = r10 * self;
|
||||
let r110 = r11.square();
|
||||
let r111 = r110 * self;
|
||||
let r1001 = r111 * r10;
|
||||
let r1101 = r111 * r110;
|
||||
let ra = sqr(*self, 129) * self;
|
||||
let rb = sqr(ra, 7) * r1001;
|
||||
let rc = sqr(rb, 7) * r1101;
|
||||
let rd = sqr(rc, 4) * r11;
|
||||
let re = sqr(rd, 6) * r111;
|
||||
let rf = sqr(re, 3) * r111;
|
||||
let rg = sqr(rf, 10) * r1001;
|
||||
let rh = sqr(rg, 5) * r1001;
|
||||
let ri = sqr(rh, 4) * r1001;
|
||||
let rj = sqr(ri, 3) * r111;
|
||||
let rk = sqr(rj, 4) * r1001;
|
||||
let rl = sqr(rk, 5) * r11;
|
||||
let rm = sqr(rl, 4) * r111;
|
||||
let rn = sqr(rm, 4) * r11;
|
||||
let ro = sqr(rn, 6) * r1001;
|
||||
let rp = sqr(ro, 5) * r1101;
|
||||
let rq = sqr(rp, 4) * r11;
|
||||
let rr = sqr(rq, 7) * r111;
|
||||
let rs = sqr(rr, 3) * r11;
|
||||
rs.square() // rt
|
||||
}
|
||||
|
||||
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 =
|
||||
|
|
@ -679,12 +723,6 @@ impl FieldExt for Fp {
|
|||
0xb4ed8e647196dad1,
|
||||
0x2cd5282c53116b5c,
|
||||
]);
|
||||
const T_MINUS1_OVER2: [u64; 4] = [
|
||||
0x04a67c8dcc969876,
|
||||
0x0000000011234c7e,
|
||||
0x0000000000000000,
|
||||
0x20000000,
|
||||
];
|
||||
const DELTA: Self = DELTA;
|
||||
const TWO_INV: Self = Fp::from_raw([
|
||||
0xcc96987680000001,
|
||||
|
|
@ -706,14 +744,6 @@ impl FieldExt for Fp {
|
|||
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])
|
||||
}
|
||||
|
|
@ -757,37 +787,6 @@ impl FieldExt for Fp {
|
|||
|
||||
tmp.0[0] as u32
|
||||
}
|
||||
|
||||
fn pow_by_t_minus1_over2(&self) -> Self {
|
||||
let sqr = |x: Fp, i: u32| (0..i).fold(x, |x, _| x.square());
|
||||
|
||||
let r10 = self.square();
|
||||
let r11 = r10 * self;
|
||||
let r110 = r11.square();
|
||||
let r111 = r110 * self;
|
||||
let r1001 = r111 * r10;
|
||||
let r1101 = r111 * r110;
|
||||
let ra = sqr(*self, 129) * self;
|
||||
let rb = sqr(ra, 7) * r1001;
|
||||
let rc = sqr(rb, 7) * r1101;
|
||||
let rd = sqr(rc, 4) * r11;
|
||||
let re = sqr(rd, 6) * r111;
|
||||
let rf = sqr(re, 3) * r111;
|
||||
let rg = sqr(rf, 10) * r1001;
|
||||
let rh = sqr(rg, 5) * r1001;
|
||||
let ri = sqr(rh, 4) * r1001;
|
||||
let rj = sqr(ri, 3) * r111;
|
||||
let rk = sqr(rj, 4) * r1001;
|
||||
let rl = sqr(rk, 5) * r11;
|
||||
let rm = sqr(rl, 4) * r111;
|
||||
let rn = sqr(rm, 4) * r11;
|
||||
let ro = sqr(rn, 6) * r1001;
|
||||
let rp = sqr(ro, 5) * r1101;
|
||||
let rq = sqr(rp, 4) * r11;
|
||||
let rr = sqr(rq, 7) * r111;
|
||||
let rs = sqr(rr, 3) * r11;
|
||||
rs.square() // rt
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "std"))]
|
||||
|
|
@ -833,7 +832,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")]
|
||||
|
|
|
|||
111
src/fields/fq.rs
111
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,
|
||||
|
|
@ -669,6 +669,50 @@ lazy_static! {
|
|||
static ref FQ_TABLES: SqrtTables<Fq> = SqrtTables::new(0x116A9E, 1206);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
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());
|
||||
|
||||
let s10 = self.square();
|
||||
let s11 = s10 * self;
|
||||
let s111 = s11.square() * self;
|
||||
let s1001 = s111 * s10;
|
||||
let s1011 = s1001 * s10;
|
||||
let s1101 = s1011 * s10;
|
||||
let sa = sqr(*self, 129) * self;
|
||||
let sb = sqr(sa, 7) * s1001;
|
||||
let sc = sqr(sb, 7) * s1101;
|
||||
let sd = sqr(sc, 4) * s11;
|
||||
let se = sqr(sd, 6) * s111;
|
||||
let sf = sqr(se, 3) * s111;
|
||||
let sg = sqr(sf, 10) * s1001;
|
||||
let sh = sqr(sg, 4) * s1001;
|
||||
let si = sqr(sh, 5) * s1001;
|
||||
let sj = sqr(si, 5) * s1001;
|
||||
let sk = sqr(sj, 3) * s1001;
|
||||
let sl = sqr(sk, 4) * s1011;
|
||||
let sm = sqr(sl, 4) * s1011;
|
||||
let sn = sqr(sm, 5) * s11;
|
||||
let so = sqr(sn, 4) * self;
|
||||
let sp = sqr(so, 5) * s11;
|
||||
let sq = sqr(sp, 4) * s111;
|
||||
let sr = sqr(sq, 5) * s1011;
|
||||
let ss = sqr(sr, 3) * self;
|
||||
sqr(ss, 4) // st
|
||||
}
|
||||
|
||||
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 =
|
||||
|
|
@ -679,12 +723,6 @@ impl FieldExt for Fq {
|
|||
0xf4c8f353124086c1,
|
||||
0x2235e1a7415bf936,
|
||||
]);
|
||||
const T_MINUS1_OVER2: [u64; 4] = [
|
||||
0x04ca546ec6237590,
|
||||
0x0000000011234c7e,
|
||||
0x0000000000000000,
|
||||
0x20000000,
|
||||
];
|
||||
const DELTA: Self = DELTA;
|
||||
const TWO_INV: Self = Fq::from_raw([
|
||||
0xc623759080000001,
|
||||
|
|
@ -706,14 +744,6 @@ impl FieldExt for Fq {
|
|||
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])
|
||||
}
|
||||
|
|
@ -757,37 +787,6 @@ impl FieldExt for Fq {
|
|||
|
||||
tmp.0[0] as u32
|
||||
}
|
||||
|
||||
fn pow_by_t_minus1_over2(&self) -> Self {
|
||||
let sqr = |x: Fq, i: u32| (0..i).fold(x, |x, _| x.square());
|
||||
|
||||
let s10 = self.square();
|
||||
let s11 = s10 * self;
|
||||
let s111 = s11.square() * self;
|
||||
let s1001 = s111 * s10;
|
||||
let s1011 = s1001 * s10;
|
||||
let s1101 = s1011 * s10;
|
||||
let sa = sqr(*self, 129) * self;
|
||||
let sb = sqr(sa, 7) * s1001;
|
||||
let sc = sqr(sb, 7) * s1101;
|
||||
let sd = sqr(sc, 4) * s11;
|
||||
let se = sqr(sd, 6) * s111;
|
||||
let sf = sqr(se, 3) * s111;
|
||||
let sg = sqr(sf, 10) * s1001;
|
||||
let sh = sqr(sg, 4) * s1001;
|
||||
let si = sqr(sh, 5) * s1001;
|
||||
let sj = sqr(si, 5) * s1001;
|
||||
let sk = sqr(sj, 3) * s1001;
|
||||
let sl = sqr(sk, 4) * s1011;
|
||||
let sm = sqr(sl, 4) * s1011;
|
||||
let sn = sqr(sm, 5) * s11;
|
||||
let so = sqr(sn, 4) * self;
|
||||
let sp = sqr(so, 5) * s11;
|
||||
let sq = sqr(sp, 4) * s111;
|
||||
let sr = sqr(sq, 5) * s1011;
|
||||
let ss = sqr(sr, 3) * self;
|
||||
sqr(ss, 4) // st
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "std"))]
|
||||
|
|
@ -833,7 +832,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")]
|
||||
|
|
|
|||
Loading…
Reference in a new issue