From bafe4a424167054ba3b0ae9021fab58817dee5cf Mon Sep 17 00:00:00 2001 From: parazyd Date: Thu, 23 Feb 2023 13:20:20 +0100 Subject: [PATCH] contract/money: Token Freeze API --- src/contract/money/proof/token_freeze_v1.zk | 5 +- src/contract/money/src/client/freeze_v1.rs | 94 +++++++++++++++++++ src/contract/money/src/client/mod.rs | 3 + .../money/src/entrypoint/freeze_v1.rs | 4 +- 4 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 src/contract/money/src/client/freeze_v1.rs diff --git a/src/contract/money/proof/token_freeze_v1.zk b/src/contract/money/proof/token_freeze_v1.zk index 95aed526f..e05502645 100644 --- a/src/contract/money/proof/token_freeze_v1.zk +++ b/src/contract/money/proof/token_freeze_v1.zk @@ -12,8 +12,9 @@ circuit "TokenFreeze_V1" { 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); + # I don't think we need to enforce these two as public inputs + #constrain_instance(mint_x); + #constrain_instance(mint_y); # Derive the token ID token_id = poseidon_hash(mint_x, mint_y); diff --git a/src/contract/money/src/client/freeze_v1.rs b/src/contract/money/src/client/freeze_v1.rs new file mode 100644 index 000000000..676fde8ab --- /dev/null +++ b/src/contract/money/src/client/freeze_v1.rs @@ -0,0 +1,94 @@ +/* This file is part of DarkFi (https://dark.fi) + * + * Copyright (C) 2020-2023 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 . + */ + +use darkfi::{ + zk::{halo2::Value, Proof, ProvingKey, Witness, ZkCircuit}, + zkas::ZkBinary, + Result, +}; +use darkfi_sdk::{ + crypto::{poseidon_hash, Keypair, TokenId}, + pasta::pallas, +}; +use log::{debug, info}; +use rand::rngs::OsRng; + +use crate::model::MoneyFreezeParamsV1; + +pub struct FreezeCallDebris { + pub params: MoneyFreezeParamsV1, + pub proofs: Vec, +} + +pub struct TokenFreezeRevealed { + pub token_id: TokenId, +} + +impl TokenFreezeRevealed { + pub fn to_vec(&self) -> Vec { + vec![self.token_id.inner()] + } +} + +/// Struct holding necessary information to build a `Money::FreezeV1` contract call. +pub struct FreezeCallBuilder { + /// Mint authority keypair + pub mint_authority: Keypair, + /// `TokenFreeze_V1` zkas circuit ZkBinary + pub token_freeze_zkbin: ZkBinary, + /// Proving key for the `TokenFreeze_V1` zk circuit, + pub token_freeze_pk: ProvingKey, +} + +impl FreezeCallBuilder { + pub fn build(&self) -> Result { + debug!("Building Money::FreezeV1 contract call"); + + // For the Freeze call, we just need to produce a valid signature, + // and enforce the correct derivation inside ZK. + + info!("Creating token freeze proof"); + let (proof, _public_inputs) = create_token_freeze_proof( + &self.token_freeze_zkbin, + &self.token_freeze_pk, + &self.mint_authority, + )?; + + let params = MoneyFreezeParamsV1 { signature_public: self.mint_authority.public }; + let debris = FreezeCallDebris { params, proofs: vec![proof] }; + Ok(debris) + } +} + +pub(crate) fn create_token_freeze_proof( + zkbin: &ZkBinary, + 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 public_inputs = TokenFreezeRevealed { token_id }; + + let prover_witnesses = vec![Witness::Base(Value::known(mint_authority.secret.inner()))]; + + let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone()); + let proof = Proof::create(pk, &[circuit], &public_inputs.to_vec(), &mut OsRng)?; + + Ok((proof, public_inputs)) +} diff --git a/src/contract/money/src/client/mod.rs b/src/contract/money/src/client/mod.rs index 8a1559597..0d754e0b8 100644 --- a/src/contract/money/src/client/mod.rs +++ b/src/contract/money/src/client/mod.rs @@ -41,6 +41,9 @@ pub mod swap_v1; /// `Money::MintV1` API pub mod mint_v1; +/// `Money::FreezeV1` API +pub mod freeze_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. diff --git a/src/contract/money/src/entrypoint/freeze_v1.rs b/src/contract/money/src/entrypoint/freeze_v1.rs index 7b43fd33e..f3bb0b439 100644 --- a/src/contract/money/src/entrypoint/freeze_v1.rs +++ b/src/contract/money/src/entrypoint/freeze_v1.rs @@ -49,8 +49,8 @@ pub(crate) fn money_freeze_get_metadata_v1( let (mint_x, mint_y) = params.signature_public.xy(); let token_id = poseidon_hash([mint_x, mint_y]); - zk_public_inputs - .push((MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1.to_string(), vec![mint_x, mint_y, token_id])); + // 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])); // Serialize everything gathered and return it let mut metadata = vec![];