Remaining tests for input circuit
This commit is contained in:
parent
b998190f9e
commit
25a8050df8
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
¶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
|
||||
// commitment to the x-coordinate is an injective encoding.
|
||||
cm.into_xy().0
|
||||
self.cm_full_point(params).into_xy().0
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue