ff: Remove SqrtField trait

The sqrt() function is now part of the Field trait. ff_derive returns an
error on fields for which it does not support generating a square root
function.

Note that Fq6 and Fq12 in pairing::bls12_381 leave the function
unimplemented. They will be dropped once the migration to the bls12_381
crate is complete. The equivalent structs in that crate are not exposed.
This commit is contained in:
Jack Grigg 2020-05-01 13:48:30 +12:00
parent b02cf3b467
commit 1761ebfb35
20 changed files with 124 additions and 137 deletions

View File

@ -1,4 +1,4 @@
use ff::{Field, PowVartime, PrimeField, ScalarEngine, SqrtField}; use ff::{Field, PowVartime, PrimeField, ScalarEngine};
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use pairing::{Engine, PairingCurveAffine}; use pairing::{Engine, PairingCurveAffine};
@ -217,9 +217,7 @@ impl Field for Fr {
fn frobenius_map(&mut self, _: usize) { fn frobenius_map(&mut self, _: usize) {
// identity // identity
} }
}
impl SqrtField for Fr {
fn sqrt(&self) -> CtOption<Self> { fn sqrt(&self) -> CtOption<Self> {
// Tonelli-Shank's algorithm for q mod 16 = 1 // Tonelli-Shank's algorithm for q mod 16 = 1
// https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5)

View File

@ -163,8 +163,8 @@ pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
&modulus, &modulus,
&endianness, &endianness,
limbs, limbs,
sqrt_impl,
)); ));
gen.extend(sqrt_impl);
// Return the generated impl // Return the generated impl
gen.into() gen.into()
@ -486,89 +486,84 @@ fn prime_field_constants_and_sqrt(
biguint_to_u64_vec((exp(generator.clone(), &t, &modulus) * &r) % modulus, limbs); biguint_to_u64_vec((exp(generator.clone(), &t, &modulus) * &r) % modulus, limbs);
let generator = biguint_to_u64_vec((generator.clone() * &r) % modulus, limbs); let generator = biguint_to_u64_vec((generator.clone() * &r) % modulus, limbs);
let sqrt_impl = if (modulus % BigUint::from_str("4").unwrap()) let sqrt_impl =
== BigUint::from_str("3").unwrap() if (modulus % BigUint::from_str("4").unwrap()) == BigUint::from_str("3").unwrap() {
{ // Addition chain for (r + 1) // 4
// Addition chain for (r + 1) // 4 let mod_plus_1_over_4 = pow_fixed::generate(
let mod_plus_1_over_4 = pow_fixed::generate( &quote! {self},
&quote! {self}, (modulus + BigUint::from_str("1").unwrap()) >> 2,
(modulus + BigUint::from_str("1").unwrap()) >> 2, );
);
quote! { quote! {
impl ::ff::SqrtField for #name { use ::subtle::ConstantTimeEq;
fn sqrt(&self) -> ::subtle::CtOption<Self> {
use ::subtle::ConstantTimeEq;
// Because r = 3 (mod 4) // Because r = 3 (mod 4)
// sqrt can be done with only one exponentiation, // sqrt can be done with only one exponentiation,
// via the computation of self^((r + 1) // 4) (mod r) // via the computation of self^((r + 1) // 4) (mod r)
let sqrt = { let sqrt = {
#mod_plus_1_over_4 #mod_plus_1_over_4
}; };
::subtle::CtOption::new( ::subtle::CtOption::new(
sqrt, sqrt,
(sqrt * &sqrt).ct_eq(self), // Only return Some if it's the square root. (sqrt * &sqrt).ct_eq(self), // Only return Some if it's the square root.
) )
}
} }
} } else if (modulus % BigUint::from_str("16").unwrap()) == BigUint::from_str("1").unwrap() {
} else if (modulus % BigUint::from_str("16").unwrap()) == BigUint::from_str("1").unwrap() { // Addition chain for (t - 1) // 2
// Addition chain for (t - 1) // 2 let t_minus_1_over_2 = pow_fixed::generate(&quote! {self}, (&t - BigUint::one()) >> 1);
let t_minus_1_over_2 = pow_fixed::generate(&quote! {self}, (&t - BigUint::one()) >> 1);
quote! { quote! {
impl ::ff::SqrtField for #name { // Tonelli-Shank's algorithm for q mod 16 = 1
fn sqrt(&self) -> ::subtle::CtOption<Self> { // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5)
// Tonelli-Shank's algorithm for q mod 16 = 1 use ::subtle::{ConditionallySelectable, ConstantTimeEq};
// https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5)
use ::subtle::{ConditionallySelectable, ConstantTimeEq};
// w = self^((t - 1) // 2) // w = self^((t - 1) // 2)
let w = { let w = {
#t_minus_1_over_2 #t_minus_1_over_2
}; };
let mut v = S; let mut v = S;
let mut x = *self * &w; let mut x = *self * &w;
let mut b = x * &w; let mut b = x * &w;
// Initialize z as the 2^S root of unity. // Initialize z as the 2^S root of unity.
let mut z = ROOT_OF_UNITY; let mut z = ROOT_OF_UNITY;
for max_v in (1..=S).rev() { for max_v in (1..=S).rev() {
let mut k = 1; let mut k = 1;
let mut tmp = b.square(); let mut tmp = b.square();
let mut j_less_than_v: ::subtle::Choice = 1.into(); let mut j_less_than_v: ::subtle::Choice = 1.into();
for j in 2..max_v { for j in 2..max_v {
let tmp_is_one = tmp.ct_eq(&#name::one()); let tmp_is_one = tmp.ct_eq(&#name::one());
let squared = #name::conditional_select(&tmp, &z, tmp_is_one).square(); let squared = #name::conditional_select(&tmp, &z, tmp_is_one).square();
tmp = #name::conditional_select(&squared, &tmp, tmp_is_one); tmp = #name::conditional_select(&squared, &tmp, tmp_is_one);
let new_z = #name::conditional_select(&z, &squared, tmp_is_one); let new_z = #name::conditional_select(&z, &squared, tmp_is_one);
j_less_than_v &= !j.ct_eq(&v); j_less_than_v &= !j.ct_eq(&v);
k = u32::conditional_select(&j, &k, tmp_is_one); k = u32::conditional_select(&j, &k, tmp_is_one);
z = #name::conditional_select(&z, &new_z, j_less_than_v); z = #name::conditional_select(&z, &new_z, j_less_than_v);
}
let result = x * &z;
x = #name::conditional_select(&result, &x, b.ct_eq(&#name::one()));
z = z.square();
b *= &z;
v = k;
} }
::subtle::CtOption::new( let result = x * &z;
x, x = #name::conditional_select(&result, &x, b.ct_eq(&#name::one()));
(x * &x).ct_eq(self), // Only return Some if it's the square root. z = z.square();
) b *= &z;
v = k;
} }
::subtle::CtOption::new(
x,
(x * &x).ct_eq(self), // Only return Some if it's the square root.
)
} }
} } else {
} else { syn::Error::new_spanned(
quote! {} &name,
}; "ff_derive can't generate a square root function for this field.",
)
.to_compile_error()
};
// Compute R^2 mod m // Compute R^2 mod m
let r2 = biguint_to_u64_vec((&r * &r) % modulus, limbs); let r2 = biguint_to_u64_vec((&r * &r) % modulus, limbs);
@ -634,6 +629,7 @@ fn prime_field_impl(
modulus: &BigUint, modulus: &BigUint,
endianness: &ReprEndianness, endianness: &ReprEndianness,
limbs: usize, limbs: usize,
sqrt_impl: proc_macro2::TokenStream,
) -> proc_macro2::TokenStream { ) -> proc_macro2::TokenStream {
// Returns r{n} as an ident. // Returns r{n} as an ident.
fn get_temp(n: usize) -> syn::Ident { fn get_temp(n: usize) -> syn::Ident {
@ -1280,6 +1276,10 @@ fn prime_field_impl(
{ {
#squaring_impl #squaring_impl
} }
fn sqrt(&self) -> ::subtle::CtOption<Self> {
#sqrt_impl
}
} }
impl #name { impl #name {

View File

@ -75,6 +75,10 @@ pub trait Field:
/// Exponentiates this element by a power of the base prime modulus via /// Exponentiates this element by a power of the base prime modulus via
/// the Frobenius automorphism. /// the Frobenius automorphism.
fn frobenius_map(&mut self, power: usize); fn frobenius_map(&mut self, power: usize);
/// Returns the square root of the field element, if it is
/// quadratic residue.
fn sqrt(&self) -> CtOption<Self>;
} }
pub trait PowVartime<L>: Field pub trait PowVartime<L>: Field
@ -124,13 +128,6 @@ impl<T: Field> PowVartime<u64> for T {
const LIMB_SIZE: u64 = 64; const LIMB_SIZE: u64 = 64;
} }
/// This trait represents an element of a field that has a square root operation described for it.
pub trait SqrtField: Field {
/// Returns the square root of the field element, if it is
/// quadratic residue.
fn sqrt(&self) -> CtOption<Self>;
}
/// This represents an element of a prime field. /// This represents an element of a prime field.
pub trait PrimeField: pub trait PrimeField:
Field + Ord + From<u64> + BitAnd<u64, Output = u64> + Shr<u32, Output = Self> Field + Ord + From<u64> + BitAnd<u64, Output = u64> + Shr<u32, Output = Self>
@ -230,7 +227,7 @@ pub trait PrimeField:
/// pairing-friendly curve) can be defined in a subtrait. /// pairing-friendly curve) can be defined in a subtrait.
pub trait ScalarEngine: Sized + 'static + Clone { pub trait ScalarEngine: Sized + 'static + Clone {
/// This is the scalar field of the engine's groups. /// This is the scalar field of the engine's groups.
type Fr: PrimeField + SqrtField; type Fr: PrimeField;
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -1,7 +1,7 @@
// Catch documentation errors caused by code changes. // Catch documentation errors caused by code changes.
#![deny(intra_doc_link_resolution_failure)] #![deny(intra_doc_link_resolution_failure)]
use ff::{PrimeField, ScalarEngine, SqrtField}; use ff::{Field, PrimeField, ScalarEngine};
use rand::RngCore; use rand::RngCore;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
@ -47,8 +47,8 @@ pub trait CurveProjective:
+ CurveOpsOwned<<Self as CurveProjective>::Affine> + CurveOpsOwned<<Self as CurveProjective>::Affine>
{ {
type Engine: ScalarEngine<Fr = Self::Scalar>; type Engine: ScalarEngine<Fr = Self::Scalar>;
type Scalar: PrimeField + SqrtField; type Scalar: PrimeField;
type Base: SqrtField; type Base: Field;
type Affine: CurveAffine<Projective = Self, Scalar = Self::Scalar>; type Affine: CurveAffine<Projective = Self, Scalar = Self::Scalar>;
/// Returns an element chosen uniformly at random using a user-provided RNG. /// Returns an element chosen uniformly at random using a user-provided RNG.
@ -105,8 +105,8 @@ pub trait CurveAffine:
+ Neg<Output = Self> + Neg<Output = Self>
{ {
type Engine: ScalarEngine<Fr = Self::Scalar>; type Engine: ScalarEngine<Fr = Self::Scalar>;
type Scalar: PrimeField + SqrtField; type Scalar: PrimeField;
type Base: SqrtField; type Base: Field;
type Projective: CurveProjective<Affine = Self, Scalar = Self::Scalar>; type Projective: CurveProjective<Affine = Self, Scalar = Self::Scalar>;
type Uncompressed: EncodedPoint<Affine = Self>; type Uncompressed: EncodedPoint<Affine = Self>;
type Compressed: EncodedPoint<Affine = Self>; type Compressed: EncodedPoint<Affine = Self>;

View File

@ -3,7 +3,7 @@ use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use ff::{Field, PrimeField, SqrtField}; use ff::{Field, PrimeField};
use pairing::bls12_381::*; use pairing::bls12_381::*;
fn bench_fq_add_assign(c: &mut Criterion) { fn bench_fq_add_assign(c: &mut Criterion) {

View File

@ -3,7 +3,7 @@ use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, MulAssign, SubAssign}; use std::ops::{AddAssign, MulAssign, SubAssign};
use ff::{Field, SqrtField}; use ff::Field;
use pairing::bls12_381::*; use pairing::bls12_381::*;
fn bench_fq2_add_assign(c: &mut Criterion) { fn bench_fq2_add_assign(c: &mut Criterion) {

View File

@ -3,7 +3,7 @@ use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use ff::{Field, PrimeField, SqrtField}; use ff::{Field, PrimeField};
use pairing::bls12_381::*; use pairing::bls12_381::*;
fn bench_fr_add_assign(c: &mut Criterion) { fn bench_fr_add_assign(c: &mut Criterion) {

View File

@ -754,7 +754,7 @@ pub mod g1 {
use super::super::{Bls12, Fq, Fq12, FqRepr, Fr}; use super::super::{Bls12, Fq, Fq12, FqRepr, Fr};
use super::g2::G2Affine; use super::g2::G2Affine;
use crate::{Engine, PairingCurveAffine}; use crate::{Engine, PairingCurveAffine};
use ff::{BitIterator, Field, PrimeField, SqrtField}; use ff::{BitIterator, Field, PrimeField};
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use rand_core::RngCore; use rand_core::RngCore;
use std::fmt; use std::fmt;
@ -1054,8 +1054,6 @@ pub mod g1 {
#[test] #[test]
fn g1_generator() { fn g1_generator() {
use crate::SqrtField;
let mut x = Fq::zero(); let mut x = Fq::zero();
let mut i = 0; let mut i = 0;
loop { loop {
@ -1366,7 +1364,7 @@ pub mod g2 {
use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr}; use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr};
use super::g1::G1Affine; use super::g1::G1Affine;
use crate::{Engine, PairingCurveAffine}; use crate::{Engine, PairingCurveAffine};
use ff::{BitIterator, Field, PrimeField, SqrtField}; use ff::{BitIterator, Field, PrimeField};
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use rand_core::RngCore; use rand_core::RngCore;
use std::fmt; use std::fmt;
@ -1708,8 +1706,6 @@ pub mod g2 {
#[test] #[test]
fn g2_generator() { fn g2_generator() {
use crate::SqrtField;
let mut x = Fq2::zero(); let mut x = Fq2::zero();
let mut i = 0; let mut i = 0;
loop { loop {

View File

@ -1715,8 +1715,6 @@ fn test_fq_pow() {
#[test] #[test]
fn test_fq_sqrt() { fn test_fq_sqrt() {
use ff::SqrtField;
let mut rng = XorShiftRng::from_seed([ let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5, 0xe5,
@ -1846,8 +1844,6 @@ fn test_fq_num_bits() {
#[test] #[test]
fn test_fq_root_of_unity() { fn test_fq_root_of_unity() {
use ff::SqrtField;
assert_eq!(Fq::S, 1); assert_eq!(Fq::S, 1);
assert_eq!(Fq::multiplicative_generator(), Fq::from(2)); assert_eq!(Fq::multiplicative_generator(), Fq::from(2));
assert_eq!( assert_eq!(

View File

@ -237,6 +237,10 @@ impl Field for Fq12 {
c1: t.mul(&self.c1).neg(), c1: t.mul(&self.c1).neg(),
}) })
} }
fn sqrt(&self) -> CtOption<Self> {
unimplemented!()
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -1,5 +1,5 @@
use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE}; use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE};
use ff::{Field, PowVartime, SqrtField}; use ff::{Field, PowVartime};
use rand_core::RngCore; use rand_core::RngCore;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
@ -241,9 +241,7 @@ impl Field for Fq2 {
fn frobenius_map(&mut self, power: usize) { fn frobenius_map(&mut self, power: usize) {
self.c1.mul_assign(&FROBENIUS_COEFF_FQ2_C1[power % 2]); self.c1.mul_assign(&FROBENIUS_COEFF_FQ2_C1[power % 2]);
} }
}
impl SqrtField for Fq2 {
/// WARNING: THIS IS NOT ACTUALLY CONSTANT TIME YET! /// WARNING: THIS IS NOT ACTUALLY CONSTANT TIME YET!
/// THIS WILL BE REPLACED BY THE bls12_381 CRATE, WHICH IS CONSTANT TIME! /// THIS WILL BE REPLACED BY THE bls12_381 CRATE, WHICH IS CONSTANT TIME!
fn sqrt(&self) -> CtOption<Self> { fn sqrt(&self) -> CtOption<Self> {

View File

@ -391,6 +391,10 @@ impl Field for Fq6 {
tmp tmp
}) })
} }
fn sqrt(&self) -> CtOption<Self> {
unimplemented!()
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -495,8 +495,6 @@ fn test_fr_pow() {
#[test] #[test]
fn test_fr_sqrt() { fn test_fr_sqrt() {
use ff::SqrtField;
let mut rng = XorShiftRng::from_seed([ let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5, 0xe5,
@ -628,8 +626,6 @@ fn test_fr_num_bits() {
#[test] #[test]
fn test_fr_root_of_unity() { fn test_fr_root_of_unity() {
use ff::SqrtField;
assert_eq!(Fr::S, 32); assert_eq!(Fr::S, 32);
assert_eq!(Fr::multiplicative_generator(), Fr::from(7)); assert_eq!(Fr::multiplicative_generator(), Fr::from(7));
assert_eq!( assert_eq!(

View File

@ -20,7 +20,7 @@ pub mod tests;
pub mod bls12_381; pub mod bls12_381;
use ff::{Field, PrimeField, ScalarEngine, SqrtField}; use ff::{Field, PrimeField, ScalarEngine};
use group::{CurveAffine, CurveOps, CurveOpsOwned, CurveProjective}; use group::{CurveAffine, CurveOps, CurveOpsOwned, CurveProjective};
use subtle::CtOption; use subtle::CtOption;
@ -61,10 +61,10 @@ pub trait Engine: ScalarEngine {
> + From<Self::G2>; > + From<Self::G2>;
/// The base field that hosts G1. /// The base field that hosts G1.
type Fq: PrimeField + SqrtField; type Fq: PrimeField;
/// The extension field that hosts G2. /// The extension field that hosts G2.
type Fqe: SqrtField; type Fqe: Field;
/// The extension field that hosts the target group of the pairing. /// The extension field that hosts the target group of the pairing.
type Fqk: Field; type Fqk: Field;

View File

@ -1,4 +1,4 @@
use ff::{Field, PowVartime, PrimeField, SqrtField}; use ff::{Field, PowVartime, PrimeField};
use rand_core::{RngCore, SeedableRng}; use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
@ -23,7 +23,7 @@ pub fn random_frobenius_tests<F: Field, C: AsRef<[u8]>>(characteristic: C, maxpo
} }
} }
pub fn random_sqrt_tests<F: SqrtField>() { pub fn random_sqrt_tests<F: Field>() {
let mut rng = XorShiftRng::from_seed([ let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5, 0xe5,

View File

@ -1,4 +1,4 @@
use ff::{BitIterator, Field, PrimeField, SqrtField}; use ff::{BitIterator, Field, PrimeField};
use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use subtle::CtOption; use subtle::CtOption;

View File

@ -1,5 +1,5 @@
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use ff::{adc, mac_with_carry, sbb, BitIterator, Field, PowVartime, PrimeField, SqrtField}; use ff::{adc, mac_with_carry, sbb, BitIterator, Field, PowVartime, PrimeField};
use rand_core::RngCore; use rand_core::RngCore;
use std::mem; use std::mem;
use std::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Neg, Shr, Sub, SubAssign}; use std::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Neg, Shr, Sub, SubAssign};
@ -541,6 +541,24 @@ impl Field for Fs {
ret.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7); ret.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7);
ret ret
} }
fn sqrt(&self) -> CtOption<Self> {
// Shank's algorithm for s mod 4 = 3
// https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2)
// a1 = self^((s - 3) // 4)
let mut a1 = self.pow_vartime([
0xb425c397b5bdcb2du64,
0x299a0824f3320420,
0x4199cec0404d0ec0,
0x39f6d3a994cebea,
]);
let mut a0 = a1.square();
a0.mul_assign(self);
a1.mul_assign(self);
CtOption::new(a1, !a0.ct_eq(&NEGATIVE_ONE))
}
} }
impl Fs { impl Fs {
@ -673,26 +691,6 @@ impl ToUniform for Fs {
} }
} }
impl SqrtField for Fs {
fn sqrt(&self) -> CtOption<Self> {
// Shank's algorithm for s mod 4 = 3
// https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2)
// a1 = self^((s - 3) // 4)
let mut a1 = self.pow_vartime([
0xb425c397b5bdcb2du64,
0x299a0824f3320420,
0x4199cec0404d0ec0,
0x39f6d3a994cebea,
]);
let mut a0 = a1.square();
a0.mul_assign(self);
a1.mul_assign(self);
CtOption::new(a1, !a0.ct_eq(&NEGATIVE_ONE))
}
}
#[test] #[test]
fn test_neg_one() { fn test_neg_one() {
let o = Fs::one().neg(); let o = Fs::one().neg();

View File

@ -23,7 +23,7 @@
//! [Jubjub]: https://zips.z.cash/protocol/protocol.pdf#jubjub //! [Jubjub]: https://zips.z.cash/protocol/protocol.pdf#jubjub
//! [BLS12-381]: pairing::bls12_381 //! [BLS12-381]: pairing::bls12_381
use ff::{Field, PrimeField, SqrtField}; use ff::{Field, PrimeField};
use pairing::Engine; use pairing::Engine;
use crate::group_hash::group_hash; use crate::group_hash::group_hash;
@ -95,7 +95,7 @@ pub trait ToUniform {
/// and some pre-computed parameters. /// and some pre-computed parameters.
pub trait JubjubEngine: Engine { pub trait JubjubEngine: Engine {
/// The scalar field of the Jubjub curve /// The scalar field of the Jubjub curve
type Fs: PrimeField + SqrtField + ToUniform; type Fs: PrimeField + ToUniform;
/// The parameters of Jubjub and the Sapling protocol /// The parameters of Jubjub and the Sapling protocol
type Params: JubjubParams<Self>; type Params: JubjubParams<Self>;
} }

View File

@ -1,4 +1,4 @@
use ff::{BitIterator, Field, PrimeField, SqrtField}; use ff::{BitIterator, Field, PrimeField};
use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use subtle::CtOption; use subtle::CtOption;

View File

@ -1,6 +1,6 @@
use super::{edwards, montgomery, JubjubEngine, JubjubParams, PrimeOrder}; use super::{edwards, montgomery, JubjubEngine, JubjubParams, PrimeOrder};
use ff::{Field, PrimeField, SqrtField}; use ff::{Field, PrimeField};
use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use rand_core::{RngCore, SeedableRng}; use rand_core::{RngCore, SeedableRng};