cargo fmt zcash_primitives

This commit is contained in:
Eirik Ogilvie-Wigley 2019-08-15 10:39:55 -06:00
parent 9a4f6812f1
commit 81c58172c3
18 changed files with 786 additions and 520 deletions

View File

@ -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(), &params)
});
b.iter(|| pedersen_hash::<Bls12, _>(personalization, bits.clone(), &params));
}

View File

@ -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_";

View File

@ -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,
}
}

View File

@ -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();

View File

@ -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());
}

View File

@ -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[..], &params).unwrap();
let q = edwards::Point::<Bls12, _>::get_for_y(
Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(),
Fr::from_str(
"22440861827555040311190986994816762244378363690614952020532787748720529117853",
)
.unwrap(),
false,
&params
).unwrap();
&params,
)
.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[..], &params).unwrap();
let q = edwards::Point::<Bls12, _>::get_for_y(
Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(),
Fr::from_str(
"22440861827555040311190986994816762244378363690614952020532787748720529117853",
)
.unwrap(),
true,
&params
).unwrap();
&params,
)
.unwrap();
assert!(p == q);
}

View File

@ -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();

View File

@ -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();

View File

@ -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;

View File

@ -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,

View File

@ -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() {

View File

@ -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(
&params.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(
&params
.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(
&params.generator(FixedGenerators::SpendingKeyGenerator)
.mul(ar, params),
params
&params
.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(
&params.generator(FixedGenerators::NullifierPosition)
.mul(position, params),
params
);
let rho = self.cm_full_point(params).add(
&params
.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

View File

@ -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,

View File

@ -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(
&params.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(
&params.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();

View File

@ -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;

View File

@ -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::{

View File

@ -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;

View File

@ -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