Changes to names and circuit design to match spec.

This commit is contained in:
Sean Bowe 2018-03-16 10:31:14 -06:00
parent c09292672a
commit 7e05feb90b
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
2 changed files with 108 additions and 85 deletions

View File

@ -28,6 +28,7 @@ use super::ecc;
use super::pedersen_hash; use super::pedersen_hash;
use super::blake2s; use super::blake2s;
use super::num; use super::num;
use super::multipack;
/// This is an instance of the `Spend` circuit. /// This is an instance of the `Spend` circuit.
pub struct Spend<'a, E: JubjubEngine> { pub struct Spend<'a, E: JubjubEngine> {
@ -46,6 +47,9 @@ pub struct Spend<'a, E: JubjubEngine> {
/// The randomness of the note commitment /// The randomness of the note commitment
pub commitment_randomness: Option<E::Fs>, pub commitment_randomness: Option<E::Fs>,
/// Re-randomization of the public key
pub ar: Option<E::Fs>,
/// The authentication path of the commitment in the tree /// The authentication path of the commitment in the tree
pub auth_path: Vec<Option<(E::Fr, bool)>> pub auth_path: Vec<Option<(E::Fr, bool)>>
} }
@ -129,25 +133,25 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
self.params self.params
)?; )?;
// Compute rk = [rsk] ProvingPublicKey // Compute nk = [nsk] ProvingPublicKey
let rk; let nk;
{ {
// Witness rsk as bits // Witness nsk as bits
let rsk = boolean::field_into_boolean_vec_le( let nsk = boolean::field_into_boolean_vec_le(
cs.namespace(|| "rsk"), cs.namespace(|| "nsk"),
self.proof_generation_key.as_ref().map(|k| k.rsk.clone()) self.proof_generation_key.as_ref().map(|k| k.nsk.clone())
)?; )?;
// NB: We don't ensure that the bit representation of rsk // NB: We don't ensure that the bit representation of nsk
// is "in the field" (Fs) because it's not used except to // is "in the field" (Fs) because it's not used except to
// demonstrate the prover knows it. If they know a // demonstrate the prover knows it. If they know a
// congruency then that's equivalent. // congruency then that's equivalent.
// Compute rk = [rsk] ProvingPublicKey // Compute nk = [nsk] ProvingPublicKey
rk = ecc::fixed_base_multiplication( nk = ecc::fixed_base_multiplication(
cs.namespace(|| "computation of rk"), cs.namespace(|| "computation of nk"),
FixedGenerators::ProofGenerationKey, FixedGenerators::ProofGenerationKey,
&rsk, &nsk,
self.params self.params
)?; )?;
} }
@ -175,22 +179,46 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
ak.repr(cs.namespace(|| "representation of ak"))? ak.repr(cs.namespace(|| "representation of ak"))?
); );
// This is the nullifier randomness preimage for PRF^nr // Rerandomize ak and expose it as an input to the circuit
let mut nr_preimage = vec![];
// Extend vk and nr preimages with the representation of
// rk.
{ {
let repr_rk = rk.repr( let ar = boolean::field_into_boolean_vec_le(
cs.namespace(|| "representation of rk") cs.namespace(|| "ar"),
self.ar
)?; )?;
vk.extend(repr_rk.iter().cloned()); // Compute the randomness in the exponent
nr_preimage.extend(repr_rk); let ar = ecc::fixed_base_multiplication(
cs.namespace(|| "computation of randomization for the signing key"),
FixedGenerators::SpendingKeyGenerator,
&ar,
self.params
)?;
let rk = ak.add(
cs.namespace(|| "computation of rk"),
&ar,
self.params
)?;
rk.inputize(cs.namespace(|| "rk"))?;
}
// This is the nullifier preimage for PRF^nf
let mut nf_preimage = vec![];
// Extend vk and nr preimages with the representation of
// nk.
{
let repr_nk = nk.repr(
cs.namespace(|| "representation of nk")
)?;
vk.extend(repr_nk.iter().cloned());
nf_preimage.extend(repr_nk);
} }
assert_eq!(vk.len(), 512); assert_eq!(vk.len(), 512);
assert_eq!(nr_preimage.len(), 256); assert_eq!(nf_preimage.len(), 256);
// Compute the incoming viewing key ivk // Compute the incoming viewing key ivk
let mut ivk = blake2s::blake2s( let mut ivk = blake2s::blake2s(
@ -353,6 +381,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
// Compute the cm + g^position for preventing // Compute the cm + g^position for preventing
// faerie gold attacks // faerie gold attacks
let mut rho = cm;
{ {
// Compute the position in the exponent // Compute the position in the exponent
let position = ecc::fixed_base_multiplication( let position = ecc::fixed_base_multiplication(
@ -363,46 +392,28 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
)?; )?;
// Add the position to the commitment // Add the position to the commitment
cm = cm.add( rho = rho.add(
cs.namespace(|| "faerie gold prevention"), cs.namespace(|| "faerie gold prevention"),
&position, &position,
self.params self.params
)?; )?;
} }
// Let's compute nr = BLAKE2s(rk || cm + position) // Let's compute nf = BLAKE2s(rk || rho)
nr_preimage.extend( nf_preimage.extend(
cm.repr(cs.namespace(|| "representation of cm"))? rho.repr(cs.namespace(|| "representation of rho"))?
); );
assert_eq!(nr_preimage.len(), 512); assert_eq!(nf_preimage.len(), 512);
// Compute nr // Compute nf
let mut nr = blake2s::blake2s( let nf = blake2s::blake2s(
cs.namespace(|| "nr computation"), cs.namespace(|| "nf computation"),
&nr_preimage, &nf_preimage,
constants::PRF_NR_PERSONALIZATION constants::PRF_NR_PERSONALIZATION
)?; )?;
// Little endian bit order multipack::pack_into_inputs(cs.namespace(|| "pack nullifier"), &nf)
nr.reverse();
// We want the randomization in the field to
// simplify outside code.
// TODO: This isn't uniformly random.
nr.truncate(E::Fs::CAPACITY as usize);
// Compute nullifier
let nf = ak.mul(
cs.namespace(|| "computation of nf"),
&nr,
self.params
)?;
// Expose the nullifier publicly
nf.inputize(cs.namespace(|| "nullifier"))?;
Ok(())
} }
} }
@ -560,12 +571,12 @@ fn test_input_circuit_with_bls12_381() {
randomness: rng.gen() randomness: rng.gen()
}; };
let rsk: fs::Fs = rng.gen(); let nsk: fs::Fs = rng.gen();
let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params); let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params);
let proof_generation_key = ::primitives::ProofGenerationKey { let proof_generation_key = ::primitives::ProofGenerationKey {
ak: ak.clone(), ak: ak.clone(),
rsk: rsk.clone() nsk: nsk.clone()
}; };
let viewing_key = proof_generation_key.into_viewing_key(params); let viewing_key = proof_generation_key.into_viewing_key(params);
@ -588,6 +599,7 @@ fn test_input_circuit_with_bls12_381() {
let g_d = payment_address.diversifier.g_d(params).unwrap(); let g_d = payment_address.diversifier.g_d(params).unwrap();
let commitment_randomness: fs::Fs = rng.gen(); 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];
let ar: fs::Fs = rng.gen();
{ {
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Bls12>::new();
@ -598,22 +610,27 @@ fn test_input_circuit_with_bls12_381() {
proof_generation_key: Some(proof_generation_key.clone()), proof_generation_key: Some(proof_generation_key.clone()),
payment_address: Some(payment_address.clone()), payment_address: Some(payment_address.clone()),
commitment_randomness: Some(commitment_randomness), commitment_randomness: Some(commitment_randomness),
ar: Some(ar),
auth_path: auth_path.clone() auth_path: auth_path.clone()
}; };
instance.synthesize(&mut cs).unwrap(); instance.synthesize(&mut cs).unwrap();
assert!(cs.is_satisfied()); assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 101018); assert_eq!(cs.num_constraints(), 98776);
assert_eq!(cs.hash(), "eedcef5fd638e0168ae4d53ac58df66f0acdabea46749cc5f4b39459c8377804"); assert_eq!(cs.hash(), "c5c377cad6310a5caa74305b2fe72b53e27a9c1db110edd9c4af164e99c0db71");
let expected_value_cm = value_commitment.cm(params).into_xy(); let expected_value_cm = value_commitment.cm(params).into_xy();
assert_eq!(cs.num_inputs(), 6); assert_eq!(cs.num_inputs(), 8);
assert_eq!(cs.get_input(0, "ONE"), Fr::one()); assert_eq!(cs.get_input(0, "ONE"), Fr::one());
assert_eq!(cs.get_input(1, "value commitment/commitment point/x/input variable"), expected_value_cm.0); assert_eq!(cs.get_input(1, "value commitment/commitment point/x/input variable"), expected_value_cm.0);
assert_eq!(cs.get_input(2, "value commitment/commitment point/y/input variable"), expected_value_cm.1); assert_eq!(cs.get_input(2, "value commitment/commitment point/y/input variable"), expected_value_cm.1);
let rk = viewing_key.rk(ar, params).into_xy();
assert_eq!(cs.get_input(3, "rk/x/input variable"), rk.0);
assert_eq!(cs.get_input(4, "rk/y/input variable"), rk.1);
let note = ::primitives::Note { let note = ::primitives::Note {
value: value_commitment.value, value: value_commitment.value,
g_d: g_d.clone(), g_d: g_d.clone(),
@ -656,12 +673,15 @@ fn test_input_circuit_with_bls12_381() {
} }
} }
let expected_nf = note.nf(&viewing_key, position, params); assert_eq!(cs.get_input(5, "anchor/input variable"), cur);
let expected_nf_xy = expected_nf.into_xy();
assert_eq!(cs.get_input(3, "anchor/input variable"), cur); let expected_nf = note.nf(&viewing_key, position, params);
assert_eq!(cs.get_input(4, "nullifier/x/input variable"), expected_nf_xy.0); let expected_nf = multipack::bytes_to_bits(&expected_nf);
assert_eq!(cs.get_input(5, "nullifier/y/input variable"), expected_nf_xy.1); let expected_nf = multipack::compute_multipacking::<Bls12>(&expected_nf);
assert_eq!(expected_nf.len(), 2);
assert_eq!(cs.get_input(6, "pack nullifier/input 0"), expected_nf[0]);
assert_eq!(cs.get_input(7, "pack nullifier/input 1"), expected_nf[1]);
} }
} }
@ -681,12 +701,12 @@ fn test_output_circuit_with_bls12_381() {
randomness: rng.gen() randomness: rng.gen()
}; };
let rsk: fs::Fs = rng.gen(); let nsk: fs::Fs = rng.gen();
let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params); let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params);
let proof_generation_key = ::primitives::ProofGenerationKey { let proof_generation_key = ::primitives::ProofGenerationKey {
ak: ak.clone(), ak: ak.clone(),
rsk: rsk.clone() nsk: nsk.clone()
}; };
let viewing_key = proof_generation_key.into_viewing_key(params); let viewing_key = proof_generation_key.into_viewing_key(params);

View File

@ -53,30 +53,42 @@ impl<E: JubjubEngine> ValueCommitment<E> {
#[derive(Clone)] #[derive(Clone)]
pub struct ProofGenerationKey<E: JubjubEngine> { pub struct ProofGenerationKey<E: JubjubEngine> {
pub ak: edwards::Point<E, PrimeOrder>, pub ak: edwards::Point<E, PrimeOrder>,
pub rsk: E::Fs pub nsk: E::Fs
} }
impl<E: JubjubEngine> ProofGenerationKey<E> { impl<E: JubjubEngine> ProofGenerationKey<E> {
pub fn into_viewing_key(&self, params: &E::Params) -> ViewingKey<E> { pub fn into_viewing_key(&self, params: &E::Params) -> ViewingKey<E> {
ViewingKey { ViewingKey {
ak: self.ak.clone(), ak: self.ak.clone(),
rk: params.generator(FixedGenerators::ProofGenerationKey) nk: params.generator(FixedGenerators::ProofGenerationKey)
.mul(self.rsk, params) .mul(self.nsk, params)
} }
} }
} }
pub struct ViewingKey<E: JubjubEngine> { pub struct ViewingKey<E: JubjubEngine> {
pub ak: edwards::Point<E, PrimeOrder>, pub ak: edwards::Point<E, PrimeOrder>,
pub rk: edwards::Point<E, PrimeOrder> pub nk: edwards::Point<E, PrimeOrder>
} }
impl<E: JubjubEngine> ViewingKey<E> { impl<E: JubjubEngine> ViewingKey<E> {
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
)
}
fn ivk(&self) -> E::Fs { fn ivk(&self) -> E::Fs {
let mut preimage = [0; 64]; let mut preimage = [0; 64];
self.ak.write(&mut preimage[0..32]).unwrap(); self.ak.write(&mut preimage[0..32]).unwrap();
self.rk.write(&mut preimage[32..64]).unwrap(); self.nk.write(&mut preimage[32..64]).unwrap();
let mut h = Blake2s::with_params(32, &[], &[], constants::CRH_IVK_PERSONALIZATION); let mut h = Blake2s::with_params(32, &[], &[], constants::CRH_IVK_PERSONALIZATION);
h.update(&preimage); h.update(&preimage);
@ -215,10 +227,10 @@ impl<E: JubjubEngine> Note<E> {
viewing_key: &ViewingKey<E>, viewing_key: &ViewingKey<E>,
position: u64, position: u64,
params: &E::Params params: &E::Params
) -> edwards::Point<E, PrimeOrder> ) -> Vec<u8>
{ {
// Compute cm + position // Compute rho = cm + position.G
let cm_plus_position = self let rho = self
.cm_full_point(params) .cm_full_point(params)
.add( .add(
&params.generator(FixedGenerators::NullifierPosition) &params.generator(FixedGenerators::NullifierPosition)
@ -226,23 +238,14 @@ impl<E: JubjubEngine> Note<E> {
params params
); );
// Compute nr = drop_5(BLAKE2s(rk | cm_plus_position)) // Compute nf = BLAKE2s(nk | rho)
let mut nr_preimage = [0u8; 64]; let mut nf_preimage = [0u8; 64];
viewing_key.rk.write(&mut nr_preimage[0..32]).unwrap(); viewing_key.nk.write(&mut nf_preimage[0..32]).unwrap();
cm_plus_position.write(&mut nr_preimage[32..64]).unwrap(); rho.write(&mut nf_preimage[32..64]).unwrap();
let mut h = Blake2s::with_params(32, &[], &[], constants::PRF_NR_PERSONALIZATION); let mut h = Blake2s::with_params(32, &[], &[], constants::PRF_NR_PERSONALIZATION);
h.update(&nr_preimage); h.update(&nf_preimage);
let mut h = h.finalize().as_ref().to_vec();
// Drop the first five bits, so it can be interpreted as a scalar. h.finalize().as_ref().to_vec()
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 /// Computes the note commitment