Remaining tests for input circuit
This commit is contained in:
@@ -22,7 +22,6 @@ use bellman::{
|
|||||||
|
|
||||||
use jubjub::{
|
use jubjub::{
|
||||||
JubjubEngine,
|
JubjubEngine,
|
||||||
Unknown,
|
|
||||||
PrimeOrder,
|
PrimeOrder,
|
||||||
FixedGenerators,
|
FixedGenerators,
|
||||||
edwards
|
edwards
|
||||||
@@ -55,9 +54,9 @@ pub struct Spend<'a, E: JubjubEngine> {
|
|||||||
/// The public key that will be re-randomized for
|
/// The public key that will be re-randomized for
|
||||||
/// use as a nullifier and signing key for the
|
/// use as a nullifier and signing key for the
|
||||||
/// transaction.
|
/// transaction.
|
||||||
pub ak: Option<edwards::Point<E, Unknown>>,
|
pub ak: Option<edwards::Point<E, PrimeOrder>>,
|
||||||
/// The diversified base used to compute pk_d.
|
/// The diversified base used to compute pk_d.
|
||||||
pub g_d: Option<edwards::Point<E, Unknown>>,
|
pub g_d: Option<edwards::Point<E, PrimeOrder>>,
|
||||||
/// The randomness used to hide the note commitment data
|
/// The randomness used to hide the note commitment data
|
||||||
pub commitment_randomness: Option<E::Fs>,
|
pub commitment_randomness: Option<E::Fs>,
|
||||||
/// The authentication path of the commitment in the tree
|
/// The authentication path of the commitment in the tree
|
||||||
@@ -482,7 +481,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_input_circuit_with_bls12_381() {
|
fn test_input_circuit_with_bls12_381() {
|
||||||
use pairing::{Field};
|
use pairing::{Field, BitIterator};
|
||||||
use pairing::bls12_381::*;
|
use pairing::bls12_381::*;
|
||||||
use rand::{SeedableRng, Rng, XorShiftRng};
|
use rand::{SeedableRng, Rng, XorShiftRng};
|
||||||
use ::circuit::test::*;
|
use ::circuit::test::*;
|
||||||
@@ -495,10 +494,34 @@ fn test_input_circuit_with_bls12_381() {
|
|||||||
|
|
||||||
let value: u64 = 1;
|
let value: u64 = 1;
|
||||||
let value_randomness: fs::Fs = rng.gen();
|
let value_randomness: fs::Fs = rng.gen();
|
||||||
let ak: edwards::Point<Bls12, Unknown> = edwards::Point::rand(rng, params);
|
|
||||||
let g_d: edwards::Point<Bls12, Unknown> = edwards::Point::rand(rng, params);
|
|
||||||
let commitment_randomness: fs::Fs = rng.gen();
|
|
||||||
let rsk: fs::Fs = rng.gen();
|
let rsk: fs::Fs = rng.gen();
|
||||||
|
let ak: edwards::Point<Bls12, PrimeOrder> = edwards::Point::rand(rng, params).mul_by_cofactor(params);
|
||||||
|
|
||||||
|
let proof_generation_key = ::primitives::ProofGenerationKey {
|
||||||
|
ak: ak.clone(),
|
||||||
|
rsk: rsk.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let viewing_key = proof_generation_key.into_viewing_key(params);
|
||||||
|
|
||||||
|
let payment_address;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let diversifier = ::primitives::Diversifier(rng.gen());
|
||||||
|
|
||||||
|
if let Some(p) = viewing_key.into_payment_address(
|
||||||
|
diversifier,
|
||||||
|
params
|
||||||
|
)
|
||||||
|
{
|
||||||
|
payment_address = p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let g_d = payment_address.diversifier.g_d(params).unwrap();
|
||||||
|
let commitment_randomness: fs::Fs = rng.gen();
|
||||||
let auth_path = vec![Some((rng.gen(), rng.gen())); tree_depth];
|
let auth_path = vec![Some((rng.gen(), rng.gen())); tree_depth];
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -510,7 +533,7 @@ fn test_input_circuit_with_bls12_381() {
|
|||||||
value_randomness: Some(value_randomness),
|
value_randomness: Some(value_randomness),
|
||||||
rsk: Some(rsk),
|
rsk: Some(rsk),
|
||||||
ak: Some(ak),
|
ak: Some(ak),
|
||||||
g_d: Some(g_d),
|
g_d: Some(g_d.clone()),
|
||||||
commitment_randomness: Some(commitment_randomness),
|
commitment_randomness: Some(commitment_randomness),
|
||||||
auth_path: auth_path.clone()
|
auth_path: auth_path.clone()
|
||||||
};
|
};
|
||||||
@@ -535,9 +558,54 @@ fn test_input_circuit_with_bls12_381() {
|
|||||||
assert_eq!(cs.get_input(1, "value commitment/x/input variable"), expected_value_cm_xy.0);
|
assert_eq!(cs.get_input(1, "value commitment/x/input variable"), expected_value_cm_xy.0);
|
||||||
assert_eq!(cs.get_input(2, "value commitment/y/input variable"), expected_value_cm_xy.1);
|
assert_eq!(cs.get_input(2, "value commitment/y/input variable"), expected_value_cm_xy.1);
|
||||||
|
|
||||||
cs.get_input(3, "anchor/input variable");
|
let note = ::primitives::Note {
|
||||||
cs.get_input(4, "nullifier/x/input variable");
|
value: value,
|
||||||
cs.get_input(5, "nullifier/y/input variable");
|
g_d: g_d.clone(),
|
||||||
|
pk_d: payment_address.pk_d.clone(),
|
||||||
|
r: commitment_randomness.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut position = 0u64;
|
||||||
|
let mut cur = note.cm(params);
|
||||||
|
|
||||||
|
assert_eq!(cs.get("randomization of note commitment/x3/num"), cur);
|
||||||
|
|
||||||
|
for (i, val) in auth_path.into_iter().enumerate()
|
||||||
|
{
|
||||||
|
let (uncle, b) = val.unwrap();
|
||||||
|
|
||||||
|
let mut lhs = cur;
|
||||||
|
let mut rhs = uncle;
|
||||||
|
|
||||||
|
if b {
|
||||||
|
::std::mem::swap(&mut lhs, &mut rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut lhs: Vec<bool> = BitIterator::new(lhs.into_repr()).collect();
|
||||||
|
let mut rhs: Vec<bool> = BitIterator::new(rhs.into_repr()).collect();
|
||||||
|
|
||||||
|
lhs.reverse();
|
||||||
|
rhs.reverse();
|
||||||
|
|
||||||
|
cur = ::pedersen_hash::pedersen_hash::<Bls12, _>(
|
||||||
|
::pedersen_hash::Personalization::MerkleTree(i),
|
||||||
|
lhs.into_iter()
|
||||||
|
.take(Fr::NUM_BITS as usize)
|
||||||
|
.chain(rhs.into_iter().take(Fr::NUM_BITS as usize)),
|
||||||
|
params
|
||||||
|
).into_xy().0;
|
||||||
|
|
||||||
|
if b {
|
||||||
|
position |= 1 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let expected_nf = note.nf(&viewing_key, position, params);
|
||||||
|
let expected_nf_xy = expected_nf.into_xy();
|
||||||
|
|
||||||
|
assert_eq!(cs.get_input(3, "anchor/input variable"), cur);
|
||||||
|
assert_eq!(cs.get_input(4, "nullifier/x/input variable"), expected_nf_xy.0);
|
||||||
|
assert_eq!(cs.get_input(5, "nullifier/y/input variable"), expected_nf_xy.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ const PRF_NR_PERSONALIZATION: &'static [u8; 8] = b"WhatTheH";
|
|||||||
// Group hash personalizations
|
// Group hash personalizations
|
||||||
/// BLAKE2s Personalization for Pedersen hash generators.
|
/// BLAKE2s Personalization for Pedersen hash generators.
|
||||||
const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8] = b"PEDERSEN";
|
const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8] = b"PEDERSEN";
|
||||||
|
/// BLAKE2s Personalization for the group hash for key diversification
|
||||||
|
const KEY_DIVERSIFICATION_PERSONALIZATION: &'static [u8; 8] = b"Zcash_gh";
|
||||||
/// BLAKE2s Personalization for the proof generation key base point
|
/// BLAKE2s Personalization for the proof generation key base point
|
||||||
const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"12345678";
|
const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"12345678";
|
||||||
/// BLAKE2s Personalization for the note commitment randomness generator
|
/// BLAKE2s Personalization for the note commitment randomness generator
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
use pairing::{
|
||||||
|
PrimeField,
|
||||||
|
PrimeFieldRepr
|
||||||
|
};
|
||||||
|
|
||||||
|
use group_hash::group_hash;
|
||||||
|
|
||||||
use pedersen_hash::{
|
use pedersen_hash::{
|
||||||
pedersen_hash,
|
pedersen_hash,
|
||||||
Personalization
|
Personalization
|
||||||
@@ -16,6 +23,83 @@ use jubjub::{
|
|||||||
FixedGenerators
|
FixedGenerators
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use blake2_rfc::blake2s::Blake2s;
|
||||||
|
|
||||||
|
pub struct ProofGenerationKey<E: JubjubEngine> {
|
||||||
|
pub ak: edwards::Point<E, PrimeOrder>,
|
||||||
|
pub rsk: E::Fs
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: JubjubEngine> ProofGenerationKey<E> {
|
||||||
|
pub fn into_viewing_key(&self, params: &E::Params) -> ViewingKey<E> {
|
||||||
|
ViewingKey {
|
||||||
|
ak: self.ak.clone(),
|
||||||
|
rk: params.generator(FixedGenerators::ProofGenerationKey)
|
||||||
|
.mul(self.rsk, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ViewingKey<E: JubjubEngine> {
|
||||||
|
pub ak: edwards::Point<E, PrimeOrder>,
|
||||||
|
pub rk: edwards::Point<E, PrimeOrder>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: JubjubEngine> ViewingKey<E> {
|
||||||
|
fn ivk(&self) -> E::Fs {
|
||||||
|
let mut preimage = [0; 64];
|
||||||
|
|
||||||
|
self.ak.write(&mut preimage[0..32]).unwrap();
|
||||||
|
self.rk.write(&mut preimage[32..64]).unwrap();
|
||||||
|
|
||||||
|
let mut h = Blake2s::with_params(32, &[], &[], ::CRH_IVK_PERSONALIZATION);
|
||||||
|
h.update(&preimage);
|
||||||
|
let mut h = h.finalize().as_ref().to_vec();
|
||||||
|
|
||||||
|
// Drop the first five bits, so it can be interpreted as a scalar.
|
||||||
|
h[0] &= 0b0000_0111;
|
||||||
|
|
||||||
|
let mut e = <E::Fs as PrimeField>::Repr::default();
|
||||||
|
e.read_be(&h[..]).unwrap();
|
||||||
|
|
||||||
|
E::Fs::from_repr(e).expect("should be a valid scalar")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_payment_address(
|
||||||
|
&self,
|
||||||
|
diversifier: Diversifier,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
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, ::KEY_DIVERSIFICATION_PERSONALIZATION, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PaymentAddress<E: JubjubEngine> {
|
||||||
|
pub pk_d: edwards::Point<E, PrimeOrder>,
|
||||||
|
pub diversifier: Diversifier
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Note<E: JubjubEngine> {
|
pub struct Note<E: JubjubEngine> {
|
||||||
/// The value of the note
|
/// The value of the note
|
||||||
pub value: u64,
|
pub value: u64,
|
||||||
@@ -28,8 +112,8 @@ pub struct Note<E: JubjubEngine> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<E: JubjubEngine> Note<E> {
|
impl<E: JubjubEngine> Note<E> {
|
||||||
/// Computes the note commitment
|
/// Computes the note commitment, returning the full point.
|
||||||
pub fn cm(&self, params: &E::Params) -> E::Fr
|
fn cm_full_point(&self, params: &E::Params) -> edwards::Point<E, PrimeOrder>
|
||||||
{
|
{
|
||||||
// Calculate the note contents, as bytes
|
// Calculate the note contents, as bytes
|
||||||
let mut note_contents = vec![];
|
let mut note_contents = vec![];
|
||||||
@@ -56,12 +140,53 @@ impl<E: JubjubEngine> Note<E> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Compute final commitment
|
// Compute final commitment
|
||||||
let cm = params.generator(FixedGenerators::NoteCommitmentRandomness)
|
params.generator(FixedGenerators::NoteCommitmentRandomness)
|
||||||
.mul(self.r, params)
|
.mul(self.r, params)
|
||||||
.add(&hash_of_contents, 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
|
||||||
|
) -> edwards::Point<E, PrimeOrder>
|
||||||
|
{
|
||||||
|
// Compute cm + position
|
||||||
|
let cm_plus_position = self
|
||||||
|
.cm_full_point(params)
|
||||||
|
.add(
|
||||||
|
¶ms.generator(FixedGenerators::NullifierPosition)
|
||||||
|
.mul(position, params),
|
||||||
|
params
|
||||||
|
);
|
||||||
|
|
||||||
|
// Compute nr = drop_5(BLAKE2s(rk | cm_plus_position))
|
||||||
|
let mut nr_preimage = [0u8; 64];
|
||||||
|
viewing_key.rk.write(&mut nr_preimage[0..32]).unwrap();
|
||||||
|
cm_plus_position.write(&mut nr_preimage[32..64]).unwrap();
|
||||||
|
let mut h = Blake2s::with_params(32, &[], &[], ::PRF_NR_PERSONALIZATION);
|
||||||
|
h.update(&nr_preimage);
|
||||||
|
let mut h = h.finalize().as_ref().to_vec();
|
||||||
|
|
||||||
|
// Drop the first five bits, so it can be interpreted as a scalar.
|
||||||
|
h[0] &= 0b0000_0111;
|
||||||
|
|
||||||
|
let mut e = <E::Fs as PrimeField>::Repr::default();
|
||||||
|
e.read_be(&h[..]).unwrap();
|
||||||
|
|
||||||
|
let nr = E::Fs::from_repr(e).expect("should be a valid scalar");
|
||||||
|
|
||||||
|
viewing_key.ak.mul(nr, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Computes the note commitment
|
||||||
|
pub fn cm(&self, params: &E::Params) -> E::Fr
|
||||||
|
{
|
||||||
// The commitment is in the prime order subgroup, so mapping the
|
// The commitment is in the prime order subgroup, so mapping the
|
||||||
// commitment to the x-coordinate is an injective encoding.
|
// commitment to the x-coordinate is an injective encoding.
|
||||||
cm.into_xy().0
|
self.cm_full_point(params).into_xy().0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user