Explorar o código

contract/consensus: distinct proposal mint proof created

aggstam %!s(int64=3) %!d(string=hai) anos
pai
achega
d897377bf8

+ 63 - 0
src/contract/consensus/proof/proposal_mint_v1.zk

@@ -0,0 +1,63 @@
+constant "ProposalMint_V1" {
+	EcFixedPointShort VALUE_COMMIT_VALUE,
+	EcFixedPoint VALUE_COMMIT_RANDOM,
+	EcFixedPointBase NULLIFIER_K,
+}
+
+witness "ProposalMint_V1" {
+	# X coordinate for public key
+	Base pub_x,
+	# Y coordinate for public key
+	Base pub_y,
+	# The value of this coin
+	Base value,
+	# The token ID
+	Base token,
+	# Unique serial number corresponding to this coin
+	Base serial,
+	# Random blinding factor for coin
+	Base coin_blind,
+	# Allows composing this ZK proof to invoke other contracts
+	Base spend_hook,
+	# Data passed from this coin to the invoked contract
+	Base user_data,
+	# Random blinding factor for the value commitment
+	Scalar value_blind,
+	# Random blinding factor for the token ID
+	Scalar token_blind,
+}
+
+circuit "ProposalMint_V1" {
+	# Poseidon hash of the coin
+	C = poseidon_hash(
+		pub_x,
+		pub_y,
+		value,
+		token,
+		serial,
+		spend_hook,
+		user_data,
+		coin_blind,
+	);
+	constrain_instance(C);
+
+	# Pedersen commitment for coin's value
+	vcv = ec_mul_short(value, VALUE_COMMIT_VALUE);
+	vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
+	value_commit = ec_add(vcv, vcr);
+	# Since the value commit is a curve point, we fetch its coordinates
+	# and constrain them:
+	constrain_instance(ec_get_x(value_commit));
+	constrain_instance(ec_get_y(value_commit));
+
+	# Pedersen commitment for coin's token ID
+	tcv = ec_mul_base(token, NULLIFIER_K);
+	tcr = ec_mul(token_blind, VALUE_COMMIT_RANDOM);
+	token_commit = ec_add(tcv, tcr);
+	# Since token_commit is also a curve point, we'll do the same
+	# coordinate dance:
+	constrain_instance(ec_get_x(token_commit));
+	constrain_instance(ec_get_y(token_commit));
+
+	# At this point we've enforced all of our public inputs.
+}

+ 60 - 9
src/contract/consensus/src/client/proposal_v1.rs

@@ -30,8 +30,9 @@ use darkfi_money_contract::{
 };
 use darkfi_sdk::{
     crypto::{
-        note::AeadEncryptedNote, pasta_prelude::*, pedersen_commitment_u64, poseidon_hash,
-        MerkleTree, Nullifier, PublicKey, SecretKey, CONSENSUS_CONTRACT_ID, DARK_TOKEN_ID,
+        note::AeadEncryptedNote, pasta_prelude::*, pedersen_commitment_base,
+        pedersen_commitment_u64, poseidon_hash, Coin, MerkleTree, Nullifier, PublicKey, SecretKey,
+        CONSENSUS_CONTRACT_ID, DARK_TOKEN_ID,
     },
     incrementalmerkletree::Tree,
     pasta::pallas,
@@ -41,7 +42,10 @@ use rand::rngs::OsRng;
 
 use crate::{
     client::{
-        stake_v1::{create_stake_mint_proof, TransactionBuilderOutputInfo as StakeTBOI},
+        stake_v1::{
+            ConsensusMintRevealed, TransactionBuilderOutputInfo as StakeTBOI,
+            TransactionBuilderOutputInfo,
+        },
         unstake_v1::{create_unstake_burn_proof, TransactionBuilderInputInfo as UnstakeTBII},
     },
     model::{
@@ -110,11 +114,11 @@ pub struct ConsensusProposalCallBuilder {
     pub burn_zkbin: ZkBinary,
     /// Proving key for the `Burn_V1` zk circuit
     pub burn_pk: ProvingKey,
-    /// `Reward_V1` zkas circuit ZkBinary
+    /// `ProposalReward_V1` zkas circuit ZkBinary
     pub reward_zkbin: ZkBinary,
     /// Proving key for the `Reward_V1` zk circuit
     pub reward_pk: ProvingKey,
-    /// `Mint_V1` zkas circuit ZkBinary
+    /// `ProposalMint_V1` zkas circuit ZkBinary
     pub mint_zkbin: ZkBinary,
     /// Proving key for the `Mint_V1` zk circuit
     pub mint_pk: ProvingKey,
@@ -122,7 +126,7 @@ pub struct ConsensusProposalCallBuilder {
 
 impl ConsensusProposalCallBuilder {
     pub fn build(&self) -> Result<ConsensusProposalCallDebris> {
-        debug!("Building Consensus::UnstakeV1 contract call for proposal");
+        debug!("Building Consensus::ProposalBurnV1 contract call for proposal");
         let value = self.coin.note.value;
         let token_id = self.coin.note.token_id;
         assert!(value != 0);
@@ -170,7 +174,7 @@ impl ConsensusProposalCallBuilder {
         let unstake_proofs = vec![proof];
         let unstake_input = input;
 
-        debug!("Building Consensus::StakeV1 contract call for proposal");
+        debug!("Building Consensus::ProposalMintV1 contract call for proposal");
         let new_value = value + REWARD;
         let nullifier = public_inputs.nullifier;
         let merkle_root = public_inputs.merkle_root;
@@ -186,7 +190,7 @@ impl ConsensusProposalCallBuilder {
         let coin_blind = pallas::Base::random(&mut OsRng);
 
         info!("Creating stake mint proof for output for proposal");
-        let (proof, public_inputs) = create_stake_mint_proof(
+        let (proof, public_inputs) = create_proposal_mint_proof(
             &self.mint_zkbin,
             &self.mint_pk,
             &output,
@@ -233,7 +237,7 @@ impl ConsensusProposalCallBuilder {
         let stake_proofs = vec![proof];
         let stake_input = input;
 
-        debug!("Building Consensus::RewardV1 contract call for proposal");
+        debug!("Building Consensus::ProposalRewardV1 contract call for proposal");
         let secret_key = self.coin.secret.inner();
         let serial = self.coin.note.serial;
         let (proof, public_inputs) = create_proposal_reward_proof(
@@ -321,3 +325,50 @@ pub fn create_proposal_reward_proof(
 
     Ok((proof, public_inputs))
 }
+
+pub fn create_proposal_mint_proof(
+    zkbin: &ZkBinary,
+    pk: &ProvingKey,
+    output: &TransactionBuilderOutputInfo,
+    value_blind: pallas::Scalar,
+    token_blind: pallas::Scalar,
+    serial: pallas::Base,
+    spend_hook: pallas::Base,
+    user_data: pallas::Base,
+    coin_blind: pallas::Base,
+) -> Result<(Proof, ConsensusMintRevealed)> {
+    let value_commit = pedersen_commitment_u64(output.value, value_blind);
+    let token_commit = pedersen_commitment_base(output.token_id.inner(), token_blind);
+    let (pub_x, pub_y) = output.public_key.xy();
+
+    let coin = Coin::from(poseidon_hash([
+        pub_x,
+        pub_y,
+        pallas::Base::from(output.value),
+        output.token_id.inner(),
+        serial,
+        spend_hook,
+        user_data,
+        coin_blind,
+    ]));
+
+    let public_inputs = ConsensusMintRevealed { coin, value_commit, token_commit };
+
+    let prover_witnesses = vec![
+        Witness::Base(Value::known(pub_x)),
+        Witness::Base(Value::known(pub_y)),
+        Witness::Base(Value::known(pallas::Base::from(output.value))),
+        Witness::Base(Value::known(output.token_id.inner())),
+        Witness::Base(Value::known(serial)),
+        Witness::Base(Value::known(coin_blind)),
+        Witness::Base(Value::known(spend_hook)),
+        Witness::Base(Value::known(user_data)),
+        Witness::Scalar(Value::known(value_blind)),
+        Witness::Scalar(Value::known(token_blind)),
+    ];
+
+    let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
+    let proof = Proof::create(pk, &[circuit], &public_inputs.to_vec(), &mut OsRng)?;
+
+    Ok((proof, public_inputs))
+}

+ 2 - 0
src/contract/consensus/src/entrypoint.rs

@@ -88,11 +88,13 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
     let money_mint_v1_bincode = include_bytes!("../../money/proof/mint_v1.zk.bin");
     let money_burn_v1_bincode = include_bytes!("../../money/proof/burn_v1.zk.bin");
     let proposal_reward_v1_bincode = include_bytes!("../proof/proposal_reward_v1.zk.bin");
+    let proposal_mint_v1_bincode = include_bytes!("../proof/proposal_mint_v1.zk.bin");
 
     // For that, we use `zkas_db_set` and pass in the bincode.
     zkas_db_set(&money_mint_v1_bincode[..])?;
     zkas_db_set(&money_burn_v1_bincode[..])?;
     zkas_db_set(&proposal_reward_v1_bincode[..])?;
+    zkas_db_set(&proposal_mint_v1_bincode[..])?;
 
     // Set up a database tree to hold Merkle roots of all coins
     // k=MerkleNode, v=[]

+ 2 - 2
src/contract/consensus/src/entrypoint/proposal_mint_v1.rs

@@ -21,7 +21,7 @@ use darkfi_money_contract::{
     model::{ConsensusStakeParamsV1, ConsensusStakeUpdateV1},
     CONSENSUS_CONTRACT_COINS_TREE, CONSENSUS_CONTRACT_COIN_MERKLE_TREE,
     CONSENSUS_CONTRACT_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_INFO_TREE,
-    CONSENSUS_CONTRACT_NULLIFIERS_TREE, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
+    CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_MINT_NS_V1,
 };
 use darkfi_sdk::{
     crypto::{
@@ -61,7 +61,7 @@ pub(crate) fn consensus_proposal_mint_get_metadata_v1(
     let token_coords = output.token_commit.to_affine().coordinates().unwrap();
 
     zk_public_inputs.push((
-        MONEY_CONTRACT_ZKAS_MINT_NS_V1.to_string(),
+        CONSENSUS_CONTRACT_ZKAS_PROPOSAL_MINT_NS_V1.to_string(),
         vec![
             output.coin.inner(),
             *value_coords.x(),

+ 3 - 2
src/contract/consensus/tests/harness.rs

@@ -43,8 +43,8 @@ use rand::rngs::OsRng;
 
 use darkfi_money_contract::{
     client::transfer_v1::TransferCallBuilder, model::MoneyTransferParamsV1, MoneyFunction,
-    CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1, MONEY_CONTRACT_ZKAS_BURN_NS_V1,
-    MONEY_CONTRACT_ZKAS_MINT_NS_V1,
+    CONSENSUS_CONTRACT_ZKAS_PROPOSAL_MINT_NS_V1, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1,
+    MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
 };
 
 pub fn init_logger() {
@@ -150,6 +150,7 @@ impl ConsensusTestHarness {
         mkpk!(MONEY_CONTRACT_ZKAS_MINT_NS_V1);
         mkpk!(MONEY_CONTRACT_ZKAS_BURN_NS_V1);
         mkpk!(CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1);
+        mkpk!(CONSENSUS_CONTRACT_ZKAS_PROPOSAL_MINT_NS_V1);
 
         Ok(Self { faucet, alice, proving_keys })
     }

+ 23 - 18
src/contract/consensus/tests/stake_unstake.rs

@@ -44,7 +44,8 @@ use darkfi_money_contract::{
     client::{
         stake_v1::MoneyStakeCallBuilder, unstake_v1::MoneyUnstakeCallBuilder, MoneyNote, OwnCoin,
     },
-    MoneyFunction, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1, MONEY_CONTRACT_ZKAS_BURN_NS_V1,
+    MoneyFunction, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_MINT_NS_V1,
+    CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1, MONEY_CONTRACT_ZKAS_BURN_NS_V1,
     MONEY_CONTRACT_ZKAS_MINT_NS_V1,
 };
 
@@ -87,10 +88,14 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
     info!(target: "consensus", "[Faucet] Building Money::Transfer params for Alice's airdrop");
     info!(target: "consensus", "[Faucet] ===================================================");
     let (airdrop_tx, airdrop_params) = th.airdrop_native(ALICE_AIRDROP, th.alice.keypair.public)?;
-    let (mint_pk, mint_zkbin) = th.proving_keys.get(&MONEY_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
-    let (burn_pk, burn_zkbin) = th.proving_keys.get(&MONEY_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
-    let (reward_pk, reward_zkbin) =
+    let (money_mint_pk, money_mint_zkbin) =
+        th.proving_keys.get(&MONEY_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
+    let (money_burn_pk, money_burn_zkbin) =
+        th.proving_keys.get(&MONEY_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
+    let (proposal_reward_pk, proposal_reward_zkbin) =
         th.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1).unwrap();
+    let (proposal_mint_pk, proposal_mint_zkbin) =
+        th.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_PROPOSAL_MINT_NS_V1).unwrap();
 
     info!(target: "consensus", "[Faucet] ==========================");
     info!(target: "consensus", "[Faucet] Executing Alice airdrop tx");
@@ -128,8 +133,8 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
     let alice_money_stake_call_debris = MoneyStakeCallBuilder {
         coin: alice_oc.clone(),
         tree: th.alice.merkle_tree.clone(),
-        burn_zkbin: burn_zkbin.clone(),
-        burn_pk: burn_pk.clone(),
+        burn_zkbin: money_burn_zkbin.clone(),
+        burn_pk: money_burn_pk.clone(),
     }
     .build()?;
     let (
@@ -155,8 +160,8 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
         nullifier: alice_money_stake_params.input.nullifier,
         merkle_root: alice_money_stake_params.input.merkle_root,
         signature_public: alice_money_stake_params.input.signature_public,
-        mint_zkbin: mint_zkbin.clone(),
-        mint_pk: mint_pk.clone(),
+        mint_zkbin: money_mint_zkbin.clone(),
+        mint_pk: money_mint_pk.clone(),
     }
     .build()?;
     let (alice_consensus_stake_params, alice_consensus_stake_proofs) =
@@ -253,12 +258,12 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
         recipient: th.alice.keypair.public,
         slot_checkpoint,
         tree: th.alice.consensus_merkle_tree.clone(),
-        burn_zkbin: burn_zkbin.clone(),
-        burn_pk: burn_pk.clone(),
-        reward_zkbin: reward_zkbin.clone(),
-        reward_pk: reward_pk.clone(),
-        mint_zkbin: mint_zkbin.clone(),
-        mint_pk: mint_pk.clone(),
+        burn_zkbin: money_burn_zkbin.clone(),
+        burn_pk: money_burn_pk.clone(),
+        reward_zkbin: proposal_reward_zkbin.clone(),
+        reward_pk: proposal_reward_pk.clone(),
+        mint_zkbin: proposal_mint_zkbin.clone(),
+        mint_pk: proposal_mint_pk.clone(),
     }
     .build()?;
     let (
@@ -376,8 +381,8 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
     let alice_consensus_unstake_call_debris = ConsensusUnstakeCallBuilder {
         coin: alice_rewarded_staked_oc.clone(),
         tree: th.alice.consensus_merkle_tree.clone(),
-        burn_zkbin: burn_zkbin.clone(),
-        burn_pk: burn_pk.clone(),
+        burn_zkbin: money_burn_zkbin.clone(),
+        burn_pk: money_burn_pk.clone(),
     }
     .build()?;
     let (
@@ -403,8 +408,8 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
         nullifier: alice_consensus_unstake_params.input.nullifier,
         merkle_root: alice_consensus_unstake_params.input.merkle_root,
         signature_public: alice_consensus_unstake_params.input.signature_public,
-        mint_zkbin: mint_zkbin.clone(),
-        mint_pk: mint_pk.clone(),
+        mint_zkbin: money_mint_zkbin.clone(),
+        mint_pk: money_mint_pk.clone(),
     }
     .build()?;
     let (alice_money_unstake_params, alice_money_unstake_proofs) =

+ 3 - 1
src/contract/money/src/lib.rs

@@ -98,5 +98,7 @@ pub const CONSENSUS_CONTRACT_NULLIFIERS_TREE: &str = "consensus_nullifiers";
 pub const CONSENSUS_CONTRACT_DB_VERSION: &str = env!("CARGO_PKG_VERSION");
 pub const CONSENSUS_CONTRACT_COIN_MERKLE_TREE: &str = "consensus_coin_tree";
 
-/// zkas reward circuit namespace
+/// zkas proposal reward circuit namespace
 pub const CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1: &str = "ProposalReward_V1";
+/// zkas proposal mint circuit namespace
+pub const CONSENSUS_CONTRACT_ZKAS_PROPOSAL_MINT_NS_V1: &str = "ProposalMint_V1";