Derive TokenID with a derivation prefix.

This commit is contained in:
parazyd
2023-05-30 09:31:00 +02:00
parent 356c661a08
commit 1a540c67e0
8 changed files with 65 additions and 47 deletions

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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()))];

View File

@@ -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())),

View File

@@ -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), &[])?;

View File

@@ -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())

View File

@@ -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)
}