Explorar o código

crypto: More type aliasing, and spend contract.

Left to do are merkle trees.
parazyd %!s(int64=4) %!d(string=hai) anos
pai
achega
40eb59e69f

+ 13 - 12
src/crypto/mint_proof.rs

@@ -4,7 +4,6 @@ use std::time::Instant;
 use halo2_gadgets::primitives;
 use halo2_gadgets::primitives::poseidon::{ConstantLength, P128Pow5T3};
 use log::debug;
-use pasta_curves as pasta;
 use pasta_curves::{
     arithmetic::{CurveAffine, FieldExt},
     group::Curve,
@@ -41,11 +40,11 @@ impl MintRevealedValues {
         let coords = public_key.to_affine().coordinates().unwrap();
         let messages = [
             [*coords.x(), *coords.y()],
-            [pasta::Fp::from_u64(value), token_id],
+            [DrkValue::from_u64(value), token_id],
             [serial, coin_blind],
         ];
 
-        let mut hash = pasta::Fp::zero();
+        let mut hash = DrkCoin::zero();
         for msg in messages.iter() {
             hash += primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(*msg);
         }
@@ -59,12 +58,12 @@ impl MintRevealedValues {
         }
     }
 
-    fn make_outputs(&self) -> [pasta::Fp; 5] {
+    fn make_outputs(&self) -> [DrkCircuitField; 5] {
         let value_coords = self.value_commit.to_affine().coordinates().unwrap();
         let token_coords = self.value_commit.to_affine().coordinates().unwrap();
 
         vec![
-            pasta::Fp::from_bytes(&self.coin).unwrap(),
+            DrkCircuitField::from_bytes(&self.coin).unwrap(),
             *value_coords.x(),
             *value_coords.y(),
             *token_coords.x(),
@@ -98,12 +97,12 @@ impl Decodable for MintRevealedValues {
 #[allow(clippy::too_many_arguments)]
 pub fn create_mint_proof(
     value: u64,
-    token_id: pasta::Fp,
-    value_blind: pasta::Fq,
-    token_blind: pasta::Fq,
-    serial: pasta::Fp,
-    coin_blind: pasta::Fp,
-    public_key: pasta::Ep,
+    token_id: DrkTokenId,
+    value_blind: DrkValueBlind,
+    token_blind: DrkValueBlind,
+    serial: DrkSerial,
+    coin_blind: DrkCoinBlind,
+    public_key: DrkPublicKey,
 ) -> Result<(Proof, MintRevealedValues)> {
     let revealed = MintRevealedValues::compute(
         value,
@@ -120,7 +119,7 @@ pub fn create_mint_proof(
     let c = MintContract {
         pub_x: Some(*coords.x()),
         pub_y: Some(*coords.y()),
-        value: Some(pasta::Fp::from_u64(value)),
+        value: Some(DrkValue::from_u64(value)),
         asset: Some(token_id),
         serial: Some(serial),
         coin_blind: Some(coin_blind),
@@ -129,6 +128,7 @@ pub fn create_mint_proof(
     };
 
     let start = Instant::now();
+    // TODO: Don't always build this
     let pk = ProvingKey::build(11, MintContract::default());
     debug!("Setup: [{:?}]", start.elapsed());
 
@@ -143,6 +143,7 @@ pub fn create_mint_proof(
 pub fn verify_mint_proof(proof: Proof, revealed: &MintRevealedValues) -> Result<()> {
     let public_inputs = revealed.make_outputs();
 
+    // TODO: Don't always build this
     let vk = VerifyingKey::build(11, MintContract::default());
     Ok(proof.verify(&vk, &public_inputs)?)
 }

+ 5 - 36
src/crypto/mod.rs

@@ -1,54 +1,23 @@
-pub mod coin;
 pub mod constants;
 pub mod diffie_hellman;
 //pub mod merkle;
 //pub mod merkle_node;
 pub mod mint_proof;
 pub mod note;
-pub mod nullifier;
 pub mod pasta_serial;
 pub mod proof;
 pub mod schnorr;
+pub mod spend_proof;
 pub mod types;
-//pub mod spend_proof;
 pub mod util;
 
-/*
-use bellman::groth16;
-use bls12_381::Bls12;
-
-use crate::error::Result;
-pub use mint_proof::{create_mint_proof, setup_mint_prover, verify_mint_proof, MintRevealedValues};
-pub use spend_proof::{
-    create_spend_proof, setup_spend_prover, verify_spend_proof, SpendRevealedValues,
-};
-
 #[derive(Clone)]
 pub struct OwnCoin {
-    pub coin: coin::Coin,
+    pub coin: types::DrkCoin,
     pub note: note::Note,
-    pub secret: jubjub::Fr,
-    pub witness: merkle::IncrementalWitness<merkle_node::MerkleNode>,
-    pub nullifier: nullifier::Nullifier,
+    pub secret: types::DrkSecretKey,
+    //pub witness: merkle::IncrementalWitness<merkle_node::MerkleNode>,
+    pub nullifier: types::DrkNullifier,
 }
 
 pub type OwnCoins = Vec<OwnCoin>;
-
-pub fn save_params(filename: &str, params: &groth16::Parameters<Bls12>) -> Result<()> {
-    let buffer = std::fs::File::create(filename)?;
-    params.write(buffer)?;
-    Ok(())
-}
-
-pub fn load_params(
-    filename: &str,
-) -> Result<(
-    groth16::Parameters<Bls12>,
-    groth16::PreparedVerifyingKey<Bls12>,
-)> {
-    let buffer = std::fs::File::open(filename)?;
-    let params = groth16::Parameters::<Bls12>::read(buffer, false)?;
-    let pvk = groth16::prepare_verifying_key(&params.vk);
-    Ok((params, pvk))
-}
-*/

+ 13 - 14
src/crypto/note.rs

@@ -1,14 +1,13 @@
 use std::io;
 
 use crypto_api_chachapoly::ChachaPolyIetf;
-use halo2_gadgets::ecc::FixedPoints;
-use pasta_curves as pasta;
 use pasta_curves::arithmetic::Field;
 use rand::rngs::OsRng;
 
 use super::{
-    constants::OrchardFixedBases,
     diffie_hellman::{kdf_sapling, sapling_ka_agree},
+    types::*,
+    util::mod_r_p,
 };
 use crate::error::{Error, Result};
 use crate::serial::{Decodable, Encodable, ReadExt, WriteExt};
@@ -23,11 +22,11 @@ pub const ENC_CIPHERTEXT_SIZE: usize = NOTE_PLAINTEXT_SIZE + AEAD_TAG_SIZE;
 
 #[derive(Clone)]
 pub struct Note {
-    pub serial: pasta::Fp,
+    pub serial: DrkSerial,
     pub value: u64,
-    pub token_id: pasta::Fp,
-    pub coin_blind: pasta::Fp,
-    pub valcom_blind: pasta::Fq,
+    pub token_id: DrkTokenId,
+    pub coin_blind: DrkCoinBlind,
+    pub valcom_blind: DrkValueBlind,
 }
 
 impl Encodable for Note {
@@ -55,10 +54,10 @@ impl Decodable for Note {
 }
 
 impl Note {
-    pub fn encrypt(&self, public: &pasta::Ep) -> Result<EncryptedNote> {
-        let ephem_secret = pasta::Fq::random(&mut OsRng);
-        let ephem_public = OrchardFixedBases::SpendAuthG.generator() * ephem_secret;
-        let shared_secret = sapling_ka_agree(&ephem_secret, public.into());
+    pub fn encrypt(&self, public: &DrkPublicKey) -> Result<EncryptedNote> {
+        let ephem_secret = DrkSecretKey::random(&mut OsRng);
+        let ephem_public = derive_publickey(ephem_secret);
+        let shared_secret = sapling_ka_agree(&mod_r_p(ephem_secret), public.into());
         let key = kdf_sapling(shared_secret, &ephem_public.into());
 
         let mut input = Vec::new();
@@ -81,7 +80,7 @@ impl Note {
 
 pub struct EncryptedNote {
     ciphertext: [u8; ENC_CIPHERTEXT_SIZE],
-    ephem_public: pasta::Ep,
+    ephem_public: DrkPublicKey,
 }
 
 impl Encodable for EncryptedNote {
@@ -106,8 +105,8 @@ impl Decodable for EncryptedNote {
 }
 
 impl EncryptedNote {
-    pub fn decrypt(&self, secret: &pasta::Fq) -> Result<Note> {
-        let shared_secret = sapling_ka_agree(secret, &self.ephem_public.into());
+    pub fn decrypt(&self, secret: &DrkSecretKey) -> Result<Note> {
+        let shared_secret = sapling_ka_agree(&mod_r_p(*secret), &self.ephem_public.into());
         let key = kdf_sapling(shared_secret, &self.ephem_public.into());
 
         let mut plaintext = [0; ENC_CIPHERTEXT_SIZE];

+ 0 - 31
src/crypto/nullifier.rs

@@ -1,31 +0,0 @@
-use std::io;
-
-use crate::{
-    serial::{Decodable, Encodable},
-    Result,
-};
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct Nullifier {
-    pub repr: [u8; 32],
-}
-
-impl Nullifier {
-    pub fn new(repr: [u8; 32]) -> Self {
-        Self { repr }
-    }
-}
-
-impl Encodable for Nullifier {
-    fn encode<S: io::Write>(&self, s: S) -> Result<usize> {
-        self.repr.encode(s)
-    }
-}
-
-impl Decodable for Nullifier {
-    fn decode<D: io::Read>(d: D) -> Result<Self> {
-        Ok(Self {
-            repr: Decodable::decode(d)?,
-        })
-    }
-}

+ 12 - 6
src/crypto/proof.rs

@@ -1,5 +1,5 @@
-use pasta_curves as pasta;
 use pasta_curves::vesta;
+// TODO: Alias vesta::Affine to something
 
 use halo2::{
     plonk,
@@ -8,6 +8,8 @@ use halo2::{
     transcript::{Blake2bRead, Blake2bWrite},
 };
 
+use super::types::*;
+
 #[derive(Debug)]
 pub struct VerifyingKey {
     pub params: commitment::Params<vesta::Affine>,
@@ -15,7 +17,7 @@ pub struct VerifyingKey {
 }
 
 impl VerifyingKey {
-    pub fn build(k: u32, c: impl Circuit<pasta::Fp>) -> Self {
+    pub fn build(k: u32, c: impl Circuit<DrkCircuitField>) -> Self {
         let params = commitment::Params::new(k);
         let vk = plonk::keygen_vk(&params, &c).unwrap();
         VerifyingKey { params, vk }
@@ -29,7 +31,7 @@ pub struct ProvingKey {
 }
 
 impl ProvingKey {
-    pub fn build(k: u32, c: impl Circuit<pasta::Fp>) -> Self {
+    pub fn build(k: u32, c: impl Circuit<DrkCircuitField>) -> Self {
         let params = commitment::Params::new(k);
         let vk = plonk::keygen_vk(&params, &c).unwrap();
         let pk = plonk::keygen_pk(&params, vk, &c).unwrap();
@@ -49,8 +51,8 @@ impl AsRef<[u8]> for Proof {
 impl Proof {
     pub fn create(
         pk: &ProvingKey,
-        circuits: &[impl Circuit<pasta::Fp>],
-        pubinputs: &[pasta::Fp],
+        circuits: &[impl Circuit<DrkCircuitField>],
+        pubinputs: &[DrkCircuitField],
     ) -> Result<Self, plonk::Error> {
         let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]);
 
@@ -65,7 +67,11 @@ impl Proof {
         Ok(Proof(transcript.finalize()))
     }
 
-    pub fn verify(&self, vk: &VerifyingKey, pubinputs: &[pasta::Fp]) -> Result<(), plonk::Error> {
+    pub fn verify(
+        &self,
+        vk: &VerifyingKey,
+        pubinputs: &[DrkCircuitField],
+    ) -> Result<(), plonk::Error> {
         let msm = vk.params.empty_msm();
         let mut transcript = Blake2bRead::init(&self.0[..]);
         let guard = plonk::verify_proof(&vk.params, &vk.vk, msm, &[&[pubinputs]], &mut transcript)?;

+ 10 - 11
src/crypto/schnorr.rs

@@ -1,45 +1,44 @@
 use std::io;
 
 use halo2_gadgets::ecc::FixedPoints;
-use pasta_curves as pasta;
 use pasta_curves::{arithmetic::Field, group::GroupEncoding};
 use rand::rngs::OsRng;
 
 use super::{
     constants::{OrchardFixedBases, DRK_SCHNORR_DOMAIN},
-    util::hash_to_scalar,
+    types::*,
+    util::{hash_to_scalar, mod_r_p},
 };
 use crate::error::Result;
 use crate::serial::{Decodable, Encodable};
 
-pub struct SecretKey(pub pasta::Fq);
+pub struct SecretKey(pub DrkSecretKey);
 
 impl SecretKey {
     pub fn random() -> Self {
-        Self(pasta::Fq::random(&mut OsRng))
+        Self(DrkSecretKey::random(&mut OsRng))
     }
 
     pub fn sign(&self, message: &[u8]) -> Signature {
-        let mask = pasta::Fq::random(&mut OsRng);
+        let mask = DrkValueBlind::random(&mut OsRng);
         let commit = OrchardFixedBases::SpendAuthG.generator() * mask;
 
         let challenge = hash_to_scalar(DRK_SCHNORR_DOMAIN, &commit.to_bytes(), message);
-        let response = mask + challenge * self.0;
+        let response = mask + challenge * mod_r_p(self.0);
 
         Signature { commit, response }
     }
 
     pub fn public_key(&self) -> PublicKey {
-        let public = OrchardFixedBases::SpendAuthG.generator() * self.0;
-        PublicKey(public)
+        PublicKey(derive_publickey(self.0))
     }
 }
 
-pub struct PublicKey(pub pasta::Ep);
+pub struct PublicKey(pub DrkPublicKey);
 
 pub struct Signature {
-    commit: pasta::Ep,
-    response: pasta::Fq,
+    commit: DrkValueCommit,
+    response: DrkValueBlind,
 }
 
 impl Encodable for Signature {

+ 113 - 225
src/crypto/spend_proof.rs

@@ -1,176 +1,96 @@
-use bellman::gadgets::multipack;
-use bellman::groth16;
-use blake2s_simd::Params as Blake2sParams;
-use bls12_381::Bls12;
-use ff::PrimeField;
-use group::{Curve, GroupEncoding};
-use rand::rngs::OsRng;
 use std::io;
 use std::time::Instant;
 
-use super::merkle_node::{merkle_hash, MerkleNode, SAPLING_COMMITMENT_TREE_DEPTH};
-use super::nullifier::Nullifier;
+use halo2_gadgets::{
+    primitives,
+    primitives::poseidon::{ConstantLength, P128Pow5T3},
+};
+use log::debug;
+use pasta_curves::{
+    arithmetic::{CurveAffine, FieldExt},
+    group::Curve,
+};
+
+use super::{
+    proof::{Proof, ProvingKey, VerifyingKey},
+    types::*,
+    util::{mod_r_p, pedersen_commitment_scalar, pedersen_commitment_u64},
+};
 use crate::circuit::spend_contract::SpendContract;
-use crate::error::Result;
 use crate::serial::{Decodable, Encodable};
+use crate::Result;
 
 pub struct SpendRevealedValues {
-    pub value_commit: jubjub::SubgroupPoint,
-    pub token_commit: jubjub::SubgroupPoint,
-    pub nullifier: Nullifier,
-    // This should not be here, we just have it for debugging
-    //coin: [u8; 32],
-    pub merkle_root: MerkleNode,
-    pub signature_public: jubjub::SubgroupPoint,
+    pub value_commit: DrkValueCommit,
+    pub token_commit: DrkValueCommit,
+    pub nullifier: DrkNullifier,
+    //pub merkle_root: MerkleNode,
+    pub signature_public: DrkPublicKey,
 }
 
 impl SpendRevealedValues {
     #[allow(clippy::too_many_arguments)]
     fn compute(
         value: u64,
-        token_id: jubjub::Fr,
-        randomness_value: &jubjub::Fr,
-        randomness_token: &jubjub::Fr,
-        serial: &jubjub::Fr,
-        randomness_coin: &jubjub::Fr,
-        secret: &jubjub::Fr,
-        merkle_path: &[(bls12_381::Scalar, bool)],
-        signature_secret: &jubjub::Fr,
+        token_id: DrkTokenId,
+        value_blind: DrkValueBlind,
+        token_blind: DrkValueBlind,
+        serial: DrkSerial,
+        coin_blind: DrkCoinBlind,
+        secret: DrkSecretKey,
+        merkle_path: Vec<DrkCoin>,
+        signature_secret: DrkSecretKey,
     ) -> Self {
-        let value_commit = (zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR
-            * jubjub::Fr::from(value))
-            + (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR
-                * randomness_value);
-
-        let token_commit = (zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR
-            * token_id)
-            + (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR
-                * randomness_token);
-
-        let mut nullifier = [0; 32];
-        nullifier.copy_from_slice(
-            Blake2sParams::new()
-                .hash_length(32)
-                .personal(zcash_primitives::constants::PRF_NF_PERSONALIZATION)
-                .to_state()
-                .update(&secret.to_bytes())
-                .update(&serial.to_bytes())
-                .finalize()
-                .as_bytes(),
-        );
-        let nullifier = Nullifier::new(nullifier);
-
-        let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
-        let signature_public =
-            zcash_primitives::constants::SPENDING_KEY_GENERATOR * signature_secret;
-
-        let mut coin = [0; 32];
-        coin.copy_from_slice(
-            Blake2sParams::new()
-                .hash_length(32)
-                .personal(zcash_primitives::constants::CRH_IVK_PERSONALIZATION)
-                .to_state()
-                .update(&public.to_bytes())
-                .update(&value.to_le_bytes())
-                .update(&token_id.to_bytes())
-                .update(&serial.to_bytes())
-                .update(&randomness_coin.to_bytes())
-                .finalize()
-                .as_bytes(),
-        );
+        let nullifier = [secret, serial];
+        let nullifier =
+            primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(nullifier);
+
+        let public_key = derive_publickey(secret);
+        let coords = public_key.to_affine().coordinates().unwrap();
+        let messages = [
+            [*coords.x(), *coords.y()],
+            [DrkValue::from_u64(value), token_id],
+            [serial, coin_blind],
+        ];
+
+        let mut coin = DrkCoin::zero();
+        for msg in messages.iter() {
+            coin += primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(*msg);
+        }
 
-        let merkle_root =
-            jubjub::ExtendedPoint::from(zcash_primitives::pedersen_hash::pedersen_hash(
-                zcash_primitives::pedersen_hash::Personalization::NoteCommitment,
-                multipack::bytes_to_bits_le(&coin),
-            ));
-        let affine = merkle_root.to_affine();
-        let mut merkle_root = affine.get_u();
+        // TODO: Merkle root
 
-        for (i, (right, is_right)) in merkle_path.iter().enumerate() {
-            if *is_right {
-                merkle_root = merkle_hash(i, &right.to_repr(), &merkle_root.to_repr());
-            } else {
-                merkle_root = merkle_hash(i, &merkle_root.to_repr(), &right.to_repr());
-            }
-        }
+        let value_commit = pedersen_commitment_u64(value, value_blind);
+        let token_commit = pedersen_commitment_scalar(mod_r_p(token_id), token_blind);
 
-        let merkle_root = MerkleNode::new(merkle_root.to_repr());
+        let signature_public = derive_publickey(signature_secret);
 
         SpendRevealedValues {
             value_commit,
             token_commit,
             nullifier,
-            merkle_root,
             signature_public,
         }
     }
 
-    fn make_outputs(&self) -> [bls12_381::Scalar; 9] {
-        let mut public_input = [bls12_381::Scalar::zero(); 9];
-
-        // CV
-        {
-            let result = jubjub::ExtendedPoint::from(self.value_commit);
-            let affine = result.to_affine();
-            //let (u, v) = (affine.get_u(), affine.get_v());
-            let u = affine.get_u();
-            let v = affine.get_v();
-            public_input[0] = u;
-            public_input[1] = v;
-        }
-
-        // CA
-        {
-            let result = jubjub::ExtendedPoint::from(self.token_commit);
-            let affine = result.to_affine();
-            //let (u, v) = (affine.get_u(), affine.get_v());
-            let u = affine.get_u();
-            let v = affine.get_v();
-            public_input[2] = u;
-            public_input[3] = v;
-        }
-
-        // NF
-        {
-            // Pack the hash as inputs for proof verification.
-            let hash = multipack::bytes_to_bits_le(&self.nullifier.repr);
-            let hash = multipack::compute_multipacking(&hash);
-
-            // There are 2 chunks for a blake hash
-            assert_eq!(hash.len(), 2);
-
-            public_input[4] = hash[0];
-            public_input[5] = hash[1];
-        }
-
-        // Not revealed. We leave this code here for debug
-        // Coin
-        /*{
-            // Pack the hash as inputs for proof verification.
-            let hash = multipack::bytes_to_bits_le(&self.coin);
-            let hash = multipack::compute_multipacking(&hash);
-
-            // There are 2 chunks for a blake hash
-            assert_eq!(hash.len(), 2);
-
-            public_input[4] = hash[0];
-            public_input[5] = hash[1];
-        }*/
-
-        public_input[6] = self.merkle_root.into();
-
-        {
-            let result = jubjub::ExtendedPoint::from(self.signature_public);
-            let affine = result.to_affine();
-            //let (u, v) = (affine.get_u(), affine.get_v());
-            let u = affine.get_u();
-            let v = affine.get_v();
-            public_input[7] = u;
-            public_input[8] = v;
-        }
-
-        public_input
+    fn make_outputs(&self) -> [DrkCircuitField; 8] {
+        let value_coords = self.value_commit.to_affine().coordinates().unwrap();
+        let token_coords = self.token_commit.to_affine().coordinates().unwrap();
+        let sig_coords = self.signature_public.to_affine().coordinates().unwrap();
+
+        // TODO: merkle
+        vec![
+            self.nullifier,
+            *value_coords.x(),
+            *value_coords.y(),
+            *token_coords.x(),
+            *token_coords.y(),
+            // merkleroot,
+            *sig_coords.x(),
+            *sig_coords.y(),
+        ]
+        .try_into()
+        .unwrap()
     }
 }
 
@@ -180,7 +100,7 @@ impl Encodable for SpendRevealedValues {
         len += self.value_commit.encode(&mut s)?;
         len += self.token_commit.encode(&mut s)?;
         len += self.nullifier.encode(&mut s)?;
-        len += self.merkle_root.encode(&mut s)?;
+        //len += self.merkle_root.encode(&mut s)?;
         len += self.signature_public.encode(s)?;
         Ok(len)
     }
@@ -192,99 +112,67 @@ impl Decodable for SpendRevealedValues {
             value_commit: Decodable::decode(&mut d)?,
             token_commit: Decodable::decode(&mut d)?,
             nullifier: Decodable::decode(&mut d)?,
-            merkle_root: Decodable::decode(&mut d)?,
+            //merkle_root: Decodable::decode(&mut d)?,
             signature_public: Decodable::decode(d)?,
         })
     }
 }
 
-pub fn setup_spend_prover() -> groth16::Parameters<Bls12> {
-    println!("Spend: Making random params...");
-    let start = Instant::now();
-    let params = {
-        let c = SpendContract {
-            value: None,
-            token_id: None,
-            randomness_value: None,
-            randomness_token: None,
-            serial: None,
-            randomness_coin: None,
-            secret: None,
-
-            branch: [None; SAPLING_COMMITMENT_TREE_DEPTH],
-            is_right: [None; SAPLING_COMMITMENT_TREE_DEPTH],
-
-            signature_secret: None,
-        };
-        groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
-    };
-    println!("Setup: [{:?}]", start.elapsed());
-    params
-}
-
 #[allow(clippy::too_many_arguments)]
 pub fn create_spend_proof(
-    params: &groth16::Parameters<Bls12>,
     value: u64,
-    token_id: jubjub::Fr,
-    randomness_value: jubjub::Fr,
-    randomness_token: jubjub::Fr,
-    serial: jubjub::Fr,
-    randomness_coin: jubjub::Fr,
-    secret: jubjub::Fr,
-    merkle_path: Vec<(bls12_381::Scalar, bool)>,
-    signature_secret: jubjub::Fr,
-) -> (groth16::Proof<Bls12>, SpendRevealedValues) {
-    assert_eq!(merkle_path.len(), SAPLING_COMMITMENT_TREE_DEPTH);
-    let mut branch: [_; SAPLING_COMMITMENT_TREE_DEPTH] = Default::default();
-    let mut is_right: [_; SAPLING_COMMITMENT_TREE_DEPTH] = Default::default();
-    for (i, (branch_i, is_right_i)) in merkle_path.iter().enumerate() {
-        branch[i] = Some(*branch_i);
-        is_right[i] = Some(*is_right_i);
-    }
+    token_id: DrkTokenId,
+    value_blind: DrkValueBlind,
+    token_blind: DrkValueBlind,
+    serial: DrkSerial,
+    coin_blind: DrkCoinBlind,
+    secret: DrkSecretKey,
+    merkle_path: Vec<DrkCoin>,
+    signature_secret: DrkSecretKey,
+) -> Result<(Proof, SpendRevealedValues)> {
+    let revealed = SpendRevealedValues::compute(
+        value,
+        token_id,
+        value_blind,
+        token_blind,
+        serial,
+        coin_blind,
+        secret,
+        merkle_path.clone(),
+        signature_secret,
+    );
+
     let c = SpendContract {
-        value: Some(value),
-        token_id: Some(token_id),
-        randomness_value: Some(randomness_value),
-        randomness_token: Some(randomness_token),
+        secret_key: Some(secret),
         serial: Some(serial),
-        randomness_coin: Some(randomness_coin),
-        secret: Some(secret),
-
-        branch,
-        is_right,
-
-        signature_secret: Some(signature_secret),
+        value: Some(DrkValue::from_u64(value)),
+        asset: Some(token_id),
+        coin_blind: Some(coin_blind),
+        value_blind: Some(value_blind),
+        asset_blind: Some(token_blind),
+        leaf: Some(pasta_curves::Fp::one()), // TODO:
+        leaf_pos: Some(0),                   // TODO:
+        merkle_path: Some(merkle_path.try_into().unwrap()),
+        sig_secret: Some(mod_r_p(signature_secret)),
     };
 
     let start = Instant::now();
-    let proof = groth16::create_random_proof(c, params, &mut OsRng).unwrap();
-    println!("Prove: [{:?}]", start.elapsed());
+    // TODO: Don't always build this
+    let pk = ProvingKey::build(11, SpendContract::default());
+    debug!("Setup: [{:?}]", start.elapsed());
 
-    let revealed = SpendRevealedValues::compute(
-        value,
-        token_id,
-        &randomness_value,
-        &randomness_token,
-        &serial,
-        &randomness_coin,
-        &secret,
-        &merkle_path,
-        &signature_secret,
-    );
+    let start = Instant::now();
+    let public_inputs = revealed.make_outputs();
+    let proof = Proof::create(&pk, &[c], &public_inputs)?;
+    debug!("Prove: [{:?}]", start.elapsed());
 
-    (proof, revealed)
+    Ok((proof, revealed))
 }
 
-pub fn verify_spend_proof(
-    pvk: &groth16::PreparedVerifyingKey<Bls12>,
-    proof: &groth16::Proof<Bls12>,
-    revealed: &SpendRevealedValues,
-) -> bool {
-    let public_input = revealed.make_outputs();
+pub fn verify_spend_proof(proof: Proof, revealed: &SpendRevealedValues) -> Result<()> {
+    let public_inputs = revealed.make_outputs();
 
-    let start = Instant::now();
-    let result = groth16::verify_proof(pvk, proof, &public_input).is_ok();
-    println!("Verify: [{:?}]", start.elapsed());
-    result
+    // TODO: Don't always build this
+    let vk = VerifyingKey::build(11, SpendContract::default());
+    Ok(proof.verify(&vk, &public_inputs)?)
 }

+ 9 - 2
src/crypto/types.rs

@@ -5,10 +5,18 @@ use pasta_curves as pasta;
 
 use super::{constants::OrchardFixedBases, util::mod_r_p};
 
+pub type DrkCircuitField = pasta::Fp;
+
 pub type DrkTokenId = pasta::Fp;
 pub type DrkSerial = pasta::Fp;
+
+pub type DrkCoin = pasta::Fp;
 pub type DrkCoinBlind = pasta::Fp;
 
+pub type DrkNullifier = pasta::Fp;
+
+pub type DrkValue = pasta::Fp;
+pub type DrkScalar = pasta::Fq;
 pub type DrkValueBlind = pasta::Fq;
 pub type DrkValueCommit = pasta::Ep;
 
@@ -16,6 +24,5 @@ pub type DrkPublicKey = pasta::Ep;
 pub type DrkSecretKey = pasta::Fp;
 
 pub fn derive_publickey(s: DrkSecretKey) -> DrkPublicKey {
-    let skrt = mod_r_p(s);
-    OrchardFixedBases::SpendAuthG.generator() * skrt
+    OrchardFixedBases::SpendAuthG.generator() * mod_r_p(s)
 }

+ 18 - 11
src/crypto/util.rs

@@ -1,35 +1,42 @@
 use blake2b_simd::Params;
-use pasta_curves as pasta;
 use pasta_curves::{
     arithmetic::{CurveExt, FieldExt},
     group::ff::PrimeField,
+    pallas,
 };
 
-use super::constants::fixed_bases::{
-    VALUE_COMMITMENT_PERSONALIZATION, VALUE_COMMITMENT_R_BYTES, VALUE_COMMITMENT_V_BYTES,
+use super::{
+    constants::fixed_bases::{
+        VALUE_COMMITMENT_PERSONALIZATION, VALUE_COMMITMENT_R_BYTES, VALUE_COMMITMENT_V_BYTES,
+    },
+    types::*,
 };
 
-pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> pasta::Fq {
+pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> DrkScalar {
     let mut hasher = Params::new().hash_length(64).personal(persona).to_state();
     hasher.update(a);
     hasher.update(b);
     let ret = hasher.finalize();
-    pasta::Fq::from_bytes_wide(ret.as_array())
+    DrkScalar::from_bytes_wide(ret.as_array())
 }
 
 #[allow(non_snake_case)]
-pub fn pedersen_commitment_scalar(value: pasta::Fq, blind: pasta::Fq) -> pasta::Ep {
-    let hasher = pasta::Ep::hash_to_curve(VALUE_COMMITMENT_PERSONALIZATION);
+pub fn pedersen_commitment_scalar(value: DrkScalar, blind: DrkValueBlind) -> DrkValueCommit {
+    let hasher = DrkValueCommit::hash_to_curve(VALUE_COMMITMENT_PERSONALIZATION);
     let V = hasher(&VALUE_COMMITMENT_V_BYTES);
     let R = hasher(&VALUE_COMMITMENT_R_BYTES);
 
     V * value + R * blind
 }
 
-pub fn pedersen_commitment_u64(value: u64, blind: pasta::Fq) -> pasta::Ep {
-    pedersen_commitment_scalar(pasta::Fq::from_u64(value), blind)
+pub fn pedersen_commitment_u64(value: u64, blind: DrkValueBlind) -> DrkValueCommit {
+    pedersen_commitment_scalar(mod_r_p(DrkValue::from_u64(value)), blind)
 }
 
-pub fn mod_r_p(x: pasta::Fp) -> pasta::Fq {
-    pasta::Fq::from_repr(x.to_repr()).unwrap()
+/// Converts from pallas::Base to pallas::Scalar (aka $x \pmod{r_\mathbb{P}}$).
+///
+/// This requires no modular reduction because Pallas' base field is smaller than its
+/// scalar field.
+pub fn mod_r_p(x: pallas::Base) -> pallas::Scalar {
+    pallas::Scalar::from_repr(x.to_repr()).unwrap()
 }