Просмотр исходного кода

Move mint and burn Rust examples into proof/ to complement zkas code.

parazyd 4 лет назад
Родитель
Сommit
f8ab5ef5e3
11 измененных файлов с 281 добавлено и 341 удалено
  1. 10 5
      Cargo.toml
  2. 2 1
      Makefile
  3. 2 2
      bin/cashierd/src/main.rs
  4. 2 2
      bin/darkfid/src/main.rs
  5. 9 72
      book/src/zkas/examples/sapling.md
  6. 4 4
      example/tx.rs
  7. 0 248
      example/vm.rs
  8. 146 0
      proof/burn.rs
  9. 99 0
      proof/mint.rs
  10. 5 5
      src/crypto/proof.rs
  11. 2 2
      src/node/client.rs

+ 10 - 5
Cargo.toml

@@ -239,11 +239,6 @@ name = "tui"
 path = "example/tui_ex.rs"
 required-features = ["async-runtime", "tui"]
 
-[[example]]
-name = "vm"
-path = "example/vm.rs"
-required-features = ["cli", "zkvm"]
-
 [[example]]
 name = "tx"
 path = "example/tx.rs"
@@ -253,3 +248,13 @@ required-features = ["node"]
 name = "tree"
 path = "example/tree.rs"
 required-features = ["crypto"]
+
+[[example]]
+name = "mint"
+path = "proof/mint.rs"
+required-features = ["cli", "zkvm"]
+
+[[example]]
+name = "burn"
+path = "proof/burn.rs"
+required-features = ["cli", "zkvm"]

+ 2 - 1
Makefile

@@ -41,8 +41,9 @@ test-tx:
 
 test-vm: zkas
 	./zkas proof/mint.zk
+	$(CARGO) run --release --features=cli,zkvm --example mint
 	./zkas proof/burn.zk
-	$(CARGO) run --release --features=cli,zkvm --example vm
+	$(CARGO) run --release --features=cli,zkvm --example burn
 
 clean:
 	rm -f $(BINS)

+ 2 - 2
bin/cashierd/src/main.rs

@@ -609,9 +609,9 @@ async fn start(
     let rocks = Rocks::new(expand_path(&config.database_path.clone())?.as_path())?;
 
     info!("Building verifying key for the mint contract...");
-    let mint_vk = VerifyingKey::build(11, MintContract::default());
+    let mint_vk = VerifyingKey::build(11, &MintContract::default());
     info!("Building verifying key for the spend contract...");
-    let spend_vk = VerifyingKey::build(11, SpendContract::default());
+    let spend_vk = VerifyingKey::build(11, &SpendContract::default());
 
     // new Client
     let gateway_urls =

+ 2 - 2
bin/darkfid/src/main.rs

@@ -775,9 +775,9 @@ async fn start(
     let nullifiers = RocksColumn::<columns::Nullifiers>::new(rocks);
 
     info!("Building verifying key for the mint contract...");
-    let mint_vk = VerifyingKey::build(11, MintContract::default());
+    let mint_vk = VerifyingKey::build(11, &MintContract::default());
     info!("Building verifying key for the spend contract...");
-    let spend_vk = VerifyingKey::build(11, SpendContract::default());
+    let spend_vk = VerifyingKey::build(11, &SpendContract::default());
 
     let state = Arc::new(Mutex::new(State {
         tree,

+ 9 - 72
book/src/zkas/examples/sapling.md

@@ -35,10 +35,10 @@ In other words, the vector of public inputs could look like this:
 ```
 let public_inputs = vec![
     coin,
-    *value_coords.x();
-    *value_coords.y();
-    *token_coords.x();
-    *token_coords.y();
+    *value_coords.x(),
+    *value_coords.y(),
+    *token_coords.x(),
+    *token_coords.y(),
 ];
 ```
 
@@ -87,33 +87,7 @@ Knowing this we can extend our pseudo-code and build the
 before-mentioned public inputs for the circuit:
 
 ```rust
-let public_key = pallas::Point::random(&mut OsRng);
-let coords = public_key.to_affine().coordinates().unwrap();
-let pub_x = *coords.x();
-let pub_y = *coords.y();
-
-let value = pallas::Base::from(42);
-let token = pallas::Base::from(1);
-let serial = pallas::Base::random(&mut OsRng);
-let coin_blind = pallas::Base::random(&mut OsRng);
-
-let coin = poseidon::Hash(pub_x, pub_y, value, token, serial, coin_blind);
-
-let value_blind = pallas::Scalar::random(&mut OsRng);
-let value_commit = pedersen_commitment(value, value_blind);
-let value_coords = value_commit.to_affine().coordinates().unwrap();
-
-let token_blind = pallas::Scalar::random(&mut OsRng);
-let token_commit = pedersen_commitment(token, token_blind);
-let token_coords = token_commit.to_affine().coordinates().unwrap();
-
-let public_inputs = vec![
-    coin,
-    *value_coords.x(),
-    *value_coords.y(),
-    *token_coords.x(),
-    *token_coords.y(),
-];
+{{#include ../../../../proof/mint.rs}}
 ```
 
 
@@ -134,13 +108,13 @@ In this case, our vector of public inputs could look like:
 ```
 let public_inputs = vec![
     nullifier,
-    merkle_root,
     *value_coords.x(),
     *value_coords.y(),
     *token_coords.x(),
     *token_coords.y(),
-    *signature_coords.x(),
-    *signature_coords.y(),
+    merkle_root,
+    *sig_coords.x(),
+    *sig_coords.y(),
 ];
 ```
 
@@ -188,44 +162,7 @@ Knowing this we can extend our pseudo-code and build the
 before-mentioned public inputs for the circuit:
 
 ```rust
-let secret_key = pallas::Base::random(&mut OsRng);
-let serial = pallas::Base::random(&mut OsRng);
-
-let nullifier = poseidon::Hash(secret_key, serial);
-
-let tree = BridgeTree::<MerkleNode, 32>::new(100);
-tree.append(some_known_coin);
-tree.witness();
-tree.append(another_known_coin);
-tree.witness();
-
-let merkle_root = tree.root();
-
-let value = pallas::Base::from(42);
-let token = pallas::Base::from(1);
-
-let value_blind = pallas::Scalar::random(&mut OsRng);
-let value_commit = pedersen_commitment(value, value_blind);
-let value_coords = value_commit.to_affine().coordinates().unwrap();
-
-let token_blind = pallas::Scalar::random(&mut OsRng);
-let token_commit = pedersen_commitment(token, token_blind);
-let token_coords = token_commit.to_affine().coordinates().unwrap();
-
-let sig_secret = pallas::Base::random(&mut OsRng);
-let sig_public = NullifierK.generator() * mod_r_p(sig_secret);
-let signature_coords = sig_public.to_affine().coordinates().unwrap();
-
-let public_inputs = vec![
-    nullifier,
-    merkle_root,
-    *value_coords.x(),
-    *value_coords.y(),
-    *token_coords.x(),
-    *token_coords.y(),
-    *signature_coords.x(),
-    *signature_coords.y(),
-];
+{{#include ../../../../proof/mint.rs}}
 ```
 
 

+ 4 - 4
example/tx.rs

@@ -105,8 +105,8 @@ fn main() -> Result<()> {
     let keypair = Keypair::random(&mut OsRng);
 
     const K: u32 = 11;
-    let mint_vk = VerifyingKey::build(K, MintContract::default());
-    let spend_vk = VerifyingKey::build(K, SpendContract::default());
+    let mint_vk = VerifyingKey::build(K, &MintContract::default());
+    let spend_vk = VerifyingKey::build(K, &SpendContract::default());
 
     let mut state = MemoryState {
         tree: BridgeTree::<MerkleNode, 32>::new(100),
@@ -136,8 +136,8 @@ fn main() -> Result<()> {
         }],
     };
 
-    let mint_pk = ProvingKey::build(K, MintContract::default());
-    let spend_pk = ProvingKey::build(K, SpendContract::default());
+    let mint_pk = ProvingKey::build(K, &MintContract::default());
+    let spend_pk = ProvingKey::build(K, &SpendContract::default());
     let tx = builder.build(&mint_pk, &spend_pk)?;
 
     tx.verify(&state.mint_vk, &state.spend_vk).expect("tx verify");

+ 0 - 248
example/vm.rs

@@ -1,248 +0,0 @@
-use std::time::Instant;
-
-#[allow(unused_imports)]
-use halo2::{
-    arithmetic::{CurveAffine, Field},
-    dev::MockProver,
-};
-use halo2_gadgets::primitives::{
-    poseidon,
-    poseidon::{ConstantLength, P128Pow5T3},
-};
-use incrementalmerkletree::{bridgetree::BridgeTree, Frontier, Tree};
-use log::info;
-use pasta_curves::{group::Curve, pallas};
-use rand::rngs::OsRng;
-use simplelog::{ColorChoice, LevelFilter, TermLogger, TerminalMode};
-
-use darkfi::{
-    crypto::{
-        keypair::{PublicKey, SecretKey},
-        merkle_node::MerkleNode,
-        mint_proof::MintRevealedValues,
-        proof::{ProvingKey, VerifyingKey},
-        spend_proof::SpendRevealedValues,
-        Proof,
-    },
-    zk::vm::{Witness, ZkCircuit},
-    zkas::decoder::ZkBinary,
-    Result,
-};
-
-fn mint_proof() -> Result<()> {
-    let bincode = include_bytes!("../proof/mint.zk.bin");
-    let zkbin = ZkBinary::decode(bincode)?;
-
-    // ======
-    // Prover
-    // ======
-    let value = 42;
-    let token_id = pallas::Base::from(22);
-    let value_blind = pallas::Scalar::random(&mut OsRng);
-    let token_blind = pallas::Scalar::random(&mut OsRng);
-    let serial = pallas::Base::random(&mut OsRng);
-    let coin_blind = pallas::Base::random(&mut OsRng);
-    let public_key = PublicKey::random(&mut OsRng);
-    let pk_coords = public_key.0.to_affine().coordinates().unwrap();
-
-    let witnesses_prover = vec![
-        Witness::Base(Some(*pk_coords.x())),
-        Witness::Base(Some(*pk_coords.y())),
-        Witness::Base(Some(pallas::Base::from(value))),
-        Witness::Base(Some(token_id)),
-        Witness::Base(Some(serial)),
-        Witness::Base(Some(coin_blind)),
-        Witness::Scalar(Some(value_blind)),
-        Witness::Scalar(Some(token_blind)),
-    ];
-
-    let public_inputs = MintRevealedValues::compute(
-        value,
-        token_id,
-        value_blind,
-        token_blind,
-        serial,
-        coin_blind,
-        public_key,
-    )
-    .make_outputs()
-    .to_vec();
-
-    let circuit = ZkCircuit::new(witnesses_prover, zkbin.clone());
-
-    // let prover = MockProver::run(11, &circuit, vec![public_inputs.clone()]).unwrap();
-    // assert_eq!(prover.verify(), Ok(()));
-
-    let start = Instant::now();
-    let proving_key = ProvingKey::build(11, circuit.clone());
-    info!("Prover setup: [{:?}]", Instant::now() - start);
-
-    let start = Instant::now();
-    let proof = Proof::create(&proving_key, &[circuit], &public_inputs)?;
-    info!("Prover prove: [{:?}]", Instant::now() - start);
-
-    // =======
-    // Verifier
-    // =======
-
-    let witnesses_verifier = vec![
-        Witness::Base(None),
-        Witness::Base(None),
-        Witness::Base(None),
-        Witness::Base(None),
-        Witness::Base(None),
-        Witness::Base(None),
-        Witness::Scalar(None),
-        Witness::Scalar(None),
-    ];
-
-    let start = Instant::now();
-    let circuit = ZkCircuit::new(witnesses_verifier, zkbin);
-    let verifying_key = VerifyingKey::build(11, circuit);
-    info!("Verifier setup: [{:?}]", Instant::now() - start);
-
-    let start = Instant::now();
-    proof.verify(&verifying_key, &public_inputs)?;
-    info!("Verifier verify: [{:?}]", Instant::now() - start);
-
-    Ok(())
-}
-
-fn fill_tree(coin2: pallas::Base) -> BridgeTree<MerkleNode, 32> {
-    let mut tree = BridgeTree::<MerkleNode, 32>::new(100);
-    let coin0 = pallas::Base::random(&mut OsRng);
-    let coin1 = pallas::Base::random(&mut OsRng);
-    let coin3 = pallas::Base::random(&mut OsRng);
-
-    tree.append(&MerkleNode(coin0));
-    tree.witness();
-
-    tree.append(&MerkleNode(coin1));
-
-    tree.append(&MerkleNode(coin2));
-    tree.witness();
-
-    tree.append(&MerkleNode(coin3));
-    tree.witness();
-
-    tree
-}
-
-fn burn_proof() -> Result<()> {
-    let bincode = include_bytes!("../proof/burn.zk.bin");
-    let zkbin = ZkBinary::decode(bincode)?;
-
-    // ======
-    // Prover
-    // ======
-    let value = 42;
-    let token_id = pallas::Base::from(22);
-    let value_blind = pallas::Scalar::random(&mut OsRng);
-    let token_blind = pallas::Scalar::random(&mut OsRng);
-    let serial = pallas::Base::random(&mut OsRng);
-    let coin_blind = pallas::Base::random(&mut OsRng);
-    let secret = SecretKey::random(&mut OsRng);
-    let sig_secret = SecretKey::random(&mut OsRng);
-
-    let coin = {
-        let coords = PublicKey::from_secret(secret).0.to_affine().coordinates().unwrap();
-        let messages =
-            [*coords.x(), *coords.y(), pallas::Base::from(value), token_id, serial, coin_blind];
-
-        poseidon::Hash::init(P128Pow5T3, ConstantLength::<6>).hash(messages)
-    };
-
-    let tree = fill_tree(coin);
-    let (leaf_position, merkle_path) = tree.authentication_path(&MerkleNode(coin)).unwrap();
-
-    // Why are these types not matched in halo2 gadgets?
-    let leaf_pos: u64 = leaf_position.into();
-    let leaf_pos = leaf_pos as u32;
-
-    let witnesses_prover = vec![
-        Witness::Base(Some(secret.0)),
-        Witness::Base(Some(serial)),
-        Witness::Base(Some(pallas::Base::from(value))),
-        Witness::Base(Some(token_id)),
-        Witness::Base(Some(coin_blind)),
-        Witness::Scalar(Some(value_blind)),
-        Witness::Scalar(Some(token_blind)),
-        Witness::Uint32(Some(leaf_pos)),
-        Witness::MerklePath(Some(merkle_path.clone().try_into().unwrap())),
-        Witness::Base(Some(sig_secret.0)),
-    ];
-
-    let public_inputs = SpendRevealedValues::compute(
-        value,
-        token_id,
-        value_blind,
-        token_blind,
-        serial,
-        coin_blind,
-        secret,
-        leaf_position,
-        merkle_path,
-        sig_secret,
-    )
-    .make_outputs()
-    .to_vec();
-
-    let circuit = ZkCircuit::new(witnesses_prover, zkbin.clone());
-
-    // let prover = MockProver::run(11, &circuit, vec![public_inputs.clone()])?;
-    // assert_eq!(prover.verify(), Ok(()));
-
-    let start = Instant::now();
-    let proving_key = ProvingKey::build(11, circuit.clone());
-    info!("Prover setup: [{:?}]", Instant::now() - start);
-
-    let start = Instant::now();
-    let proof = Proof::create(&proving_key, &[circuit], &public_inputs)?;
-    info!("Prover prove: [{:?}]", Instant::now() - start);
-
-    // ========
-    // Verifier
-    // ========
-
-    let witnesses_verifier = vec![
-        Witness::Base(None),
-        Witness::Base(None),
-        Witness::Base(None),
-        Witness::Base(None),
-        Witness::Base(None),
-        Witness::Scalar(None),
-        Witness::Scalar(None),
-        Witness::Uint32(None),
-        Witness::MerklePath(None),
-        Witness::Base(None),
-    ];
-
-    let start = Instant::now();
-    let circuit = ZkCircuit::new(witnesses_verifier, zkbin);
-    let verifying_key = VerifyingKey::build(11, circuit);
-    info!("Verifier setup: [{:?}]", Instant::now() - start);
-
-    let start = Instant::now();
-    proof.verify(&verifying_key, &public_inputs)?;
-    info!("Verifier verify: [{:?}]", Instant::now() - start);
-
-    Ok(())
-}
-
-fn main() -> Result<()> {
-    TermLogger::init(
-        LevelFilter::Debug,
-        //LevelFilter::Info,
-        simplelog::Config::default(),
-        TerminalMode::Mixed,
-        ColorChoice::Auto,
-    )?;
-
-    info!("Executing Mint proof");
-    mint_proof()?;
-
-    info!("Executing Burn proof");
-    burn_proof()?;
-
-    Ok(())
-}

+ 146 - 0
proof/burn.rs

@@ -0,0 +1,146 @@
+use darkfi::{
+    crypto::{
+        keypair::{PublicKey, SecretKey},
+        merkle_node::MerkleNode,
+        proof::{ProvingKey, VerifyingKey},
+        util::{mod_r_p, pedersen_commitment_scalar, pedersen_commitment_u64},
+        Proof,
+    },
+    zk::vm::{Witness, ZkCircuit},
+    zkas::decoder::ZkBinary,
+    Result,
+};
+use halo2_gadgets::primitives::{
+    poseidon,
+    poseidon::{ConstantLength, P128Pow5T3},
+};
+use incrementalmerkletree::{bridgetree::BridgeTree, Frontier, Tree};
+use pasta_curves::{
+    arithmetic::{CurveAffine, Field},
+    group::Curve,
+    pallas,
+};
+use rand::rngs::OsRng;
+use simplelog::{ColorChoice::Auto, Config, LevelFilter::Debug, TermLogger, TerminalMode::Mixed};
+
+fn main() -> Result<()> {
+    TermLogger::init(Debug, Config::default(), Mixed, Auto)?;
+
+    let bincode = include_bytes!("burn.zk.bin");
+    let zkbin = ZkBinary::decode(bincode)?;
+
+    // ======
+    // Prover
+    // ======
+
+    // Witness values
+    let value = 42;
+    let token_id = pallas::Base::from(22);
+    let value_blind = pallas::Scalar::random(&mut OsRng);
+    let token_blind = pallas::Scalar::random(&mut OsRng);
+    let serial = pallas::Base::random(&mut OsRng);
+    let coin_blind = pallas::Base::random(&mut OsRng);
+    let secret = SecretKey::random(&mut OsRng);
+    let sig_secret = SecretKey::random(&mut OsRng);
+
+    // Build the coin
+    let coin2 = {
+        let coords = PublicKey::from_secret(secret).0.to_affine().coordinates().unwrap();
+        let messages =
+            [*coords.x(), *coords.y(), pallas::Base::from(value), token_id, serial, coin_blind];
+
+        poseidon::Hash::init(P128Pow5T3, ConstantLength::<6>).hash(messages)
+    };
+
+    // Fill the merkle tree with some random coins that we want to witness,
+    // and also add the above coin.
+    let mut tree = BridgeTree::<MerkleNode, 32>::new(100);
+    let coin0 = pallas::Base::random(&mut OsRng);
+    let coin1 = pallas::Base::random(&mut OsRng);
+    let coin3 = pallas::Base::random(&mut OsRng);
+
+    tree.append(&MerkleNode(coin0));
+    tree.witness();
+    tree.append(&MerkleNode(coin1));
+    tree.append(&MerkleNode(coin2));
+    tree.witness();
+    tree.append(&MerkleNode(coin3));
+    tree.witness();
+
+    let (leaf_pos, merkle_path) = tree.authentication_path(&MerkleNode(coin2)).unwrap();
+    let leaf_pos: u64 = leaf_pos.into();
+    let leaf_pos = leaf_pos as u32;
+
+    let prover_witnesses = vec![
+        Witness::Base(Some(secret.0)),
+        Witness::Base(Some(serial)),
+        Witness::Base(Some(pallas::Base::from(value))),
+        Witness::Base(Some(token_id)),
+        Witness::Base(Some(coin_blind)),
+        Witness::Scalar(Some(value_blind)),
+        Witness::Scalar(Some(token_blind)),
+        Witness::Uint32(Some(leaf_pos)),
+        Witness::MerklePath(Some(merkle_path.try_into().unwrap())),
+        Witness::Base(Some(sig_secret.0)),
+    ];
+
+    // Create the public inputs
+    let nullifier = [secret.0, serial];
+    let nullifier = poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(nullifier);
+
+    let value_commit = pedersen_commitment_u64(value, value_blind);
+    let value_coords = value_commit.to_affine().coordinates().unwrap();
+
+    let token_commit = pedersen_commitment_scalar(mod_r_p(token_id), token_blind);
+    let token_coords = token_commit.to_affine().coordinates().unwrap();
+
+    let sig_pubkey = PublicKey::from_secret(sig_secret);
+    let sig_coords = sig_pubkey.0.to_affine().coordinates().unwrap();
+
+    let merkle_root = tree.root();
+
+    let public_inputs = vec![
+        nullifier,
+        *value_coords.x(),
+        *value_coords.y(),
+        *token_coords.x(),
+        *token_coords.y(),
+        merkle_root.0,
+        *sig_coords.x(),
+        *sig_coords.y(),
+    ];
+
+    // Create the circuit
+    let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
+
+    // Build the proving key and create the zero-knowledge proof
+    let proving_key = ProvingKey::build(11, &circuit);
+    let proof = Proof::create(&proving_key, &[circuit], &public_inputs)?;
+
+    // ========
+    // Verifier
+    // ========
+
+    // Construct empty witnesses
+    let verifier_witnesses = vec![
+        Witness::Base(None),
+        Witness::Base(None),
+        Witness::Base(None),
+        Witness::Base(None),
+        Witness::Base(None),
+        Witness::Scalar(None),
+        Witness::Scalar(None),
+        Witness::Uint32(None),
+        Witness::MerklePath(None),
+        Witness::Base(None),
+    ];
+
+    // Create the circuit
+    let circuit = ZkCircuit::new(verifier_witnesses, zkbin);
+
+    // Build the verifying key and verify the zero-knowledge proof
+    let verifying_key = VerifyingKey::build(11, &circuit);
+    proof.verify(&verifying_key, &public_inputs)?;
+
+    Ok(())
+}

+ 99 - 0
proof/mint.rs

@@ -0,0 +1,99 @@
+use darkfi::{
+    crypto::{
+        keypair::PublicKey,
+        proof::{ProvingKey, VerifyingKey},
+        util::{mod_r_p, pedersen_commitment_scalar, pedersen_commitment_u64},
+        Proof,
+    },
+    zk::vm::{Witness, ZkCircuit},
+    zkas::decoder::ZkBinary,
+    Result,
+};
+use halo2_gadgets::primitives::{
+    poseidon,
+    poseidon::{ConstantLength, P128Pow5T3},
+};
+use pasta_curves::{
+    arithmetic::{CurveAffine, Field},
+    group::Curve,
+    pallas,
+};
+use rand::rngs::OsRng;
+use simplelog::{ColorChoice::Auto, Config, LevelFilter::Debug, TermLogger, TerminalMode::Mixed};
+
+fn main() -> Result<()> {
+    TermLogger::init(Debug, Config::default(), Mixed, Auto)?;
+
+    let bincode = include_bytes!("mint.zk.bin");
+    let zkbin = ZkBinary::decode(bincode)?;
+
+    // ======
+    // Prover
+    // ======
+
+    // Witness values
+    let value = 42;
+    let token_id = pallas::Base::from(22);
+    let value_blind = pallas::Scalar::random(&mut OsRng);
+    let token_blind = pallas::Scalar::random(&mut OsRng);
+    let serial = pallas::Base::random(&mut OsRng);
+    let coin_blind = pallas::Base::random(&mut OsRng);
+    let public_key = PublicKey::random(&mut OsRng);
+    let coords = public_key.0.to_affine().coordinates().unwrap();
+
+    let prover_witnesses = vec![
+        Witness::Base(Some(*coords.x())),
+        Witness::Base(Some(*coords.y())),
+        Witness::Base(Some(pallas::Base::from(value))),
+        Witness::Base(Some(token_id)),
+        Witness::Base(Some(serial)),
+        Witness::Base(Some(coin_blind)),
+        Witness::Scalar(Some(value_blind)),
+        Witness::Scalar(Some(token_blind)),
+    ];
+
+    // Create the public inputs
+    let msgs = [*coords.x(), *coords.y(), pallas::Base::from(value), token_id, serial, coin_blind];
+    let coin = poseidon::Hash::init(P128Pow5T3, ConstantLength::<6>).hash(msgs);
+
+    let value_commit = pedersen_commitment_u64(value, value_blind);
+    let value_coords = value_commit.to_affine().coordinates().unwrap();
+
+    let token_commit = pedersen_commitment_scalar(mod_r_p(token_id), token_blind);
+    let token_coords = token_commit.to_affine().coordinates().unwrap();
+
+    let public_inputs =
+        vec![coin, *value_coords.x(), *value_coords.y(), *token_coords.x(), *token_coords.y()];
+
+    // Create the circuit
+    let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
+
+    // Build the proving key and create the zero-knowledge proof
+    let proving_key = ProvingKey::build(11, &circuit);
+    let proof = Proof::create(&proving_key, &[circuit], &public_inputs)?;
+
+    // ========
+    // Verifier
+    // ========
+
+    // Construct empty witnesses
+    let verifier_witnesses = vec![
+        Witness::Base(None),
+        Witness::Base(None),
+        Witness::Base(None),
+        Witness::Base(None),
+        Witness::Base(None),
+        Witness::Base(None),
+        Witness::Scalar(None),
+        Witness::Scalar(None),
+    ];
+
+    // Create the circuit
+    let circuit = ZkCircuit::new(verifier_witnesses, zkbin);
+
+    // Build the verifying key and verify the zero-knowledge proof
+    let verifying_key = VerifyingKey::build(11, &circuit);
+    proof.verify(&verifying_key, &public_inputs)?;
+
+    Ok(())
+}

+ 5 - 5
src/crypto/proof.rs

@@ -22,9 +22,9 @@ pub struct VerifyingKey {
 }
 
 impl VerifyingKey {
-    pub fn build(k: u32, c: impl Circuit<DrkCircuitField>) -> Self {
+    pub fn build(k: u32, c: &impl Circuit<DrkCircuitField>) -> Self {
         let params = Params::new(k);
-        let vk = plonk::keygen_vk(&params, &c).unwrap();
+        let vk = plonk::keygen_vk(&params, c).unwrap();
         VerifyingKey { params, vk }
     }
 }
@@ -36,10 +36,10 @@ pub struct ProvingKey {
 }
 
 impl ProvingKey {
-    pub fn build(k: u32, c: impl Circuit<DrkCircuitField>) -> Self {
+    pub fn build(k: u32, c: &impl Circuit<DrkCircuitField>) -> Self {
         let params = Params::new(k);
-        let vk = plonk::keygen_vk(&params, &c).unwrap();
-        let pk = plonk::keygen_pk(&params, vk, &c).unwrap();
+        let vk = plonk::keygen_vk(&params, c).unwrap();
+        let pk = plonk::keygen_pk(&params, vk, c).unwrap();
         ProvingKey { params, pk }
     }
 }

+ 2 - 2
src/node/client.rs

@@ -115,9 +115,9 @@ impl Client {
 
         // TODO: These should go to a better place.
         debug!("Building proving key for the mint contract...");
-        let mint_pk = ProvingKey::build(11, MintContract::default());
+        let mint_pk = ProvingKey::build(11, &MintContract::default());
         debug!("Building proving key for the spend contract...");
-        let spend_pk = ProvingKey::build(11, SpendContract::default());
+        let spend_pk = ProvingKey::build(11, &SpendContract::default());
 
         let client = Client { main_keypair, gateway, wallet, mint_pk, spend_pk };
         Ok(client)