|
|
@@ -17,18 +17,22 @@ use halo2_gadgets::{
|
|
|
utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
|
|
|
};
|
|
|
use halo2_proofs::{
|
|
|
- circuit::{AssignedCell, Layouter, SimpleFloorPlanner, Value},
|
|
|
+ circuit::{floor_planner, AssignedCell, Layouter, Value},
|
|
|
plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Instance as InstanceColumn},
|
|
|
};
|
|
|
use pasta_curves::{pallas, Fp};
|
|
|
|
|
|
-use crate::crypto::{
|
|
|
- constants::{
|
|
|
- sinsemilla::{OrchardCommitDomains, OrchardHashDomains},
|
|
|
- util::gen_const_array,
|
|
|
- NullifierK, OrchardFixedBases, OrchardFixedBasesFull, ValueCommitV, MERKLE_DEPTH_ORCHARD,
|
|
|
+use crate::{
|
|
|
+ crypto::{
|
|
|
+ constants::{
|
|
|
+ sinsemilla::{OrchardCommitDomains, OrchardHashDomains},
|
|
|
+ util::gen_const_array,
|
|
|
+ NullifierK, OrchardFixedBases, OrchardFixedBasesFull, ValueCommitV,
|
|
|
+ MERKLE_DEPTH_ORCHARD,
|
|
|
+ },
|
|
|
+ merkle_node::MerkleNode,
|
|
|
},
|
|
|
- merkle_node::MerkleNode,
|
|
|
+ zk::assign_free_advice,
|
|
|
};
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
@@ -112,7 +116,7 @@ impl UtilitiesInstructions<pallas::Base> for BurnContract {
|
|
|
|
|
|
impl Circuit<pallas::Base> for BurnContract {
|
|
|
type Config = BurnConfig;
|
|
|
- type FloorPlanner = SimpleFloorPlanner;
|
|
|
+ type FloorPlanner = floor_planner::V1;
|
|
|
|
|
|
fn without_witnesses(&self) -> Self {
|
|
|
Self::default()
|
|
|
@@ -245,13 +249,13 @@ impl Circuit<pallas::Base> for BurnContract {
|
|
|
// =========
|
|
|
// Nullifier
|
|
|
// =========
|
|
|
- let secret_key = self.load_private(
|
|
|
+ let secret_key = assign_free_advice(
|
|
|
layouter.namespace(|| "load sinsemilla(secret key)"),
|
|
|
config.advices[0],
|
|
|
self.secret_key,
|
|
|
)?;
|
|
|
|
|
|
- let serial = self.load_private(
|
|
|
+ let serial = assign_free_advice(
|
|
|
layouter.namespace(|| "load serial"),
|
|
|
config.advices[0],
|
|
|
self.serial,
|
|
|
@@ -287,12 +291,12 @@ impl Circuit<pallas::Base> for BurnContract {
|
|
|
// )?
|
|
|
|
|
|
let value =
|
|
|
- self.load_private(layouter.namespace(|| "load value"), config.advices[0], self.value)?;
|
|
|
+ assign_free_advice(layouter.namespace(|| "load value"), config.advices[0], self.value)?;
|
|
|
|
|
|
let token =
|
|
|
- self.load_private(layouter.namespace(|| "load token"), config.advices[0], self.token)?;
|
|
|
+ assign_free_advice(layouter.namespace(|| "load token"), config.advices[0], self.token)?;
|
|
|
|
|
|
- let coin_blind = self.load_private(
|
|
|
+ let coin_blind = assign_free_advice(
|
|
|
layouter.namespace(|| "load coin_blind"),
|
|
|
config.advices[0],
|
|
|
self.coin_blind,
|
|
|
@@ -358,14 +362,14 @@ impl Circuit<pallas::Base> for BurnContract {
|
|
|
// ================
|
|
|
|
|
|
// This constant one is used for multiplication
|
|
|
- let one = self.load_private(
|
|
|
+ let one = assign_free_advice(
|
|
|
layouter.namespace(|| "load constant one"),
|
|
|
config.advices[0],
|
|
|
Value::known(pallas::Base::one()),
|
|
|
)?;
|
|
|
|
|
|
let value =
|
|
|
- self.load_private(layouter.namespace(|| "load value"), config.advices[0], self.value)?;
|
|
|
+ assign_free_advice(layouter.namespace(|| "load value"), config.advices[0], self.value)?;
|
|
|
|
|
|
// v * G_1
|
|
|
let (commitment, _) = {
|
|
|
@@ -409,7 +413,7 @@ impl Circuit<pallas::Base> for BurnContract {
|
|
|
// ================
|
|
|
|
|
|
let token =
|
|
|
- self.load_private(layouter.namespace(|| "load token"), config.advices[0], self.token)?;
|
|
|
+ assign_free_advice(layouter.namespace(|| "load token"), config.advices[0], self.token)?;
|
|
|
|
|
|
// a * G_1
|
|
|
let (commitment, _) = {
|
|
|
@@ -453,7 +457,7 @@ impl Circuit<pallas::Base> for BurnContract {
|
|
|
// ========================
|
|
|
// Signature key derivation
|
|
|
// ========================
|
|
|
- let sig_secret = self.load_private(
|
|
|
+ let sig_secret = assign_free_advice(
|
|
|
layouter.namespace(|| "load sig_secret"),
|
|
|
config.advices[0],
|
|
|
self.sig_secret,
|
|
|
@@ -480,3 +484,106 @@ impl Circuit<pallas::Base> for BurnContract {
|
|
|
Ok(())
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+#[cfg(test)]
|
|
|
+mod tests {
|
|
|
+ use super::*;
|
|
|
+ use crate::{
|
|
|
+ crypto::{
|
|
|
+ keypair::{PublicKey, SecretKey},
|
|
|
+ util::{mod_r_p, pedersen_commitment_scalar},
|
|
|
+ },
|
|
|
+ Result,
|
|
|
+ };
|
|
|
+ use group::{ff::Field, Curve};
|
|
|
+ use halo2_gadgets::poseidon::{
|
|
|
+ primitives as poseidon,
|
|
|
+ primitives::{ConstantLength, P128Pow5T3},
|
|
|
+ };
|
|
|
+ use halo2_proofs::dev::{CircuitLayout, MockProver};
|
|
|
+ use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
|
|
|
+ use pasta_curves::arithmetic::CurveAffine;
|
|
|
+ use rand::rngs::OsRng;
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn burn_circuit_assert() -> Result<()> {
|
|
|
+ let value = pallas::Base::from(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 coin2 = {
|
|
|
+ let coords = PublicKey::from_secret(secret).0.to_affine().coordinates().unwrap();
|
|
|
+ let msg = [*coords.x(), *coords.y(), value, token_id, serial, coin_blind];
|
|
|
+ poseidon::Hash::<_, P128Pow5T3, ConstantLength<6>, 3, 2>::init().hash(msg)
|
|
|
+ };
|
|
|
+
|
|
|
+ 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));
|
|
|
+ let leaf_pos = tree.witness().unwrap();
|
|
|
+ tree.append(&MerkleNode(coin3));
|
|
|
+ tree.witness();
|
|
|
+
|
|
|
+ let merkle_root = tree.root(0).unwrap();
|
|
|
+ let merkle_path = tree.authentication_path(leaf_pos, &merkle_root).unwrap();
|
|
|
+ let leaf_pos: u64 = leaf_pos.into();
|
|
|
+
|
|
|
+ let nullifier = [secret.0, serial];
|
|
|
+ let nullifier =
|
|
|
+ poseidon::Hash::<_, P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(nullifier);
|
|
|
+
|
|
|
+ let value_commit = pedersen_commitment_scalar(mod_r_p(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 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(),
|
|
|
+ ];
|
|
|
+
|
|
|
+ let circuit = BurnContract {
|
|
|
+ secret_key: Value::known(secret.0),
|
|
|
+ serial: Value::known(serial),
|
|
|
+ value: Value::known(value),
|
|
|
+ token: Value::known(token_id),
|
|
|
+ coin_blind: Value::known(coin_blind),
|
|
|
+ value_blind: Value::known(value_blind),
|
|
|
+ token_blind: Value::known(token_blind),
|
|
|
+ leaf_pos: Value::known(leaf_pos.try_into().unwrap()),
|
|
|
+ merkle_path: Value::known(merkle_path.try_into().unwrap()),
|
|
|
+ sig_secret: Value::known(sig_secret.0),
|
|
|
+ };
|
|
|
+
|
|
|
+ use plotters::prelude::*;
|
|
|
+ let root = BitMapBackend::new("burn_circuit_layout.png", (3840, 2160)).into_drawing_area();
|
|
|
+ root.fill(&WHITE).unwrap();
|
|
|
+ let root = root.titled("Burn Circuit Layout", ("sans-serif", 60)).unwrap();
|
|
|
+ CircuitLayout::default().render(11, &circuit, &root).unwrap();
|
|
|
+
|
|
|
+ let prover = MockProver::run(11, &circuit, vec![public_inputs])?;
|
|
|
+ prover.assert_satisfied();
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+}
|