mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-09 14:48:08 -05:00
Derive TokenID with a derivation prefix.
This commit is contained in:
@@ -521,19 +521,14 @@ impl Drk {
|
||||
if call.contract_id == cid && call.data[0] == MoneyFunction::TokenMintV1 as u8 {
|
||||
eprintln!("Found Money::MintV1 in call {}", i);
|
||||
let params: MoneyTokenMintParamsV1 = deserialize(&call.data[1..])?;
|
||||
|
||||
outputs.push(params.output);
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if call.contract_id == cid && call.data[0] == MoneyFunction::TokenFreezeV1 as u8 {
|
||||
eprintln!("Found Money::FreezeV1 in call {}", i);
|
||||
let params: MoneyTokenFreezeParamsV1 = deserialize(&call.data[1..])?;
|
||||
|
||||
let (mint_x, mint_y) = params.signature_public.xy();
|
||||
let token_id = TokenId::from(poseidon_hash([mint_x, mint_y]));
|
||||
|
||||
let token_id = TokenId::derive_public(params.signature_public);
|
||||
freezes.push(token_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,17 @@ witness "TokenFreeze_V1" {
|
||||
}
|
||||
|
||||
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_x = ec_get_x(mint_public);
|
||||
mint_y = ec_get_y(mint_public);
|
||||
# I don't think we need to enforce these two as public inputs
|
||||
#constrain_instance(mint_x);
|
||||
#constrain_instance(mint_y);
|
||||
constrain_instance(mint_x);
|
||||
constrain_instance(mint_y);
|
||||
|
||||
# Derive the token ID
|
||||
token_id = poseidon_hash(mint_x, mint_y);
|
||||
token_id = poseidon_hash(derivation_path, mint_x, mint_y);
|
||||
constrain_instance(token_id);
|
||||
}
|
||||
|
||||
@@ -31,16 +31,18 @@ witness "TokenMint_V1" {
|
||||
circuit "TokenMint_V1" {
|
||||
# TODO: verify if supply must be > 0 and add corresponding opcode
|
||||
|
||||
# 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);
|
||||
# I don't think we need to have these two as public inputs
|
||||
#constrain_instance(mint_x);
|
||||
#constrain_instance(mint_y);
|
||||
constrain_instance(mint_x);
|
||||
constrain_instance(mint_y);
|
||||
|
||||
# Derive the token ID
|
||||
token_id = poseidon_hash(mint_x, mint_y);
|
||||
token_id = poseidon_hash(derivation_path, mint_x, mint_y);
|
||||
constrain_instance(token_id);
|
||||
|
||||
# Poseidon hash of the minted coin
|
||||
|
||||
@@ -22,7 +22,7 @@ use darkfi::{
|
||||
Result,
|
||||
};
|
||||
use darkfi_sdk::{
|
||||
crypto::{poseidon_hash, Keypair, TokenId},
|
||||
crypto::{Keypair, PublicKey, TokenId},
|
||||
pasta::pallas,
|
||||
};
|
||||
use log::{debug, info};
|
||||
@@ -36,12 +36,14 @@ pub struct TokenFreezeCallDebris {
|
||||
}
|
||||
|
||||
pub struct TokenFreezeRevealed {
|
||||
pub signature_public: PublicKey,
|
||||
pub token_id: TokenId,
|
||||
}
|
||||
|
||||
impl TokenFreezeRevealed {
|
||||
pub fn to_vec(&self) -> Vec<pallas::Base> {
|
||||
vec![self.token_id.inner()]
|
||||
let (sig_x, sig_y) = self.signature_public.xy();
|
||||
vec![sig_x, sig_y, self.token_id.inner()]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,10 +81,9 @@ pub(crate) fn create_token_freeze_proof(
|
||||
pk: &ProvingKey,
|
||||
mint_authority: &Keypair,
|
||||
) -> Result<(Proof, TokenFreezeRevealed)> {
|
||||
let (mint_x, mint_y) = mint_authority.public.xy();
|
||||
let token_id = TokenId::from(poseidon_hash([mint_x, mint_y]));
|
||||
let token_id = TokenId::derive(mint_authority.secret);
|
||||
|
||||
let public_inputs = TokenFreezeRevealed { token_id };
|
||||
let public_inputs = TokenFreezeRevealed { signature_public: mint_authority.public, token_id };
|
||||
|
||||
let prover_witnesses = vec![Witness::Base(Value::known(mint_authority.secret.inner()))];
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ pub struct TokenMintCallDebris {
|
||||
}
|
||||
|
||||
pub struct TokenMintRevealed {
|
||||
pub signature_public: PublicKey,
|
||||
pub token_id: TokenId,
|
||||
pub coin: Coin,
|
||||
pub value_commit: pallas::Point,
|
||||
@@ -53,12 +54,15 @@ pub struct TokenMintRevealed {
|
||||
|
||||
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();
|
||||
let tokcom_coords = self.token_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(),
|
||||
@@ -94,8 +98,7 @@ impl TokenMintCallBuilder {
|
||||
|
||||
// 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 (mint_x, mint_y) = self.mint_authority.public.xy();
|
||||
let token_id = TokenId::from(poseidon_hash([mint_x, mint_y]));
|
||||
let token_id = TokenId::derive(self.mint_authority.secret);
|
||||
|
||||
let input = TransactionBuilderClearInputInfo {
|
||||
value: self.amount,
|
||||
@@ -181,8 +184,7 @@ pub fn create_token_mint_proof(
|
||||
user_data: pallas::Base,
|
||||
coin_blind: pallas::Base,
|
||||
) -> Result<(Proof, TokenMintRevealed)> {
|
||||
let (mint_x, mint_y) = mint_authority.public.xy();
|
||||
let token_id = TokenId::from(poseidon_hash([mint_x, mint_y]));
|
||||
let token_id = TokenId::derive(mint_authority.secret);
|
||||
|
||||
let value_commit = pedersen_commitment_u64(output.value, value_blind);
|
||||
let token_commit = pedersen_commitment_base(token_id.inner(), token_blind);
|
||||
@@ -200,7 +202,13 @@ pub fn create_token_mint_proof(
|
||||
coin_blind,
|
||||
]));
|
||||
|
||||
let public_inputs = TokenMintRevealed { token_id, coin, value_commit, token_commit };
|
||||
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())),
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
use darkfi_sdk::{
|
||||
crypto::{poseidon_hash, ContractId, PublicKey, TokenId},
|
||||
crypto::{ContractId, PublicKey, TokenId},
|
||||
db::{db_contains_key, db_lookup, db_set},
|
||||
error::{ContractError, ContractResult},
|
||||
msg,
|
||||
@@ -46,11 +46,15 @@ pub(crate) fn money_token_freeze_get_metadata_v1(
|
||||
// Public keys for the transaction signatures we have to verify
|
||||
let signature_pubkeys: Vec<PublicKey> = vec![params.signature_public];
|
||||
|
||||
let (mint_x, mint_y) = params.signature_public.xy();
|
||||
let token_id = poseidon_hash([mint_x, mint_y]);
|
||||
// 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);
|
||||
|
||||
// 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![token_id]));
|
||||
zk_public_inputs.push((
|
||||
MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1.to_string(),
|
||||
vec![sig_x, sig_y, token_id.inner()],
|
||||
));
|
||||
|
||||
// Serialize everything gathered and return it
|
||||
let mut metadata = vec![];
|
||||
@@ -72,8 +76,7 @@ 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 (mint_x, mint_y) = params.signature_public.xy();
|
||||
let token_id = TokenId::from(poseidon_hash([mint_x, mint_y]));
|
||||
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))? {
|
||||
@@ -96,10 +99,7 @@ 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 (mint_x, mint_y) = update.signature_public.xy();
|
||||
let token_id = TokenId::from(poseidon_hash([mint_x, mint_y]));
|
||||
|
||||
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), &[])?;
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
use darkfi_sdk::{
|
||||
crypto::{
|
||||
pasta_prelude::*, pedersen_commitment_base, pedersen_commitment_u64, poseidon_hash,
|
||||
ContractId, MerkleNode, TokenId,
|
||||
pasta_prelude::*, pedersen_commitment_base, pedersen_commitment_u64, ContractId,
|
||||
MerkleNode, TokenId,
|
||||
},
|
||||
db::{db_contains_key, db_lookup, db_set},
|
||||
error::{ContractError, ContractResult},
|
||||
@@ -54,18 +54,19 @@ pub(crate) fn money_token_mint_get_metadata_v1(
|
||||
// signed by the mint authority.
|
||||
let signature_pubkeys = vec![params.input.signature_public];
|
||||
|
||||
// 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 token_coords = params.output.token_commit.to_affine().coordinates().unwrap();
|
||||
|
||||
// Since we expect a signature from the mint authority, we use those coordinates
|
||||
// as public inputs for the ZK proof:
|
||||
let (sig_x, sig_y) = params.input.signature_public.xy();
|
||||
let token_id = poseidon_hash([sig_x, sig_y]);
|
||||
|
||||
zk_public_inputs.push((
|
||||
MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1.to_string(),
|
||||
vec![
|
||||
token_id,
|
||||
sig_x,
|
||||
sig_y,
|
||||
token_id.inner(),
|
||||
params.output.coin.inner(),
|
||||
*value_coords.x(),
|
||||
*value_coords.y(),
|
||||
@@ -97,8 +98,7 @@ pub(crate) fn money_token_mint_process_instruction_v1(
|
||||
let token_freeze_db = db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
|
||||
|
||||
// Check that the signature public key is actually the token ID
|
||||
let (mint_x, mint_y) = params.input.signature_public.xy();
|
||||
let token_id = TokenId::from(poseidon_hash([mint_x, mint_y]));
|
||||
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())
|
||||
|
||||
@@ -29,9 +29,12 @@ lazy_static! {
|
||||
// avoid hardcoding contract IDs for arbitrary contract deployments, because
|
||||
// the contracts with 0 as their x coordinate can never have a valid signature.
|
||||
|
||||
/// Derivation prefix for `TokenId`
|
||||
pub static ref TOKEN_ID_PREFIX: pallas::Base = pallas::Base::from(69);
|
||||
|
||||
/// Native DARK token ID
|
||||
pub static ref DARK_TOKEN_ID: TokenId =
|
||||
TokenId::from(poseidon_hash([pallas::Base::zero(), pallas::Base::from(42)]));
|
||||
TokenId::from(poseidon_hash([*TOKEN_ID_PREFIX, pallas::Base::zero(), pallas::Base::from(42)]));
|
||||
}
|
||||
|
||||
/// TokenId represents an on-chain identifier for a certain token.
|
||||
@@ -39,11 +42,18 @@ lazy_static! {
|
||||
pub struct TokenId(pallas::Base);
|
||||
|
||||
impl TokenId {
|
||||
/// Derives a `TokenId` given a `SecretKey` (mint authority)
|
||||
/// Derives a `TokenId` from a `SecretKey` (mint authority)
|
||||
pub fn derive(mint_authority: SecretKey) -> Self {
|
||||
let public_key = PublicKey::from_secret(mint_authority);
|
||||
let (x, y) = public_key.xy();
|
||||
let hash = poseidon_hash::<2>([x, y]);
|
||||
let hash = poseidon_hash([*TOKEN_ID_PREFIX, x, y]);
|
||||
Self(hash)
|
||||
}
|
||||
|
||||
/// Derives a `TokenId` from a `PublicKey`
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user