mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-07-31 12:31:22 +00:00
Constant-time field square root
WARNING: THIS IS NOT FULLY CONSTANT TIME YET! This will be fixed once we migrate to the jubjub and bls12_381 crates.
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use ff::{
|
||||
adc, mac_with_carry, sbb, BitIterator, Field,
|
||||
LegendreSymbol::{self, *},
|
||||
PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, SqrtField,
|
||||
adc, mac_with_carry, sbb, BitIterator, Field, PrimeField, PrimeFieldDecodingError,
|
||||
PrimeFieldRepr, SqrtField,
|
||||
};
|
||||
use rand_core::RngCore;
|
||||
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use subtle::{Choice, ConditionallySelectable, CtOption};
|
||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
||||
|
||||
use super::ToUniform;
|
||||
|
||||
@@ -264,6 +263,15 @@ impl Default for Fs {
|
||||
}
|
||||
}
|
||||
|
||||
impl ConstantTimeEq for Fs {
|
||||
fn ct_eq(&self, other: &Fs) -> Choice {
|
||||
(self.0).0[0].ct_eq(&(other.0).0[0])
|
||||
& (self.0).0[1].ct_eq(&(other.0).0[1])
|
||||
& (self.0).0[2].ct_eq(&(other.0).0[2])
|
||||
& (self.0).0[3].ct_eq(&(other.0).0[3])
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for Fs {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
write!(f, "Fs({})", self.into_repr())
|
||||
@@ -731,24 +739,7 @@ impl ToUniform for Fs {
|
||||
}
|
||||
|
||||
impl SqrtField for Fs {
|
||||
fn legendre(&self) -> LegendreSymbol {
|
||||
// s = self^((s - 1) // 2)
|
||||
let s = self.pow([
|
||||
0x684b872f6b7b965b,
|
||||
0x53341049e6640841,
|
||||
0x83339d80809a1d80,
|
||||
0x73eda753299d7d4,
|
||||
]);
|
||||
if s == Self::zero() {
|
||||
Zero
|
||||
} else if s == Self::one() {
|
||||
QuadraticResidue
|
||||
} else {
|
||||
QuadraticNonResidue
|
||||
}
|
||||
}
|
||||
|
||||
fn sqrt(&self) -> Option<Self> {
|
||||
fn sqrt(&self) -> CtOption<Self> {
|
||||
// Shank's algorithm for s mod 4 = 3
|
||||
// https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2)
|
||||
|
||||
@@ -761,13 +752,9 @@ impl SqrtField for Fs {
|
||||
]);
|
||||
let mut a0 = a1.square();
|
||||
a0.mul_assign(self);
|
||||
a1.mul_assign(self);
|
||||
|
||||
if a0 == NEGATIVE_ONE {
|
||||
None
|
||||
} else {
|
||||
a1.mul_assign(self);
|
||||
Some(a1)
|
||||
}
|
||||
CtOption::new(a1, !a0.ct_eq(&NEGATIVE_ONE))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1025,27 +1012,6 @@ fn test_fs_repr_sub_noborrow() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fs_legendre() {
|
||||
assert_eq!(QuadraticResidue, Fs::one().legendre());
|
||||
assert_eq!(Zero, Fs::zero().legendre());
|
||||
|
||||
let e = FsRepr([
|
||||
0x8385eec23df1f88e,
|
||||
0x9a01fb412b2dba16,
|
||||
0x4c928edcdd6c22f,
|
||||
0x9f2df7ef69ecef9,
|
||||
]);
|
||||
assert_eq!(QuadraticResidue, Fs::from_repr(e).unwrap().legendre());
|
||||
let e = FsRepr([
|
||||
0xe8ed9f299da78568,
|
||||
0x35efdebc88b2209,
|
||||
0xc82125cb1f916dbe,
|
||||
0x6813d2b38c39bd0,
|
||||
]);
|
||||
assert_eq!(QuadraticNonResidue, Fs::from_repr(e).unwrap().legendre());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_repr_add_nocarry() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
@@ -1569,8 +1535,9 @@ fn test_fs_sqrt() {
|
||||
// Ensure sqrt(a)^2 = a for random a
|
||||
let a = Fs::random(&mut rng);
|
||||
|
||||
if let Some(tmp) = a.sqrt() {
|
||||
assert_eq!(a, tmp.square());
|
||||
let tmp = a.sqrt();
|
||||
if tmp.is_some().into() {
|
||||
assert_eq!(a, tmp.unwrap().square());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1730,5 +1697,5 @@ fn test_fs_root_of_unity() {
|
||||
Fs::root_of_unity()
|
||||
);
|
||||
assert_eq!(Fs::root_of_unity().pow([1 << Fs::S]), Fs::one());
|
||||
assert!(Fs::multiplicative_generator().sqrt().is_none());
|
||||
assert!(bool::from(Fs::multiplicative_generator().sqrt().is_none()));
|
||||
}
|
||||
|
Reference in New Issue
Block a user