mirror of
https://github.com/saymrwulf/pasta_curves-source.git
synced 2026-09-04 20:03:39 +00:00
Place SqrtTables behind a sqrt-tables feature flag
This enables the crate to be compiled without the tables, instead using a simple fallback for `SqrtRatio::sqrt_ratio`.
This commit is contained in:
parent
96116e20e5
commit
314b1bcb94
4 changed files with 72 additions and 28 deletions
|
|
@ -52,6 +52,7 @@ subtle = { version = "2.3", default-features = false }
|
|||
lazy_static = { version = "1.4.0", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["bits", "std"]
|
||||
default = ["bits", "sqrt-table", "std"]
|
||||
bits = ["ff/bits"]
|
||||
sqrt-table = ["std"]
|
||||
std = ["group/alloc", "lazy_static", "rand/getrandom"]
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@
|
|||
use core::mem::size_of;
|
||||
|
||||
use static_assertions::const_assert;
|
||||
use subtle::Choice;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use subtle::CtOption;
|
||||
use subtle::{Choice, ConditionallySelectable, CtOption};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use super::Group;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::{assert, boxed::Box, convert::TryInto, marker::PhantomData, vec::Vec};
|
||||
use std::assert;
|
||||
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
use std::{boxed::Box, convert::TryInto, marker::PhantomData, vec::Vec};
|
||||
|
||||
const_assert!(size_of::<usize>() >= 4);
|
||||
|
||||
|
|
@ -55,7 +55,40 @@ pub trait SqrtRatio: ff::PrimeField {
|
|||
/// 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);
|
||||
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
|
||||
// General implementation:
|
||||
//
|
||||
// a = num * inv0(div)
|
||||
// = { 0 if div is zero
|
||||
// { num/div otherwise
|
||||
//
|
||||
// b = G_S * a
|
||||
// = { 0 if div is zero
|
||||
// { G_S*num/div otherwise
|
||||
//
|
||||
// Since G_S is non-square, a and b are either both zero (and both square), or
|
||||
// only one them is square. We can therefore choose the square root to return
|
||||
// based on whether a is square, but for the boolean output we need to handle the
|
||||
// num != 0 && div == 0 case specifically.
|
||||
|
||||
let a = div.invert().unwrap_or_else(Self::zero) * num;
|
||||
let b = a * Self::root_of_unity();
|
||||
let sqrt_a = a.sqrt();
|
||||
let sqrt_b = b.sqrt();
|
||||
|
||||
let num_is_zero = num.is_zero();
|
||||
let div_is_zero = div.is_zero();
|
||||
let is_square = sqrt_a.is_some();
|
||||
let is_nonsquare = sqrt_b.is_some();
|
||||
assert!(bool::from(
|
||||
num_is_zero | div_is_zero | (is_square ^ is_nonsquare)
|
||||
));
|
||||
|
||||
(
|
||||
is_square & !(!num_is_zero & div_is_zero),
|
||||
CtOption::conditional_select(&sqrt_b, &sqrt_a, is_square).unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Equivalent to `Self::sqrt_ratio(self, one())`.
|
||||
fn sqrt_alt(&self) -> (Choice, Self) {
|
||||
|
|
@ -120,13 +153,13 @@ pub trait FieldExt: SqrtRatio + From<bool> + Ord + Group<Scalar = Self> {
|
|||
/// https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5)
|
||||
///
|
||||
/// `tm1d2` should be set to `(t - 1) // 2`, where `t = (modulus - 1) >> F::S`.
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "std"))))]
|
||||
#[cfg(not(feature = "sqrt-table"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "sqrt-table"))))]
|
||||
pub(crate) fn sqrt_tonelli_shanks<F: ff::PrimeField, S: AsRef<[u64]>>(
|
||||
f: &F,
|
||||
tm1d2: S,
|
||||
) -> CtOption<F> {
|
||||
use subtle::{ConditionallySelectable, ConstantTimeEq};
|
||||
use subtle::ConstantTimeEq;
|
||||
|
||||
// w = self^((t - 1) // 2)
|
||||
let w = f.pow_vartime(tm1d2);
|
||||
|
|
@ -167,8 +200,8 @@ pub(crate) fn sqrt_tonelli_shanks<F: ff::PrimeField, S: AsRef<[u64]>>(
|
|||
}
|
||||
|
||||
/// Parameters for a perfect hash function used in square root computation.
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "sqrt-table")))]
|
||||
#[derive(Debug)]
|
||||
struct SqrtHasher<F: FieldExt> {
|
||||
hash_xor: u32,
|
||||
|
|
@ -176,7 +209,7 @@ struct SqrtHasher<F: FieldExt> {
|
|||
marker: PhantomData<F>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
impl<F: FieldExt> SqrtHasher<F> {
|
||||
/// Returns a perfect hash of x for use with SqrtTables::inv.
|
||||
fn hash(&self, x: &F) -> usize {
|
||||
|
|
@ -189,8 +222,8 @@ impl<F: FieldExt> SqrtHasher<F> {
|
|||
}
|
||||
|
||||
/// Tables used for square root computation.
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "sqrt-table")))]
|
||||
#[derive(Debug)]
|
||||
pub struct SqrtTables<F: FieldExt> {
|
||||
hasher: SqrtHasher<F>,
|
||||
|
|
@ -201,7 +234,7 @@ pub struct SqrtTables<F: FieldExt> {
|
|||
g3: Box<[F; 129]>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
impl<F: FieldExt> SqrtTables<F> {
|
||||
/// Build tables given parameters for the perfect hash.
|
||||
pub fn new(hash_xor: u32, hash_mod: usize) -> Self {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use ff::PrimeField;
|
|||
use rand::RngCore;
|
||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
#[cfg(feature = "bits")]
|
||||
|
|
@ -15,7 +15,10 @@ use ff::{FieldBits, PrimeFieldBits};
|
|||
use crate::arithmetic::{adc, mac, sbb};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::arithmetic::{FieldExt, Group, SqrtRatio, SqrtTables};
|
||||
use crate::arithmetic::{FieldExt, Group, SqrtRatio};
|
||||
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
use crate::arithmetic::SqrtTables;
|
||||
|
||||
/// This represents an element of $\mathbb{F}_p$ where
|
||||
///
|
||||
|
|
@ -516,13 +519,13 @@ impl ff::Field for Fp {
|
|||
|
||||
/// Computes the square root of this element, if it exists.
|
||||
fn sqrt(&self) -> CtOption<Self> {
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
{
|
||||
let (is_square, res) = FP_TABLES.sqrt_alt(self);
|
||||
CtOption::new(res, is_square)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[cfg(not(feature = "sqrt-table"))]
|
||||
crate::arithmetic::sqrt_tonelli_shanks(self, &T_MINUS1_OVER2)
|
||||
}
|
||||
|
||||
|
|
@ -666,10 +669,10 @@ impl PrimeFieldBits for Fp {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
lazy_static! {
|
||||
// The perfect hash parameters are found by `squareroottab.sage` in zcash/pasta.
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "sqrt-table")))]
|
||||
static ref FP_TABLES: SqrtTables<Fp> = SqrtTables::new(0x11BE, 1098);
|
||||
}
|
||||
|
||||
|
|
@ -716,10 +719,12 @@ impl SqrtRatio for Fp {
|
|||
tmp.0[0] as u32
|
||||
}
|
||||
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
|
||||
FP_TABLES.sqrt_ratio(num, div)
|
||||
}
|
||||
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
fn sqrt_alt(&self) -> (Choice, Self) {
|
||||
FP_TABLES.sqrt_alt(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use ff::PrimeField;
|
|||
use rand::RngCore;
|
||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
#[cfg(feature = "bits")]
|
||||
|
|
@ -15,7 +15,10 @@ use ff::{FieldBits, PrimeFieldBits};
|
|||
use crate::arithmetic::{adc, mac, sbb};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::arithmetic::{FieldExt, Group, SqrtRatio, SqrtTables};
|
||||
use crate::arithmetic::{FieldExt, Group, SqrtRatio};
|
||||
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
use crate::arithmetic::SqrtTables;
|
||||
|
||||
/// This represents an element of $\mathbb{F}_q$ where
|
||||
///
|
||||
|
|
@ -516,13 +519,13 @@ impl ff::Field for Fq {
|
|||
|
||||
/// Computes the square root of this element, if it exists.
|
||||
fn sqrt(&self) -> CtOption<Self> {
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
{
|
||||
let (is_square, res) = FQ_TABLES.sqrt_alt(self);
|
||||
CtOption::new(res, is_square)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[cfg(not(feature = "sqrt-table"))]
|
||||
crate::arithmetic::sqrt_tonelli_shanks(self, &T_MINUS1_OVER2)
|
||||
}
|
||||
|
||||
|
|
@ -665,10 +668,10 @@ impl PrimeFieldBits for Fq {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
lazy_static! {
|
||||
// The perfect hash parameters are found by `squareroottab.sage` in zcash/pasta.
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "sqrt-table")))]
|
||||
static ref FQ_TABLES: SqrtTables<Fq> = SqrtTables::new(0x116A9E, 1206);
|
||||
}
|
||||
|
||||
|
|
@ -715,10 +718,12 @@ impl SqrtRatio for Fq {
|
|||
tmp.0[0] as u32
|
||||
}
|
||||
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
|
||||
FQ_TABLES.sqrt_ratio(num, div)
|
||||
}
|
||||
|
||||
#[cfg(feature = "sqrt-table")]
|
||||
fn sqrt_alt(&self) -> (Choice, Self) {
|
||||
FQ_TABLES.sqrt_alt(self)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue