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

This commit is contained in:
parazyd
2022-01-26 10:11:13 +01:00
parent 287302f4ec
commit f8ab5ef5e3
11 changed files with 281 additions and 341 deletions

View File

@@ -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"]

View File

@@ -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)

View File

@@ -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 =

View File

@@ -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,

View File

@@ -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}}
```

View File

@@ -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");

View File

@@ -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
proof/burn.rs Normal file
View File

@@ -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
proof/mint.rs Normal file
View File

@@ -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(())
}

View File

@@ -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 }
}
}

View File

@@ -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)