mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
apply DEP 0003: Token Mint Authorization
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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()`
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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 =
|
||||
|
||||
64
src/contract/money/proof/auth_token_mint_v1.zk
Normal file
64
src/contract/money/proof/auth_token_mint_v1.zk
Normal 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));
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
122
src/contract/money/src/client/auth_token_mint_v1.rs
Normal file
122
src/contract/money/src/client/auth_token_mint_v1.rs
Normal 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(¬e, &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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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(¬e, &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))
|
||||
}
|
||||
|
||||
@@ -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)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
112
src/contract/money/src/entrypoint/auth_token_mint_v1.rs
Normal file
112
src/contract/money/src/entrypoint/auth_token_mint_v1.rs
Normal 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(¶ms.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(())
|
||||
}
|
||||
@@ -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(¶ms.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(())
|
||||
}
|
||||
|
||||
@@ -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(¶ms.output.coin))? {
|
||||
if db_contains_key(coins_db, &serialize(¶ms.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)?;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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, ¶ms, 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, ¶ms.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, ¶ms, 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, ¶ms.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, ¶ms.outputs[0], None)?;
|
||||
let alice_oc = th.gather_owncoin_from_output(&Holder::Alice, ¶ms.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, ¶ms.outputs[0], None)?;
|
||||
let bob_oc = th.gather_owncoin_from_output(&Holder::Bob, ¶ms.outputs[0], None)?;
|
||||
bob_owncoins.push(bob_oc);
|
||||
|
||||
assert!(bob_owncoins.len() == 1);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
48
src/sdk/src/crypto/func_ref.rs
Normal file
48
src/sdk/src/crypto/func_ref.rs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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};
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user