From e6455facb71a1b04a6354b2bdd58a3fcdde68854 Mon Sep 17 00:00:00 2001 From: parazyd Date: Mon, 7 Nov 2022 22:27:24 +0100 Subject: [PATCH] Migrate more crypto API to sdk --- .../daod/src/contract/dao/exec/validate.rs | 8 +- bin/dao/daod/src/contract/dao/exec/wallet.rs | 4 +- bin/dao/daod/src/contract/dao/mint/wallet.rs | 4 +- .../daod/src/contract/dao/propose/wallet.rs | 6 +- bin/dao/daod/src/contract/dao/state.rs | 15 +-- bin/dao/daod/src/contract/dao/vote/wallet.rs | 5 +- bin/dao/daod/src/main.rs | 50 +++++----- bin/dao/daod/src/rpc.rs | 6 +- bin/dao/daod/src/util.rs | 20 +--- bin/darkotc/src/main.rs | 2 +- example/dao/src/contract/dao/exec/validate.rs | 8 +- example/dao/src/contract/dao/exec/wallet.rs | 4 +- example/dao/src/contract/dao/mint/wallet.rs | 4 +- .../dao/src/contract/dao/propose/wallet.rs | 6 +- example/dao/src/contract/dao/state.rs | 15 +-- example/dao/src/contract/dao/vote/wallet.rs | 5 +- example/dao/src/main.rs | 11 ++- example/dao/src/util.rs | 20 +--- example/dao2/src/contract/dao/exec/wallet.rs | 4 +- example/dao2/src/contract/dao/mint/wallet.rs | 4 +- .../dao2/src/contract/dao/propose/wallet.rs | 6 +- example/dao2/src/contract/dao/vote/wallet.rs | 5 +- example/dao2/src/main.rs | 5 +- example/dao2/src/schema.rs | 5 +- example/tx.rs | 3 +- src/consensus/coins.rs | 2 +- src/consensus/ouroboros/state.rs | 5 +- src/crypto/burn_proof.rs | 11 +-- src/crypto/mimc_vdf.rs | 4 +- src/crypto/mint_proof.rs | 3 +- src/crypto/mod.rs | 1 - src/crypto/util.rs | 47 --------- src/node/state.rs | 5 +- src/sdk/src/crypto/contract_id.rs | 51 ++++++++-- src/sdk/src/crypto/keypair.rs | 14 ++- src/sdk/src/crypto/mod.rs | 4 + src/sdk/src/crypto/token_id.rs | 96 +++++++++++++++++++ src/sdk/src/db.rs | 6 +- src/sdk/src/entrypoint.rs | 12 ++- src/sdk/src/merkle.rs | 3 +- src/sdk/src/util.rs | 8 +- src/wallet/walletdb.rs | 7 +- tests/burn_proof.rs | 3 +- 43 files changed, 294 insertions(+), 213 deletions(-) delete mode 100644 src/crypto/util.rs create mode 100644 src/sdk/src/crypto/token_id.rs diff --git a/bin/dao/daod/src/contract/dao/exec/validate.rs b/bin/dao/daod/src/contract/dao/exec/validate.rs index 1182d3fb1..42f62b4bf 100644 --- a/bin/dao/daod/src/contract/dao/exec/validate.rs +++ b/bin/dao/daod/src/contract/dao/exec/validate.rs @@ -22,7 +22,7 @@ use darkfi_sdk::{ crypto::PublicKey, pasta::{ arithmetic::CurveAffine, - group::{Curve, Group}, + group::{ff::PrimeField, Curve, Group}, pallas, }, }; @@ -35,7 +35,7 @@ use darkfi::{ use crate::{ contract::{dao, dao::CONTRACT_ID, money}, - util::{CallDataBase, HashableBase, StateRegistry, Transaction, UpdateBase}, + util::{CallDataBase, StateRegistry, Transaction, UpdateBase}, }; type Result = std::result::Result; @@ -191,7 +191,7 @@ pub fn state_transition( // 3. get the ProposalVote from DAO::State let state = states.lookup::(*CONTRACT_ID).expect("Return type is not of type State"); - let proposal_votes = state.proposal_votes.get(&HashableBase(call_data.proposal)).unwrap(); + let proposal_votes = state.proposal_votes.get(&call_data.proposal.to_repr()).unwrap(); // 4. check yes_votes_commit is the same as in ProposalVote if proposal_votes.yes_votes_commit != call_data.yes_votes_commit { @@ -215,6 +215,6 @@ impl UpdateBase for Update { let state = states .lookup_mut::(*CONTRACT_ID) .expect("Return type is not of type State"); - state.proposal_votes.remove(&HashableBase(self.proposal)).unwrap(); + state.proposal_votes.remove(&self.proposal.to_repr()).unwrap(); } } diff --git a/bin/dao/daod/src/contract/dao/exec/wallet.rs b/bin/dao/daod/src/contract/dao/exec/wallet.rs index ec569eb12..5a311c67a 100644 --- a/bin/dao/daod/src/contract/dao/exec/wallet.rs +++ b/bin/dao/daod/src/contract/dao/exec/wallet.rs @@ -16,14 +16,14 @@ * along with this program. If not, see . */ -use darkfi_sdk::crypto::{pedersen::pedersen_commitment_u64, SecretKey}; +use darkfi_sdk::crypto::{pedersen::pedersen_commitment_u64, poseidon_hash, SecretKey}; use halo2_proofs::circuit::Value; use log::debug; use pasta_curves::{arithmetic::CurveAffine, group::Curve, pallas}; use rand::rngs::OsRng; use darkfi::{ - crypto::{util::poseidon_hash, Proof}, + crypto::Proof, zk::vm::{Witness, ZkCircuit}, }; diff --git a/bin/dao/daod/src/contract/dao/mint/wallet.rs b/bin/dao/daod/src/contract/dao/mint/wallet.rs index 18960061a..b01b47731 100644 --- a/bin/dao/daod/src/contract/dao/mint/wallet.rs +++ b/bin/dao/daod/src/contract/dao/mint/wallet.rs @@ -16,13 +16,13 @@ * along with this program. If not, see . */ -use darkfi_sdk::crypto::{PublicKey, SecretKey}; +use darkfi_sdk::crypto::{poseidon_hash, PublicKey, SecretKey}; use halo2_proofs::circuit::Value; use pasta_curves::pallas; use rand::rngs::OsRng; use darkfi::{ - crypto::{util::poseidon_hash, Proof}, + crypto::Proof, zk::vm::{Witness, ZkCircuit}, }; diff --git a/bin/dao/daod/src/contract/dao/propose/wallet.rs b/bin/dao/daod/src/contract/dao/propose/wallet.rs index f78c35b48..818af4e61 100644 --- a/bin/dao/daod/src/contract/dao/propose/wallet.rs +++ b/bin/dao/daod/src/contract/dao/propose/wallet.rs @@ -16,7 +16,9 @@ * along with this program. If not, see . */ -use darkfi_sdk::crypto::{pedersen::pedersen_commitment_u64, MerkleNode, PublicKey, SecretKey}; +use darkfi_sdk::crypto::{ + pedersen::pedersen_commitment_u64, poseidon_hash, MerkleNode, PublicKey, SecretKey, +}; use darkfi_serial::{SerialDecodable, SerialEncodable}; use halo2_proofs::circuit::Value; use incrementalmerkletree::Hashable; @@ -28,7 +30,7 @@ use pasta_curves::{ use rand::rngs::OsRng; use darkfi::{ - crypto::{util::poseidon_hash, Proof}, + crypto::Proof, zk::vm::{Witness, ZkCircuit}, }; diff --git a/bin/dao/daod/src/contract/dao/state.rs b/bin/dao/daod/src/contract/dao/state.rs index 76b012857..a204ea0d9 100644 --- a/bin/dao/daod/src/contract/dao/state.rs +++ b/bin/dao/daod/src/contract/dao/state.rs @@ -21,9 +21,10 @@ use std::{any::Any, collections::HashMap}; use darkfi_sdk::crypto::{constants::MERKLE_DEPTH, MerkleNode, Nullifier}; use darkfi_serial::{SerialDecodable, SerialEncodable}; use incrementalmerkletree::{bridgetree::BridgeTree, Tree}; -use pasta_curves::{group::Group, pallas}; - -use crate::util::HashableBase; +use pasta_curves::{ + group::{ff::PrimeField, Group}, + pallas, +}; #[derive(Clone, SerialEncodable, SerialDecodable)] pub struct DaoBulla(pub pallas::Base); @@ -55,7 +56,7 @@ pub struct State { //proposal_bullas: Vec, pub proposal_tree: MerkleTree, pub proposal_roots: Vec, - pub proposal_votes: HashMap, + pub proposal_votes: HashMap<[u8; 32], ProposalVotes>, } impl State { @@ -84,7 +85,7 @@ impl State { self.proposal_tree.append(&node); self.proposal_roots.push(self.proposal_tree.root(0).unwrap()); self.proposal_votes.insert( - HashableBase(bulla), + bulla.to_repr(), ProposalVotes { yes_votes_commit: pallas::Point::identity(), all_votes_commit: pallas::Point::identity(), @@ -94,13 +95,13 @@ impl State { } pub fn lookup_proposal_votes(&self, proposal_bulla: pallas::Base) -> Option<&ProposalVotes> { - self.proposal_votes.get(&HashableBase(proposal_bulla)) + self.proposal_votes.get(&proposal_bulla.to_repr()) } pub fn lookup_proposal_votes_mut( &mut self, proposal_bulla: pallas::Base, ) -> Option<&mut ProposalVotes> { - self.proposal_votes.get_mut(&HashableBase(proposal_bulla)) + self.proposal_votes.get_mut(&proposal_bulla.to_repr()) } pub fn is_valid_dao_merkle(&self, root: &MerkleNode) -> bool { diff --git a/bin/dao/daod/src/contract/dao/vote/wallet.rs b/bin/dao/daod/src/contract/dao/vote/wallet.rs index 04f69c15d..641dbbcff 100644 --- a/bin/dao/daod/src/contract/dao/vote/wallet.rs +++ b/bin/dao/daod/src/contract/dao/vote/wallet.rs @@ -17,7 +17,8 @@ */ use darkfi_sdk::crypto::{ - pedersen::pedersen_commitment_u64, Keypair, MerkleNode, Nullifier, PublicKey, SecretKey, + pedersen::pedersen_commitment_u64, poseidon_hash, Keypair, MerkleNode, Nullifier, PublicKey, + SecretKey, }; use darkfi_serial::{SerialDecodable, SerialEncodable}; use halo2_proofs::circuit::Value; @@ -31,7 +32,7 @@ use pasta_curves::{ use rand::rngs::OsRng; use darkfi::{ - crypto::{util::poseidon_hash, Proof}, + crypto::Proof, zk::vm::{Witness, ZkCircuit}, }; diff --git a/bin/dao/daod/src/main.rs b/bin/dao/daod/src/main.rs index c49d7d397..092a393de 100644 --- a/bin/dao/daod/src/main.rs +++ b/bin/dao/daod/src/main.rs @@ -22,7 +22,6 @@ use darkfi::{ crypto::{ proof::{ProvingKey, VerifyingKey}, types::{DrkSpendHook, DrkUserData, DrkValue}, - util::poseidon_hash, }, rpc::server::listen_and_serve, zk::circuit::{BurnContract, MintContract}, @@ -30,7 +29,7 @@ use darkfi::{ Error, Result, }; use darkfi_sdk::crypto::{ - pedersen::pedersen_commitment_u64, Keypair, MerkleNode, PublicKey, SecretKey, + pedersen::pedersen_commitment_u64, poseidon_hash, Keypair, MerkleNode, PublicKey, SecretKey, }; use fxhash::FxHashMap; use group::ff::PrimeField; @@ -166,7 +165,7 @@ use crate::{ pub struct Client { dao_wallet: DaoWallet, - money_wallets: FxHashMap, + money_wallets: FxHashMap<[u8; 32], MoneyWallet>, cashier_wallet: CashierWallet, states: StateRegistry, zk_bins: ZkContractTable, @@ -426,7 +425,7 @@ impl Client { debug!("DAO received a coin worth {} xDRK", note.value); } - for (_key, wallet) in &mut self.money_wallets { + for wallet in self.money_wallets.values_mut() { let coins = state.wallet_cache.get_received(&wallet.keypair.secret); for coin in coins { let note = coin.note.clone(); @@ -465,7 +464,7 @@ impl Client { // To be able to make a proposal, we must prove we have ownership // of governance tokens, and that the quantity of governance // tokens is within the accepted proposer limit. - let sender_wallet = self.money_wallets.get_mut(&sender); + let sender_wallet = self.money_wallets.get_mut(&sender.to_bytes()); if sender_wallet.is_none() { return Err(DaoError::NoWalletFound) } @@ -502,7 +501,7 @@ impl Client { let dao_params = self.dao_wallet.params[0].clone(); let dao_keypair = self.dao_wallet.keypair; - let voter_wallet = self.money_wallets.get_mut(&pubkey); + let voter_wallet = self.money_wallets.get_mut(&pubkey.to_bytes()); if voter_wallet.is_none() { return Err(DaoError::NoWalletFound) } @@ -641,7 +640,8 @@ impl DaoWallet { let state = states.lookup_mut::(*dao::CONTRACT_ID).ok_or(DaoError::StateNotFound)?; - let path = state.dao_tree.witness().ok_or(Error::Custom("Tree is empty".to_owned()))?; + let path = + state.dao_tree.witness().ok_or_else(|| Error::Custom("Tree is empty".to_owned()))?; self.leaf_position = path; Ok(()) } @@ -719,13 +719,15 @@ impl DaoWallet { let tree = &state.tree; let leaf_position = own_coin.leaf_position; - let root = tree.root(0).ok_or(Error::Custom( - "Not enough checkpoints available to reach the requested checkpoint depth." - .to_owned(), - ))?; + let root = tree.root(0).ok_or_else(|| { + Error::Custom( + "Not enough checkpoints available to reach the requested checkpoint depth." + .to_owned(), + ) + })?; let merkle_path = tree .authentication_path(leaf_position, &root) - .ok_or(Error::Custom("No available authentication path to that position or if the root does not correspond to a checkpointed root of the tree".to_owned()))?; + .ok_or_else(|| Error::Custom("No available authentication path to that position or if the root does not correspond to a checkpointed root of the tree".to_owned()))?; (leaf_position, merkle_path) }; @@ -957,12 +959,14 @@ impl MoneyWallet { let state = states.lookup::(*dao::CONTRACT_ID).ok_or(DaoError::StateNotFound)?; let tree = &state.dao_tree; - let root = tree.root(0).ok_or(Error::Custom( - "Not enough checkpoints available to reach the requested checkpoint depth." - .to_owned(), - ))?; + let root = tree.root(0).ok_or_else(|| { + Error::Custom( + "Not enough checkpoints available to reach the requested checkpoint depth." + .to_owned(), + ) + })?; let merkle_path = tree.authentication_path(dao_leaf_position, &root) - .ok_or(Error::Custom( + .ok_or_else(|| Error::Custom( "No available authentication path to that position or if the root does not correspond to a checkpointed root of the tree" .to_owned() ))?; @@ -1012,11 +1016,13 @@ impl MoneyWallet { let tree = &state.tree; let leaf_position = own_coin.leaf_position; - let root = tree.root(0).ok_or(Error::Custom( - "Not enough checkpoints available to reach the requested checkpoint depth." - .to_owned(), - ))?; - let merkle_path = tree.authentication_path(leaf_position, &root).ok_or(Error::Custom( + let root = tree.root(0).ok_or_else(|| { + Error::Custom( + "Not enough checkpoints available to reach the requested checkpoint depth." + .to_owned(), + ) + })?; + let merkle_path = tree.authentication_path(leaf_position, &root).ok_or_else(|| Error::Custom( "No available authentication path to that position or the root does not correspond to a checkpointed root of the tree" .to_owned() ))?; diff --git a/bin/dao/daod/src/rpc.rs b/bin/dao/daod/src/rpc.rs index f7e4f2143..ef3bed83d 100644 --- a/bin/dao/daod/src/rpc.rs +++ b/bin/dao/daod/src/rpc.rs @@ -199,7 +199,7 @@ impl JsonRpcInterface { let nym = nym.unwrap(); match PublicKey::from_str(nym) { - Ok(key) => match client.money_wallets.get(&key) { + Ok(key) => match client.money_wallets.get(&key.to_bytes()) { Some(wallet) => { let balance = wallet.balances().unwrap(); JsonResponse::new(json!(balance), id).into() @@ -260,7 +260,7 @@ impl JsonRpcInterface { match money_wallet.track(&mut client.states) { Ok(_) => { - client.money_wallets.insert(keypair.public, money_wallet); + client.money_wallets.insert(keypair.public.to_bytes(), money_wallet); //let addr: String = bs58::encode(keypair.public.to_bytes()).into_string(); let addr: String = keypair.public.to_string(); JsonResponse::new(json!(addr), id).into() @@ -368,7 +368,7 @@ impl JsonRpcInterface { let addr = addr.unwrap(); let balance = match PublicKey::from_str(addr) { - Ok(key) => match client.money_wallets.get(&key) { + Ok(key) => match client.money_wallets.get(&key.to_bytes()) { Some(wallet) => { let balance = wallet.balances().unwrap(); let token_id = bs58::encode((*GOV_ID).to_repr()).into_string(); diff --git a/bin/dao/daod/src/util.rs b/bin/dao/daod/src/util.rs index 3a0364ea7..324725b3f 100644 --- a/bin/dao/daod/src/util.rs +++ b/bin/dao/daod/src/util.rs @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -use std::{any::Any, collections::HashMap, hash::Hasher}; +use std::{any::Any, collections::HashMap}; use darkfi_sdk::crypto::{ schnorr::{SchnorrPublic, SchnorrSecret, Signature}, @@ -69,16 +69,6 @@ lazy_static! { pub static ref GOV_ID: pallas::Base = pallas::Base::random(&mut OsRng); } -#[derive(Eq, PartialEq, Debug)] -pub struct HashableBase(pub pallas::Base); - -impl std::hash::Hash for HashableBase { - fn hash(&self, state: &mut H) { - let bytes = self.0.to_repr(); - bytes.hash(state); - } -} - #[derive(Clone)] pub struct ZkBinaryContractInfo { pub k_param: u32, @@ -263,7 +253,7 @@ pub trait CallDataBase { type GenericContractState = Box; pub struct StateRegistry { - pub states: HashMap, + pub states: HashMap<[u8; 32], GenericContractState>, } impl StateRegistry { @@ -273,15 +263,15 @@ impl StateRegistry { pub fn register(&mut self, contract_id: ContractId, state: GenericContractState) { debug!(target: "StateRegistry::register()", "contract_id: {:?}", contract_id); - self.states.insert(HashableBase(contract_id), state); + self.states.insert(contract_id.to_repr(), state); } pub fn lookup_mut<'a, S: 'static>(&'a mut self, contract_id: ContractId) -> Option<&'a mut S> { - self.states.get_mut(&HashableBase(contract_id)).and_then(|state| state.downcast_mut()) + self.states.get_mut(&contract_id.to_repr()).and_then(|state| state.downcast_mut()) } pub fn lookup<'a, S: 'static>(&'a self, contract_id: ContractId) -> Option<&'a S> { - self.states.get(&HashableBase(contract_id)).and_then(|state| state.downcast_ref()) + self.states.get(&contract_id.to_repr()).and_then(|state| state.downcast_ref()) } } diff --git a/bin/darkotc/src/main.rs b/bin/darkotc/src/main.rs index 56c61b2e3..f5e640800 100644 --- a/bin/darkotc/src/main.rs +++ b/bin/darkotc/src/main.rs @@ -551,7 +551,7 @@ async fn sign_tx(endpoint: Url, data: &str) -> Result { exit(1); } - tx.inputs[idx_to_sign].signature = signature.clone(); + tx.inputs[idx_to_sign].signature = signature; Ok(tx) } diff --git a/example/dao/src/contract/dao/exec/validate.rs b/example/dao/src/contract/dao/exec/validate.rs index da978722d..1f0f58b5f 100644 --- a/example/dao/src/contract/dao/exec/validate.rs +++ b/example/dao/src/contract/dao/exec/validate.rs @@ -22,7 +22,7 @@ use darkfi_sdk::crypto::PublicKey; use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable}; use pasta_curves::{ arithmetic::CurveAffine, - group::{Curve, Group}, + group::{ff::PrimeField, Curve, Group}, pallas, }; @@ -33,7 +33,7 @@ use darkfi::{ use crate::{ contract::{dao, dao::CONTRACT_ID, money}, - util::{CallDataBase, HashableBase, StateRegistry, Transaction, UpdateBase}, + util::{CallDataBase, StateRegistry, Transaction, UpdateBase}, }; type Result = std::result::Result; @@ -189,7 +189,7 @@ pub fn state_transition( // 3. get the ProposalVote from DAO::State let state = states.lookup::(*CONTRACT_ID).expect("Return type is not of type State"); - let proposal_votes = state.proposal_votes.get(&HashableBase(call_data.proposal)).unwrap(); + let proposal_votes = state.proposal_votes.get(&call_data.proposal.to_repr()).unwrap(); // 4. check yes_votes_commit is the same as in ProposalVote if proposal_votes.yes_votes_commit != call_data.yes_votes_commit { @@ -213,6 +213,6 @@ impl UpdateBase for Update { let state = states .lookup_mut::(*CONTRACT_ID) .expect("Return type is not of type State"); - state.proposal_votes.remove(&HashableBase(self.proposal)).unwrap(); + state.proposal_votes.remove(&self.proposal.to_repr()).unwrap(); } } diff --git a/example/dao/src/contract/dao/exec/wallet.rs b/example/dao/src/contract/dao/exec/wallet.rs index ec569eb12..5a311c67a 100644 --- a/example/dao/src/contract/dao/exec/wallet.rs +++ b/example/dao/src/contract/dao/exec/wallet.rs @@ -16,14 +16,14 @@ * along with this program. If not, see . */ -use darkfi_sdk::crypto::{pedersen::pedersen_commitment_u64, SecretKey}; +use darkfi_sdk::crypto::{pedersen::pedersen_commitment_u64, poseidon_hash, SecretKey}; use halo2_proofs::circuit::Value; use log::debug; use pasta_curves::{arithmetic::CurveAffine, group::Curve, pallas}; use rand::rngs::OsRng; use darkfi::{ - crypto::{util::poseidon_hash, Proof}, + crypto::Proof, zk::vm::{Witness, ZkCircuit}, }; diff --git a/example/dao/src/contract/dao/mint/wallet.rs b/example/dao/src/contract/dao/mint/wallet.rs index 18960061a..b01b47731 100644 --- a/example/dao/src/contract/dao/mint/wallet.rs +++ b/example/dao/src/contract/dao/mint/wallet.rs @@ -16,13 +16,13 @@ * along with this program. If not, see . */ -use darkfi_sdk::crypto::{PublicKey, SecretKey}; +use darkfi_sdk::crypto::{poseidon_hash, PublicKey, SecretKey}; use halo2_proofs::circuit::Value; use pasta_curves::pallas; use rand::rngs::OsRng; use darkfi::{ - crypto::{util::poseidon_hash, Proof}, + crypto::Proof, zk::vm::{Witness, ZkCircuit}, }; diff --git a/example/dao/src/contract/dao/propose/wallet.rs b/example/dao/src/contract/dao/propose/wallet.rs index f78c35b48..818af4e61 100644 --- a/example/dao/src/contract/dao/propose/wallet.rs +++ b/example/dao/src/contract/dao/propose/wallet.rs @@ -16,7 +16,9 @@ * along with this program. If not, see . */ -use darkfi_sdk::crypto::{pedersen::pedersen_commitment_u64, MerkleNode, PublicKey, SecretKey}; +use darkfi_sdk::crypto::{ + pedersen::pedersen_commitment_u64, poseidon_hash, MerkleNode, PublicKey, SecretKey, +}; use darkfi_serial::{SerialDecodable, SerialEncodable}; use halo2_proofs::circuit::Value; use incrementalmerkletree::Hashable; @@ -28,7 +30,7 @@ use pasta_curves::{ use rand::rngs::OsRng; use darkfi::{ - crypto::{util::poseidon_hash, Proof}, + crypto::Proof, zk::vm::{Witness, ZkCircuit}, }; diff --git a/example/dao/src/contract/dao/state.rs b/example/dao/src/contract/dao/state.rs index b9dbaf5d2..b5b1b7ac9 100644 --- a/example/dao/src/contract/dao/state.rs +++ b/example/dao/src/contract/dao/state.rs @@ -21,9 +21,10 @@ use std::{any::Any, collections::HashMap}; use darkfi_sdk::crypto::{constants::MERKLE_DEPTH, MerkleNode, Nullifier}; use darkfi_serial::{SerialDecodable, SerialEncodable}; use incrementalmerkletree::{bridgetree::BridgeTree, Tree}; -use pasta_curves::{group::Group, pallas}; - -use crate::util::HashableBase; +use pasta_curves::{ + group::{ff::PrimeField, Group}, + pallas, +}; #[derive(Clone, SerialEncodable, SerialDecodable)] pub struct DaoBulla(pub pallas::Base); @@ -55,7 +56,7 @@ pub struct State { //proposal_bullas: Vec, pub proposal_tree: MerkleTree, pub proposal_roots: Vec, - pub proposal_votes: HashMap, + pub proposal_votes: HashMap<[u8; 32], ProposalVotes>, } impl State { @@ -84,7 +85,7 @@ impl State { self.proposal_tree.append(&node); self.proposal_roots.push(self.proposal_tree.root(0).unwrap()); self.proposal_votes.insert( - HashableBase(bulla), + bulla.to_repr(), ProposalVotes { yes_votes_commit: pallas::Point::identity(), all_votes_commit: pallas::Point::identity(), @@ -94,13 +95,13 @@ impl State { } pub fn lookup_proposal_votes(&self, proposal_bulla: pallas::Base) -> Option<&ProposalVotes> { - self.proposal_votes.get(&HashableBase(proposal_bulla)) + self.proposal_votes.get(&proposal_bulla.to_repr()) } pub fn lookup_proposal_votes_mut( &mut self, proposal_bulla: pallas::Base, ) -> Option<&mut ProposalVotes> { - self.proposal_votes.get_mut(&HashableBase(proposal_bulla)) + self.proposal_votes.get_mut(&proposal_bulla.to_repr()) } pub fn is_valid_dao_merkle(&self, root: &MerkleNode) -> bool { diff --git a/example/dao/src/contract/dao/vote/wallet.rs b/example/dao/src/contract/dao/vote/wallet.rs index 04f69c15d..641dbbcff 100644 --- a/example/dao/src/contract/dao/vote/wallet.rs +++ b/example/dao/src/contract/dao/vote/wallet.rs @@ -17,7 +17,8 @@ */ use darkfi_sdk::crypto::{ - pedersen::pedersen_commitment_u64, Keypair, MerkleNode, Nullifier, PublicKey, SecretKey, + pedersen::pedersen_commitment_u64, poseidon_hash, Keypair, MerkleNode, Nullifier, PublicKey, + SecretKey, }; use darkfi_serial::{SerialDecodable, SerialEncodable}; use halo2_proofs::circuit::Value; @@ -31,7 +32,7 @@ use pasta_curves::{ use rand::rngs::OsRng; use darkfi::{ - crypto::{util::poseidon_hash, Proof}, + crypto::Proof, zk::vm::{Witness, ZkCircuit}, }; diff --git a/example/dao/src/main.rs b/example/dao/src/main.rs index e3a917997..739330e71 100644 --- a/example/dao/src/main.rs +++ b/example/dao/src/main.rs @@ -22,8 +22,8 @@ use std::{ }; use darkfi_sdk::crypto::{ - constants::MERKLE_DEPTH, pedersen::pedersen_commitment_u64, Keypair, MerkleNode, PublicKey, - SecretKey, + constants::MERKLE_DEPTH, pedersen::pedersen_commitment_u64, poseidon_hash, Keypair, MerkleNode, + PublicKey, SecretKey, }; use incrementalmerkletree::{bridgetree::BridgeTree, Tree}; use log::debug; @@ -38,7 +38,6 @@ use darkfi::{ coin::Coin, proof::{ProvingKey, VerifyingKey}, types::{DrkSpendHook, DrkUserData, DrkValue}, - util::poseidon_hash, }, zk::circuit::{BurnContract, MintContract}, zkas::decoder::ZkBinary, @@ -71,6 +70,12 @@ pub struct WalletCache { tree: MerkleTree, } +impl Default for WalletCache { + fn default() -> Self { + Self { cache: Vec::new(), tree: MerkleTree::new(100) } + } +} + impl WalletCache { pub fn new() -> Self { Self { cache: Vec::new(), tree: MerkleTree::new(100) } diff --git a/example/dao/src/util.rs b/example/dao/src/util.rs index ca3b3ea70..9f7f3b595 100644 --- a/example/dao/src/util.rs +++ b/example/dao/src/util.rs @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -use std::{any::Any, collections::HashMap, hash::Hasher}; +use std::{any::Any, collections::HashMap}; use darkfi_sdk::crypto::{ schnorr::{SchnorrPublic, SchnorrSecret, Signature}, @@ -68,16 +68,6 @@ lazy_static! { pub static ref GOV_ID: pallas::Base = pallas::Base::random(&mut OsRng); } -#[derive(Eq, PartialEq, Debug)] -pub struct HashableBase(pub pallas::Base); - -impl std::hash::Hash for HashableBase { - fn hash(&self, state: &mut H) { - let bytes = self.0.to_repr(); - bytes.hash(state); - } -} - #[derive(Clone)] pub struct ZkBinaryContractInfo { pub k_param: u32, @@ -255,7 +245,7 @@ pub trait CallDataBase { type GenericContractState = Box; pub struct StateRegistry { - pub states: HashMap, + pub states: HashMap<[u8; 32], GenericContractState>, } impl StateRegistry { @@ -265,15 +255,15 @@ impl StateRegistry { pub fn register(&mut self, contract_id: ContractId, state: GenericContractState) { debug!(target: "StateRegistry::register()", "contract_id: {:?}", contract_id); - self.states.insert(HashableBase(contract_id), state); + self.states.insert(contract_id.to_repr(), state); } pub fn lookup_mut<'a, S: 'static>(&'a mut self, contract_id: ContractId) -> Option<&'a mut S> { - self.states.get_mut(&HashableBase(contract_id)).and_then(|state| state.downcast_mut()) + self.states.get_mut(&contract_id.to_repr()).and_then(|state| state.downcast_mut()) } pub fn lookup<'a, S: 'static>(&'a self, contract_id: ContractId) -> Option<&'a S> { - self.states.get(&HashableBase(contract_id)).and_then(|state| state.downcast_ref()) + self.states.get(&contract_id.to_repr()).and_then(|state| state.downcast_ref()) } } diff --git a/example/dao2/src/contract/dao/exec/wallet.rs b/example/dao2/src/contract/dao/exec/wallet.rs index ec569eb12..5a311c67a 100644 --- a/example/dao2/src/contract/dao/exec/wallet.rs +++ b/example/dao2/src/contract/dao/exec/wallet.rs @@ -16,14 +16,14 @@ * along with this program. If not, see . */ -use darkfi_sdk::crypto::{pedersen::pedersen_commitment_u64, SecretKey}; +use darkfi_sdk::crypto::{pedersen::pedersen_commitment_u64, poseidon_hash, SecretKey}; use halo2_proofs::circuit::Value; use log::debug; use pasta_curves::{arithmetic::CurveAffine, group::Curve, pallas}; use rand::rngs::OsRng; use darkfi::{ - crypto::{util::poseidon_hash, Proof}, + crypto::Proof, zk::vm::{Witness, ZkCircuit}, }; diff --git a/example/dao2/src/contract/dao/mint/wallet.rs b/example/dao2/src/contract/dao/mint/wallet.rs index ded73b4d3..25bf1952e 100644 --- a/example/dao2/src/contract/dao/mint/wallet.rs +++ b/example/dao2/src/contract/dao/mint/wallet.rs @@ -16,13 +16,13 @@ * along with this program. If not, see . */ -use darkfi_sdk::crypto::{PublicKey, SecretKey}; +use darkfi_sdk::crypto::{poseidon_hash, PublicKey, SecretKey}; use halo2_proofs::circuit::Value; use pasta_curves::{arithmetic::CurveAffine, group::Curve, pallas}; use rand::rngs::OsRng; use darkfi::{ - crypto::{util::poseidon_hash, Proof}, + crypto::Proof, zk::vm::{Witness, ZkCircuit}, }; diff --git a/example/dao2/src/contract/dao/propose/wallet.rs b/example/dao2/src/contract/dao/propose/wallet.rs index f78c35b48..818af4e61 100644 --- a/example/dao2/src/contract/dao/propose/wallet.rs +++ b/example/dao2/src/contract/dao/propose/wallet.rs @@ -16,7 +16,9 @@ * along with this program. If not, see . */ -use darkfi_sdk::crypto::{pedersen::pedersen_commitment_u64, MerkleNode, PublicKey, SecretKey}; +use darkfi_sdk::crypto::{ + pedersen::pedersen_commitment_u64, poseidon_hash, MerkleNode, PublicKey, SecretKey, +}; use darkfi_serial::{SerialDecodable, SerialEncodable}; use halo2_proofs::circuit::Value; use incrementalmerkletree::Hashable; @@ -28,7 +30,7 @@ use pasta_curves::{ use rand::rngs::OsRng; use darkfi::{ - crypto::{util::poseidon_hash, Proof}, + crypto::Proof, zk::vm::{Witness, ZkCircuit}, }; diff --git a/example/dao2/src/contract/dao/vote/wallet.rs b/example/dao2/src/contract/dao/vote/wallet.rs index 04f69c15d..641dbbcff 100644 --- a/example/dao2/src/contract/dao/vote/wallet.rs +++ b/example/dao2/src/contract/dao/vote/wallet.rs @@ -17,7 +17,8 @@ */ use darkfi_sdk::crypto::{ - pedersen::pedersen_commitment_u64, Keypair, MerkleNode, Nullifier, PublicKey, SecretKey, + pedersen::pedersen_commitment_u64, poseidon_hash, Keypair, MerkleNode, Nullifier, PublicKey, + SecretKey, }; use darkfi_serial::{SerialDecodable, SerialEncodable}; use halo2_proofs::circuit::Value; @@ -31,7 +32,7 @@ use pasta_curves::{ use rand::rngs::OsRng; use darkfi::{ - crypto::{util::poseidon_hash, Proof}, + crypto::Proof, zk::vm::{Witness, ZkCircuit}, }; diff --git a/example/dao2/src/main.rs b/example/dao2/src/main.rs index 1a830a4bb..843765f5c 100644 --- a/example/dao2/src/main.rs +++ b/example/dao2/src/main.rs @@ -5,7 +5,6 @@ use darkfi::{ coin::Coin, proof::{ProvingKey, VerifyingKey}, types::{DrkSpendHook, DrkUserData, DrkValue}, - util::poseidon_hash, }, runtime::vm_runtime::Runtime, zk::circuit::{BurnContract, MintContract}, @@ -14,8 +13,8 @@ use darkfi::{ }; use darkfi_sdk::{ crypto::{ - constants::MERKLE_DEPTH, pedersen::pedersen_commitment_u64, ContractId, Keypair, - MerkleNode, MerkleTree, PublicKey, SecretKey, + constants::MERKLE_DEPTH, pedersen::pedersen_commitment_u64, poseidon_hash, ContractId, + Keypair, MerkleNode, MerkleTree, PublicKey, SecretKey, }, tx::ContractCall, }; diff --git a/example/dao2/src/schema.rs b/example/dao2/src/schema.rs index b4fe6ce2c..9ffb56060 100644 --- a/example/dao2/src/schema.rs +++ b/example/dao2/src/schema.rs @@ -22,8 +22,8 @@ use std::{ }; use darkfi_sdk::crypto::{ - constants::MERKLE_DEPTH, pedersen::pedersen_commitment_u64, Keypair, MerkleNode, PublicKey, - SecretKey, + constants::MERKLE_DEPTH, pedersen::pedersen_commitment_u64, poseidon_hash, Keypair, MerkleNode, + PublicKey, SecretKey, }; use incrementalmerkletree::{bridgetree::BridgeTree, Tree}; use log::debug; @@ -35,7 +35,6 @@ use darkfi::{ coin::Coin, proof::{ProvingKey, VerifyingKey}, types::{DrkSpendHook, DrkUserData, DrkValue}, - util::poseidon_hash, }, zk::circuit::{BurnContract, MintContract}, zkas::decoder::ZkBinary, diff --git a/example/tx.rs b/example/tx.rs index dc4b3727e..cb03448c0 100644 --- a/example/tx.rs +++ b/example/tx.rs @@ -18,7 +18,7 @@ // Example transaction flow use darkfi_sdk::crypto::{ - constants::MERKLE_DEPTH, Keypair, MerkleNode, Nullifier, PublicKey, SecretKey, + constants::MERKLE_DEPTH, poseidon_hash, Keypair, MerkleNode, Nullifier, PublicKey, SecretKey, }; use incrementalmerkletree::{bridgetree::BridgeTree, Tree}; use pasta_curves::{group::ff::Field, pallas}; @@ -29,7 +29,6 @@ use darkfi::{ coin::OwnCoin, note::{EncryptedNote, Note}, proof::{ProvingKey, VerifyingKey}, - util::poseidon_hash, }, node::state::{state_transition, ProgramState, StateUpdate}, tx::builder::{ diff --git a/src/consensus/coins.rs b/src/consensus/coins.rs index 93e940e54..f271b3890 100644 --- a/src/consensus/coins.rs +++ b/src/consensus/coins.rs @@ -20,6 +20,7 @@ use darkfi_sdk::{ crypto::{ constants::MERKLE_DEPTH_ORCHARD, pedersen::{pedersen_commitment_base, pedersen_commitment_u64}, + poseidon_hash, util::mod_r_p, Keypair, MerkleNode, Nullifier, SecretKey, }, @@ -45,7 +46,6 @@ use crate::{ leadcoin::LeadCoin, note::Note, types::{DrkCoinBlind, DrkSerial, DrkTokenId, DrkValueBlind}, - util::poseidon_hash, }, wallet::walletdb::WalletDb, Result, diff --git a/src/consensus/ouroboros/state.rs b/src/consensus/ouroboros/state.rs index fee6f2bb0..236625628 100644 --- a/src/consensus/ouroboros/state.rs +++ b/src/consensus/ouroboros/state.rs @@ -16,7 +16,9 @@ * along with this program. If not, see . */ -use darkfi_sdk::crypto::{constants::MERKLE_DEPTH, MerkleNode, Nullifier, PublicKey, SecretKey}; +use darkfi_sdk::crypto::{ + constants::MERKLE_DEPTH, poseidon_hash, MerkleNode, Nullifier, PublicKey, SecretKey, +}; use incrementalmerkletree::{bridgetree::BridgeTree, Tree}; use crate::{ @@ -24,7 +26,6 @@ use crate::{ coin::OwnCoin, note::{EncryptedNote, Note}, proof::VerifyingKey, - util::poseidon_hash, }, node::state::{ProgramState, StateUpdate}, }; diff --git a/src/crypto/burn_proof.rs b/src/crypto/burn_proof.rs index 23d25fa42..93c1d7090 100644 --- a/src/crypto/burn_proof.rs +++ b/src/crypto/burn_proof.rs @@ -21,7 +21,7 @@ use std::time::Instant; use darkfi_sdk::{ crypto::{ pedersen::{pedersen_commitment_base, pedersen_commitment_u64}, - MerkleNode, Nullifier, PublicKey, SecretKey, + poseidon_hash, MerkleNode, Nullifier, PublicKey, SecretKey, }, incrementalmerkletree::Hashable, pasta::{arithmetic::CurveAffine, group::Curve}, @@ -33,12 +33,9 @@ use rand::rngs::OsRng; use super::proof::{Proof, ProvingKey, VerifyingKey}; use crate::{ - crypto::{ - types::{ - DrkCircuitField, DrkCoinBlind, DrkSerial, DrkSpendHook, DrkTokenId, DrkUserData, - DrkUserDataBlind, DrkUserDataEnc, DrkValue, DrkValueBlind, DrkValueCommit, - }, - util::poseidon_hash, + crypto::types::{ + DrkCircuitField, DrkCoinBlind, DrkSerial, DrkSpendHook, DrkTokenId, DrkUserData, + DrkUserDataBlind, DrkUserDataEnc, DrkValue, DrkValueBlind, DrkValueCommit, }, zk::circuit::burn_contract::BurnContract, Result, diff --git a/src/crypto/mimc_vdf.rs b/src/crypto/mimc_vdf.rs index b8afc74e6..1ee70a807 100644 --- a/src/crypto/mimc_vdf.rs +++ b/src/crypto/mimc_vdf.rs @@ -22,11 +22,11 @@ use num_bigint::BigUint; use num_traits::Num; /// Modulus of prime field 2^256 - 2^32 * 351 + 1 -pub const MODULUS: &str = +const MODULUS: &str = "115792089237316195423570985008687907853269984665640564039457584006405596119041"; /// An exponent to perform inverse of x^3 on prime field based on Fermat's Little Theorem -pub const L_FERMAT_EXPONENT: &str = +const L_FERMAT_EXPONENT: &str = "77194726158210796949047323339125271902179989777093709359638389337603730746027"; /// Calculates set of round constants to perform MiMC-calculation on. diff --git a/src/crypto/mint_proof.rs b/src/crypto/mint_proof.rs index 9d69c2516..6a5faaa8f 100644 --- a/src/crypto/mint_proof.rs +++ b/src/crypto/mint_proof.rs @@ -21,7 +21,7 @@ use std::time::Instant; use darkfi_sdk::{ crypto::{ pedersen::{pedersen_commitment_base, pedersen_commitment_u64}, - PublicKey, + poseidon_hash, PublicKey, }, pasta::{arithmetic::CurveAffine, group::Curve}, }; @@ -38,7 +38,6 @@ use crate::{ DrkCircuitField, DrkCoinBlind, DrkSerial, DrkSpendHook, DrkTokenId, DrkUserData, DrkValue, DrkValueBlind, DrkValueCommit, }, - util::poseidon_hash, }, zk::circuit::mint_contract::MintContract, Result, diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs index e6fa653d5..af28d7268 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -25,7 +25,6 @@ pub mod proof; pub mod token_id; pub mod token_list; pub mod types; -pub mod util; /// VDF (Verifiable Delay Function) using MiMC pub mod mimc_vdf; diff --git a/src/crypto/util.rs b/src/crypto/util.rs deleted file mode 100644 index 7352f0cad..000000000 --- a/src/crypto/util.rs +++ /dev/null @@ -1,47 +0,0 @@ -/* 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 blake2b_simd::Params; -use darkfi_sdk::crypto::constants::util::gen_const_array; -use halo2_gadgets::poseidon::primitives as poseidon; -use pasta_curves::{arithmetic::FieldExt, pallas}; - -pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> pallas::Scalar { - let mut hasher = Params::new().hash_length(64).personal(persona).to_state(); - hasher.update(a); - hasher.update(b); - let ret = hasher.finalize(); - pallas::Scalar::from_bytes_wide(ret.as_array()) -} - -/// Simplified wrapper for poseidon hash function. -pub fn poseidon_hash(messages: [pallas::Base; N]) -> pallas::Base { - poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength, 3, 2>::init() - .hash(messages) -} - -/// The sequence of bits representing a u64 in little-endian order. -/// -/// # Panics -/// -/// Panics if the expected length of the sequence `NUM_BITS` exceeds -/// 64. -pub fn i2lebsp(int: u64) -> [bool; NUM_BITS] { - assert!(NUM_BITS <= 64); - gen_const_array(|mask: usize| (int & (1 << mask)) != 0) -} diff --git a/src/node/state.rs b/src/node/state.rs index 515404a55..4ace5029a 100644 --- a/src/node/state.rs +++ b/src/node/state.rs @@ -16,7 +16,9 @@ * along with this program. If not, see . */ -use darkfi_sdk::crypto::{constants::MERKLE_DEPTH, MerkleNode, Nullifier, PublicKey, SecretKey}; +use darkfi_sdk::crypto::{ + constants::MERKLE_DEPTH, poseidon_hash, MerkleNode, Nullifier, PublicKey, SecretKey, +}; use incrementalmerkletree::{bridgetree::BridgeTree, Tree}; use lazy_init::Lazy; use log::{debug, error}; @@ -28,7 +30,6 @@ use crate::{ coin::{Coin, OwnCoin}, note::{EncryptedNote, Note}, proof::VerifyingKey, - util::poseidon_hash, }, tx::Transaction, wallet::walletdb::WalletPtr, diff --git a/src/sdk/src/crypto/contract_id.rs b/src/sdk/src/crypto/contract_id.rs index 2691a4466..4cf1b4004 100644 --- a/src/sdk/src/crypto/contract_id.rs +++ b/src/sdk/src/crypto/contract_id.rs @@ -20,9 +20,9 @@ use darkfi_serial::{serialize, SerialDecodable, SerialEncodable}; use pasta_curves::{group::ff::PrimeField, pallas}; use super::{poseidon_hash, PublicKey, SecretKey}; +use crate::error::ContractError; -/// ContractId represents an on-chain identifier for a certain -/// smart contract. +/// ContractId represents an on-chain identifier for a certain smart contract. #[derive(Copy, Clone, Debug, Eq, PartialEq, SerialEncodable, SerialDecodable)] pub struct ContractId(pallas::Base); @@ -41,9 +41,13 @@ impl ContractId { } /// Create a `ContractId` object from given bytes. - pub fn from_bytes(x: [u8; 32]) -> Self { - // FIXME: Handle Option - Self(pallas::Base::from_repr(x).unwrap()) + pub fn from_bytes(x: [u8; 32]) -> Result { + match pallas::Base::from_repr(x).into() { + Some(v) => Ok(Self(v)), + None => Err(ContractError::IoError( + "Failed to instantiate ContractId from bytes".to_string(), + )), + } } /// `blake3(self || tree_name)` is used in datbases to have a @@ -63,10 +67,41 @@ impl From for ContractId { } } -impl std::fmt::Display for ContractId { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - // base58 encoding +impl core::fmt::Display for ContractId { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + // Base58 encoding let contractid: String = bs58::encode(self.0.to_repr()).into_string(); write!(f, "{}", contractid) } } + +impl TryFrom<&str> for ContractId { + type Error = ContractError; + + fn try_from(s: &str) -> Result { + let bytes: [u8; 32] = match bs58::decode(s).into_vec() { + Ok(v) => { + if v.len() != 32 { + return Err(ContractError::IoError( + "Decoded bs58 string for ContractId is not 32 bytes long".to_string(), + )) + } + + v.try_into().unwrap() + } + Err(e) => { + return Err(ContractError::IoError(format!( + "Failed to decode bs58 for ContractId: {}", + e + ))) + } + }; + + match pallas::Base::from_repr(bytes).into() { + Some(v) => Ok(Self(v)), + None => { + Err(ContractError::IoError("Bytes for ContractId are noncanonical".to_string())) + } + } + } +} diff --git a/src/sdk/src/crypto/keypair.rs b/src/sdk/src/crypto/keypair.rs index 5c5fc9eed..f5283940f 100644 --- a/src/sdk/src/crypto/keypair.rs +++ b/src/sdk/src/crypto/keypair.rs @@ -119,7 +119,7 @@ impl PublicKey { /// Derive a new `PublicKey` object given a `SecretKey` pub fn from_secret(s: SecretKey) -> Self { let p = NullifierK.generator() * mod_r_p(s.inner()); - Self(pallas::Point::from(p)) + Self(p) } /// Instantiate a `PublicKey` given 32 bytes. Returns an error @@ -131,6 +131,11 @@ impl PublicKey { } } + /// Downcast the `PublicKey` to 32 bytes of `pallas::Point` + pub fn to_bytes(&self) -> [u8; 32] { + self.0.to_bytes() + } + /// Fetch the `x` coordinate of this `PublicKey` pub fn x(&self) -> pallas::Base { *self.0.to_affine().coordinates().unwrap().x() @@ -154,13 +159,6 @@ impl From for PublicKey { } } -impl core::hash::Hash for PublicKey { - fn hash(&self, state: &mut H) { - let bytes = self.0.to_affine().to_bytes(); - bytes.hash(state); - } -} - impl FromStr for PublicKey { type Err = ContractError; diff --git a/src/sdk/src/crypto/mod.rs b/src/sdk/src/crypto/mod.rs index d5960f9b4..83d35db90 100644 --- a/src/sdk/src/crypto/mod.rs +++ b/src/sdk/src/crypto/mod.rs @@ -46,6 +46,10 @@ pub use address::Address; pub mod contract_id; pub use contract_id::ContractId; +/// Token ID definitions and methods +pub mod token_id; +pub use token_id::TokenId; + /// Merkle node definitions pub mod merkle_node; pub use merkle_node::{MerkleNode, MerkleTree}; diff --git a/src/sdk/src/crypto/token_id.rs b/src/sdk/src/crypto/token_id.rs new file mode 100644 index 000000000..381f334da --- /dev/null +++ b/src/sdk/src/crypto/token_id.rs @@ -0,0 +1,96 @@ +/* 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 darkfi_serial::{SerialDecodable, SerialEncodable}; +use pasta_curves::{group::ff::PrimeField, pallas}; + +use super::{poseidon_hash, PublicKey, SecretKey}; +use crate::error::ContractError; + +/// TokenId represents an on-chain identifier for a certain token. +#[derive(Copy, Clone, Debug, Eq, PartialEq, SerialEncodable, SerialDecodable)] +pub struct TokenId(pallas::Base); + +impl TokenId { + /// Derives a `TokenId` given 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]); + Self(hash) + } + + /// Get the inner `pallas::Base` element. + pub fn inner(&self) -> pallas::Base { + self.0 + } + + /// Create a `TokenId` object from given bytes, erroring if the input + /// bytes are noncanonical. + pub fn from_bytes(x: [u8; 32]) -> Result { + match pallas::Base::from_repr(x).into() { + Some(v) => Ok(Self(v)), + None => { + Err(ContractError::IoError("Failed to instantiate TokenId from bytes".to_string())) + } + } + } +} + +impl From for TokenId { + fn from(x: pallas::Base) -> Self { + Self(x) + } +} + +impl core::fmt::Display for TokenId { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + // Base58 encoding + let tokenid: String = bs58::encode(self.0.to_repr()).into_string(); + write!(f, "{}", tokenid) + } +} + +impl TryFrom<&str> for TokenId { + type Error = ContractError; + + fn try_from(s: &str) -> Result { + let bytes: [u8; 32] = match bs58::decode(s).into_vec() { + Ok(v) => { + if v.len() != 32 { + return Err(ContractError::IoError( + "Decoded bs58 string for TokenId is not 32 bytes long".to_string(), + )) + } + + v.try_into().unwrap() + } + Err(e) => { + return Err(ContractError::IoError(format!( + "Failed to decode bs58 for TokenId: {}", + e + ))) + } + }; + + match pallas::Base::from_repr(bytes).into() { + Some(v) => Ok(Self(v)), + None => Err(ContractError::IoError("Bytes for TokenId are noncanonical".to_string())), + } + } +} diff --git a/src/sdk/src/db.rs b/src/sdk/src/db.rs index 0431dd6b0..e35d59272 100644 --- a/src/sdk/src/db.rs +++ b/src/sdk/src/db.rs @@ -49,7 +49,7 @@ pub fn db_init(contract_id: ContractId, db_name: &str) -> GenericResult GenericResult GenericResult<() len += key.to_vec().encode(&mut buf)?; len += value.to_vec().encode(&mut buf)?; - return match db_set_(buf.as_ptr(), len as u32) { + match db_set_(buf.as_ptr(), len as u32) { 0 => Ok(()), -1 => Err(ContractError::CallerAccessDenied), -2 => Err(ContractError::DbSetFailed), diff --git a/src/sdk/src/entrypoint.rs b/src/sdk/src/entrypoint.rs index 1c8ec369f..6cdd63b28 100644 --- a/src/sdk/src/entrypoint.rs +++ b/src/sdk/src/entrypoint.rs @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -use std::{mem::size_of, slice::from_raw_parts}; +use core::{mem::size_of, slice::from_raw_parts}; use crate::crypto::ContractId; @@ -72,6 +72,7 @@ macro_rules! define_contract { } /// Deserialize a given payload in `entrypoint` +/// The return values from this are the input values for the above defined functions. /// # Safety pub unsafe fn deserialize<'a>(input: *mut u8) -> (ContractId, &'a [u8]) { let mut offset: usize = 0; @@ -84,8 +85,9 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (ContractId, &'a [u8]) { offset += size_of::(); let instruction_data = { from_raw_parts(input.add(offset), instruction_data_len) }; - // FIXME: ContractId recovery should use proper serialization, and also - // there should be a Result<>; we can match on it in the macros - // above and return errors if needed. - (ContractId::from_bytes(contract_id_slice.try_into().unwrap()), instruction_data) + let contract_id = ContractId::from_bytes(contract_id_slice.try_into().unwrap()); + // We unwrap here because if this panics, something's wrong in the runtime: + let contract_id = contract_id.unwrap(); + + (contract_id, instruction_data) } diff --git a/src/sdk/src/merkle.rs b/src/sdk/src/merkle.rs index 52b45684b..2595d54e3 100644 --- a/src/sdk/src/merkle.rs +++ b/src/sdk/src/merkle.rs @@ -36,7 +36,8 @@ pub fn merkle_add( len += db_roots.encode(&mut buf)?; len += key.to_vec().encode(&mut buf)?; len += coin.encode(&mut buf)?; - return match unsafe { merkle_add_(buf.as_ptr(), len as u32) } { + + match unsafe { merkle_add_(buf.as_ptr(), len as u32) } { 0 => Ok(()), -1 => Err(ContractError::CallerAccessDenied), -2 => Err(ContractError::DbSetFailed), diff --git a/src/sdk/src/util.rs b/src/sdk/src/util.rs index 63cf62b0b..9b30114d6 100644 --- a/src/sdk/src/util.rs +++ b/src/sdk/src/util.rs @@ -20,7 +20,7 @@ use super::error::ContractError; pub fn set_return_data(data: &[u8]) -> Result<(), ContractError> { unsafe { - return match set_return_data_(data.as_ptr(), data.len() as u32) { + match set_return_data_(data.as_ptr(), data.len() as u32) { 0 => Ok(()), errcode => Err(ContractError::from(errcode)), } @@ -28,15 +28,15 @@ pub fn set_return_data(data: &[u8]) -> Result<(), ContractError> { } pub fn put_object_bytes(data: &[u8]) -> i64 { - unsafe { return put_object_bytes_(data.as_ptr(), data.len() as u32) } + unsafe { put_object_bytes_(data.as_ptr(), data.len() as u32) } } pub fn get_object_bytes(data: &mut [u8], object_index: u32) -> i64 { - unsafe { return get_object_bytes_(data.as_mut_ptr(), object_index as u32) } + unsafe { get_object_bytes_(data.as_mut_ptr(), object_index as u32) } } pub fn get_object_size(object_index: u32) -> i64 { - unsafe { return get_object_size_(object_index as u32) } + unsafe { get_object_size_(object_index as u32) } } extern "C" { diff --git a/src/wallet/walletdb.rs b/src/wallet/walletdb.rs index 696e0681e..f7bad71b4 100644 --- a/src/wallet/walletdb.rs +++ b/src/wallet/walletdb.rs @@ -534,11 +534,8 @@ impl WalletDb { #[cfg(test)] mod tests { use super::*; - use crate::crypto::{ - types::{DrkCoinBlind, DrkSerial, DrkValueBlind}, - util::poseidon_hash, - }; - use darkfi_sdk::crypto::MerkleNode; + use crate::crypto::types::{DrkCoinBlind, DrkSerial, DrkValueBlind}; + use darkfi_sdk::crypto::{poseidon_hash, MerkleNode}; use incrementalmerkletree::Tree; use pasta_curves::{group::ff::Field, pallas}; use rand::rngs::OsRng; diff --git a/tests/burn_proof.rs b/tests/burn_proof.rs index ff9735dd0..fa649983b 100644 --- a/tests/burn_proof.rs +++ b/tests/burn_proof.rs @@ -19,7 +19,6 @@ use darkfi::{ crypto::{ proof::{ProvingKey, VerifyingKey}, - util::poseidon_hash, Proof, }, zk::{ @@ -31,7 +30,7 @@ use darkfi::{ }; use darkfi_sdk::crypto::{ pedersen::{pedersen_commitment_base, pedersen_commitment_u64}, - MerkleNode, Nullifier, PublicKey, SecretKey, + poseidon_hash, MerkleNode, Nullifier, PublicKey, SecretKey, }; use halo2_gadgets::poseidon::primitives as poseidon; use halo2_proofs::circuit::Value;