/* This file is part of DarkFi (https://dark.fi) * * Copyright (C) 2020-2022 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 std::time::Instant; use darkfi_sdk::{ crypto::{ pedersen::{pedersen_commitment_base, pedersen_commitment_u64}, PublicKey, }, pasta::{arithmetic::CurveAffine, group::Curve}, }; use darkfi_serial::{SerialDecodable, SerialEncodable}; use halo2_proofs::circuit::Value; use log::debug; use rand::rngs::OsRng; use crate::{ crypto::{ coin::Coin, proof::{Proof, ProvingKey, VerifyingKey}, types::{ DrkCircuitField, DrkCoinBlind, DrkSerial, DrkSpendHook, DrkTokenId, DrkUserData, DrkValue, DrkValueBlind, DrkValueCommit, }, util::poseidon_hash, }, zk::circuit::mint_contract::MintContract, Result, }; #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)] pub struct MintRevealedValues { pub value_commit: DrkValueCommit, pub token_commit: DrkValueCommit, pub coin: Coin, } impl MintRevealedValues { #[allow(clippy::too_many_arguments)] pub fn compute( value: u64, token_id: DrkTokenId, value_blind: DrkValueBlind, token_blind: DrkValueBlind, serial: DrkSerial, spend_hook: DrkSpendHook, user_data: DrkUserData, coin_blind: DrkCoinBlind, public_key: PublicKey, ) -> Self { let value_commit = pedersen_commitment_u64(value, value_blind); let token_commit = pedersen_commitment_base(token_id, token_blind); let (pub_x, pub_y) = public_key.xy(); let coin = poseidon_hash::<8>([ pub_x, pub_y, DrkValue::from(value), token_id, serial, spend_hook, user_data, coin_blind, ]); MintRevealedValues { value_commit, token_commit, coin: Coin(coin) } } pub fn make_outputs(&self) -> Vec { let value_coords = self.value_commit.to_affine().coordinates().unwrap(); let token_coords = self.token_commit.to_affine().coordinates().unwrap(); vec![ self.coin.0, *value_coords.x(), *value_coords.y(), *token_coords.x(), *token_coords.y(), ] } } #[allow(clippy::too_many_arguments)] pub fn create_mint_proof( pk: &ProvingKey, value: u64, token_id: DrkTokenId, value_blind: DrkValueBlind, token_blind: DrkValueBlind, serial: DrkSerial, spend_hook: DrkSpendHook, user_data: DrkUserData, coin_blind: DrkCoinBlind, public_key: PublicKey, ) -> Result<(Proof, MintRevealedValues)> { let revealed = MintRevealedValues::compute( value, token_id, value_blind, token_blind, serial, spend_hook, user_data, coin_blind, public_key, ); let (pub_x, pub_y) = public_key.xy(); let c = MintContract { pub_x: Value::known(pub_x), pub_y: Value::known(pub_y), value: Value::known(DrkValue::from(value)), token: Value::known(token_id), serial: Value::known(serial), coin_blind: Value::known(coin_blind), spend_hook: Value::known(spend_hook), user_data: Value::known(user_data), value_blind: Value::known(value_blind), token_blind: Value::known(token_blind), }; let start = Instant::now(); let public_inputs = revealed.make_outputs(); let proof = Proof::create(pk, &[c], &public_inputs, &mut OsRng)?; debug!("Prove mint: [{:?}]", start.elapsed()); Ok((proof, revealed)) } pub fn verify_mint_proof( vk: &VerifyingKey, proof: &Proof, revealed: &MintRevealedValues, ) -> Result<()> { let start = Instant::now(); let public_inputs = revealed.make_outputs(); proof.verify(vk, &public_inputs)?; debug!("Verify mint: [{:?}]", start.elapsed()); Ok(()) }