cargo fmt zcash_primitives
This commit is contained in:
parent
9a4f6812f1
commit
81c58172c3
|
@ -1,14 +1,14 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate pairing;
|
||||
extern crate rand_core;
|
||||
extern crate rand_os;
|
||||
extern crate test;
|
||||
extern crate pairing;
|
||||
extern crate zcash_primitives;
|
||||
|
||||
use pairing::bls12_381::Bls12;
|
||||
use rand_core::RngCore;
|
||||
use rand_os::OsRng;
|
||||
use pairing::bls12_381::Bls12;
|
||||
use zcash_primitives::jubjub::JubjubBls12;
|
||||
use zcash_primitives::pedersen_hash::{pedersen_hash, Personalization};
|
||||
|
||||
|
@ -16,10 +16,10 @@ use zcash_primitives::pedersen_hash::{pedersen_hash, Personalization};
|
|||
fn bench_pedersen_hash(b: &mut test::Bencher) {
|
||||
let params = JubjubBls12::new();
|
||||
let rng = &mut OsRng;
|
||||
let bits = (0..510).map(|_| (rng.next_u32() % 2) != 0).collect::<Vec<_>>();
|
||||
let bits = (0..510)
|
||||
.map(|_| (rng.next_u32() % 2) != 0)
|
||||
.collect::<Vec<_>>();
|
||||
let personalization = Personalization::MerkleTree(31);
|
||||
|
||||
b.iter(|| {
|
||||
pedersen_hash::<Bls12, _>(personalization, bits.clone(), ¶ms)
|
||||
});
|
||||
b.iter(|| pedersen_hash::<Bls12, _>(personalization, bits.clone(), ¶ms));
|
||||
}
|
||||
|
|
|
@ -2,39 +2,31 @@
|
|||
/// This is chosen to be some random string that we couldn't have anticipated when we designed
|
||||
/// the algorithm, for rigidity purposes.
|
||||
/// We deliberately use an ASCII hex string of 32 bytes here.
|
||||
pub const GH_FIRST_BLOCK: &'static [u8; 64]
|
||||
= b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0";
|
||||
pub const GH_FIRST_BLOCK: &'static [u8; 64] =
|
||||
b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0";
|
||||
|
||||
// BLAKE2s invocation personalizations
|
||||
/// BLAKE2s Personalization for CRH^ivk = BLAKE2s(ak | nk)
|
||||
pub const CRH_IVK_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcashivk";
|
||||
pub const CRH_IVK_PERSONALIZATION: &'static [u8; 8] = b"Zcashivk";
|
||||
|
||||
/// BLAKE2s Personalization for PRF^nf = BLAKE2s(nk | rho)
|
||||
pub const PRF_NF_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcash_nf";
|
||||
pub const PRF_NF_PERSONALIZATION: &'static [u8; 8] = b"Zcash_nf";
|
||||
|
||||
// Group hash personalizations
|
||||
/// BLAKE2s Personalization for Pedersen hash generators.
|
||||
pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcash_PH";
|
||||
pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8] = b"Zcash_PH";
|
||||
|
||||
/// BLAKE2s Personalization for the group hash for key diversification
|
||||
pub const KEY_DIVERSIFICATION_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcash_gd";
|
||||
pub const KEY_DIVERSIFICATION_PERSONALIZATION: &'static [u8; 8] = b"Zcash_gd";
|
||||
|
||||
/// BLAKE2s Personalization for the spending key base point
|
||||
pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcash_G_";
|
||||
pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_G_";
|
||||
|
||||
/// BLAKE2s Personalization for the proof generation key base point
|
||||
pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcash_H_";
|
||||
pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_H_";
|
||||
|
||||
/// BLAKE2s Personalization for the value commitment generator for the value
|
||||
pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcash_cv";
|
||||
pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_cv";
|
||||
|
||||
/// BLAKE2s Personalization for the nullifier position generator (for computing rho)
|
||||
pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcash_J_";
|
||||
pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_J_";
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
use jubjub::{
|
||||
JubjubEngine,
|
||||
PrimeOrder,
|
||||
edwards
|
||||
};
|
||||
use jubjub::{edwards, JubjubEngine, PrimeOrder};
|
||||
|
||||
use ff::{
|
||||
PrimeField
|
||||
};
|
||||
use ff::PrimeField;
|
||||
|
||||
use blake2s_simd::Params;
|
||||
use constants;
|
||||
|
@ -17,9 +11,8 @@ use constants;
|
|||
pub fn group_hash<E: JubjubEngine>(
|
||||
tag: &[u8],
|
||||
personalization: &[u8],
|
||||
params: &E::Params
|
||||
) -> Option<edwards::Point<E, PrimeOrder>>
|
||||
{
|
||||
params: &E::Params,
|
||||
) -> Option<edwards::Point<E, PrimeOrder>> {
|
||||
assert_eq!(personalization.len(), 8);
|
||||
|
||||
// Check to see that scalar field is 255 bits
|
||||
|
@ -42,7 +35,7 @@ pub fn group_hash<E: JubjubEngine>(
|
|||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
Err(_) => None
|
||||
}
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,12 @@
|
|||
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
|
||||
|
||||
use super::{
|
||||
JubjubEngine,
|
||||
JubjubParams,
|
||||
Unknown,
|
||||
PrimeOrder,
|
||||
montgomery
|
||||
};
|
||||
use super::{montgomery, JubjubEngine, JubjubParams, PrimeOrder, Unknown};
|
||||
|
||||
use rand_core::RngCore;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use std::io::{
|
||||
self,
|
||||
Write,
|
||||
Read
|
||||
};
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
// Represents the affine point (X/Z, Y/Z) via the extended
|
||||
// twisted Edwards coordinates.
|
||||
|
@ -29,46 +19,38 @@ pub struct Point<E: JubjubEngine, Subgroup> {
|
|||
y: E::Fr,
|
||||
t: E::Fr,
|
||||
z: E::Fr,
|
||||
_marker: PhantomData<Subgroup>
|
||||
_marker: PhantomData<Subgroup>,
|
||||
}
|
||||
|
||||
fn convert_subgroup<E: JubjubEngine, S1, S2>(from: &Point<E, S1>) -> Point<E, S2>
|
||||
{
|
||||
fn convert_subgroup<E: JubjubEngine, S1, S2>(from: &Point<E, S1>) -> Point<E, S2> {
|
||||
Point {
|
||||
x: from.x,
|
||||
y: from.y,
|
||||
t: from.t,
|
||||
z: from.z,
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> From<&Point<E, Unknown>> for Point<E, Unknown>
|
||||
{
|
||||
fn from(p: &Point<E, Unknown>) -> Point<E, Unknown>
|
||||
{
|
||||
impl<E: JubjubEngine> From<&Point<E, Unknown>> for Point<E, Unknown> {
|
||||
fn from(p: &Point<E, Unknown>) -> Point<E, Unknown> {
|
||||
p.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> From<Point<E, PrimeOrder>> for Point<E, Unknown>
|
||||
{
|
||||
fn from(p: Point<E, PrimeOrder>) -> Point<E, Unknown>
|
||||
{
|
||||
impl<E: JubjubEngine> From<Point<E, PrimeOrder>> for Point<E, Unknown> {
|
||||
fn from(p: Point<E, PrimeOrder>) -> Point<E, Unknown> {
|
||||
convert_subgroup(&p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> From<&Point<E, PrimeOrder>> for Point<E, Unknown>
|
||||
{
|
||||
fn from(p: &Point<E, PrimeOrder>) -> Point<E, Unknown>
|
||||
{
|
||||
impl<E: JubjubEngine> From<&Point<E, PrimeOrder>> for Point<E, Unknown> {
|
||||
fn from(p: &Point<E, PrimeOrder>) -> Point<E, Unknown> {
|
||||
convert_subgroup(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine, Subgroup> Clone for Point<E, Subgroup>
|
||||
{
|
||||
impl<E: JubjubEngine, Subgroup> Clone for Point<E, Subgroup> {
|
||||
fn clone(&self) -> Self {
|
||||
convert_subgroup(self)
|
||||
}
|
||||
|
@ -99,11 +81,7 @@ impl<E: JubjubEngine, Subgroup> PartialEq for Point<E, Subgroup> {
|
|||
}
|
||||
|
||||
impl<E: JubjubEngine> Point<E, Unknown> {
|
||||
pub fn read<R: Read>(
|
||||
reader: R,
|
||||
params: &E::Params
|
||||
) -> io::Result<Self>
|
||||
{
|
||||
pub fn read<R: Read>(reader: R, params: &E::Params) -> io::Result<Self> {
|
||||
let mut y_repr = <E::Fr as PrimeField>::Repr::default();
|
||||
y_repr.read_le(reader)?;
|
||||
|
||||
|
@ -111,22 +89,18 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
|||
y_repr.as_mut()[3] &= 0x7fffffffffffffff;
|
||||
|
||||
match E::Fr::from_repr(y_repr) {
|
||||
Ok(y) => {
|
||||
match Self::get_for_y(y, x_sign, params) {
|
||||
Some(p) => Ok(p),
|
||||
None => {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve"))
|
||||
}
|
||||
}
|
||||
Ok(y) => match Self::get_for_y(y, x_sign, params) {
|
||||
Some(p) => Ok(p),
|
||||
None => Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve")),
|
||||
},
|
||||
Err(_) => {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidInput, "y is not in field"))
|
||||
}
|
||||
Err(_) => Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"y is not in field",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> Option<Self>
|
||||
{
|
||||
pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> Option<Self> {
|
||||
// Given a y on the curve, x^2 = (y^2 - 1) / (dy^2 + 1)
|
||||
// This is defined for all valid y-coordinates,
|
||||
// as dy^2 + 1 = 0 has no solution in Fr.
|
||||
|
@ -162,29 +136,25 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
|||
y: y,
|
||||
t: t,
|
||||
z: E::Fr::one(),
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
})
|
||||
},
|
||||
None => None
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
},
|
||||
None => None
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// This guarantees the point is in the prime order subgroup
|
||||
#[must_use]
|
||||
pub fn mul_by_cofactor(&self, params: &E::Params) -> Point<E, PrimeOrder>
|
||||
{
|
||||
let tmp = self.double(params)
|
||||
.double(params)
|
||||
.double(params);
|
||||
pub fn mul_by_cofactor(&self, params: &E::Params) -> Point<E, PrimeOrder> {
|
||||
let tmp = self.double(params).double(params).double(params);
|
||||
|
||||
convert_subgroup(&tmp)
|
||||
}
|
||||
|
||||
pub fn rand<R: RngCore>(rng: &mut R, params: &E::Params) -> Self
|
||||
{
|
||||
pub fn rand<R: RngCore>(rng: &mut R, params: &E::Params) -> Self {
|
||||
loop {
|
||||
let y = E::Fr::random(rng);
|
||||
let sign = rng.next_u32() % 2 != 0;
|
||||
|
@ -197,11 +167,7 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
|||
}
|
||||
|
||||
impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
pub fn write<W: Write>(
|
||||
&self,
|
||||
writer: W
|
||||
) -> io::Result<()>
|
||||
{
|
||||
pub fn write<W: Write>(&self, writer: W) -> io::Result<()> {
|
||||
let (x, y) = self.into_xy();
|
||||
|
||||
assert_eq!(E::Fr::NUM_BITS, 255);
|
||||
|
@ -216,16 +182,12 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||
}
|
||||
|
||||
/// Convert from a Montgomery point
|
||||
pub fn from_montgomery(
|
||||
m: &montgomery::Point<E, Subgroup>,
|
||||
params: &E::Params
|
||||
) -> Self
|
||||
{
|
||||
pub fn from_montgomery(m: &montgomery::Point<E, Subgroup>, params: &E::Params) -> Self {
|
||||
match m.into_xy() {
|
||||
None => {
|
||||
// Map the point at infinity to the neutral element.
|
||||
Point::zero()
|
||||
},
|
||||
}
|
||||
Some((x, y)) => {
|
||||
// The map from a Montgomery curve is defined as:
|
||||
// (x, y) -> (u, v) where
|
||||
|
@ -258,7 +220,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||
y: neg1,
|
||||
t: E::Fr::zero(),
|
||||
z: E::Fr::one(),
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
}
|
||||
} else {
|
||||
// Otherwise, as stated above, the mapping is still
|
||||
|
@ -317,7 +279,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||
y: v,
|
||||
t: t,
|
||||
z: z,
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -340,12 +302,11 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||
y: E::Fr::one(),
|
||||
t: E::Fr::zero(),
|
||||
z: E::Fr::one(),
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_xy(&self) -> (E::Fr, E::Fr)
|
||||
{
|
||||
pub fn into_xy(&self) -> (E::Fr, E::Fr) {
|
||||
let zinv = self.z.inverse().unwrap();
|
||||
|
||||
let mut x = self.x;
|
||||
|
@ -432,13 +393,12 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||
y: y3,
|
||||
t: t3,
|
||||
z: z3,
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn add(&self, other: &Self, params: &E::Params) -> Self
|
||||
{
|
||||
pub fn add(&self, other: &Self, params: &E::Params) -> Self {
|
||||
// See "Twisted Edwards Curves Revisited"
|
||||
// Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson
|
||||
// 3.1 Unified Addition in E^e
|
||||
|
@ -505,17 +465,12 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||
y: y3,
|
||||
t: t3,
|
||||
z: z3,
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn mul<S: Into<<E::Fs as PrimeField>::Repr>>(
|
||||
&self,
|
||||
scalar: S,
|
||||
params: &E::Params
|
||||
) -> Self
|
||||
{
|
||||
pub fn mul<S: Into<<E::Fs as PrimeField>::Repr>>(&self, scalar: S, params: &E::Params) -> Self {
|
||||
// Standard double-and-add scalar multiplication
|
||||
|
||||
let mut res = Self::zero();
|
||||
|
|
|
@ -9,7 +9,12 @@ use rand_core::RngCore;
|
|||
use super::ToUniform;
|
||||
|
||||
// s = 6554484396890773809930967563523245729705921265872317281365359162392183254199
|
||||
const MODULUS: FsRepr = FsRepr([0xd0970e5ed6f72cb7, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9]);
|
||||
const MODULUS: FsRepr = FsRepr([
|
||||
0xd0970e5ed6f72cb7,
|
||||
0xa6682093ccc81082,
|
||||
0x6673b0101343b00,
|
||||
0xe7db4ea6533afa9,
|
||||
]);
|
||||
|
||||
// The number of bits needed to represent the modulus.
|
||||
const MODULUS_BITS: u32 = 252;
|
||||
|
@ -19,32 +24,56 @@ const MODULUS_BITS: u32 = 252;
|
|||
const REPR_SHAVE_BITS: u32 = 4;
|
||||
|
||||
// R = 2**256 % s
|
||||
const R: FsRepr = FsRepr([0x25f80bb3b99607d9, 0xf315d62f66b6e750, 0x932514eeeb8814f4, 0x9a6fc6f479155c6]);
|
||||
const R: FsRepr = FsRepr([
|
||||
0x25f80bb3b99607d9,
|
||||
0xf315d62f66b6e750,
|
||||
0x932514eeeb8814f4,
|
||||
0x9a6fc6f479155c6,
|
||||
]);
|
||||
|
||||
// R2 = R^2 % s
|
||||
const R2: FsRepr = FsRepr([0x67719aa495e57731, 0x51b0cef09ce3fc26, 0x69dab7fac026e9a5, 0x4f6547b8d127688]);
|
||||
const R2: FsRepr = FsRepr([
|
||||
0x67719aa495e57731,
|
||||
0x51b0cef09ce3fc26,
|
||||
0x69dab7fac026e9a5,
|
||||
0x4f6547b8d127688,
|
||||
]);
|
||||
|
||||
// INV = -(s^{-1} mod 2^64) mod s
|
||||
const INV: u64 = 0x1ba3a358ef788ef9;
|
||||
|
||||
// GENERATOR = 6 (multiplicative generator of r-1 order, that is also quadratic nonresidue)
|
||||
const GENERATOR: FsRepr = FsRepr([0x720b1b19d49ea8f1, 0xbf4aa36101f13a58, 0x5fa8cc968193ccbb, 0xe70cbdc7dccf3ac]);
|
||||
const GENERATOR: FsRepr = FsRepr([
|
||||
0x720b1b19d49ea8f1,
|
||||
0xbf4aa36101f13a58,
|
||||
0x5fa8cc968193ccbb,
|
||||
0xe70cbdc7dccf3ac,
|
||||
]);
|
||||
|
||||
// 2^S * t = MODULUS - 1 with t odd
|
||||
const S: u32 = 1;
|
||||
|
||||
// 2^S root of unity computed by GENERATOR^t
|
||||
const ROOT_OF_UNITY: FsRepr = FsRepr([0xaa9f02ab1d6124de, 0xb3524a6466112932, 0x7342261215ac260b, 0x4d6b87b1da259e2]);
|
||||
const ROOT_OF_UNITY: FsRepr = FsRepr([
|
||||
0xaa9f02ab1d6124de,
|
||||
0xb3524a6466112932,
|
||||
0x7342261215ac260b,
|
||||
0x4d6b87b1da259e2,
|
||||
]);
|
||||
|
||||
// -((2**256) mod s) mod s
|
||||
const NEGATIVE_ONE: Fs = Fs(FsRepr([0xaa9f02ab1d6124de, 0xb3524a6466112932, 0x7342261215ac260b, 0x4d6b87b1da259e2]));
|
||||
const NEGATIVE_ONE: Fs = Fs(FsRepr([
|
||||
0xaa9f02ab1d6124de,
|
||||
0xb3524a6466112932,
|
||||
0x7342261215ac260b,
|
||||
0x4d6b87b1da259e2,
|
||||
]));
|
||||
|
||||
/// This is the underlying representation of an element of `Fs`.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
|
||||
pub struct FsRepr(pub [u64; 4]);
|
||||
|
||||
impl ::std::fmt::Display for FsRepr
|
||||
{
|
||||
impl ::std::fmt::Display for FsRepr {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
try!(write!(f, "0x"));
|
||||
for i in self.0.iter().rev() {
|
||||
|
@ -83,9 +112,9 @@ impl Ord for FsRepr {
|
|||
fn cmp(&self, other: &FsRepr) -> ::std::cmp::Ordering {
|
||||
for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
|
||||
if a < b {
|
||||
return ::std::cmp::Ordering::Less
|
||||
return ::std::cmp::Ordering::Less;
|
||||
} else if a > b {
|
||||
return ::std::cmp::Ordering::Greater
|
||||
return ::std::cmp::Ordering::Greater;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,8 +256,7 @@ impl PrimeFieldRepr for FsRepr {
|
|||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Fs(FsRepr);
|
||||
|
||||
impl ::std::fmt::Display for Fs
|
||||
{
|
||||
impl ::std::fmt::Display for Fs {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
write!(f, "Fs({})", self.into_repr())
|
||||
}
|
||||
|
@ -256,9 +284,16 @@ impl PrimeField for Fs {
|
|||
|
||||
fn into_repr(&self) -> FsRepr {
|
||||
let mut r = *self;
|
||||
r.mont_reduce((self.0).0[0], (self.0).0[1],
|
||||
(self.0).0[2], (self.0).0[3],
|
||||
0, 0, 0, 0);
|
||||
r.mont_reduce(
|
||||
(self.0).0[0],
|
||||
(self.0).0[1],
|
||||
(self.0).0[2],
|
||||
(self.0).0[3],
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
r.0
|
||||
}
|
||||
|
||||
|
@ -296,7 +331,7 @@ impl Field for Fs {
|
|||
tmp.0.as_mut()[3] &= 0xffffffffffffffff >> REPR_SHAVE_BITS;
|
||||
|
||||
if tmp.is_valid() {
|
||||
return tmp
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -414,8 +449,7 @@ impl Field for Fs {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn mul_assign(&mut self, other: &Fs)
|
||||
{
|
||||
fn mul_assign(&mut self, other: &Fs) {
|
||||
let mut carry = 0;
|
||||
let r0 = mac_with_carry(0, (self.0).0[0], (other.0).0[0], &mut carry);
|
||||
let r1 = mac_with_carry(0, (self.0).0[0], (other.0).0[1], &mut carry);
|
||||
|
@ -444,8 +478,7 @@ impl Field for Fs {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn square(&mut self)
|
||||
{
|
||||
fn square(&mut self) {
|
||||
let mut carry = 0;
|
||||
let r1 = mac_with_carry(0, (self.0).0[0], (self.0).0[1], &mut carry);
|
||||
let r2 = mac_with_carry(0, (self.0).0[0], (self.0).0[2], &mut carry);
|
||||
|
@ -507,9 +540,8 @@ impl Fs {
|
|||
mut r4: u64,
|
||||
mut r5: u64,
|
||||
mut r6: u64,
|
||||
mut r7: u64
|
||||
)
|
||||
{
|
||||
mut r7: u64,
|
||||
) {
|
||||
// The Montgomery reduction here is based on Algorithm 14.32 in
|
||||
// Handbook of Applied Cryptography
|
||||
// <http://cacr.uwaterloo.ca/hac/about/chap14.pdf>.
|
||||
|
@ -579,13 +611,21 @@ 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 }
|
||||
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> {
|
||||
|
@ -593,24 +633,25 @@ impl SqrtField for Fs {
|
|||
// https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2)
|
||||
|
||||
// a1 = self^((s - 3) // 4)
|
||||
let mut a1 = self.pow([0xb425c397b5bdcb2d, 0x299a0824f3320420, 0x4199cec0404d0ec0, 0x39f6d3a994cebea]);
|
||||
let mut a1 = self.pow([
|
||||
0xb425c397b5bdcb2d,
|
||||
0x299a0824f3320420,
|
||||
0x4199cec0404d0ec0,
|
||||
0x39f6d3a994cebea,
|
||||
]);
|
||||
let mut a0 = a1;
|
||||
a0.square();
|
||||
a0.mul_assign(self);
|
||||
|
||||
if a0 == NEGATIVE_ONE
|
||||
{
|
||||
if a0 == NEGATIVE_ONE {
|
||||
None
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
a1.mul_assign(self);
|
||||
Some(a1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_neg_one() {
|
||||
let mut o = Fs::one();
|
||||
|
@ -636,12 +677,30 @@ fn test_fs_repr_ordering() {
|
|||
assert!(b > a);
|
||||
}
|
||||
|
||||
assert_equality(FsRepr([9999, 9999, 9999, 9999]), FsRepr([9999, 9999, 9999, 9999]));
|
||||
assert_equality(FsRepr([9999, 9998, 9999, 9999]), FsRepr([9999, 9998, 9999, 9999]));
|
||||
assert_equality(FsRepr([9999, 9999, 9999, 9997]), FsRepr([9999, 9999, 9999, 9997]));
|
||||
assert_lt(FsRepr([9999, 9997, 9999, 9998]), FsRepr([9999, 9997, 9999, 9999]));
|
||||
assert_lt(FsRepr([9999, 9997, 9998, 9999]), FsRepr([9999, 9997, 9999, 9999]));
|
||||
assert_lt(FsRepr([9, 9999, 9999, 9997]), FsRepr([9999, 9999, 9999, 9997]));
|
||||
assert_equality(
|
||||
FsRepr([9999, 9999, 9999, 9999]),
|
||||
FsRepr([9999, 9999, 9999, 9999]),
|
||||
);
|
||||
assert_equality(
|
||||
FsRepr([9999, 9998, 9999, 9999]),
|
||||
FsRepr([9999, 9998, 9999, 9999]),
|
||||
);
|
||||
assert_equality(
|
||||
FsRepr([9999, 9999, 9999, 9997]),
|
||||
FsRepr([9999, 9999, 9999, 9997]),
|
||||
);
|
||||
assert_lt(
|
||||
FsRepr([9999, 9997, 9999, 9998]),
|
||||
FsRepr([9999, 9997, 9999, 9999]),
|
||||
);
|
||||
assert_lt(
|
||||
FsRepr([9999, 9997, 9998, 9999]),
|
||||
FsRepr([9999, 9997, 9999, 9999]),
|
||||
);
|
||||
assert_lt(
|
||||
FsRepr([9, 9999, 9999, 9997]),
|
||||
FsRepr([9999, 9999, 9999, 9997]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -670,13 +729,34 @@ fn test_fs_repr_is_zero() {
|
|||
|
||||
#[test]
|
||||
fn test_fs_repr_div2() {
|
||||
let mut a = FsRepr([0xbd2920b19c972321, 0x174ed0466a3be37e, 0xd468d5e3b551f0b5, 0xcb67c072733beefc]);
|
||||
let mut a = FsRepr([
|
||||
0xbd2920b19c972321,
|
||||
0x174ed0466a3be37e,
|
||||
0xd468d5e3b551f0b5,
|
||||
0xcb67c072733beefc,
|
||||
]);
|
||||
a.div2();
|
||||
assert_eq!(a, FsRepr([0x5e949058ce4b9190, 0x8ba76823351df1bf, 0x6a346af1daa8f85a, 0x65b3e039399df77e]));
|
||||
assert_eq!(
|
||||
a,
|
||||
FsRepr([
|
||||
0x5e949058ce4b9190,
|
||||
0x8ba76823351df1bf,
|
||||
0x6a346af1daa8f85a,
|
||||
0x65b3e039399df77e
|
||||
])
|
||||
);
|
||||
for _ in 0..10 {
|
||||
a.div2();
|
||||
}
|
||||
assert_eq!(a, FsRepr([0x6fd7a524163392e4, 0x16a2e9da08cd477c, 0xdf9a8d1abc76aa3e, 0x196cf80e4e677d]));
|
||||
assert_eq!(
|
||||
a,
|
||||
FsRepr([
|
||||
0x6fd7a524163392e4,
|
||||
0x16a2e9da08cd477c,
|
||||
0xdf9a8d1abc76aa3e,
|
||||
0x196cf80e4e677d
|
||||
])
|
||||
);
|
||||
for _ in 0..200 {
|
||||
a.div2();
|
||||
}
|
||||
|
@ -695,32 +775,46 @@ fn test_fs_repr_div2() {
|
|||
|
||||
#[test]
|
||||
fn test_fs_repr_shr() {
|
||||
let mut a = FsRepr([0xb33fbaec482a283f, 0x997de0d3a88cb3df, 0x9af62d2a9a0e5525, 0x36003ab08de70da1]);
|
||||
let mut a = FsRepr([
|
||||
0xb33fbaec482a283f,
|
||||
0x997de0d3a88cb3df,
|
||||
0x9af62d2a9a0e5525,
|
||||
0x36003ab08de70da1,
|
||||
]);
|
||||
a.shr(0);
|
||||
assert_eq!(
|
||||
a,
|
||||
FsRepr([0xb33fbaec482a283f, 0x997de0d3a88cb3df, 0x9af62d2a9a0e5525, 0x36003ab08de70da1])
|
||||
FsRepr([
|
||||
0xb33fbaec482a283f,
|
||||
0x997de0d3a88cb3df,
|
||||
0x9af62d2a9a0e5525,
|
||||
0x36003ab08de70da1
|
||||
])
|
||||
);
|
||||
a.shr(1);
|
||||
assert_eq!(
|
||||
a,
|
||||
FsRepr([0xd99fdd762415141f, 0xccbef069d44659ef, 0xcd7b16954d072a92, 0x1b001d5846f386d0])
|
||||
FsRepr([
|
||||
0xd99fdd762415141f,
|
||||
0xccbef069d44659ef,
|
||||
0xcd7b16954d072a92,
|
||||
0x1b001d5846f386d0
|
||||
])
|
||||
);
|
||||
a.shr(50);
|
||||
assert_eq!(
|
||||
a,
|
||||
FsRepr([0xbc1a7511967bf667, 0xc5a55341caa4b32f, 0x75611bce1b4335e, 0x6c0])
|
||||
FsRepr([
|
||||
0xbc1a7511967bf667,
|
||||
0xc5a55341caa4b32f,
|
||||
0x75611bce1b4335e,
|
||||
0x6c0
|
||||
])
|
||||
);
|
||||
a.shr(130);
|
||||
assert_eq!(
|
||||
a,
|
||||
FsRepr([0x1d5846f386d0cd7, 0x1b0, 0x0, 0x0])
|
||||
);
|
||||
assert_eq!(a, FsRepr([0x1d5846f386d0cd7, 0x1b0, 0x0, 0x0]));
|
||||
a.shr(64);
|
||||
assert_eq!(
|
||||
a,
|
||||
FsRepr([0x1b0, 0x0, 0x0, 0x0])
|
||||
);
|
||||
assert_eq!(a, FsRepr([0x1b0, 0x0, 0x0, 0x0]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -765,9 +859,26 @@ fn test_fs_repr_sub_noborrow() {
|
|||
0xe5,
|
||||
]);
|
||||
|
||||
let mut t = FsRepr([0x8e62a7e85264e2c3, 0xb23d34c1941d3ca, 0x5976930b7502dd15, 0x600f3fb517bf5495]);
|
||||
t.sub_noborrow(&FsRepr([0xd64f669809cbc6a4, 0xfa76cb9d90cf7637, 0xfefb0df9038d43b3, 0x298a30c744b31acf]));
|
||||
assert!(t == FsRepr([0xb813415048991c1f, 0x10ad07ae88725d92, 0x5a7b851271759961, 0x36850eedd30c39c5]));
|
||||
let mut t = FsRepr([
|
||||
0x8e62a7e85264e2c3,
|
||||
0xb23d34c1941d3ca,
|
||||
0x5976930b7502dd15,
|
||||
0x600f3fb517bf5495,
|
||||
]);
|
||||
t.sub_noborrow(&FsRepr([
|
||||
0xd64f669809cbc6a4,
|
||||
0xfa76cb9d90cf7637,
|
||||
0xfefb0df9038d43b3,
|
||||
0x298a30c744b31acf,
|
||||
]));
|
||||
assert!(
|
||||
t == FsRepr([
|
||||
0xb813415048991c1f,
|
||||
0x10ad07ae88725d92,
|
||||
0x5a7b851271759961,
|
||||
0x36850eedd30c39c5
|
||||
])
|
||||
);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut a = Fs::random(&mut rng).into_repr();
|
||||
|
@ -801,9 +912,19 @@ fn test_fs_legendre() {
|
|||
assert_eq!(QuadraticResidue, Fs::one().legendre());
|
||||
assert_eq!(Zero, Fs::zero().legendre());
|
||||
|
||||
let e = FsRepr([0x8385eec23df1f88e, 0x9a01fb412b2dba16, 0x4c928edcdd6c22f, 0x9f2df7ef69ecef9]);
|
||||
let e = FsRepr([
|
||||
0x8385eec23df1f88e,
|
||||
0x9a01fb412b2dba16,
|
||||
0x4c928edcdd6c22f,
|
||||
0x9f2df7ef69ecef9,
|
||||
]);
|
||||
assert_eq!(QuadraticResidue, Fs::from_repr(e).unwrap().legendre());
|
||||
let e = FsRepr([0xe8ed9f299da78568, 0x35efdebc88b2209, 0xc82125cb1f916dbe, 0x6813d2b38c39bd0]);
|
||||
let e = FsRepr([
|
||||
0xe8ed9f299da78568,
|
||||
0x35efdebc88b2209,
|
||||
0xc82125cb1f916dbe,
|
||||
0x6813d2b38c39bd0,
|
||||
]);
|
||||
assert_eq!(QuadraticNonResidue, Fs::from_repr(e).unwrap().legendre());
|
||||
}
|
||||
|
||||
|
@ -814,9 +935,27 @@ fn test_fr_repr_add_nocarry() {
|
|||
0xe5,
|
||||
]);
|
||||
|
||||
let mut t = FsRepr([0xd64f669809cbc6a4, 0xfa76cb9d90cf7637, 0xfefb0df9038d43b3, 0x298a30c744b31acf]);
|
||||
t.add_nocarry(&FsRepr([0x8e62a7e85264e2c3, 0xb23d34c1941d3ca, 0x5976930b7502dd15, 0x600f3fb517bf5495]));
|
||||
assert_eq!(t, FsRepr([0x64b20e805c30a967, 0x59a9ee9aa114a02, 0x5871a104789020c9, 0x8999707c5c726f65]));
|
||||
let mut t = FsRepr([
|
||||
0xd64f669809cbc6a4,
|
||||
0xfa76cb9d90cf7637,
|
||||
0xfefb0df9038d43b3,
|
||||
0x298a30c744b31acf,
|
||||
]);
|
||||
t.add_nocarry(&FsRepr([
|
||||
0x8e62a7e85264e2c3,
|
||||
0xb23d34c1941d3ca,
|
||||
0x5976930b7502dd15,
|
||||
0x600f3fb517bf5495,
|
||||
]));
|
||||
assert_eq!(
|
||||
t,
|
||||
FsRepr([
|
||||
0x64b20e805c30a967,
|
||||
0x59a9ee9aa114a02,
|
||||
0x5871a104789020c9,
|
||||
0x8999707c5c726f65
|
||||
])
|
||||
);
|
||||
|
||||
// Test for the associativity of addition.
|
||||
for _ in 0..1000 {
|
||||
|
@ -868,8 +1007,20 @@ fn test_fs_is_valid() {
|
|||
a.0.sub_noborrow(&FsRepr::from(1));
|
||||
assert!(a.is_valid());
|
||||
assert!(Fs(FsRepr::from(0)).is_valid());
|
||||
assert!(Fs(FsRepr([0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9])).is_valid());
|
||||
assert!(!Fs(FsRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])).is_valid());
|
||||
assert!(Fs(FsRepr([
|
||||
0xd0970e5ed6f72cb6,
|
||||
0xa6682093ccc81082,
|
||||
0x6673b0101343b00,
|
||||
0xe7db4ea6533afa9
|
||||
]))
|
||||
.is_valid());
|
||||
assert!(!Fs(FsRepr([
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff
|
||||
]))
|
||||
.is_valid());
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
|
@ -886,25 +1037,80 @@ fn test_fs_is_valid() {
|
|||
fn test_fs_add_assign() {
|
||||
{
|
||||
// Random number
|
||||
let mut tmp = Fs::from_str("4577408157467272683998459759522778614363623736323078995109579213719612604198").unwrap();
|
||||
let mut tmp = Fs::from_str(
|
||||
"4577408157467272683998459759522778614363623736323078995109579213719612604198",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(tmp.is_valid());
|
||||
// Test that adding zero has no effect.
|
||||
tmp.add_assign(&Fs(FsRepr::from(0)));
|
||||
assert_eq!(tmp, Fs(FsRepr([0x8e6bfff4722d6e67, 0x5643da5c892044f9, 0x9465f4b281921a69, 0x25f752d3edd7162])));
|
||||
assert_eq!(
|
||||
tmp,
|
||||
Fs(FsRepr([
|
||||
0x8e6bfff4722d6e67,
|
||||
0x5643da5c892044f9,
|
||||
0x9465f4b281921a69,
|
||||
0x25f752d3edd7162
|
||||
]))
|
||||
);
|
||||
// Add one and test for the result.
|
||||
tmp.add_assign(&Fs(FsRepr::from(1)));
|
||||
assert_eq!(tmp, Fs(FsRepr([0x8e6bfff4722d6e68, 0x5643da5c892044f9, 0x9465f4b281921a69, 0x25f752d3edd7162])));
|
||||
assert_eq!(
|
||||
tmp,
|
||||
Fs(FsRepr([
|
||||
0x8e6bfff4722d6e68,
|
||||
0x5643da5c892044f9,
|
||||
0x9465f4b281921a69,
|
||||
0x25f752d3edd7162
|
||||
]))
|
||||
);
|
||||
// Add another random number that exercises the reduction.
|
||||
tmp.add_assign(&Fs(FsRepr([0xb634d07bc42d4a70, 0xf724f0c008411f5f, 0x456d4053d865af34, 0x24ce814e8c63027])));
|
||||
assert_eq!(tmp, Fs(FsRepr([0x44a0d070365ab8d8, 0x4d68cb1c91616459, 0xd9d3350659f7c99e, 0x4ac5d4227a3a189])));
|
||||
tmp.add_assign(&Fs(FsRepr([
|
||||
0xb634d07bc42d4a70,
|
||||
0xf724f0c008411f5f,
|
||||
0x456d4053d865af34,
|
||||
0x24ce814e8c63027,
|
||||
])));
|
||||
assert_eq!(
|
||||
tmp,
|
||||
Fs(FsRepr([
|
||||
0x44a0d070365ab8d8,
|
||||
0x4d68cb1c91616459,
|
||||
0xd9d3350659f7c99e,
|
||||
0x4ac5d4227a3a189
|
||||
]))
|
||||
);
|
||||
// Add one to (s - 1) and test for the result.
|
||||
tmp = Fs(FsRepr([0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9]));
|
||||
tmp = Fs(FsRepr([
|
||||
0xd0970e5ed6f72cb6,
|
||||
0xa6682093ccc81082,
|
||||
0x6673b0101343b00,
|
||||
0xe7db4ea6533afa9,
|
||||
]));
|
||||
tmp.add_assign(&Fs(FsRepr::from(1)));
|
||||
assert!(tmp.0.is_zero());
|
||||
// Add a random number to another one such that the result is s - 1
|
||||
tmp = Fs(FsRepr([0xa11fda5950ce3636, 0x922e0dbccfe0ca0e, 0xacebb6e215b82d4a, 0x97ffb8cdc3aee93]));
|
||||
tmp.add_assign(&Fs(FsRepr([0x2f7734058628f680, 0x143a12d6fce74674, 0x597b841eeb7c0db6, 0x4fdb95d88f8c115])));
|
||||
assert_eq!(tmp, Fs(FsRepr([0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9])));
|
||||
tmp = Fs(FsRepr([
|
||||
0xa11fda5950ce3636,
|
||||
0x922e0dbccfe0ca0e,
|
||||
0xacebb6e215b82d4a,
|
||||
0x97ffb8cdc3aee93,
|
||||
]));
|
||||
tmp.add_assign(&Fs(FsRepr([
|
||||
0x2f7734058628f680,
|
||||
0x143a12d6fce74674,
|
||||
0x597b841eeb7c0db6,
|
||||
0x4fdb95d88f8c115,
|
||||
])));
|
||||
assert_eq!(
|
||||
tmp,
|
||||
Fs(FsRepr([
|
||||
0xd0970e5ed6f72cb6,
|
||||
0xa6682093ccc81082,
|
||||
0x6673b0101343b00,
|
||||
0xe7db4ea6533afa9
|
||||
]))
|
||||
);
|
||||
// Add one to the result and test for it.
|
||||
tmp.add_assign(&Fs(FsRepr::from(1)));
|
||||
assert!(tmp.0.is_zero());
|
||||
|
@ -941,23 +1147,72 @@ fn test_fs_add_assign() {
|
|||
fn test_fs_sub_assign() {
|
||||
{
|
||||
// Test arbitrary subtraction that tests reduction.
|
||||
let mut tmp = Fs(FsRepr([0xb384d9f6877afd99, 0x4442513958e1a1c1, 0x352c4b8a95eccc3f, 0x2db62dee4b0f2]));
|
||||
tmp.sub_assign(&Fs(FsRepr([0xec5bd2d13ed6b05a, 0x2adc0ab3a39b5fa, 0x82d3360a493e637e, 0x53ccff4a64d6679])));
|
||||
assert_eq!(tmp, Fs(FsRepr([0x97c015841f9b79f6, 0xe7fcb121eb6ffc49, 0xb8c050814de2a3c1, 0x943c0589dcafa21])));
|
||||
let mut tmp = Fs(FsRepr([
|
||||
0xb384d9f6877afd99,
|
||||
0x4442513958e1a1c1,
|
||||
0x352c4b8a95eccc3f,
|
||||
0x2db62dee4b0f2,
|
||||
]));
|
||||
tmp.sub_assign(&Fs(FsRepr([
|
||||
0xec5bd2d13ed6b05a,
|
||||
0x2adc0ab3a39b5fa,
|
||||
0x82d3360a493e637e,
|
||||
0x53ccff4a64d6679,
|
||||
])));
|
||||
assert_eq!(
|
||||
tmp,
|
||||
Fs(FsRepr([
|
||||
0x97c015841f9b79f6,
|
||||
0xe7fcb121eb6ffc49,
|
||||
0xb8c050814de2a3c1,
|
||||
0x943c0589dcafa21
|
||||
]))
|
||||
);
|
||||
|
||||
// Test the opposite subtraction which doesn't test reduction.
|
||||
tmp = Fs(FsRepr([0xec5bd2d13ed6b05a, 0x2adc0ab3a39b5fa, 0x82d3360a493e637e, 0x53ccff4a64d6679]));
|
||||
tmp.sub_assign(&Fs(FsRepr([0xb384d9f6877afd99, 0x4442513958e1a1c1, 0x352c4b8a95eccc3f, 0x2db62dee4b0f2])));
|
||||
assert_eq!(tmp, Fs(FsRepr([0x38d6f8dab75bb2c1, 0xbe6b6f71e1581439, 0x4da6ea7fb351973e, 0x539f491c768b587])));
|
||||
tmp = Fs(FsRepr([
|
||||
0xec5bd2d13ed6b05a,
|
||||
0x2adc0ab3a39b5fa,
|
||||
0x82d3360a493e637e,
|
||||
0x53ccff4a64d6679,
|
||||
]));
|
||||
tmp.sub_assign(&Fs(FsRepr([
|
||||
0xb384d9f6877afd99,
|
||||
0x4442513958e1a1c1,
|
||||
0x352c4b8a95eccc3f,
|
||||
0x2db62dee4b0f2,
|
||||
])));
|
||||
assert_eq!(
|
||||
tmp,
|
||||
Fs(FsRepr([
|
||||
0x38d6f8dab75bb2c1,
|
||||
0xbe6b6f71e1581439,
|
||||
0x4da6ea7fb351973e,
|
||||
0x539f491c768b587
|
||||
]))
|
||||
);
|
||||
|
||||
// Test for sensible results with zero
|
||||
tmp = Fs(FsRepr::from(0));
|
||||
tmp.sub_assign(&Fs(FsRepr::from(0)));
|
||||
assert!(tmp.is_zero());
|
||||
|
||||
tmp = Fs(FsRepr([0x361e16aef5cce835, 0x55bbde2536e274c1, 0x4dc77a63fd15ee75, 0x1e14bb37c14f230]));
|
||||
tmp = Fs(FsRepr([
|
||||
0x361e16aef5cce835,
|
||||
0x55bbde2536e274c1,
|
||||
0x4dc77a63fd15ee75,
|
||||
0x1e14bb37c14f230,
|
||||
]));
|
||||
tmp.sub_assign(&Fs(FsRepr::from(0)));
|
||||
assert_eq!(tmp, Fs(FsRepr([0x361e16aef5cce835, 0x55bbde2536e274c1, 0x4dc77a63fd15ee75, 0x1e14bb37c14f230])));
|
||||
assert_eq!(
|
||||
tmp,
|
||||
Fs(FsRepr([
|
||||
0x361e16aef5cce835,
|
||||
0x55bbde2536e274c1,
|
||||
0x4dc77a63fd15ee75,
|
||||
0x1e14bb37c14f230
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
|
@ -983,9 +1238,26 @@ fn test_fs_sub_assign() {
|
|||
|
||||
#[test]
|
||||
fn test_fs_mul_assign() {
|
||||
let mut tmp = Fs(FsRepr([0xb433b01287f71744, 0x4eafb86728c4d108, 0xfdd52c14b9dfbe65, 0x2ff1f3434821118]));
|
||||
tmp.mul_assign(&Fs(FsRepr([0xdae00fc63c9fa90f, 0x5a5ed89b96ce21ce, 0x913cd26101bd6f58, 0x3f0822831697fe9])));
|
||||
assert!(tmp == Fs(FsRepr([0xb68ecb61d54d2992, 0x5ff95874defce6a6, 0x3590eb053894657d, 0x53823a118515933])));
|
||||
let mut tmp = Fs(FsRepr([
|
||||
0xb433b01287f71744,
|
||||
0x4eafb86728c4d108,
|
||||
0xfdd52c14b9dfbe65,
|
||||
0x2ff1f3434821118,
|
||||
]));
|
||||
tmp.mul_assign(&Fs(FsRepr([
|
||||
0xdae00fc63c9fa90f,
|
||||
0x5a5ed89b96ce21ce,
|
||||
0x913cd26101bd6f58,
|
||||
0x3f0822831697fe9,
|
||||
])));
|
||||
assert!(
|
||||
tmp == Fs(FsRepr([
|
||||
0xb68ecb61d54d2992,
|
||||
0x5ff95874defce6a6,
|
||||
0x3590eb053894657d,
|
||||
0x53823a118515933
|
||||
]))
|
||||
);
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
|
@ -1035,10 +1307,24 @@ fn test_fs_mul_assign() {
|
|||
|
||||
#[test]
|
||||
fn test_fr_squaring() {
|
||||
let mut a = Fs(FsRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xe7db4ea6533afa8]));
|
||||
let mut a = Fs(FsRepr([
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xe7db4ea6533afa8,
|
||||
]));
|
||||
assert!(a.is_valid());
|
||||
a.square();
|
||||
assert_eq!(a, Fs::from_repr(FsRepr([0x12c7f55cbc52fbaa, 0xdedc98a0b5e6ce9e, 0xad2892726a5396a, 0x9fe82af8fee77b3])).unwrap());
|
||||
assert_eq!(
|
||||
a,
|
||||
Fs::from_repr(FsRepr([
|
||||
0x12c7f55cbc52fbaa,
|
||||
0xdedc98a0b5e6ce9e,
|
||||
0xad2892726a5396a,
|
||||
0x9fe82af8fee77b3
|
||||
]))
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
|
@ -1185,17 +1471,38 @@ fn test_fs_sqrt() {
|
|||
#[test]
|
||||
fn test_fs_from_into_repr() {
|
||||
// r + 1 should not be in the field
|
||||
assert!(Fs::from_repr(FsRepr([0xd0970e5ed6f72cb8, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9])).is_err());
|
||||
assert!(Fs::from_repr(FsRepr([
|
||||
0xd0970e5ed6f72cb8,
|
||||
0xa6682093ccc81082,
|
||||
0x6673b0101343b00,
|
||||
0xe7db4ea6533afa9
|
||||
]))
|
||||
.is_err());
|
||||
|
||||
// r should not be in the field
|
||||
assert!(Fs::from_repr(Fs::char()).is_err());
|
||||
|
||||
// Multiply some arbitrary representations to see if the result is as expected.
|
||||
let a = FsRepr([0x5f2d0c05d0337b71, 0xa1df2b0f8a20479, 0xad73785e71bb863, 0x504a00480c9acec]);
|
||||
let a = FsRepr([
|
||||
0x5f2d0c05d0337b71,
|
||||
0xa1df2b0f8a20479,
|
||||
0xad73785e71bb863,
|
||||
0x504a00480c9acec,
|
||||
]);
|
||||
let mut a_fs = Fs::from_repr(a).unwrap();
|
||||
let b = FsRepr([0x66356ff51e477562, 0x60a92ab55cf7603, 0x8e4273c7364dd192, 0x36df8844a344dc5]);
|
||||
let b = FsRepr([
|
||||
0x66356ff51e477562,
|
||||
0x60a92ab55cf7603,
|
||||
0x8e4273c7364dd192,
|
||||
0x36df8844a344dc5,
|
||||
]);
|
||||
let b_fs = Fs::from_repr(b).unwrap();
|
||||
let c = FsRepr([0x7eef61708f4f2868, 0x747a7e6cf52946fb, 0x83dd75d7c9120017, 0x762f5177f0f3df7]);
|
||||
let c = FsRepr([
|
||||
0x7eef61708f4f2868,
|
||||
0x747a7e6cf52946fb,
|
||||
0x83dd75d7c9120017,
|
||||
0x762f5177f0f3df7,
|
||||
]);
|
||||
a_fs.mul_assign(&b_fs);
|
||||
assert_eq!(a_fs.into_repr(), c);
|
||||
|
||||
|
@ -1222,15 +1529,39 @@ fn test_fs_from_into_repr() {
|
|||
#[test]
|
||||
fn test_fs_repr_display() {
|
||||
assert_eq!(
|
||||
format!("{}", FsRepr([0xa296db59787359df, 0x8d3e33077430d318, 0xd1abf5c606102eb7, 0xcbc33ee28108f0])),
|
||||
format!(
|
||||
"{}",
|
||||
FsRepr([
|
||||
0xa296db59787359df,
|
||||
0x8d3e33077430d318,
|
||||
0xd1abf5c606102eb7,
|
||||
0xcbc33ee28108f0
|
||||
])
|
||||
),
|
||||
"0x00cbc33ee28108f0d1abf5c606102eb78d3e33077430d318a296db59787359df".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", FsRepr([0x14cb03535054a620, 0x312aa2bf2d1dff52, 0x970fe98746ab9361, 0xc1e18acf82711e6])),
|
||||
format!(
|
||||
"{}",
|
||||
FsRepr([
|
||||
0x14cb03535054a620,
|
||||
0x312aa2bf2d1dff52,
|
||||
0x970fe98746ab9361,
|
||||
0xc1e18acf82711e6
|
||||
])
|
||||
),
|
||||
"0x0c1e18acf82711e6970fe98746ab9361312aa2bf2d1dff5214cb03535054a620".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", FsRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])),
|
||||
format!(
|
||||
"{}",
|
||||
FsRepr([
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff
|
||||
])
|
||||
),
|
||||
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
|
@ -1242,11 +1573,29 @@ fn test_fs_repr_display() {
|
|||
#[test]
|
||||
fn test_fs_display() {
|
||||
assert_eq!(
|
||||
format!("{}", Fs::from_repr(FsRepr([0x5528efb9998a01a3, 0x5bd2add5cb357089, 0xc061fa6adb491f98, 0x70db9d143db03d9])).unwrap()),
|
||||
format!(
|
||||
"{}",
|
||||
Fs::from_repr(FsRepr([
|
||||
0x5528efb9998a01a3,
|
||||
0x5bd2add5cb357089,
|
||||
0xc061fa6adb491f98,
|
||||
0x70db9d143db03d9
|
||||
]))
|
||||
.unwrap()
|
||||
),
|
||||
"Fs(0x070db9d143db03d9c061fa6adb491f985bd2add5cb3570895528efb9998a01a3)".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", Fs::from_repr(FsRepr([0xd674745e2717999e, 0xbeb1f52d3e96f338, 0x9c7ae147549482b9, 0x999706024530d22])).unwrap()),
|
||||
format!(
|
||||
"{}",
|
||||
Fs::from_repr(FsRepr([
|
||||
0xd674745e2717999e,
|
||||
0xbeb1f52d3e96f338,
|
||||
0x9c7ae147549482b9,
|
||||
0x999706024530d22
|
||||
]))
|
||||
.unwrap()
|
||||
),
|
||||
"Fs(0x0999706024530d229c7ae147549482b9beb1f52d3e96f338d674745e2717999e)".to_string()
|
||||
);
|
||||
}
|
||||
|
@ -1260,14 +1609,19 @@ fn test_fs_num_bits() {
|
|||
#[test]
|
||||
fn test_fs_root_of_unity() {
|
||||
assert_eq!(Fs::S, 1);
|
||||
assert_eq!(Fs::multiplicative_generator(), Fs::from_repr(FsRepr::from(6)).unwrap());
|
||||
assert_eq!(
|
||||
Fs::multiplicative_generator().pow([0x684b872f6b7b965b, 0x53341049e6640841, 0x83339d80809a1d80, 0x73eda753299d7d4]),
|
||||
Fs::multiplicative_generator(),
|
||||
Fs::from_repr(FsRepr::from(6)).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
Fs::multiplicative_generator().pow([
|
||||
0x684b872f6b7b965b,
|
||||
0x53341049e6640841,
|
||||
0x83339d80809a1d80,
|
||||
0x73eda753299d7d4
|
||||
]),
|
||||
Fs::root_of_unity()
|
||||
);
|
||||
assert_eq!(
|
||||
Fs::root_of_unity().pow([1 << Fs::S]),
|
||||
Fs::one()
|
||||
);
|
||||
assert_eq!(Fs::root_of_unity().pow([1 << Fs::S]), Fs::one());
|
||||
assert!(Fs::multiplicative_generator().sqrt().is_none());
|
||||
}
|
||||
|
|
|
@ -24,10 +24,7 @@ use group_hash::group_hash;
|
|||
|
||||
use constants;
|
||||
|
||||
use pairing::bls12_381::{
|
||||
Bls12,
|
||||
Fr
|
||||
};
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
|
||||
/// This is an implementation of the twisted Edwards Jubjub curve.
|
||||
pub mod edwards;
|
||||
|
@ -44,11 +41,11 @@ pub mod tests;
|
|||
|
||||
/// Point of unknown order.
|
||||
#[derive(Debug)]
|
||||
pub enum Unknown { }
|
||||
pub enum Unknown {}
|
||||
|
||||
/// Point of prime order.
|
||||
#[derive(Debug)]
|
||||
pub enum PrimeOrder { }
|
||||
pub enum PrimeOrder {}
|
||||
|
||||
/// Fixed generators of the Jubjub curve of unknown
|
||||
/// exponent.
|
||||
|
@ -80,7 +77,7 @@ pub enum FixedGenerators {
|
|||
/// base at spend time.
|
||||
SpendingKeyGenerator = 5,
|
||||
|
||||
Max = 6
|
||||
Max = 6,
|
||||
}
|
||||
|
||||
pub trait ToUniform {
|
||||
|
@ -151,10 +148,18 @@ pub struct JubjubBls12 {
|
|||
}
|
||||
|
||||
impl JubjubParams<Bls12> for JubjubBls12 {
|
||||
fn edwards_d(&self) -> &Fr { &self.edwards_d }
|
||||
fn montgomery_a(&self) -> &Fr { &self.montgomery_a }
|
||||
fn montgomery_2a(&self) -> &Fr { &self.montgomery_2a }
|
||||
fn scale(&self) -> &Fr { &self.scale }
|
||||
fn edwards_d(&self) -> &Fr {
|
||||
&self.edwards_d
|
||||
}
|
||||
fn montgomery_a(&self) -> &Fr {
|
||||
&self.montgomery_a
|
||||
}
|
||||
fn montgomery_2a(&self) -> &Fr {
|
||||
&self.montgomery_2a
|
||||
}
|
||||
fn scale(&self) -> &Fr {
|
||||
&self.scale
|
||||
}
|
||||
fn pedersen_hash_generators(&self) -> &[edwards::Point<Bls12, PrimeOrder>] {
|
||||
&self.pedersen_hash_generators
|
||||
}
|
||||
|
@ -170,12 +175,10 @@ impl JubjubParams<Bls12> for JubjubBls12 {
|
|||
fn pedersen_circuit_generators(&self) -> &[Vec<Vec<(Fr, Fr)>>] {
|
||||
&self.pedersen_circuit_generators
|
||||
}
|
||||
fn generator(&self, base: FixedGenerators) -> &edwards::Point<Bls12, PrimeOrder>
|
||||
{
|
||||
fn generator(&self, base: FixedGenerators) -> &edwards::Point<Bls12, PrimeOrder> {
|
||||
&self.fixed_base_generators[base as usize]
|
||||
}
|
||||
fn circuit_generators(&self, base: FixedGenerators) -> &[Vec<(Fr, Fr)>]
|
||||
{
|
||||
fn circuit_generators(&self, base: FixedGenerators) -> &[Vec<(Fr, Fr)>] {
|
||||
&self.fixed_base_circuit_generators[base as usize][..]
|
||||
}
|
||||
fn pedersen_hash_exp_window_size() -> u32 {
|
||||
|
@ -191,13 +194,19 @@ impl JubjubBls12 {
|
|||
|
||||
let mut tmp_params = JubjubBls12 {
|
||||
// d = -(10240/10241)
|
||||
edwards_d: Fr::from_str("19257038036680949359750312669786877991949435402254120286184196891950884077233").unwrap(),
|
||||
edwards_d: Fr::from_str(
|
||||
"19257038036680949359750312669786877991949435402254120286184196891950884077233",
|
||||
)
|
||||
.unwrap(),
|
||||
// A = 40962
|
||||
montgomery_a: montgomery_a,
|
||||
// 2A = 2.A
|
||||
montgomery_2a: montgomery_2a,
|
||||
// scaling factor = sqrt(4 / (a - d))
|
||||
scale: Fr::from_str("17814886934372412843466061268024708274627479829237077604635722030778476050649").unwrap(),
|
||||
scale: Fr::from_str(
|
||||
"17814886934372412843466061268024708274627479829237077604635722030778476050649",
|
||||
)
|
||||
.unwrap(),
|
||||
|
||||
// We'll initialize these below
|
||||
pedersen_hash_generators: vec![],
|
||||
|
@ -210,19 +219,14 @@ impl JubjubBls12 {
|
|||
fn find_group_hash<E: JubjubEngine>(
|
||||
m: &[u8],
|
||||
personalization: &[u8; 8],
|
||||
params: &E::Params
|
||||
) -> edwards::Point<E, PrimeOrder>
|
||||
{
|
||||
params: &E::Params,
|
||||
) -> edwards::Point<E, PrimeOrder> {
|
||||
let mut tag = m.to_vec();
|
||||
let i = tag.len();
|
||||
tag.push(0u8);
|
||||
|
||||
loop {
|
||||
let gh = group_hash(
|
||||
&tag,
|
||||
personalization,
|
||||
params
|
||||
);
|
||||
let gh = group_hash(&tag, personalization, params);
|
||||
|
||||
// We don't want to overflow and start reusing generators
|
||||
assert!(tag[i] != u8::max_value());
|
||||
|
@ -239,18 +243,18 @@ impl JubjubBls12 {
|
|||
let mut pedersen_hash_generators = vec![];
|
||||
|
||||
for m in 0..5 {
|
||||
use byteorder::{WriteBytesExt, LittleEndian};
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
|
||||
let mut segment_number = [0u8; 4];
|
||||
(&mut segment_number[0..4]).write_u32::<LittleEndian>(m).unwrap();
|
||||
(&mut segment_number[0..4])
|
||||
.write_u32::<LittleEndian>(m)
|
||||
.unwrap();
|
||||
|
||||
pedersen_hash_generators.push(
|
||||
find_group_hash(
|
||||
&segment_number,
|
||||
constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION,
|
||||
&tmp_params
|
||||
)
|
||||
);
|
||||
pedersen_hash_generators.push(find_group_hash(
|
||||
&segment_number,
|
||||
constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
));
|
||||
}
|
||||
|
||||
// Check for duplicates, far worse than spec inconsistencies!
|
||||
|
@ -259,7 +263,7 @@ impl JubjubBls12 {
|
|||
panic!("Neutral element!");
|
||||
}
|
||||
|
||||
for p2 in pedersen_hash_generators.iter().skip(i+1) {
|
||||
for p2 in pedersen_hash_generators.iter().skip(i + 1) {
|
||||
if p1 == p2 {
|
||||
panic!("Duplicate generator!");
|
||||
}
|
||||
|
@ -307,25 +311,46 @@ impl JubjubBls12 {
|
|||
|
||||
// Create the bases for other parts of the protocol
|
||||
{
|
||||
let mut fixed_base_generators = vec![edwards::Point::zero(); FixedGenerators::Max as usize];
|
||||
let mut fixed_base_generators =
|
||||
vec![edwards::Point::zero(); FixedGenerators::Max as usize];
|
||||
|
||||
fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] =
|
||||
find_group_hash(&[], constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION, &tmp_params);
|
||||
fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] = find_group_hash(
|
||||
&[],
|
||||
constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
|
||||
fixed_base_generators[FixedGenerators::NoteCommitmentRandomness as usize] =
|
||||
find_group_hash(b"r", constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, &tmp_params);
|
||||
find_group_hash(
|
||||
b"r",
|
||||
constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
|
||||
fixed_base_generators[FixedGenerators::NullifierPosition as usize] =
|
||||
find_group_hash(&[], constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION, &tmp_params);
|
||||
fixed_base_generators[FixedGenerators::NullifierPosition as usize] = find_group_hash(
|
||||
&[],
|
||||
constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
|
||||
fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] =
|
||||
find_group_hash(b"v", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params);
|
||||
fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] = find_group_hash(
|
||||
b"v",
|
||||
constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
|
||||
fixed_base_generators[FixedGenerators::ValueCommitmentRandomness as usize] =
|
||||
find_group_hash(b"r", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params);
|
||||
find_group_hash(
|
||||
b"r",
|
||||
constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
|
||||
fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] =
|
||||
find_group_hash(&[], constants::SPENDING_KEY_GENERATOR_PERSONALIZATION, &tmp_params);
|
||||
fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] = find_group_hash(
|
||||
&[],
|
||||
constants::SPENDING_KEY_GENERATOR_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
|
||||
// Check for duplicates, far worse than spec inconsistencies!
|
||||
for (i, p1) in fixed_base_generators.iter().enumerate() {
|
||||
|
@ -333,7 +358,7 @@ impl JubjubBls12 {
|
|||
panic!("Neutral element!");
|
||||
}
|
||||
|
||||
for p2 in fixed_base_generators.iter().skip(i+1) {
|
||||
for p2 in fixed_base_generators.iter().skip(i + 1) {
|
||||
if p1 == p2 {
|
||||
panic!("Duplicate generator!");
|
||||
}
|
||||
|
@ -413,10 +438,14 @@ fn test_jubjub_bls12() {
|
|||
let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139d31");
|
||||
let p = edwards::Point::<Bls12, _>::read(&test_repr[..], ¶ms).unwrap();
|
||||
let q = edwards::Point::<Bls12, _>::get_for_y(
|
||||
Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(),
|
||||
Fr::from_str(
|
||||
"22440861827555040311190986994816762244378363690614952020532787748720529117853",
|
||||
)
|
||||
.unwrap(),
|
||||
false,
|
||||
¶ms
|
||||
).unwrap();
|
||||
¶ms,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(p == q);
|
||||
|
||||
|
@ -424,10 +453,14 @@ fn test_jubjub_bls12() {
|
|||
let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139db1");
|
||||
let p = edwards::Point::<Bls12, _>::read(&test_repr[..], ¶ms).unwrap();
|
||||
let q = edwards::Point::<Bls12, _>::get_for_y(
|
||||
Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(),
|
||||
Fr::from_str(
|
||||
"22440861827555040311190986994816762244378363690614952020532787748720529117853",
|
||||
)
|
||||
.unwrap(),
|
||||
true,
|
||||
¶ms
|
||||
).unwrap();
|
||||
¶ms,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(p == q);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
|
||||
|
||||
use super::{
|
||||
JubjubEngine,
|
||||
JubjubParams,
|
||||
Unknown,
|
||||
PrimeOrder,
|
||||
edwards
|
||||
};
|
||||
use super::{edwards, JubjubEngine, JubjubParams, PrimeOrder, Unknown};
|
||||
|
||||
use rand_core::RngCore;
|
||||
|
||||
|
@ -17,29 +11,25 @@ pub struct Point<E: JubjubEngine, Subgroup> {
|
|||
x: E::Fr,
|
||||
y: E::Fr,
|
||||
infinity: bool,
|
||||
_marker: PhantomData<Subgroup>
|
||||
_marker: PhantomData<Subgroup>,
|
||||
}
|
||||
|
||||
fn convert_subgroup<E: JubjubEngine, S1, S2>(from: &Point<E, S1>) -> Point<E, S2>
|
||||
{
|
||||
fn convert_subgroup<E: JubjubEngine, S1, S2>(from: &Point<E, S1>) -> Point<E, S2> {
|
||||
Point {
|
||||
x: from.x,
|
||||
y: from.y,
|
||||
infinity: from.infinity,
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> From<Point<E, PrimeOrder>> for Point<E, Unknown>
|
||||
{
|
||||
fn from(p: Point<E, PrimeOrder>) -> Point<E, Unknown>
|
||||
{
|
||||
impl<E: JubjubEngine> From<Point<E, PrimeOrder>> for Point<E, Unknown> {
|
||||
fn from(p: Point<E, PrimeOrder>) -> Point<E, Unknown> {
|
||||
convert_subgroup(&p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine, Subgroup> Clone for Point<E, Subgroup>
|
||||
{
|
||||
impl<E: JubjubEngine, Subgroup> Clone for Point<E, Subgroup> {
|
||||
fn clone(&self) -> Self {
|
||||
convert_subgroup(self)
|
||||
}
|
||||
|
@ -50,16 +40,13 @@ impl<E: JubjubEngine, Subgroup> PartialEq for Point<E, Subgroup> {
|
|||
match (self.infinity, other.infinity) {
|
||||
(true, true) => true,
|
||||
(true, false) | (false, true) => false,
|
||||
(false, false) => {
|
||||
self.x == other.x && self.y == other.y
|
||||
}
|
||||
(false, false) => self.x == other.x && self.y == other.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> Point<E, Unknown> {
|
||||
pub fn get_for_x(x: E::Fr, sign: bool, params: &E::Params) -> Option<Self>
|
||||
{
|
||||
pub fn get_for_x(x: E::Fr, sign: bool, params: &E::Params) -> Option<Self> {
|
||||
// Given an x on the curve, y = sqrt(x^3 + A*x^2 + x)
|
||||
|
||||
let mut x2 = x;
|
||||
|
@ -81,34 +68,28 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
|||
x: x,
|
||||
y: y,
|
||||
infinity: false,
|
||||
_marker: PhantomData
|
||||
})
|
||||
},
|
||||
None => None
|
||||
_marker: PhantomData,
|
||||
});
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// This guarantees the point is in the prime order subgroup
|
||||
#[must_use]
|
||||
pub fn mul_by_cofactor(&self, params: &E::Params) -> Point<E, PrimeOrder>
|
||||
{
|
||||
let tmp = self.double(params)
|
||||
.double(params)
|
||||
.double(params);
|
||||
pub fn mul_by_cofactor(&self, params: &E::Params) -> Point<E, PrimeOrder> {
|
||||
let tmp = self.double(params).double(params).double(params);
|
||||
|
||||
convert_subgroup(&tmp)
|
||||
}
|
||||
|
||||
pub fn rand<R: RngCore>(rng: &mut R, params: &E::Params) -> Self
|
||||
{
|
||||
pub fn rand<R: RngCore>(rng: &mut R, params: &E::Params) -> Self {
|
||||
loop {
|
||||
let x = E::Fr::random(rng);
|
||||
let sign = rng.next_u32() % 2 != 0;
|
||||
|
||||
match Self::get_for_x(x, sign, params) {
|
||||
Some(p) => {
|
||||
return p
|
||||
},
|
||||
Some(p) => return p,
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
@ -117,11 +98,7 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
|||
|
||||
impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
/// Convert from an Edwards point
|
||||
pub fn from_edwards(
|
||||
e: &edwards::Point<E, Subgroup>,
|
||||
params: &E::Params
|
||||
) -> Self
|
||||
{
|
||||
pub fn from_edwards(e: &edwards::Point<E, Subgroup>, params: &E::Params) -> Self {
|
||||
let (x, y) = e.into_xy();
|
||||
|
||||
if y == E::Fr::one() {
|
||||
|
@ -149,7 +126,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||
x: E::Fr::zero(),
|
||||
y: E::Fr::zero(),
|
||||
infinity: false,
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
}
|
||||
} else {
|
||||
// The mapping is defined as above.
|
||||
|
@ -176,7 +153,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||
x: u,
|
||||
y: v,
|
||||
infinity: false,
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -197,12 +174,11 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||
x: E::Fr::zero(),
|
||||
y: E::Fr::zero(),
|
||||
infinity: true,
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_xy(&self) -> Option<(E::Fr, E::Fr)>
|
||||
{
|
||||
pub fn into_xy(&self) -> Option<(E::Fr, E::Fr)> {
|
||||
if self.infinity {
|
||||
None
|
||||
} else {
|
||||
|
@ -272,13 +248,12 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||
x: x3,
|
||||
y: y3,
|
||||
infinity: false,
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn add(&self, other: &Self, params: &E::Params) -> Self
|
||||
{
|
||||
pub fn add(&self, other: &Self, params: &E::Params) -> Self {
|
||||
// This is a standard affine point addition formula
|
||||
// See 4.3.2 The group law for Weierstrass curves
|
||||
// Montgomery curves and the Montgomery Ladder
|
||||
|
@ -301,7 +276,10 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||
{
|
||||
let mut tmp = other.x;
|
||||
tmp.sub_assign(&self.x);
|
||||
delta.mul_assign(&tmp.inverse().expect("self.x != other.x, so this must be nonzero"));
|
||||
delta.mul_assign(
|
||||
&tmp.inverse()
|
||||
.expect("self.x != other.x, so this must be nonzero"),
|
||||
);
|
||||
}
|
||||
|
||||
let mut x3 = delta;
|
||||
|
@ -320,7 +298,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||
x: x3,
|
||||
y: y3,
|
||||
infinity: false,
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -328,12 +306,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn mul<S: Into<<E::Fs as PrimeField>::Repr>>(
|
||||
&self,
|
||||
scalar: S,
|
||||
params: &E::Params
|
||||
) -> Self
|
||||
{
|
||||
pub fn mul<S: Into<<E::Fs as PrimeField>::Repr>>(&self, scalar: S, params: &E::Params) -> Self {
|
||||
// Standard double-and-add scalar multiplication
|
||||
|
||||
let mut res = Self::zero();
|
||||
|
|
|
@ -1,18 +1,6 @@
|
|||
use super::{
|
||||
JubjubEngine,
|
||||
JubjubParams,
|
||||
PrimeOrder,
|
||||
montgomery,
|
||||
edwards
|
||||
};
|
||||
use super::{edwards, montgomery, JubjubEngine, JubjubParams, PrimeOrder};
|
||||
|
||||
use ff::{
|
||||
Field,
|
||||
PrimeField,
|
||||
PrimeFieldRepr,
|
||||
SqrtField,
|
||||
LegendreSymbol
|
||||
};
|
||||
use ff::{Field, LegendreSymbol, PrimeField, PrimeFieldRepr, SqrtField};
|
||||
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
@ -30,12 +18,7 @@ pub fn test_suite<E: JubjubEngine>(params: &E::Params) {
|
|||
test_read_write::<E>(params);
|
||||
}
|
||||
|
||||
fn is_on_mont_curve<E: JubjubEngine, P: JubjubParams<E>>(
|
||||
x: E::Fr,
|
||||
y: E::Fr,
|
||||
params: &P
|
||||
) -> bool
|
||||
{
|
||||
fn is_on_mont_curve<E: JubjubEngine, P: JubjubParams<E>>(x: E::Fr, y: E::Fr, params: &P) -> bool {
|
||||
let mut lhs = y;
|
||||
lhs.square();
|
||||
|
||||
|
@ -56,9 +39,8 @@ fn is_on_mont_curve<E: JubjubEngine, P: JubjubParams<E>>(
|
|||
fn is_on_twisted_edwards_curve<E: JubjubEngine, P: JubjubParams<E>>(
|
||||
x: E::Fr,
|
||||
y: E::Fr,
|
||||
params: &P
|
||||
) -> bool
|
||||
{
|
||||
params: &P,
|
||||
) -> bool {
|
||||
let mut x2 = x;
|
||||
x2.square();
|
||||
|
||||
|
@ -156,7 +138,9 @@ fn test_order<E: JubjubEngine>(params: &E::Params) {
|
|||
]);
|
||||
|
||||
// The neutral element is in the prime order subgroup.
|
||||
assert!(Point::<E, PrimeOrder>::zero().as_prime_order(params).is_some());
|
||||
assert!(Point::<E, PrimeOrder>::zero()
|
||||
.as_prime_order(params)
|
||||
.is_some());
|
||||
|
||||
for _ in 0..50 {
|
||||
// Pick a random point and multiply it by the cofactor
|
||||
|
@ -256,11 +240,7 @@ fn test_get_for<E: JubjubEngine>(params: &E::Params) {
|
|||
if let Some(mut p) = edwards::Point::<E, _>::get_for_y(y, sign, params) {
|
||||
assert!(p.into_xy().0.into_repr().is_odd() == sign);
|
||||
p = p.negate();
|
||||
assert!(
|
||||
edwards::Point::<E, _>::get_for_y(y, !sign, params).unwrap()
|
||||
==
|
||||
p
|
||||
);
|
||||
assert!(edwards::Point::<E, _>::get_for_y(y, !sign, params).unwrap() == p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -321,13 +301,9 @@ fn test_back_and_forth<E: JubjubEngine>(params: &E::Params) {
|
|||
let mont = mont_p1.add(&mont_p2, params).mul(s, params);
|
||||
let edwards = edwards_p1.add(&edwards_p2, params).mul(s, params);
|
||||
|
||||
assert!(
|
||||
montgomery::Point::from_edwards(&edwards, params) == mont
|
||||
);
|
||||
assert!(montgomery::Point::from_edwards(&edwards, params) == mont);
|
||||
|
||||
assert!(
|
||||
edwards::Point::from_montgomery(&mont, params) == edwards
|
||||
);
|
||||
assert!(edwards::Point::from_montgomery(&mont, params) == edwards);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -411,8 +387,7 @@ fn test_jubjub_params<E: JubjubEngine>(params: &E::Params) {
|
|||
let mut pacc = E::Fs::zero().into_repr();
|
||||
let mut nacc = E::Fs::char();
|
||||
|
||||
for _ in 0..params.pedersen_hash_chunks_per_generator()
|
||||
{
|
||||
for _ in 0..params.pedersen_hash_chunks_per_generator() {
|
||||
// tmp = cur * 4
|
||||
let mut tmp = cur;
|
||||
tmp.mul2();
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
//!
|
||||
//! Implements section 4.2.2 of the Zcash Protocol Specification.
|
||||
|
||||
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
|
||||
use ff::{PrimeField, PrimeFieldRepr};
|
||||
use crate::{
|
||||
jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, ToUniform, Unknown},
|
||||
primitives::{ProofGenerationKey, ViewingKey},
|
||||
};
|
||||
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
|
||||
use ff::{PrimeField, PrimeFieldRepr};
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
pub const PRF_EXPAND_PERSONALIZATION: &'static [u8; 16] = b"Zcash_ExpandSeed";
|
||||
|
@ -187,8 +187,8 @@ impl<E: JubjubEngine> FullViewingKey<E> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pairing::bls12_381::Bls12;
|
||||
use crate::jubjub::{edwards, FixedGenerators, JubjubParams, PrimeOrder};
|
||||
use pairing::bls12_381::Bls12;
|
||||
use std::error::Error;
|
||||
|
||||
use super::FullViewingKey;
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
//! Implementation of in-band secret distribution for Zcash transactions.
|
||||
|
||||
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf};
|
||||
use ff::{PrimeField, PrimeFieldRepr};
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
use crate::{
|
||||
jubjub::{
|
||||
edwards,
|
||||
|
@ -14,6 +8,12 @@ use crate::{
|
|||
},
|
||||
primitives::{Diversifier, Note, PaymentAddress},
|
||||
};
|
||||
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf};
|
||||
use ff::{PrimeField, PrimeFieldRepr};
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
|
@ -544,11 +544,6 @@ pub fn try_sapling_output_recovery(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crypto_api_chachapoly::ChachaPolyIetf;
|
||||
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||
use pairing::bls12_381::{Bls12, Fr, FrRepr};
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
use rand_os::OsRng;
|
||||
use crate::{
|
||||
jubjub::{
|
||||
edwards,
|
||||
|
@ -557,6 +552,11 @@ mod tests {
|
|||
},
|
||||
primitives::{Diversifier, PaymentAddress, ValueCommitment},
|
||||
};
|
||||
use crypto_api_chachapoly::ChachaPolyIetf;
|
||||
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||
use pairing::bls12_381::{Bls12, Fr, FrRepr};
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
use rand_os::OsRng;
|
||||
|
||||
use super::{
|
||||
kdf_sapling, prf_ock, sapling_ka_agree, try_sapling_compact_note_decryption,
|
||||
|
|
|
@ -4,14 +4,13 @@ use jubjub::*;
|
|||
#[derive(Copy, Clone)]
|
||||
pub enum Personalization {
|
||||
NoteCommitment,
|
||||
MerkleTree(usize)
|
||||
MerkleTree(usize),
|
||||
}
|
||||
|
||||
impl Personalization {
|
||||
pub fn get_bits(&self) -> Vec<bool> {
|
||||
match *self {
|
||||
Personalization::NoteCommitment =>
|
||||
vec![true, true, true, true, true, true],
|
||||
Personalization::NoteCommitment => vec![true, true, true, true, true, true],
|
||||
Personalization::MerkleTree(num) => {
|
||||
assert!(num < 63);
|
||||
|
||||
|
@ -24,12 +23,16 @@ impl Personalization {
|
|||
pub fn pedersen_hash<E, I>(
|
||||
personalization: Personalization,
|
||||
bits: I,
|
||||
params: &E::Params
|
||||
params: &E::Params,
|
||||
) -> edwards::Point<E, PrimeOrder>
|
||||
where I: IntoIterator<Item=bool>,
|
||||
E: JubjubEngine
|
||||
where
|
||||
I: IntoIterator<Item = bool>,
|
||||
E: JubjubEngine,
|
||||
{
|
||||
let mut bits = personalization.get_bits().into_iter().chain(bits.into_iter());
|
||||
let mut bits = personalization
|
||||
.get_bits()
|
||||
.into_iter()
|
||||
.chain(bits.into_iter());
|
||||
|
||||
let mut result = edwards::Point::zero();
|
||||
let mut generators = params.pedersen_hash_exp_table().iter();
|
||||
|
@ -79,12 +82,13 @@ pub fn pedersen_hash<E, I>(
|
|||
break;
|
||||
}
|
||||
|
||||
let mut table: &[Vec<edwards::Point<E, _>>] = &generators.next().expect("we don't have enough generators");
|
||||
let mut table: &[Vec<edwards::Point<E, _>>] =
|
||||
&generators.next().expect("we don't have enough generators");
|
||||
let window = JubjubBls12::pedersen_hash_exp_window_size();
|
||||
let window_mask = (1 << window) - 1;
|
||||
|
||||
let mut acc = acc.into_repr();
|
||||
|
||||
|
||||
let mut tmp = edwards::Point::zero();
|
||||
|
||||
while !acc.is_zero() {
|
||||
|
|
|
@ -4,60 +4,47 @@ use constants;
|
|||
|
||||
use group_hash::group_hash;
|
||||
|
||||
use pedersen_hash::{
|
||||
pedersen_hash,
|
||||
Personalization
|
||||
};
|
||||
use pedersen_hash::{pedersen_hash, Personalization};
|
||||
|
||||
use byteorder::{
|
||||
LittleEndian,
|
||||
WriteBytesExt
|
||||
};
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
|
||||
use jubjub::{
|
||||
JubjubEngine,
|
||||
JubjubParams,
|
||||
edwards,
|
||||
PrimeOrder,
|
||||
FixedGenerators
|
||||
};
|
||||
use jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder};
|
||||
|
||||
use blake2s_simd::Params as Blake2sParams;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ValueCommitment<E: JubjubEngine> {
|
||||
pub value: u64,
|
||||
pub randomness: E::Fs
|
||||
pub randomness: E::Fs,
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> ValueCommitment<E> {
|
||||
pub fn cm(
|
||||
&self,
|
||||
params: &E::Params
|
||||
) -> edwards::Point<E, PrimeOrder>
|
||||
{
|
||||
params.generator(FixedGenerators::ValueCommitmentValue)
|
||||
.mul(self.value, params)
|
||||
.add(
|
||||
¶ms.generator(FixedGenerators::ValueCommitmentRandomness)
|
||||
.mul(self.randomness, params),
|
||||
params
|
||||
)
|
||||
pub fn cm(&self, params: &E::Params) -> edwards::Point<E, PrimeOrder> {
|
||||
params
|
||||
.generator(FixedGenerators::ValueCommitmentValue)
|
||||
.mul(self.value, params)
|
||||
.add(
|
||||
¶ms
|
||||
.generator(FixedGenerators::ValueCommitmentRandomness)
|
||||
.mul(self.randomness, params),
|
||||
params,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ProofGenerationKey<E: JubjubEngine> {
|
||||
pub ak: edwards::Point<E, PrimeOrder>,
|
||||
pub nsk: E::Fs
|
||||
pub nsk: E::Fs,
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> ProofGenerationKey<E> {
|
||||
pub fn into_viewing_key(&self, params: &E::Params) -> ViewingKey<E> {
|
||||
ViewingKey {
|
||||
ak: self.ak.clone(),
|
||||
nk: params.generator(FixedGenerators::ProofGenerationKey)
|
||||
.mul(self.nsk, params)
|
||||
nk: params
|
||||
.generator(FixedGenerators::ProofGenerationKey)
|
||||
.mul(self.nsk, params),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,19 +52,16 @@ impl<E: JubjubEngine> ProofGenerationKey<E> {
|
|||
#[derive(Debug)]
|
||||
pub struct ViewingKey<E: JubjubEngine> {
|
||||
pub ak: edwards::Point<E, PrimeOrder>,
|
||||
pub nk: edwards::Point<E, PrimeOrder>
|
||||
pub nk: edwards::Point<E, PrimeOrder>,
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> ViewingKey<E> {
|
||||
pub fn rk(
|
||||
&self,
|
||||
ar: E::Fs,
|
||||
params: &E::Params
|
||||
) -> edwards::Point<E, PrimeOrder> {
|
||||
pub fn rk(&self, ar: E::Fs, params: &E::Params) -> edwards::Point<E, PrimeOrder> {
|
||||
self.ak.add(
|
||||
¶ms.generator(FixedGenerators::SpendingKeyGenerator)
|
||||
.mul(ar, params),
|
||||
params
|
||||
¶ms
|
||||
.generator(FixedGenerators::SpendingKeyGenerator)
|
||||
.mul(ar, params),
|
||||
params,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -88,11 +72,13 @@ impl<E: JubjubEngine> ViewingKey<E> {
|
|||
self.nk.write(&mut preimage[32..64]).unwrap();
|
||||
|
||||
let mut h = [0; 32];
|
||||
h.copy_from_slice(Blake2sParams::new()
|
||||
.hash_length(32)
|
||||
.personal(constants::CRH_IVK_PERSONALIZATION)
|
||||
.hash(&preimage)
|
||||
.as_bytes());
|
||||
h.copy_from_slice(
|
||||
Blake2sParams::new()
|
||||
.hash_length(32)
|
||||
.personal(constants::CRH_IVK_PERSONALIZATION)
|
||||
.hash(&preimage)
|
||||
.as_bytes(),
|
||||
);
|
||||
|
||||
// Drop the most significant five bits, so it can be interpreted as a scalar.
|
||||
h[31] &= 0b0000_0111;
|
||||
|
@ -106,15 +92,14 @@ impl<E: JubjubEngine> ViewingKey<E> {
|
|||
pub fn into_payment_address(
|
||||
&self,
|
||||
diversifier: Diversifier,
|
||||
params: &E::Params
|
||||
) -> Option<PaymentAddress<E>>
|
||||
{
|
||||
params: &E::Params,
|
||||
) -> Option<PaymentAddress<E>> {
|
||||
diversifier.g_d(params).map(|g_d| {
|
||||
let pk_d = g_d.mul(self.ivk(), params);
|
||||
|
||||
PaymentAddress {
|
||||
pk_d: pk_d,
|
||||
diversifier: diversifier
|
||||
diversifier: diversifier,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -126,17 +111,20 @@ pub struct Diversifier(pub [u8; 11]);
|
|||
impl Diversifier {
|
||||
pub fn g_d<E: JubjubEngine>(
|
||||
&self,
|
||||
params: &E::Params
|
||||
) -> Option<edwards::Point<E, PrimeOrder>>
|
||||
{
|
||||
group_hash::<E>(&self.0, constants::KEY_DIVERSIFICATION_PERSONALIZATION, params)
|
||||
params: &E::Params,
|
||||
) -> Option<edwards::Point<E, PrimeOrder>> {
|
||||
group_hash::<E>(
|
||||
&self.0,
|
||||
constants::KEY_DIVERSIFICATION_PERSONALIZATION,
|
||||
params,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PaymentAddress<E: JubjubEngine> {
|
||||
pub pk_d: edwards::Point<E, PrimeOrder>,
|
||||
pub diversifier: Diversifier
|
||||
pub diversifier: Diversifier,
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> PartialEq for PaymentAddress<E> {
|
||||
|
@ -146,11 +134,7 @@ impl<E: JubjubEngine> PartialEq for PaymentAddress<E> {
|
|||
}
|
||||
|
||||
impl<E: JubjubEngine> PaymentAddress<E> {
|
||||
pub fn g_d(
|
||||
&self,
|
||||
params: &E::Params
|
||||
) -> Option<edwards::Point<E, PrimeOrder>>
|
||||
{
|
||||
pub fn g_d(&self, params: &E::Params) -> Option<edwards::Point<E, PrimeOrder>> {
|
||||
self.diversifier.g_d(params)
|
||||
}
|
||||
|
||||
|
@ -158,16 +142,13 @@ impl<E: JubjubEngine> PaymentAddress<E> {
|
|||
&self,
|
||||
value: u64,
|
||||
randomness: E::Fs,
|
||||
params: &E::Params
|
||||
) -> Option<Note<E>>
|
||||
{
|
||||
self.g_d(params).map(|g_d| {
|
||||
Note {
|
||||
value: value,
|
||||
r: randomness,
|
||||
g_d: g_d,
|
||||
pk_d: self.pk_d.clone()
|
||||
}
|
||||
params: &E::Params,
|
||||
) -> Option<Note<E>> {
|
||||
self.g_d(params).map(|g_d| Note {
|
||||
value: value,
|
||||
r: randomness,
|
||||
g_d: g_d,
|
||||
pk_d: self.pk_d.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +162,7 @@ pub struct Note<E: JubjubEngine> {
|
|||
/// The public key of the address, g_d^ivk
|
||||
pub pk_d: edwards::Point<E, PrimeOrder>,
|
||||
/// The commitment randomness
|
||||
pub r: E::Fs
|
||||
pub r: E::Fs,
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> PartialEq for Note<E> {
|
||||
|
@ -204,13 +185,14 @@ impl<E: JubjubEngine> Note<E> {
|
|||
}
|
||||
|
||||
/// Computes the note commitment, returning the full point.
|
||||
fn cm_full_point(&self, params: &E::Params) -> edwards::Point<E, PrimeOrder>
|
||||
{
|
||||
fn cm_full_point(&self, params: &E::Params) -> edwards::Point<E, PrimeOrder> {
|
||||
// Calculate the note contents, as bytes
|
||||
let mut note_contents = vec![];
|
||||
|
||||
// Writing the value in little endian
|
||||
(&mut note_contents).write_u64::<LittleEndian>(self.value).unwrap();
|
||||
(&mut note_contents)
|
||||
.write_u64::<LittleEndian>(self.value)
|
||||
.unwrap();
|
||||
|
||||
// Write g_d
|
||||
self.g_d.write(&mut note_contents).unwrap();
|
||||
|
@ -223,36 +205,29 @@ impl<E: JubjubEngine> Note<E> {
|
|||
// Compute the Pedersen hash of the note contents
|
||||
let hash_of_contents = pedersen_hash(
|
||||
Personalization::NoteCommitment,
|
||||
note_contents.into_iter()
|
||||
.flat_map(|byte| {
|
||||
(0..8).map(move |i| ((byte >> i) & 1) == 1)
|
||||
}),
|
||||
params
|
||||
note_contents
|
||||
.into_iter()
|
||||
.flat_map(|byte| (0..8).map(move |i| ((byte >> i) & 1) == 1)),
|
||||
params,
|
||||
);
|
||||
|
||||
// Compute final commitment
|
||||
params.generator(FixedGenerators::NoteCommitmentRandomness)
|
||||
.mul(self.r, params)
|
||||
.add(&hash_of_contents, params)
|
||||
params
|
||||
.generator(FixedGenerators::NoteCommitmentRandomness)
|
||||
.mul(self.r, params)
|
||||
.add(&hash_of_contents, params)
|
||||
}
|
||||
|
||||
/// Computes the nullifier given the viewing key and
|
||||
/// note position
|
||||
pub fn nf(
|
||||
&self,
|
||||
viewing_key: &ViewingKey<E>,
|
||||
position: u64,
|
||||
params: &E::Params
|
||||
) -> Vec<u8>
|
||||
{
|
||||
pub fn nf(&self, viewing_key: &ViewingKey<E>, position: u64, params: &E::Params) -> Vec<u8> {
|
||||
// Compute rho = cm + position.G
|
||||
let rho = self
|
||||
.cm_full_point(params)
|
||||
.add(
|
||||
¶ms.generator(FixedGenerators::NullifierPosition)
|
||||
.mul(position, params),
|
||||
params
|
||||
);
|
||||
let rho = self.cm_full_point(params).add(
|
||||
¶ms
|
||||
.generator(FixedGenerators::NullifierPosition)
|
||||
.mul(position, params),
|
||||
params,
|
||||
);
|
||||
|
||||
// Compute nf = BLAKE2s(nk | rho)
|
||||
let mut nf_preimage = [0u8; 64];
|
||||
|
@ -267,8 +242,7 @@ impl<E: JubjubEngine> Note<E> {
|
|||
}
|
||||
|
||||
/// Computes the note commitment
|
||||
pub fn cm(&self, params: &E::Params) -> E::Fr
|
||||
{
|
||||
pub fn cm(&self, params: &E::Params) -> E::Fr {
|
||||
// The commitment is in the prime order subgroup, so mapping the
|
||||
// commitment to the x-coordinate is an injective encoding.
|
||||
self.cm_full_point(params).into_xy().0
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
//! Abstractions over the proving system and parameters.
|
||||
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use crate::{
|
||||
jubjub::{edwards, fs::Fs, Unknown},
|
||||
primitives::{Diversifier, PaymentAddress, ProofGenerationKey},
|
||||
};
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
|
||||
use crate::{
|
||||
merkle_tree::CommitmentTreeWitness,
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
//! Implementation of RedJubjub, a specialization of RedDSA to the Jubjub curve.
|
||||
//! See section 5.4.6 of the Sapling protocol specification.
|
||||
|
||||
use crate::jubjub::{edwards::Point, FixedGenerators, JubjubEngine, JubjubParams, Unknown};
|
||||
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||
use rand_core::RngCore;
|
||||
use crate::jubjub::{
|
||||
edwards::Point, FixedGenerators, JubjubEngine, JubjubParams, Unknown,
|
||||
};
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use util::hash_to_scalar;
|
||||
|
@ -150,10 +148,15 @@ impl<E: JubjubEngine> PublicKey<E> {
|
|||
Err(_) => return false,
|
||||
};
|
||||
// 0 = h_G(-S . P_G + R + c . vk)
|
||||
self.0.mul(c, params).add(&r, params).add(
|
||||
¶ms.generator(p_g).mul(s, params).negate().into(),
|
||||
params
|
||||
).mul_by_cofactor(params).eq(&Point::zero())
|
||||
self.0
|
||||
.mul(c, params)
|
||||
.add(&r, params)
|
||||
.add(
|
||||
¶ms.generator(p_g).mul(s, params).negate().into(),
|
||||
params,
|
||||
)
|
||||
.mul_by_cofactor(params)
|
||||
.eq(&Point::zero())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,8 +173,7 @@ pub fn batch_verify<'a, E: JubjubEngine, R: RngCore>(
|
|||
batch: &[BatchEntry<'a, E>],
|
||||
p_g: FixedGenerators,
|
||||
params: &E::Params,
|
||||
) -> bool
|
||||
{
|
||||
) -> bool {
|
||||
let mut acc = Point::<E, Unknown>::zero();
|
||||
|
||||
for entry in batch {
|
||||
|
@ -218,8 +220,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_batch_verify() {
|
||||
let rng = &mut XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
let params = &JubjubBls12::new();
|
||||
let p_g = FixedGenerators::SpendingKeyGenerator;
|
||||
|
@ -237,8 +239,16 @@ mod tests {
|
|||
assert!(vk2.verify(msg2, &sig2, p_g, params));
|
||||
|
||||
let mut batch = vec![
|
||||
BatchEntry { vk: vk1, msg: msg1, sig: sig1 },
|
||||
BatchEntry { vk: vk2, msg: msg2, sig: sig2 }
|
||||
BatchEntry {
|
||||
vk: vk1,
|
||||
msg: msg1,
|
||||
sig: sig1,
|
||||
},
|
||||
BatchEntry {
|
||||
vk: vk2,
|
||||
msg: msg2,
|
||||
sig: sig2,
|
||||
},
|
||||
];
|
||||
|
||||
assert!(batch_verify(rng, &batch, p_g, params));
|
||||
|
@ -251,8 +261,8 @@ mod tests {
|
|||
#[test]
|
||||
fn cofactor_check() {
|
||||
let rng = &mut XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
let params = &JubjubBls12::new();
|
||||
let zero = edwards::Point::zero();
|
||||
|
@ -286,8 +296,8 @@ mod tests {
|
|||
#[test]
|
||||
fn round_trip_serialization() {
|
||||
let rng = &mut XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
let p_g = FixedGenerators::SpendingKeyGenerator;
|
||||
let params = &JubjubBls12::new();
|
||||
|
@ -322,8 +332,8 @@ mod tests {
|
|||
#[test]
|
||||
fn random_signatures() {
|
||||
let rng = &mut XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
let p_g = FixedGenerators::SpendingKeyGenerator;
|
||||
let params = &JubjubBls12::new();
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
//! Structs and constants specific to the Sapling shielded pool.
|
||||
|
||||
use ff::{BitIterator, PrimeField, PrimeFieldRepr};
|
||||
use pairing::bls12_381::{Bls12, Fr, FrRepr};
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
use crate::{
|
||||
jubjub::{fs::Fs, FixedGenerators, JubjubBls12},
|
||||
pedersen_hash::{pedersen_hash, Personalization},
|
||||
primitives::Note,
|
||||
};
|
||||
use ff::{BitIterator, PrimeField, PrimeFieldRepr};
|
||||
use pairing::bls12_381::{Bls12, Fr, FrRepr};
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use crate::merkle_tree::Hashable;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
//! Structs for building transactions.
|
||||
|
||||
use ff::Field;
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use rand::{rngs::OsRng, seq::SliceRandom, CryptoRng, RngCore};
|
||||
use crate::{
|
||||
jubjub::fs::Fs,
|
||||
primitives::{Diversifier, Note, PaymentAddress},
|
||||
};
|
||||
use ff::Field;
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use rand::{rngs::OsRng, seq::SliceRandom, CryptoRng, RngCore};
|
||||
use zip32::ExtendedSpendingKey;
|
||||
|
||||
use crate::{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::jubjub::{edwards, Unknown};
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use ff::{PrimeField, PrimeFieldRepr};
|
||||
use pairing::bls12_381::{Bls12, Fr, FrRepr};
|
||||
use crate::jubjub::{edwards, Unknown};
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use legacy::Script;
|
||||
|
|
|
@ -135,7 +135,10 @@ impl DiversifierKey {
|
|||
/// Returns the first index starting from j that generates a valid
|
||||
/// diversifier, along with the corresponding diversifier. Returns
|
||||
/// an error if the diversifier space is exhausted.
|
||||
pub fn diversifier(&self, mut j: DiversifierIndex) -> Result<(DiversifierIndex, Diversifier), ()> {
|
||||
pub fn diversifier(
|
||||
&self,
|
||||
mut j: DiversifierIndex,
|
||||
) -> Result<(DiversifierIndex, Diversifier), ()> {
|
||||
let ff = FF1::<Aes256>::new(&self.0, 2).unwrap();
|
||||
loop {
|
||||
// Generate d_j
|
||||
|
|
Loading…
Reference in New Issue