Remaining tests for input circuit

This commit is contained in:
Sean Bowe 2018-03-07 23:59:04 -07:00
parent b998190f9e
commit 25a8050df8
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
3 changed files with 212 additions and 17 deletions

View File

@ -22,7 +22,6 @@ use bellman::{
use jubjub::{
JubjubEngine,
Unknown,
PrimeOrder,
FixedGenerators,
edwards
@ -55,9 +54,9 @@ pub struct Spend<'a, E: JubjubEngine> {
/// The public key that will be re-randomized for
/// use as a nullifier and signing key for the
/// transaction.
pub ak: Option<edwards::Point<E, Unknown>>,
pub ak: Option<edwards::Point<E, PrimeOrder>>,
/// 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
pub commitment_randomness: Option<E::Fs>,
/// The authentication path of the commitment in the tree
@ -482,7 +481,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
#[test]
fn test_input_circuit_with_bls12_381() {
use pairing::{Field};
use pairing::{Field, BitIterator};
use pairing::bls12_381::*;
use rand::{SeedableRng, Rng, XorShiftRng};
use ::circuit::test::*;
@ -495,10 +494,34 @@ fn test_input_circuit_with_bls12_381() {
let value: u64 = 1;
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 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];
{
@ -510,7 +533,7 @@ fn test_input_circuit_with_bls12_381() {
value_randomness: Some(value_randomness),
rsk: Some(rsk),
ak: Some(ak),
g_d: Some(g_d),
g_d: Some(g_d.clone()),
commitment_randomness: Some(commitment_randomness),
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(2, "value commitment/y/input variable"), expected_value_cm_xy.1);
cs.get_input(3, "anchor/input variable");
cs.get_input(4, "nullifier/x/input variable");
cs.get_input(5, "nullifier/y/input variable");
let note = ::primitives::Note {
value: value,
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);
}
}

View File

@ -25,6 +25,8 @@ const PRF_NR_PERSONALIZATION: &'static [u8; 8] = b"WhatTheH";
// Group hash personalizations
/// BLAKE2s Personalization for Pedersen hash generators.
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
const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"12345678";
/// BLAKE2s Personalization for the note commitment randomness generator

View File

@ -1,3 +1,10 @@
use pairing::{
PrimeField,
PrimeFieldRepr
};
use group_hash::group_hash;
use pedersen_hash::{
pedersen_hash,
Personalization
@ -16,6 +23,83 @@ use jubjub::{
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> {
/// The value of the note
pub value: u64,
@ -28,8 +112,8 @@ pub struct Note<E: JubjubEngine> {
}
impl<E: JubjubEngine> Note<E> {
/// Computes the note commitment
pub fn cm(&self, params: &E::Params) -> E::Fr
/// Computes the note commitment, returning the full point.
fn cm_full_point(&self, params: &E::Params) -> edwards::Point<E, PrimeOrder>
{
// Calculate the note contents, as bytes
let mut note_contents = vec![];
@ -56,12 +140,53 @@ impl<E: JubjubEngine> Note<E> {
);
// Compute final commitment
let cm = 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
) -> edwards::Point<E, PrimeOrder>
{
// Compute cm + position
let cm_plus_position = self
.cm_full_point(params)
.add(
&params.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
// commitment to the x-coordinate is an injective encoding.
cm.into_xy().0
self.cm_full_point(params).into_xy().0
}
}