apply DEP 0003: Token Mint Authorization

This commit is contained in:
zero
2024-02-01 17:32:59 +01:00
parent ccc6b25754
commit 7edb0cd217
35 changed files with 761 additions and 452 deletions

View File

@@ -67,7 +67,7 @@
- [DEP 0001: Version Message Info (accepted)](dep/0001.md)
- [DEP 0002: Smart Contract Composability (deprecated)](dep/0002.md)
- [DEP 0003: Token Mint Authorization (draft)](dep/0003.md)
- [DEP 0003: Token Mint Authorization (accepted)](dep/0003.md)
# Specs

View File

@@ -1,7 +1,7 @@
# DEP 0003: Token Mint Authorization
```
status: draft
status: accepted
```
## Current Situation
@@ -43,8 +43,6 @@ For each coin $Cᵢ$, let there be corresponding proofs $πᵢ$ such that
**Token ID integrity**   $T$ is calculated correctly committing to
`auth_parent`.
**User data commitment**   $U = \t{PoseidonHash}(u, bᵤ)$
**Coin commitment integrity**   $Cᵢ = \t{PoseidonHash}(…, T, …)$
Additionally the contract checks that `auth_parent` is the function ID of
@@ -69,8 +67,6 @@ The contract performs the following checks:
* Constructs a pedersen commit $V$ to the value in the coin, along with a proof.
This allows auditing the supply since all commitments are linked publicly with
the token ID.
* Unwrap the `user_data` exported from `Money::token_mint_v1()` which should
be a commitment to the public key. Prove ownership of the public key.
### `Money::auth_mint_freeze_v1()`

View File

@@ -97,8 +97,7 @@ impl DaoAuthMoneyTransferCall {
let circuit = ZkCircuit::new(prover_witnesses, auth_xfer_enc_coin_zkbin);
let proof =
Proof::create(auth_xfer_enc_coin_pk, &[circuit], &public_inputs, &mut OsRng)
.expect("DAO::exec() proving error!)");
Proof::create(auth_xfer_enc_coin_pk, &[circuit], &public_inputs, &mut OsRng)?;
proofs.push(proof);
enc_attrs.push(enc_note);
@@ -169,8 +168,7 @@ impl DaoAuthMoneyTransferCall {
];
let circuit = ZkCircuit::new(prover_witnesses, auth_xfer_zkbin);
let proof = Proof::create(auth_xfer_pk, &[circuit], &public_inputs, &mut OsRng)
.expect("DAO::exec() proving error!)");
let proof = Proof::create(auth_xfer_pk, &[circuit], &public_inputs, &mut OsRng)?;
proofs.push(proof);
Ok((params, proofs))

View File

@@ -109,8 +109,7 @@ impl DaoExecCall {
//export_witness_json("witness.json", &prover_witnesses, &public_inputs);
let circuit = ZkCircuit::new(prover_witnesses, exec_zkbin);
let input_proof = Proof::create(exec_pk, &[circuit], &public_inputs, &mut OsRng)
.expect("DAO::exec() proving error!)");
let input_proof = Proof::create(exec_pk, &[circuit], &public_inputs, &mut OsRng)?;
proofs.push(input_proof);
let params = DaoExecParams {

View File

@@ -143,8 +143,7 @@ impl DaoProposeCall {
let circuit = ZkCircuit::new(prover_witnesses, burn_zkbin);
let proving_key = &burn_pk;
let input_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
.expect("DAO::propose() proving error!");
let input_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)?;
proofs.push(input_proof);
let input =
@@ -203,8 +202,7 @@ impl DaoProposeCall {
];
let circuit = ZkCircuit::new(prover_witnesses, main_zkbin);
let main_proof = Proof::create(main_pk, &[circuit], &public_inputs, &mut OsRng)
.expect("DAO::propose() proving error!");
let main_proof = Proof::create(main_pk, &[circuit], &public_inputs, &mut OsRng)?;
proofs.push(main_proof);
let enc_note =

View File

@@ -166,8 +166,7 @@ impl DaoVoteCall {
let circuit = ZkCircuit::new(prover_witnesses, burn_zkbin);
debug!(target: "dao", "input_proof Proof::create()");
let input_proof = Proof::create(burn_pk, &[circuit], &public_inputs, &mut OsRng)
.expect("DAO::vote() proving error!");
let input_proof = Proof::create(burn_pk, &[circuit], &public_inputs, &mut OsRng)?;
proofs.push(input_proof);
let input = DaoVoteParamsInput {
@@ -270,8 +269,7 @@ impl DaoVoteCall {
let circuit = ZkCircuit::new(prover_witnesses, main_zkbin);
debug!(target: "dao", "main_proof = Proof::create()");
let main_proof = Proof::create(main_pk, &[circuit], &public_inputs, &mut OsRng)
.expect("DAO::vote() proving error!");
let main_proof = Proof::create(main_pk, &[circuit], &public_inputs, &mut OsRng)?;
proofs.push(main_proof);
let params =

View File

@@ -0,0 +1,64 @@
# Circuit used to mint arbitrary coins given a mint authority secret.
k = 13;
field = "pallas";
constant "AuthTokenMint_V1" {
EcFixedPointShort VALUE_COMMIT_VALUE,
EcFixedPoint VALUE_COMMIT_RANDOM,
EcFixedPointBase NULLIFIER_K,
}
witness "AuthTokenMint_V1" {
# CoinAttributes {
Base coin_public_x,
Base coin_public_y,
Base coin_value,
Base coin_spend_hook,
Base coin_user_data,
Base coin_blind,
# }
# TokenAttributes {
Base token_auth_parent,
Base token_blind,
# }
# Secret key used by mint
Base mint_secret,
# Random blinding factor for the value commitment
Scalar value_commit_blind,
}
circuit "AuthTokenMint_V1" {
# Derive public key for the mint authority
mint_public = ec_mul_base(mint_secret, NULLIFIER_K);
mint_x = ec_get_x(mint_public);
mint_y = ec_get_y(mint_public);
constrain_instance(mint_x);
constrain_instance(mint_y);
# Derive the token ID
token_user_data = poseidon_hash(mint_x, mint_y);
token_id = poseidon_hash(token_auth_parent, token_user_data, token_blind);
constrain_instance(token_id);
# Poseidon hash of the minted coin
coin = poseidon_hash(
coin_public_x,
coin_public_y,
coin_value,
token_id,
coin_spend_hook,
coin_user_data,
coin_blind
);
constrain_instance(coin);
# Pedersen commitment for the coin's value
vcv = ec_mul_short(coin_value, VALUE_COMMIT_VALUE);
vcr = ec_mul(value_commit_blind, VALUE_COMMIT_RANDOM);
value_commit = ec_add(vcv, vcr);
constrain_instance(ec_get_x(value_commit));
constrain_instance(ec_get_y(value_commit));
}

View File

@@ -6,22 +6,26 @@ constant "TokenFreeze_V1" {
}
witness "TokenFreeze_V1" {
# Token mint authority secret
Base mint_authority,
# TokenAttributes {
Base token_auth_parent,
Base token_blind,
# }
# Secret key used by mint
Base mint_secret,
}
circuit "TokenFreeze_V1" {
# TokenID derivation path (See darkfi_sdk::crypto::ContractId)
derivation_path = witness_base(69);
# Derive public key for the mint authority
mint_public = ec_mul_base(mint_authority, NULLIFIER_K);
mint_public = ec_mul_base(mint_secret, NULLIFIER_K);
mint_x = ec_get_x(mint_public);
mint_y = ec_get_y(mint_public);
constrain_instance(mint_x);
constrain_instance(mint_y);
# Derive the token ID
token_id = poseidon_hash(derivation_path, mint_x, mint_y);
token_user_data = poseidon_hash(mint_x, mint_y);
token_id = poseidon_hash(token_auth_parent, token_user_data, token_blind);
constrain_instance(token_id);
}

View File

@@ -9,61 +9,36 @@ constant "TokenMint_V1" {
}
witness "TokenMint_V1" {
# Token mint authority secret
Base mint_authority,
# Token supply
Base supply,
# Recipient's public key x coordinate
Base rcpt_x,
# Recipient's public key y coordinate
Base rcpt_y,
# Unique serial number for the minted coin
Base serial,
# Allows composing this ZK proof to invoke other contracts
# CoinAttributes {
Base public_x,
Base public_y,
Base value,
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
Base coin_user_data,
Base coin_blind,
# }
# TokenAttributes {
Base auth_parent,
Base token_user_data,
Base token_blind,
# }
}
circuit "TokenMint_V1" {
# TokenID derivation path (See darkfi_sdk::crypto::TokenId)
derivation_path = witness_base(69);
# Derive public key for the mint authority
mint_public = ec_mul_base(mint_authority, NULLIFIER_K);
mint_x = ec_get_x(mint_public);
mint_y = ec_get_y(mint_public);
constrain_instance(mint_x);
constrain_instance(mint_y);
# Derive the token ID
token_id = poseidon_hash(derivation_path, mint_x, mint_y);
constrain_instance(token_id);
token_id = poseidon_hash(auth_parent, token_user_data, token_blind);
constrain_instance(auth_parent);
# Poseidon hash of the minted coin
C = poseidon_hash(
rcpt_x,
rcpt_y,
supply,
# Then show the coin contains the token ID
coin = poseidon_hash(
public_x,
public_y,
value,
token_id,
serial,
spend_hook,
user_data,
coin_user_data,
coin_blind,
);
constrain_instance(C);
# Pedersen commitment for the coin's value
vcv = ec_mul_short(supply, VALUE_COMMIT_VALUE);
vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
value_commit = ec_add(vcv, vcr);
constrain_instance(ec_get_x(value_commit));
constrain_instance(ec_get_y(value_commit));
# Commitment for the coin's token ID
token_commit = poseidon_hash(token_id, token_blind);
constrain_instance(token_commit);
constrain_instance(coin);
}

View File

@@ -0,0 +1,122 @@
/* This file is part of DarkFi (https://dark.fi)
*
* Copyright (C) 2020-2024 Dyne.org foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use darkfi::{
zk::{halo2::Value, Proof, ProvingKey, Witness, ZkCircuit},
zkas::ZkBinary,
Result,
};
use darkfi_sdk::{
crypto::{note::AeadEncryptedNote, pasta_prelude::*, pedersen_commitment_u64, Keypair},
pasta::pallas,
};
use log::info;
use rand::rngs::OsRng;
use crate::{
client::MoneyNote,
model::{CoinAttributes, MoneyAuthTokenMintParamsV1, TokenAttributes},
};
pub struct AuthTokenMintCallDebris {
pub params: MoneyAuthTokenMintParamsV1,
pub proofs: Vec<Proof>,
}
/// Struct holding necessary information to build a `Money::AuthTokenMintV1` contract call.
pub struct AuthTokenMintCallBuilder {
pub coin_attrs: CoinAttributes,
pub token_attrs: TokenAttributes,
/// Mint authority keypair
pub mint_keypair: Keypair,
/// `AuthTokenMint_V1` zkas circuit ZkBinary
pub auth_mint_zkbin: ZkBinary,
/// Proving key for the `AuthTokenMint_V1` zk circuit,
pub auth_mint_pk: ProvingKey,
}
impl AuthTokenMintCallBuilder {
pub fn build(&self) -> Result<AuthTokenMintCallDebris> {
info!("Building Money::AuthTokenMintV1 contract call");
let value_blind = pallas::Scalar::random(&mut OsRng);
let value_commit = pedersen_commitment_u64(self.coin_attrs.value, value_blind);
// Create the proof
let (public_x, public_y) = self.coin_attrs.public_key.xy();
let prover_witnesses = vec![
// Coin attributes
Witness::Base(Value::known(public_x)),
Witness::Base(Value::known(public_y)),
Witness::Base(Value::known(pallas::Base::from(self.coin_attrs.value))),
Witness::Base(Value::known(self.coin_attrs.spend_hook)),
Witness::Base(Value::known(self.coin_attrs.user_data)),
Witness::Base(Value::known(self.coin_attrs.blind)),
// Token attributes
Witness::Base(Value::known(self.token_attrs.auth_parent.inner())),
Witness::Base(Value::known(self.token_attrs.blind)),
// Secret key used by mint
Witness::Base(Value::known(self.mint_keypair.secret.inner())),
// Random blinding factor for the value commitment
Witness::Scalar(Value::known(value_blind)),
];
let mint_pubkey = self.mint_keypair.public;
let value_coords = value_commit.to_affine().coordinates().unwrap();
let public_inputs = vec![
mint_pubkey.x(),
mint_pubkey.y(),
self.token_attrs.to_token_id().inner(),
self.coin_attrs.to_coin().inner(),
*value_coords.x(),
*value_coords.y(),
];
let circuit = ZkCircuit::new(prover_witnesses, &self.auth_mint_zkbin);
let proof = Proof::create(&self.auth_mint_pk, &[circuit], &public_inputs, &mut OsRng)?;
// Create the note
let note = MoneyNote {
value: self.coin_attrs.value,
token_id: self.coin_attrs.token_id,
spend_hook: self.coin_attrs.spend_hook,
user_data: self.coin_attrs.user_data,
coin_blind: self.coin_attrs.blind,
value_blind,
token_blind: pallas::Base::ZERO,
memo: vec![],
};
let enc_note = AeadEncryptedNote::encrypt(&note, &self.coin_attrs.public_key, &mut OsRng)?;
let params = MoneyAuthTokenMintParamsV1 {
token_id: self.token_attrs.to_token_id(),
value_commit,
enc_note,
mint_pubkey,
};
let debris = AuthTokenMintCallDebris { params, proofs: vec![proof] };
Ok(debris)
}
}

View File

@@ -35,11 +35,11 @@ use crate::{
},
MoneyNote,
},
model::{ClearInput, Coin, MoneyTokenMintParamsV1, Output},
model::{ClearInput, Coin, MoneyGenesisMintParamsV1, Output},
};
pub struct GenesisMintCallDebris {
pub params: MoneyTokenMintParamsV1,
pub params: MoneyGenesisMintParamsV1,
pub proofs: Vec<Proof>,
}
@@ -147,7 +147,7 @@ impl GenesisMintCallBuilder {
note: encrypted_note,
};
let params = MoneyTokenMintParamsV1 { input: c_input, output: c_output };
let params = MoneyGenesisMintParamsV1 { input: c_input, output: c_output };
let debris = GenesisMintCallDebris { params, proofs: vec![proof] };
Ok(debris)
}

View File

@@ -56,6 +56,48 @@ pub mod token_freeze_v1;
/// `Money::PoWRewardV1` API
pub mod pow_reward_v1;
/// `Money::AuthTokenMintV1` API
pub mod auth_token_mint_v1;
// Wallet SQL table constant names. These have to represent the `wallet.sql`
// SQL schema.
// TODO: They should also be prefixed with the contract ID to avoid collisions.
pub const MONEY_INFO_TABLE: &str = "money_info";
pub const MONEY_INFO_COL_LAST_SCANNED_SLOT: &str = "last_scanned_slot";
pub const MONEY_TREE_TABLE: &str = "money_tree";
pub const MONEY_TREE_COL_TREE: &str = "tree";
pub const MONEY_KEYS_TABLE: &str = "money_keys";
pub const MONEY_KEYS_COL_KEY_ID: &str = "key_id";
pub const MONEY_KEYS_COL_IS_DEFAULT: &str = "is_default";
pub const MONEY_KEYS_COL_PUBLIC: &str = "public";
pub const MONEY_KEYS_COL_SECRET: &str = "secret";
pub const MONEY_COINS_TABLE: &str = "money_coins";
pub const MONEY_COINS_COL_COIN: &str = "coin";
pub const MONEY_COINS_COL_IS_SPENT: &str = "is_spent";
pub const MONEY_COINS_COL_SERIAL: &str = "serial";
pub const MONEY_COINS_COL_VALUE: &str = "value";
pub const MONEY_COINS_COL_TOKEN_ID: &str = "token_id";
pub const MONEY_COINS_COL_SPEND_HOOK: &str = "spend_hook";
pub const MONEY_COINS_COL_USER_DATA: &str = "user_data";
pub const MONEY_COINS_COL_VALUE_BLIND: &str = "value_blind";
pub const MONEY_COINS_COL_TOKEN_BLIND: &str = "token_blind";
pub const MONEY_COINS_COL_SECRET: &str = "secret";
pub const MONEY_COINS_COL_NULLIFIER: &str = "nullifier";
pub const MONEY_COINS_COL_LEAF_POSITION: &str = "leaf_position";
pub const MONEY_COINS_COL_MEMO: &str = "memo";
pub const MONEY_TOKENS_TABLE: &str = "money_tokens";
pub const MONEY_TOKENS_COL_MINT_AUTHORITY: &str = "mint_authority";
pub const MONEY_TOKENS_COL_TOKEN_ID: &str = "token_id";
pub const MONEY_TOKENS_COL_IS_FROZEN: &str = "is_frozen";
pub const MONEY_ALIASES_TABLE: &str = "money_aliases";
pub const MONEY_ALIASES_COL_ALIAS: &str = "alias";
pub const MONEY_ALIASES_COL_TOKEN_ID: &str = "token_id";
/// `MoneyNote` holds the inner attributes of a `Coin`
/// It does not store the public key since it's encrypted for that key,
/// and so is not needed to infer the coin attributes.

View File

@@ -21,40 +21,26 @@ use darkfi::{
zkas::ZkBinary,
Result,
};
use darkfi_sdk::{
crypto::{Keypair, PublicKey, TokenId},
pasta::pallas,
};
use log::{debug, info};
use darkfi_sdk::crypto::Keypair;
use log::info;
use rand::rngs::OsRng;
use crate::model::MoneyTokenFreezeParamsV1;
use crate::model::{MoneyTokenFreezeParamsV1, TokenAttributes};
pub struct TokenFreezeCallDebris {
pub params: MoneyTokenFreezeParamsV1,
pub proofs: Vec<Proof>,
}
pub struct TokenFreezeRevealed {
pub signature_public: PublicKey,
pub token_id: TokenId,
}
impl TokenFreezeRevealed {
pub fn to_vec(&self) -> Vec<pallas::Base> {
let (sig_x, sig_y) = self.signature_public.xy();
vec![sig_x, sig_y, self.token_id.inner()]
}
}
/// Struct holding necessary information to build a `Money::TokenFreezeV1` contract call.
pub struct TokenFreezeCallBuilder {
/// Mint authority keypair
pub mint_authority: Keypair,
pub mint_keypair: Keypair,
pub token_attrs: TokenAttributes,
/// `TokenFreeze_V1` zkas circuit ZkBinary
pub token_freeze_zkbin: ZkBinary,
pub freeze_zkbin: ZkBinary,
/// Proving key for the `TokenFreeze_V1` zk circuit,
pub token_freeze_pk: ProvingKey,
pub freeze_pk: ProvingKey,
}
impl TokenFreezeCallBuilder {
@@ -63,32 +49,25 @@ impl TokenFreezeCallBuilder {
// For the TokenFreeze call, we just need to produce a valid signature,
// and enforce the correct derivation inside ZK.
debug!("Creating token freeze ZK proof");
let (proof, _public_inputs) = create_token_freeze_proof(
&self.token_freeze_zkbin,
&self.token_freeze_pk,
&self.mint_authority,
)?;
let prover_witnesses = vec![
// Token attributes
Witness::Base(Value::known(self.token_attrs.auth_parent.inner())),
Witness::Base(Value::known(self.token_attrs.blind)),
// Secret key used by mint
Witness::Base(Value::known(self.mint_keypair.secret.inner())),
];
let params = MoneyTokenFreezeParamsV1 { signature_public: self.mint_authority.public };
let mint_pubkey = self.mint_keypair.public;
let token_id = self.token_attrs.to_token_id();
let public_inputs = vec![mint_pubkey.x(), mint_pubkey.y(), token_id.inner()];
darkfi::zk::export_witness_json("witness.json", &prover_witnesses, &public_inputs);
let circuit = ZkCircuit::new(prover_witnesses, &self.freeze_zkbin);
let proof = Proof::create(&self.freeze_pk, &[circuit], &public_inputs, &mut OsRng)?;
let params = MoneyTokenFreezeParamsV1 { mint_public: self.mint_keypair.public, token_id };
let debris = TokenFreezeCallDebris { params, proofs: vec![proof] };
Ok(debris)
}
}
pub(crate) fn create_token_freeze_proof(
zkbin: &ZkBinary,
pk: &ProvingKey,
mint_authority: &Keypair,
) -> Result<(Proof, TokenFreezeRevealed)> {
let token_id = TokenId::derive(mint_authority.secret);
let public_inputs = TokenFreezeRevealed { signature_public: mint_authority.public, token_id };
let prover_witnesses = vec![Witness::Base(Value::known(mint_authority.secret.inner()))];
let circuit = ZkCircuit::new(prover_witnesses, zkbin);
let proof = Proof::create(pk, &[circuit], &public_inputs.to_vec(), &mut OsRng)?;
Ok((proof, public_inputs))
}

View File

@@ -21,205 +21,56 @@ use darkfi::{
zkas::ZkBinary,
Result,
};
use darkfi_sdk::{
crypto::{
note::AeadEncryptedNote, pasta_prelude::*, pedersen_commitment_u64, poseidon_hash, Keypair,
PublicKey, TokenId,
},
pasta::pallas,
};
use darkfi_sdk::pasta::pallas;
use log::info;
use rand::rngs::OsRng;
use crate::{
client::{
transfer_v1::{TransferCallClearInput, TransferCallOutput},
MoneyNote,
},
model::{ClearInput, Coin, MoneyTokenMintParamsV1, Output},
};
use crate::model::{CoinAttributes, MoneyTokenMintParamsV1, TokenAttributes};
pub struct TokenMintCallDebris {
pub params: MoneyTokenMintParamsV1,
pub proofs: Vec<Proof>,
}
pub struct TokenMintRevealed {
pub signature_public: PublicKey,
pub token_id: TokenId,
pub coin: Coin,
pub value_commit: pallas::Point,
pub token_commit: pallas::Base,
}
impl TokenMintRevealed {
pub fn to_vec(&self) -> Vec<pallas::Base> {
let (sig_x, sig_y) = self.signature_public.xy();
let valcom_coords = self.value_commit.to_affine().coordinates().unwrap();
// NOTE: It's important to keep these in the same order
// as the `constrain_instance` calls in the zkas code.
vec![
sig_x,
sig_y,
self.token_id.inner(),
self.coin.inner(),
*valcom_coords.x(),
*valcom_coords.y(),
self.token_commit,
]
}
}
/// Struct holding necessary information to build a `Money::TokenMintV1` contract call.
pub struct TokenMintCallBuilder {
/// Mint authority keypair
pub mint_authority: Keypair,
/// Recipient of the minted tokens
pub recipient: PublicKey,
/// Amount of tokens we want to mint
pub amount: u64,
/// Spend hook for the output
pub spend_hook: pallas::Base,
/// User data for the output
pub user_data: pallas::Base,
pub coin_attrs: CoinAttributes,
pub token_attrs: TokenAttributes,
/// `TokenMint_V1` zkas circuit ZkBinary
pub token_mint_zkbin: ZkBinary,
pub mint_zkbin: ZkBinary,
/// Proving key for the `TokenMint_V1` zk circuit,
pub token_mint_pk: ProvingKey,
pub mint_pk: ProvingKey,
}
impl TokenMintCallBuilder {
pub fn build(&self) -> Result<TokenMintCallDebris> {
info!("Building Money::TokenMintV1 contract call");
assert!(self.amount != 0);
let (public_x, public_y) = self.coin_attrs.public_key.xy();
// In this call, we will build one clear input and one anonymous output.
// The mint authority pubkey is used to derive the token ID.
let token_id = TokenId::derive(self.mint_authority.secret);
let prover_witnesses = vec![
// Coin attributes
Witness::Base(Value::known(public_x)),
Witness::Base(Value::known(public_y)),
Witness::Base(Value::known(pallas::Base::from(self.coin_attrs.value))),
Witness::Base(Value::known(self.coin_attrs.spend_hook)),
Witness::Base(Value::known(self.coin_attrs.user_data)),
Witness::Base(Value::known(self.coin_attrs.blind)),
// Token attributes
Witness::Base(Value::known(self.token_attrs.auth_parent.inner())),
Witness::Base(Value::known(self.token_attrs.user_data)),
Witness::Base(Value::known(self.token_attrs.blind)),
];
let input = TransferCallClearInput {
value: self.amount,
token_id,
signature_secret: self.mint_authority.secret,
};
let coin = self.coin_attrs.to_coin();
let output = TransferCallOutput {
public_key: self.recipient,
value: self.amount,
token_id,
spend_hook: pallas::Base::ZERO,
user_data: pallas::Base::ZERO,
blind: pallas::Base::random(&mut OsRng),
};
let public_inputs = vec![self.token_attrs.auth_parent.inner(), coin.inner()];
// We just create the pedersen commitment blinds here. We simply
// enforce that the clear input and the anon output have the same
// commitments. Not sure if this can be avoided, but also is it
// really necessary to avoid?
let value_blind = pallas::Scalar::random(&mut OsRng);
let token_blind = pallas::Base::random(&mut OsRng);
let circuit = ZkCircuit::new(prover_witnesses, &self.mint_zkbin);
let proof = Proof::create(&self.mint_pk, &[circuit], &public_inputs, &mut OsRng)?;
let c_input = ClearInput {
value: input.value,
token_id: input.token_id,
value_blind,
token_blind,
signature_public: PublicKey::from_secret(input.signature_secret),
};
let coin_blind = pallas::Base::random(&mut OsRng);
info!("Creating token mint proof for output");
let (proof, public_inputs) = create_token_mint_proof(
&self.token_mint_zkbin,
&self.token_mint_pk,
&output,
&self.mint_authority,
value_blind,
token_blind,
self.spend_hook,
self.user_data,
coin_blind,
)?;
let note = MoneyNote {
value: output.value,
token_id: output.token_id,
spend_hook: self.spend_hook,
user_data: self.user_data,
coin_blind,
value_blind,
token_blind,
memo: vec![],
};
let encrypted_note = AeadEncryptedNote::encrypt(&note, &output.public_key, &mut OsRng)?;
let c_output = Output {
value_commit: public_inputs.value_commit,
token_commit: public_inputs.token_commit,
coin: public_inputs.coin,
note: encrypted_note,
};
let params = MoneyTokenMintParamsV1 { input: c_input, output: c_output };
let params = MoneyTokenMintParamsV1 { coin };
let debris = TokenMintCallDebris { params, proofs: vec![proof] };
Ok(debris)
}
}
#[allow(clippy::too_many_arguments)]
pub fn create_token_mint_proof(
zkbin: &ZkBinary,
pk: &ProvingKey,
output: &TransferCallOutput,
mint_authority: &Keypair,
value_blind: pallas::Scalar,
token_blind: pallas::Base,
spend_hook: pallas::Base,
user_data: pallas::Base,
coin_blind: pallas::Base,
) -> Result<(Proof, TokenMintRevealed)> {
let token_id = TokenId::derive(mint_authority.secret);
let value_commit = pedersen_commitment_u64(output.value, value_blind);
let token_commit = poseidon_hash([token_id.inner(), token_blind]);
let (rcpt_x, rcpt_y) = output.public_key.xy();
let coin = Coin::from(poseidon_hash([
rcpt_x,
rcpt_y,
pallas::Base::from(output.value),
token_id.inner(),
spend_hook,
user_data,
coin_blind,
]));
let public_inputs = TokenMintRevealed {
signature_public: mint_authority.public,
token_id,
coin,
value_commit,
token_commit,
};
let prover_witnesses = vec![
Witness::Base(Value::known(mint_authority.secret.inner())),
Witness::Base(Value::known(pallas::Base::from(output.value))),
Witness::Base(Value::known(rcpt_x)),
Witness::Base(Value::known(rcpt_y)),
Witness::Base(Value::known(spend_hook)),
Witness::Base(Value::known(user_data)),
Witness::Base(Value::known(coin_blind)),
Witness::Scalar(Value::known(value_blind)),
Witness::Base(Value::known(token_blind)),
];
let circuit = ZkCircuit::new(prover_witnesses, zkbin);
let proof = Proof::create(pk, &[circuit], &public_inputs.to_vec(), &mut OsRng)?;
Ok((proof, public_inputs))
}

View File

@@ -29,8 +29,9 @@ use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
use crate::{
model::{
MoneyFeeUpdateV1, MoneyGenesisMintUpdateV1, MoneyPoWRewardUpdateV1,
MoneyTokenFreezeUpdateV1, MoneyTokenMintUpdateV1, MoneyTransferUpdateV1,
MoneyAuthTokenMintUpdateV1, MoneyFeeUpdateV1, MoneyGenesisMintUpdateV1,
MoneyPoWRewardUpdateV1, MoneyTokenFreezeUpdateV1, MoneyTokenMintUpdateV1,
MoneyTransferUpdateV1,
},
MoneyFunction, MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE,
MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_DB_VERSION, MONEY_CONTRACT_FAUCET_PUBKEYS,
@@ -86,6 +87,13 @@ use pow_reward_v1::{
money_pow_reward_process_update_v1,
};
/// `Money::AuthTokenMint` functions
mod auth_token_mint_v1;
use auth_token_mint_v1::{
money_auth_token_mint_get_metadata_v1, money_auth_token_mint_process_instruction_v1,
money_auth_token_mint_process_update_v1,
};
darkfi_sdk::define_contract!(
init: init_contract,
exec: process_instruction,
@@ -196,6 +204,9 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
MoneyFunction::TokenMintV1 => money_token_mint_get_metadata_v1(cid, call_idx, calls)?,
MoneyFunction::TokenFreezeV1 => money_token_freeze_get_metadata_v1(cid, call_idx, calls)?,
MoneyFunction::PoWRewardV1 => money_pow_reward_get_metadata_v1(cid, call_idx, calls)?,
MoneyFunction::AuthTokenMintV1 => {
money_auth_token_mint_get_metadata_v1(cid, call_idx, calls)?
}
};
set_return_data(&metadata)
@@ -232,6 +243,9 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
MoneyFunction::PoWRewardV1 => {
money_pow_reward_process_instruction_v1(cid, call_idx, calls)?
}
MoneyFunction::AuthTokenMintV1 => {
money_auth_token_mint_process_instruction_v1(cid, call_idx, calls)?
}
};
set_return_data(&update_data)
@@ -279,5 +293,10 @@ fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
let update: MoneyPoWRewardUpdateV1 = deserialize(&update_data[1..])?;
Ok(money_pow_reward_process_update_v1(cid, update)?)
}
MoneyFunction::AuthTokenMintV1 => {
let update: MoneyAuthTokenMintUpdateV1 = deserialize(&update_data[1..])?;
Ok(money_auth_token_mint_process_update_v1(cid, update)?)
}
}
}

View File

@@ -0,0 +1,112 @@
/* This file is part of DarkFi (https://dark.fi)
*
* Copyright (C) 2020-2024 Dyne.org foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use darkfi_sdk::{
crypto::{pasta_prelude::*, ContractId, PublicKey},
dark_tree::DarkLeaf,
db::{db_contains_key, db_lookup},
error::{ContractError, ContractResult},
msg,
pasta::pallas,
ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
use crate::{
error::MoneyError,
model::{MoneyAuthTokenMintParamsV1, MoneyAuthTokenMintUpdateV1, MoneyTokenMintParamsV1},
MoneyFunction, MONEY_CONTRACT_TOKEN_FREEZE_TREE, MONEY_CONTRACT_ZKAS_AUTH_TOKEN_MINT_NS_V1,
};
/// `get_metadata` function for `Money::AuthTokenMintV1`
pub(crate) fn money_auth_token_mint_get_metadata_v1(
_cid: ContractId,
call_idx: u32,
calls: Vec<DarkLeaf<ContractCall>>,
) -> Result<Vec<u8>, ContractError> {
let self_node = &calls[call_idx as usize];
let self_data = &self_node.data;
let self_params: MoneyAuthTokenMintParamsV1 = deserialize(&self_data.data[1..])?;
assert_eq!(self_node.children_indexes.len(), 1);
let child_idx = self_node.children_indexes[0];
let child_node = &calls[child_idx];
let child_data = &child_node.data;
let child_params: MoneyTokenMintParamsV1 = deserialize(&child_data.data[1..])?;
// Public inputs for the ZK proofs we have to verify
let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)> = vec![];
// Public keys for the transaction signatures we have to verify.
let signature_pubkeys: Vec<PublicKey> = vec![self_params.mint_pubkey];
let value_commit = self_params.value_commit.to_affine().coordinates().unwrap();
zk_public_inputs.push((
MONEY_CONTRACT_ZKAS_AUTH_TOKEN_MINT_NS_V1.to_string(),
vec![
self_params.mint_pubkey.x(),
self_params.mint_pubkey.y(),
self_params.token_id.inner(),
child_params.coin.inner(),
*value_commit.x(),
*value_commit.y(),
],
));
// Serialize everything gathered and return it
let mut metadata = vec![];
zk_public_inputs.encode(&mut metadata)?;
signature_pubkeys.encode(&mut metadata)?;
Ok(metadata)
}
/// `process_instruction` function for `Money::AuthTokenMintV1`
pub(crate) fn money_auth_token_mint_process_instruction_v1(
cid: ContractId,
call_idx: u32,
calls: Vec<DarkLeaf<ContractCall>>,
) -> Result<Vec<u8>, ContractError> {
let self_ = &calls[call_idx as usize].data;
let params: MoneyAuthTokenMintParamsV1 = deserialize(&self_.data[1..])?;
// We have to check if the token mint is frozen.
let token_freeze_db = db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
// Check that the mint is not frozen
if db_contains_key(token_freeze_db, &serialize(&params.token_id))? {
msg!("[MintV1] Error: Token mint for {} is frozen", params.token_id);
return Err(MoneyError::TokenMintFrozen.into())
}
// Create a state update.
let update = MoneyAuthTokenMintUpdateV1 {};
let mut update_data = vec![];
update_data.write_u8(MoneyFunction::AuthTokenMintV1 as u8)?;
update.encode(&mut update_data)?;
Ok(update_data)
}
/// `process_update` function for `Money::AuthTokenMintV1`
pub(crate) fn money_auth_token_mint_process_update_v1(
_cid: ContractId,
_update: MoneyAuthTokenMintUpdateV1,
) -> ContractResult {
// Do nothing... Coin is added with token_mint() call instead.
Ok(())
}

View File

@@ -17,7 +17,7 @@
*/
use darkfi_sdk::{
crypto::{ContractId, PublicKey, TokenId},
crypto::{ContractId, PublicKey},
dark_tree::DarkLeaf,
db::{db_contains_key, db_lookup, db_set},
error::{ContractError, ContractResult},
@@ -45,16 +45,15 @@ pub(crate) fn money_token_freeze_get_metadata_v1(
// Public inputs for the ZK proofs we have to verify
let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)> = vec![];
// Public keys for the transaction signatures we have to verify
let signature_pubkeys: Vec<PublicKey> = vec![params.signature_public];
let signature_pubkeys: Vec<PublicKey> = vec![params.mint_public];
// Derive the TokenId from the public key
let (sig_x, sig_y) = params.signature_public.xy();
let token_id = TokenId::derive_public(params.signature_public);
let (mint_x, mint_y) = params.mint_public.xy();
// In ZK we just verify that the token ID is properly derived from the authority.
zk_public_inputs.push((
MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1.to_string(),
vec![sig_x, sig_y, token_id.inner()],
vec![mint_x, mint_y, params.token_id.inner()],
));
// Serialize everything gathered and return it
@@ -76,16 +75,15 @@ pub(crate) fn money_token_freeze_process_instruction_v1(
// We just check if the mint was already frozen beforehand
let token_freeze_db = db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
let token_id = TokenId::derive_public(params.signature_public);
// Check that the mint is not frozen
if db_contains_key(token_freeze_db, &serialize(&token_id))? {
msg!("[MintV1] Error: Token mint for {} is frozen", token_id);
if db_contains_key(token_freeze_db, &serialize(&params.token_id))? {
msg!("[MintV1] Error: Token mint for {} is frozen", params.token_id);
return Err(MoneyError::TokenMintFrozen.into())
}
// Create a state update. We only need the new coin.
let update = MoneyTokenFreezeUpdateV1 { signature_public: params.signature_public };
let update = MoneyTokenFreezeUpdateV1 { token_id: params.token_id };
let mut update_data = vec![];
update_data.write_u8(MoneyFunction::TokenFreezeV1 as u8)?;
update.encode(&mut update_data)?;
@@ -99,9 +97,8 @@ pub(crate) fn money_token_freeze_process_update_v1(
update: MoneyTokenFreezeUpdateV1,
) -> ContractResult {
let token_freeze_db = db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
let token_id = TokenId::derive_public(update.signature_public);
msg!("[MintV1] Freezing mint for token {}", token_id);
db_set(token_freeze_db, &serialize(&token_id), &[])?;
msg!("[MintV1] Freezing mint for token {}", update.token_id);
db_set(token_freeze_db, &serialize(&update.token_id), &[])?;
Ok(())
}

View File

@@ -17,9 +17,7 @@
*/
use darkfi_sdk::{
crypto::{
pasta_prelude::*, pedersen_commitment_u64, poseidon_hash, ContractId, MerkleNode, TokenId,
},
crypto::{ContractId, FuncRef, MerkleNode, PublicKey},
dark_tree::DarkLeaf,
db::{db_contains_key, db_lookup, db_set},
error::{ContractError, ContractResult},
@@ -34,7 +32,7 @@ use crate::{
model::{MoneyTokenMintParamsV1, MoneyTokenMintUpdateV1},
MoneyFunction, MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE,
MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_LATEST_COIN_ROOT,
MONEY_CONTRACT_TOKEN_FREEZE_TREE, MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1,
MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1,
};
/// `get_metadata` function for `Money::TokenMintV1`
@@ -46,31 +44,22 @@ pub(crate) fn money_token_mint_get_metadata_v1(
let self_ = &calls[call_idx as usize].data;
let params: MoneyTokenMintParamsV1 = deserialize(&self_.data[1..])?;
let parent_idx = calls[call_idx as usize].parent_index.unwrap();
let parent_call = &calls[parent_idx].data;
let parent_contract_id = parent_call.contract_id;
let parent_func_code = parent_call.data[0];
// Public inputs for the ZK proofs we have to verify
let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)> = vec![];
// Public keys for the transaction signatures we have to verify.
// The minting transaction creates 1 clear input and 1 anonymous output.
// We check the signature from the clear input, which is supposed to be
// signed by the mint authority.
let signature_pubkeys = vec![params.input.signature_public];
let signature_pubkeys: Vec<PublicKey> = vec![];
// Derive the TokenId from the public key
let (sig_x, sig_y) = params.input.signature_public.xy();
let token_id = TokenId::derive_public(params.input.signature_public);
let value_coords = params.output.value_commit.to_affine().coordinates().unwrap();
let parent_func_id =
FuncRef { contract_id: parent_contract_id, func_code: parent_func_code }.to_func_id();
zk_public_inputs.push((
MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1.to_string(),
vec![
sig_x,
sig_y,
token_id.inner(),
params.output.coin.inner(),
*value_coords.x(),
*value_coords.y(),
params.output.token_commit,
],
vec![parent_func_id.inner(), params.coin.inner()],
));
// Serialize everything gathered and return it
@@ -93,46 +82,15 @@ pub(crate) fn money_token_mint_process_instruction_v1(
// We have to check if the token mint is frozen, and if by some chance
// the minted coin has existed already.
let coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
let token_freeze_db = db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
// Check that the signature public key is actually the token ID
let token_id = TokenId::derive_public(params.input.signature_public);
if token_id != params.input.token_id {
msg!("[MintV1] Error: Token ID does not derive from mint authority");
return Err(MoneyError::TokenIdDoesNotDeriveFromMint.into())
}
// Check that the mint is not frozen
if db_contains_key(token_freeze_db, &serialize(&token_id))? {
msg!("[MintV1] Error: Token mint for {} is frozen", token_id);
return Err(MoneyError::TokenMintFrozen.into())
}
// Check that the coin from the output hasn't existed before
if db_contains_key(coins_db, &serialize(&params.output.coin))? {
if db_contains_key(coins_db, &serialize(&params.coin))? {
msg!("[MintV1] Error: Duplicate coin in output");
return Err(MoneyError::DuplicateCoin.into())
}
// Verify that the value and token commitments match. In here we just
// confirm that the clear input and the anon output have the same
// commitments.
if pedersen_commitment_u64(params.input.value, params.input.value_blind) !=
params.output.value_commit
{
msg!("[MintV1] Error: Value commitment mismatch");
return Err(MoneyError::ValueMismatch.into())
}
if poseidon_hash([params.input.token_id.inner(), params.input.token_blind]) !=
params.output.token_commit
{
msg!("[MintV1] Error: Token commitment mismatch");
return Err(MoneyError::TokenMismatch.into())
}
// Create a state update. We only need the new coin.
let update = MoneyTokenMintUpdateV1 { coin: params.output.coin };
let update = MoneyTokenMintUpdateV1 { coin: params.coin };
let mut update_data = vec![];
update_data.write_u8(MoneyFunction::TokenMintV1 as u8)?;
update.encode(&mut update_data)?;

View File

@@ -32,6 +32,7 @@ pub enum MoneyFunction {
TokenMintV1 = 0x04,
TokenFreezeV1 = 0x05,
PoWRewardV1 = 0x06,
AuthTokenMintV1 = 0x07,
}
// ANCHOR_END: money-function
@@ -47,6 +48,7 @@ impl TryFrom<u8> for MoneyFunction {
0x04 => Ok(Self::TokenMintV1),
0x05 => Ok(Self::TokenFreezeV1),
0x06 => Ok(Self::PoWRewardV1),
0x07 => Ok(Self::AuthTokenMintV1),
_ => Err(ContractError::InvalidFunction),
}
}
@@ -90,3 +92,5 @@ pub const MONEY_CONTRACT_ZKAS_BURN_NS_V1: &str = "Burn_V1";
pub const MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1: &str = "TokenMint_V1";
/// zkas token freeze circuit namespace
pub const MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1: &str = "TokenFreeze_V1";
/// zkas token auth mint circuit namespace
pub const MONEY_CONTRACT_ZKAS_AUTH_TOKEN_MINT_NS_V1: &str = "AuthTokenMint_V1";

View File

@@ -18,7 +18,7 @@
use darkfi_sdk::{
crypto::{
ecvrf::VrfProof, note::AeadEncryptedNote, pasta_prelude::PrimeField, poseidon_hash,
ecvrf::VrfProof, note::AeadEncryptedNote, pasta_prelude::PrimeField, poseidon_hash, FuncId,
MerkleNode, Nullifier, PublicKey, SecretKey, TokenId,
},
error::ContractError,
@@ -90,6 +90,20 @@ impl CoinAttributes {
}
}
#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
pub struct TokenAttributes {
pub auth_parent: FuncId,
pub user_data: pallas::Base,
pub blind: pallas::Base,
}
impl TokenAttributes {
pub fn to_token_id(&self) -> TokenId {
let token_id = poseidon_hash([self.auth_parent.inner(), self.user_data, self.blind]);
TokenId::from(token_id)
}
}
#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
pub struct NullifierAttributes {
/// Secret key for the public key in the coin.
@@ -228,10 +242,8 @@ pub struct MoneyGenesisMintUpdateV1 {
/// Parameters for `Money::TokenMint`
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct MoneyTokenMintParamsV1 {
/// Clear input
pub input: ClearInput,
/// Anonymous output
pub output: Output,
/// The newly minted coin
pub coin: Coin,
}
/// State update for `Money::TokenMint`
@@ -241,20 +253,33 @@ pub struct MoneyTokenMintUpdateV1 {
pub coin: Coin,
}
/// Parameters for `Money::auth_token_mint()`
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct MoneyAuthTokenMintParamsV1 {
pub token_id: TokenId,
pub value_commit: pallas::Point,
pub enc_note: AeadEncryptedNote,
pub mint_pubkey: PublicKey,
}
/// State update for `Money::auth_token_mint()`
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct MoneyAuthTokenMintUpdateV1 {}
/// Parameters for `Money::TokenFreeze`
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct MoneyTokenFreezeParamsV1 {
/// Mint authority public key
///
/// We use this to derive the token ID and verify the signature.
pub signature_public: PublicKey,
pub mint_public: PublicKey,
pub token_id: TokenId,
}
/// State update for `Money::TokenFreeze`
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct MoneyTokenFreezeUpdateV1 {
/// Mint authority public key
pub signature_public: PublicKey,
pub token_id: TokenId,
}
/// Parameters for `Money::PoWReward`

View File

@@ -106,7 +106,8 @@ fn genesis_mint() -> Result<()> {
th.assert_trees(&HOLDERS);
// Alice gathers her new owncoin
let alice_oc = th.gather_owncoin(&Holder::Alice, &genesis_mint_params.output, None)?;
let alice_oc =
th.gather_owncoin_from_output(&Holder::Alice, &genesis_mint_params.output, None)?;
alice_owncoins.push(alice_oc);
info!(target: "money", "[Bob] ========================");
@@ -130,7 +131,8 @@ fn genesis_mint() -> Result<()> {
th.assert_trees(&HOLDERS);
// Bob gathers his new owncoin
let bob_oc = th.gather_owncoin(&Holder::Bob, &genesis_mint_params.output, None)?;
let bob_oc =
th.gather_owncoin_from_output(&Holder::Bob, &genesis_mint_params.output, None)?;
bob_owncoins.push(bob_oc);
// Now Alice can send a little bit of funds to Bob
@@ -164,11 +166,13 @@ fn genesis_mint() -> Result<()> {
th.assert_trees(&HOLDERS);
// Bob should have his old OwnCoin, and this new one.
let bob_oc = th.gather_owncoin(&Holder::Bob, &transfer_params.outputs[0], None)?;
let bob_oc =
th.gather_owncoin_from_output(&Holder::Bob, &transfer_params.outputs[0], None)?;
bob_owncoins.push(bob_oc);
// Alice should now have one OwnCoin with the change from the above transaction.
let alice_oc = th.gather_owncoin(&Holder::Alice, &transfer_params.outputs[1], None)?;
let alice_oc =
th.gather_owncoin_from_output(&Holder::Alice, &transfer_params.outputs[1], None)?;
alice_owncoins.push(alice_oc);
assert!(alice_owncoins.len() == 1);
@@ -205,11 +209,13 @@ fn genesis_mint() -> Result<()> {
th.assert_trees(&HOLDERS);
// Alice should now have two OwnCoins
let alice_oc = th.gather_owncoin(&Holder::Alice, &transfer_params.outputs[0], None)?;
let alice_oc =
th.gather_owncoin_from_output(&Holder::Alice, &transfer_params.outputs[0], None)?;
alice_owncoins.push(alice_oc);
// Bob should have two with the change from the above tx
let bob_oc = th.gather_owncoin(&Holder::Bob, &transfer_params.outputs[1], None)?;
let bob_oc =
th.gather_owncoin_from_output(&Holder::Bob, &transfer_params.outputs[1], None)?;
bob_owncoins.push(bob_oc);
// Validating transaction outcomes

View File

@@ -52,7 +52,7 @@ fn money_integration() -> Result<()> {
}
let alice_owncoin =
th.gather_owncoin(&Holder::Alice, &alice_proposal_params.output, None)?;
th.gather_owncoin_from_output(&Holder::Alice, &alice_proposal_params.output, None)?;
assert!(alice_owncoin.note.value == expected_reward(current_block_height));
th.assert_trees(&HOLDERS);
@@ -73,7 +73,7 @@ fn money_integration() -> Result<()> {
.await?;
}
let _ = th.gather_owncoin(&Holder::Bob, &bob_proposal_params.output, None)?;
let _ = th.gather_owncoin_from_output(&Holder::Bob, &bob_proposal_params.output, None)?;
th.assert_trees(&HOLDERS);

View File

@@ -62,40 +62,42 @@ fn mint_pay_swap() -> Result<()> {
info!(target: "money", "[Alice] ================================");
info!(target: "money", "[Alice] Building token mint tx for Alice");
info!(target: "money", "[Alice] ================================");
let (mint_tx, params) =
let (mint_tx, mint_params, mint_auth_params) =
th.token_mint(ALICE_INITIAL, &Holder::Alice, &Holder::Alice, None, None)?;
for holder in &HOLDERS {
info!(target: "money", "[{holder:?}] ==============================");
info!(target: "money", "[{holder:?}] Executing Alice token mint tx");
info!(target: "money", "[{holder:?}] ==============================");
th.execute_token_mint_tx(holder, &mint_tx, &params, current_block_height).await?;
th.execute_token_mint_tx(holder, &mint_tx, &mint_params, current_block_height).await?;
}
th.assert_trees(&HOLDERS);
// Alice gathers her new owncoin
let alice_oc = th.gather_owncoin(&Holder::Alice, &params.output, None)?;
let alice_oc =
th.gather_owncoin(&Holder::Alice, &mint_params.coin, &mint_auth_params.enc_note, None)?;
let alice_token_id = alice_oc.note.token_id;
alice_owncoins.push(alice_oc);
info!(target: "money", "[Bob] ==============================");
info!(target: "money", "[Bob] Building token mint tx for Bob");
info!(target: "money", "[Bob] ==============================");
let (mint_tx, params) =
let (mint_tx, mint_params, mint_auth_params) =
th.token_mint(BOB_INITIAL, &Holder::Bob, &Holder::Bob, None, None)?;
for holder in &HOLDERS {
info!(target: "money", "[{holder:?}] ===========================");
info!(target: "money", "[{holder:?}] Executing Bob token mint tx");
info!(target: "money", "[{holder:?}] ===========================");
th.execute_token_mint_tx(holder, &mint_tx, &params, current_block_height).await?;
th.execute_token_mint_tx(holder, &mint_tx, &mint_params, current_block_height).await?;
}
th.assert_trees(&HOLDERS);
// Bob gathers hist new owncoin
let bob_oc = th.gather_owncoin(&Holder::Bob, &params.output, None)?;
let bob_oc =
th.gather_owncoin(&Holder::Bob, &mint_params.coin, &mint_auth_params.enc_note, None)?;
let bob_token_id = bob_oc.note.token_id;
bob_owncoins.push(bob_oc);
@@ -282,7 +284,7 @@ fn mint_pay_swap() -> Result<()> {
th.assert_trees(&HOLDERS);
// Alice should now have a single OwnCoin with her initial airdrop
let alice_oc = th.gather_owncoin(&Holder::Alice, &params.outputs[0], None)?;
let alice_oc = th.gather_owncoin_from_output(&Holder::Alice, &params.outputs[0], None)?;
alice_owncoins.push(alice_oc);
assert!(alice_owncoins.len() == 1);
@@ -313,7 +315,7 @@ fn mint_pay_swap() -> Result<()> {
th.assert_trees(&HOLDERS);
// Bob should now have a single OwnCoin with his initial airdrop
let bob_oc = th.gather_owncoin(&Holder::Bob, &params.outputs[0], None)?;
let bob_oc = th.gather_owncoin_from_output(&Holder::Bob, &params.outputs[0], None)?;
bob_owncoins.push(bob_oc);
assert!(bob_owncoins.len() == 1);

View File

@@ -105,7 +105,8 @@ fn pow_reward() -> Result<()> {
th.assert_trees(&HOLDERS);
// Alice gathers her new owncoin
let alice_oc = th.gather_owncoin(&Holder::Alice, &pow_reward_params.output, None)?;
let alice_oc =
th.gather_owncoin_from_output(&Holder::Alice, &pow_reward_params.output, None)?;
alice_owncoins.push(alice_oc);
// Now Alice can send a little bit of funds to Bob
@@ -140,11 +141,13 @@ fn pow_reward() -> Result<()> {
th.assert_trees(&HOLDERS);
// Bob should have this new OwnCoin.
let bob_oc = th.gather_owncoin(&Holder::Bob, &transfer_params.outputs[0], None)?;
let bob_oc =
th.gather_owncoin_from_output(&Holder::Bob, &transfer_params.outputs[0], None)?;
bob_owncoins.push(bob_oc);
// Alice should now have one OwnCoin with the change from the above transaction.
let alice_oc = th.gather_owncoin(&Holder::Alice, &transfer_params.outputs[1], None)?;
let alice_oc =
th.gather_owncoin_from_output(&Holder::Alice, &transfer_params.outputs[1], None)?;
alice_owncoins.push(alice_oc);
// Alice can also send her PoW reward directly to bob
@@ -170,7 +173,8 @@ fn pow_reward() -> Result<()> {
th.assert_trees(&HOLDERS);
// Bob gathers his new owncoin
let bob_oc = th.gather_owncoin(&Holder::Bob, &pow_reward_params.output, None)?;
let bob_oc =
th.gather_owncoin_from_output(&Holder::Bob, &pow_reward_params.output, None)?;
bob_owncoins.push(bob_oc);
// Validating transaction outcomes

View File

@@ -38,7 +38,7 @@ fn token_mint() -> Result<()> {
let mut th = TestHarness::new(&["money".to_string()], false).await?;
info!("[Bob] Building BOB token mint tx");
let (token_mint_tx, token_mint_params) =
let (token_mint_tx, token_mint_params, token_auth_mint_params) =
th.token_mint(BOB_SUPPLY, &Holder::Bob, &Holder::Bob, None, None)?;
for holder in &HOLDERS {
@@ -55,7 +55,12 @@ fn token_mint() -> Result<()> {
th.assert_trees(&HOLDERS);
// Bob gathers his new coin
th.gather_owncoin(&Holder::Bob, &token_mint_params.output, None)?;
th.gather_owncoin(
&Holder::Bob,
&token_mint_params.coin,
&token_auth_mint_params.enc_note,
None,
)?;
info!("[Bob] Building BOB token freeze tx");
let (token_frz_tx, token_frz_params) = th.token_freeze(&Holder::Bob)?;

View File

@@ -55,7 +55,7 @@ fn txs_verification() -> Result<()> {
info!(target: "money", "[Alice] ================================");
info!(target: "money", "[Alice] Building token mint tx for Alice");
info!(target: "money", "[Alice] ================================");
let (token_mint_tx, token_mint_params) =
let (token_mint_tx, token_mint_params, token_auth_mint_params) =
th.token_mint(ALICE_INITIAL, &Holder::Alice, &Holder::Alice, None, None)?;
for holder in &HOLDERS {
@@ -74,7 +74,12 @@ fn txs_verification() -> Result<()> {
th.assert_trees(&HOLDERS);
// Alice gathers her new owncoin
let alice_oc = th.gather_owncoin(&Holder::Alice, &token_mint_params.output, None)?;
let alice_oc = th.gather_owncoin(
&Holder::Alice,
&token_mint_params.coin,
&token_auth_mint_params.enc_note,
None,
)?;
let alice_token_id = alice_oc.note.token_id;
alice_owncoins.push(alice_oc);
@@ -144,11 +149,13 @@ fn txs_verification() -> Result<()> {
th.assert_trees(&HOLDERS);
// Bob should now have the new OwnCoin.
let bob_oc = th.gather_owncoin(&Holder::Bob, &txs_params[0].outputs[0], None)?;
let bob_oc =
th.gather_owncoin_from_output(&Holder::Bob, &txs_params[0].outputs[0], None)?;
bob_owncoins.push(bob_oc);
// Alice should now have one OwnCoin with the change from the above transaction.
let alice_oc = th.gather_owncoin(&Holder::Alice, &txs_params[0].outputs[1], None)?;
let alice_oc =
th.gather_owncoin_from_output(&Holder::Alice, &txs_params[0].outputs[1], None)?;
alice_owncoins.push(alice_oc);
assert!(alice_owncoins.len() == 1);

View File

@@ -75,7 +75,8 @@ fn alice2alice_random_amounts() -> Result<()> {
// Gather new owncoins
let mut owncoins = vec![];
let owncoin = th.gather_owncoin(&Holder::Alice, &airdrop_params.outputs[0], None)?;
let owncoin =
th.gather_owncoin_from_output(&Holder::Alice, &airdrop_params.outputs[0], None)?;
let token_id = owncoin.note.token_id;
owncoins.push(owncoin);
@@ -175,7 +176,8 @@ fn alice2alice_multiplecoins_random_amounts() -> Result<()> {
th.assert_trees(&HOLDERS);
// Gather new owncoins
let owncoin = th.gather_owncoin(&Holder::Alice, &mint_params.output, None)?;
let owncoin =
th.gather_owncoin_from_output(&Holder::Alice, &mint_params.output, None)?;
let token_id = owncoin.note.token_id;
owncoins.push(vec![owncoin]);
minted_amounts.push(amount);

View File

@@ -33,13 +33,13 @@ use darkfi::{
use darkfi_dao_contract::model::{DaoBulla, DaoProposalBulla};
use darkfi_money_contract::{
client::{MoneyNote, OwnCoin},
model::Output,
model::{Coin, Output},
};
use darkfi_sdk::{
bridgetree,
crypto::{
pasta_prelude::Field, poseidon_hash, ContractId, Keypair, MerkleNode, MerkleTree,
Nullifier, PublicKey, SecretKey, TokenId,
note::AeadEncryptedNote, pasta_prelude::Field, poseidon_hash, ContractId, Keypair,
MerkleNode, MerkleTree, Nullifier, PublicKey, SecretKey,
},
pasta::pallas,
};
@@ -115,6 +115,7 @@ pub enum TxAction {
pub struct Wallet {
pub keypair: Keypair,
pub token_mint_authority: Keypair,
pub token_blind: pallas::Base,
pub contract_deploy_authority: Keypair,
pub validator: ValidatorPtr,
pub money_merkle_tree: MerkleTree,
@@ -168,11 +169,13 @@ impl Wallet {
let spent_money_coins = vec![];
let token_mint_authority = Keypair::random(&mut OsRng);
let token_blind = pallas::Base::random(&mut OsRng);
let contract_deploy_authority = Keypair::random(&mut OsRng);
Ok(Self {
keypair,
token_mint_authority,
token_blind,
contract_deploy_authority,
validator,
money_merkle_tree,
@@ -288,7 +291,8 @@ impl TestHarness {
pub fn gather_owncoin(
&mut self,
holder: &Holder,
output: &Output,
coin: &Coin,
note: &AeadEncryptedNote,
secret_key: Option<SecretKey>,
) -> Result<OwnCoin> {
let wallet = self.holders.get_mut(holder).unwrap();
@@ -298,14 +302,14 @@ impl TestHarness {
None => wallet.keypair.secret,
};
let note: MoneyNote = output.note.decrypt(&secret_key)?;
let note: MoneyNote = note.decrypt(&secret_key)?;
let oc = OwnCoin {
coin: output.coin,
coin: coin.clone(),
note: note.clone(),
secret: secret_key,
nullifier: Nullifier::from(poseidon_hash([
wallet.keypair.secret.inner(),
output.coin.inner(),
coin.inner(),
])),
leaf_position,
};
@@ -315,6 +319,15 @@ impl TestHarness {
Ok(oc)
}
pub fn gather_owncoin_from_output(
&mut self,
holder: &Holder,
output: &Output,
secret_key: Option<SecretKey>,
) -> Result<OwnCoin> {
self.gather_owncoin(holder, &output.coin, &output.note, secret_key)
}
/// This should be used after transfer call, so we can mark the merkle tree
/// before each output coin. Assumes using wallet secret key.
pub fn gather_multiple_owncoins(
@@ -397,11 +410,6 @@ impl TestHarness {
}
}
pub fn token_id(&self, holder: &Holder) -> TokenId {
let holder = self.holders.get(holder).unwrap();
TokenId::derive_public(holder.token_mint_authority.public)
}
pub fn contract_id(&self, holder: &Holder) -> ContractId {
let holder = self.holders.get(holder).unwrap();
ContractId::derive_public(holder.contract_deploy_authority.public)

View File

@@ -147,7 +147,7 @@ impl TestHarness {
self.assert_trees(holders);
// Gather new owncoin
let oc = self.gather_owncoin(holder, &airdrop_params.outputs[0], None)?;
let oc = self.gather_owncoin_from_output(holder, &airdrop_params.outputs[0], None)?;
Ok(oc)
}

View File

@@ -23,8 +23,8 @@ use darkfi::{
Result,
};
use darkfi_money_contract::{
client::genesis_mint_v1::GenesisMintCallBuilder, model::MoneyTokenMintParamsV1, MoneyFunction,
MONEY_CONTRACT_ZKAS_MINT_NS_V1,
client::genesis_mint_v1::GenesisMintCallBuilder, model::MoneyGenesisMintParamsV1,
MoneyFunction, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
};
use darkfi_sdk::{
crypto::{MerkleNode, MONEY_CONTRACT_ID},
@@ -41,7 +41,7 @@ impl TestHarness {
&mut self,
holder: &Holder,
amount: u64,
) -> Result<(Transaction, MoneyTokenMintParamsV1)> {
) -> Result<(Transaction, MoneyGenesisMintParamsV1)> {
let wallet = self.holders.get(holder).unwrap();
let (mint_pk, mint_zkbin) =
@@ -92,7 +92,7 @@ impl TestHarness {
&mut self,
holder: &Holder,
tx: &Transaction,
params: &MoneyTokenMintParamsV1,
params: &MoneyGenesisMintParamsV1,
block_height: u64,
) -> Result<()> {
let wallet = self.holders.get_mut(holder).unwrap();

View File

@@ -24,12 +24,20 @@ use darkfi::{
Result,
};
use darkfi_money_contract::{
client::{token_freeze_v1::TokenFreezeCallBuilder, token_mint_v1::TokenMintCallBuilder},
model::{MoneyTokenFreezeParamsV1, MoneyTokenMintParamsV1},
MoneyFunction, MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1, MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1,
client::{
auth_token_mint_v1::AuthTokenMintCallBuilder, token_freeze_v1::TokenFreezeCallBuilder,
token_mint_v1::TokenMintCallBuilder,
},
model::{
CoinAttributes, MoneyAuthTokenMintParamsV1, MoneyTokenFreezeParamsV1,
MoneyTokenMintParamsV1, TokenAttributes,
},
MoneyFunction, MONEY_CONTRACT_ZKAS_AUTH_TOKEN_MINT_NS_V1, MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1,
MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1,
};
use darkfi_sdk::{
crypto::{MerkleNode, MONEY_CONTRACT_ID},
crypto::{poseidon_hash, FuncRef, MerkleNode, MONEY_CONTRACT_ID},
dark_tree::DarkLeaf,
pasta::pallas,
ContractCall,
};
@@ -46,40 +54,85 @@ impl TestHarness {
recipient: &Holder,
spend_hook: Option<pallas::Base>,
user_data: Option<pallas::Base>,
) -> Result<(Transaction, MoneyTokenMintParamsV1)> {
) -> Result<(Transaction, MoneyTokenMintParamsV1, MoneyAuthTokenMintParamsV1)> {
let wallet = self.holders.get(holder).unwrap();
let mint_authority = wallet.token_mint_authority;
let token_blind = wallet.token_blind;
let rcpt = self.holders.get(recipient).unwrap().keypair.public;
let (mint_pk, mint_zkbin) =
self.proving_keys.get(&MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1.to_string()).unwrap();
let (mint_pk, mint_zkbin) = self
.proving_keys
.get(&MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1.to_string())
.unwrap()
.clone();
let (auth_mint_pk, auth_mint_zkbin) = self
.proving_keys
.get(&MONEY_CONTRACT_ZKAS_AUTH_TOKEN_MINT_NS_V1.to_string())
.unwrap()
.clone();
let tx_action_benchmark =
self.tx_action_benchmarks.get_mut(&TxAction::MoneyTokenMint).unwrap();
let timer = Instant::now();
let builder = TokenMintCallBuilder {
mint_authority,
recipient: rcpt,
amount,
let auth_func_id = FuncRef {
contract_id: *MONEY_CONTRACT_ID,
func_code: MoneyFunction::AuthTokenMintV1 as u8,
}
.to_func_id();
let token_attrs = TokenAttributes {
auth_parent: auth_func_id,
user_data: poseidon_hash([mint_authority.public.x(), mint_authority.public.y()]),
blind: token_blind,
};
let token_id = token_attrs.to_token_id();
let coin_attrs = CoinAttributes {
public_key: rcpt,
value: amount,
token_id,
spend_hook: spend_hook.unwrap_or(pallas::Base::ZERO),
user_data: user_data.unwrap_or(pallas::Base::ZERO),
token_mint_zkbin: mint_zkbin.clone(),
token_mint_pk: mint_pk.clone(),
blind: pallas::Base::random(&mut OsRng),
};
let debris = builder.build()?;
let builder = TokenMintCallBuilder {
coin_attrs: coin_attrs.clone(),
token_attrs: token_attrs.clone(),
mint_zkbin,
mint_pk,
};
let mint_debris = builder.build()?;
let mut data = vec![MoneyFunction::TokenMintV1 as u8];
debris.params.encode(&mut data)?;
let call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
let mut tx_builder =
TransactionBuilder::new(ContractCallLeaf { call, proofs: debris.proofs }, vec![])?;
let mut tx = tx_builder.build()?;
let sigs = tx.create_sigs(&mut OsRng, &[mint_authority.secret])?;
tx.signatures = vec![sigs];
mint_debris.params.encode(&mut data)?;
let mint_call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
let builder = AuthTokenMintCallBuilder {
coin_attrs,
token_attrs,
mint_keypair: mint_authority,
auth_mint_zkbin,
auth_mint_pk,
};
let auth_debris = builder.build()?;
let mut data = vec![MoneyFunction::AuthTokenMintV1 as u8];
auth_debris.params.encode(&mut data)?;
let auth_call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
let mut tx = Transaction {
calls: vec![
DarkLeaf { data: mint_call, parent_index: Some(1), children_indexes: vec![] },
DarkLeaf { data: auth_call, parent_index: None, children_indexes: vec![0] },
],
proofs: vec![mint_debris.proofs, auth_debris.proofs],
signatures: vec![],
};
let mint_sigs = tx.create_sigs(&mut OsRng, &[])?;
let auth_sigs = tx.create_sigs(&mut OsRng, &[mint_authority.secret])?;
tx.signatures = vec![mint_sigs, auth_sigs];
tx_action_benchmark.creation_times.push(timer.elapsed());
// Calculate transaction sizes
@@ -90,7 +143,7 @@ impl TestHarness {
let size = std::mem::size_of_val(&*base58);
tx_action_benchmark.broadcasted_sizes.push(size);
Ok((tx, debris.params))
Ok((tx, mint_debris.params, auth_debris.params))
}
pub async fn execute_token_mint_tx(
@@ -106,7 +159,8 @@ impl TestHarness {
let timer = Instant::now();
wallet.validator.add_transactions(&[tx.clone()], block_height, true).await?;
wallet.money_merkle_tree.append(MerkleNode::from(params.output.coin.inner()));
wallet.money_merkle_tree.append(MerkleNode::from(params.coin.inner()));
tx_action_benchmark.verify_times.push(timer.elapsed());
Ok(())
@@ -117,7 +171,8 @@ impl TestHarness {
holder: &Holder,
) -> Result<(Transaction, MoneyTokenFreezeParamsV1)> {
let wallet = self.holders.get(holder).unwrap();
let mint_authority = wallet.token_mint_authority;
let mint_keypair = wallet.token_mint_authority;
let token_blind = wallet.token_blind;
let (frz_pk, frz_zkbin) =
self.proving_keys.get(&MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1.to_string()).unwrap();
@@ -127,10 +182,23 @@ impl TestHarness {
let timer = Instant::now();
let auth_func_id = FuncRef {
contract_id: *MONEY_CONTRACT_ID,
func_code: MoneyFunction::AuthTokenMintV1 as u8,
}
.to_func_id();
let token_attrs = TokenAttributes {
auth_parent: auth_func_id,
user_data: poseidon_hash([mint_keypair.public.x(), mint_keypair.public.y()]),
blind: token_blind,
};
let builder = TokenFreezeCallBuilder {
mint_authority,
token_freeze_zkbin: frz_zkbin.clone(),
token_freeze_pk: frz_pk.clone(),
mint_keypair,
token_attrs,
freeze_zkbin: frz_zkbin.clone(),
freeze_pk: frz_pk.clone(),
};
let debris = builder.build()?;
@@ -141,7 +209,7 @@ impl TestHarness {
let mut tx_builder =
TransactionBuilder::new(ContractCallLeaf { call, proofs: debris.proofs }, vec![])?;
let mut tx = tx_builder.build()?;
let sigs = tx.create_sigs(&mut OsRng, &[mint_authority.secret])?;
let sigs = tx.create_sigs(&mut OsRng, &[mint_keypair.secret])?;
tx.signatures = vec![sigs];
tx_action_benchmark.creation_times.push(timer.elapsed());

View File

@@ -38,7 +38,8 @@ use darkfi_dao_contract::{
};
use darkfi_deployooor_contract::DEPLOY_CONTRACT_ZKAS_DERIVE_NS_V1;
use darkfi_money_contract::{
MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_FEE_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
MONEY_CONTRACT_ZKAS_AUTH_TOKEN_MINT_NS_V1, MONEY_CONTRACT_ZKAS_BURN_NS_V1,
MONEY_CONTRACT_ZKAS_FEE_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1, MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1,
};
use darkfi_sdk::crypto::{contract_id::DEPLOYOOOR_CONTRACT_ID, DAO_CONTRACT_ID, MONEY_CONTRACT_ID};
@@ -46,8 +47,8 @@ use darkfi_serial::{deserialize, serialize};
use log::debug;
/// Update this if any circuits are changed
const VKS_HASH: &str = "8d491e5f127c14ddaa4eb9ac0de25fa3971c5ce7c794a62807c1c7283bcdaeae";
const PKS_HASH: &str = "a9e4e440db9d467bbd61fb9ddc900c9bd155bbbd02f7c73e9012b558daf4af00";
const VKS_HASH: &str = "e775e5a40a07a5048819bf137040c644a881624f3cf0785487f7a2253400d105";
const PKS_HASH: &str = "a3307265fb6fbf8620080634a6ae10d82ceaf0394faeaad2a4bdf00c92bb8ade";
fn pks_path(typ: &str) -> Result<PathBuf> {
let output = Command::new("git").arg("rev-parse").arg("--show-toplevel").output()?.stdout;
@@ -119,6 +120,7 @@ pub fn read_or_gen_vks_and_pks() -> Result<(Pks, Vks)> {
&include_bytes!("../../money/proof/burn_v1.zk.bin")[..],
&include_bytes!("../../money/proof/token_mint_v1.zk.bin")[..],
&include_bytes!("../../money/proof/token_freeze_v1.zk.bin")[..],
&include_bytes!("../../money/proof/auth_token_mint_v1.zk.bin")[..],
// DAO
&include_bytes!("../../dao/proof/dao-mint.zk.bin")[..],
&include_bytes!("../../dao/proof/dao-propose-input.zk.bin")[..],
@@ -187,7 +189,8 @@ pub fn inject(sled_db: &sled::Db, vks: &Vks) -> Result<()> {
MONEY_CONTRACT_ZKAS_MINT_NS_V1 |
MONEY_CONTRACT_ZKAS_BURN_NS_V1 |
MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1 |
MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1 => {
MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1 |
MONEY_CONTRACT_ZKAS_AUTH_TOKEN_MINT_NS_V1 => {
let key = serialize(&namespace.as_str());
let value = serialize(&(bincode.clone(), vk.clone()));
money_zkas_tree.insert(key, value)?;

View File

@@ -0,0 +1,48 @@
/* This file is part of DarkFi (https://dark.fi)
*
* Copyright (C) 2020-2024 Dyne.org foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#[cfg(feature = "async")]
use darkfi_serial::async_trait;
use darkfi_serial::{SerialDecodable, SerialEncodable};
use pasta_curves::pallas;
use super::{poseidon_hash, ContractId};
pub type FunctionCode = u8;
#[derive(Copy, Clone, Debug, Eq, PartialEq, SerialEncodable, SerialDecodable)]
pub struct FuncRef {
pub contract_id: ContractId,
pub func_code: FunctionCode,
}
impl FuncRef {
pub fn to_func_id(&self) -> FuncId {
let func_id =
poseidon_hash([self.contract_id.inner(), pallas::Base::from(self.func_code as u64)]);
FuncId(func_id)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, SerialEncodable, SerialDecodable)]
pub struct FuncId(pallas::Base);
impl FuncId {
pub fn inner(&self) -> pallas::Base {
self.0
}
}

View File

@@ -34,6 +34,10 @@ pub use keypair::{Keypair, PublicKey, SecretKey};
pub mod contract_id;
pub use contract_id::{ContractId, DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID, MONEY_CONTRACT_ID};
/// Function ID definitions and methods
pub mod func_ref;
pub use func_ref::{FuncId, FuncRef};
/// Token ID definitions and methods
pub mod token_id;
pub use token_id::{TokenId, DARK_TOKEN_ID};

View File

@@ -45,6 +45,7 @@ pub struct TokenId(pallas::Base);
impl TokenId {
/// Derives a `TokenId` from a `SecretKey` (mint authority)
#[deprecated]
pub fn derive(mint_authority: SecretKey) -> Self {
let public_key = PublicKey::from_secret(mint_authority);
let (x, y) = public_key.xy();
@@ -53,12 +54,22 @@ impl TokenId {
}
/// Derives a `TokenId` from a `PublicKey`
#[deprecated]
pub fn derive_public(public_key: PublicKey) -> Self {
let (x, y) = public_key.xy();
let hash = poseidon_hash([*TOKEN_ID_PREFIX, x, y]);
Self(hash)
}
pub fn derive_from(
func_id: pallas::Base,
user_data: pallas::Base,
blind: pallas::Base,
) -> Self {
let token_id = poseidon_hash([func_id, user_data, blind]);
Self(token_id)
}
/// Get the inner `pallas::Base` element.
pub fn inner(&self) -> pallas::Base {
self.0