Эх сурвалжийг харах

Migrate more crypto API to sdk

parazyd 3 жил өмнө
parent
commit
e6455facb7
43 өөрчлөгдсөн 294 нэмэгдсэн , 213 устгасан
  1. 4 4
      bin/dao/daod/src/contract/dao/exec/validate.rs
  2. 2 2
      bin/dao/daod/src/contract/dao/exec/wallet.rs
  3. 2 2
      bin/dao/daod/src/contract/dao/mint/wallet.rs
  4. 4 2
      bin/dao/daod/src/contract/dao/propose/wallet.rs
  5. 8 7
      bin/dao/daod/src/contract/dao/state.rs
  6. 3 2
      bin/dao/daod/src/contract/dao/vote/wallet.rs
  7. 28 22
      bin/dao/daod/src/main.rs
  8. 3 3
      bin/dao/daod/src/rpc.rs
  9. 5 15
      bin/dao/daod/src/util.rs
  10. 1 1
      bin/darkotc/src/main.rs
  11. 4 4
      example/dao/src/contract/dao/exec/validate.rs
  12. 2 2
      example/dao/src/contract/dao/exec/wallet.rs
  13. 2 2
      example/dao/src/contract/dao/mint/wallet.rs
  14. 4 2
      example/dao/src/contract/dao/propose/wallet.rs
  15. 8 7
      example/dao/src/contract/dao/state.rs
  16. 3 2
      example/dao/src/contract/dao/vote/wallet.rs
  17. 8 3
      example/dao/src/main.rs
  18. 5 15
      example/dao/src/util.rs
  19. 2 2
      example/dao2/src/contract/dao/exec/wallet.rs
  20. 2 2
      example/dao2/src/contract/dao/mint/wallet.rs
  21. 4 2
      example/dao2/src/contract/dao/propose/wallet.rs
  22. 3 2
      example/dao2/src/contract/dao/vote/wallet.rs
  23. 2 3
      example/dao2/src/main.rs
  24. 2 3
      example/dao2/src/schema.rs
  25. 1 2
      example/tx.rs
  26. 1 1
      src/consensus/coins.rs
  27. 3 2
      src/consensus/ouroboros/state.rs
  28. 4 7
      src/crypto/burn_proof.rs
  29. 2 2
      src/crypto/mimc_vdf.rs
  30. 1 2
      src/crypto/mint_proof.rs
  31. 0 1
      src/crypto/mod.rs
  32. 0 47
      src/crypto/util.rs
  33. 3 2
      src/node/state.rs
  34. 43 8
      src/sdk/src/crypto/contract_id.rs
  35. 6 8
      src/sdk/src/crypto/keypair.rs
  36. 4 0
      src/sdk/src/crypto/mod.rs
  37. 96 0
      src/sdk/src/crypto/token_id.rs
  38. 3 3
      src/sdk/src/db.rs
  39. 7 5
      src/sdk/src/entrypoint.rs
  40. 2 1
      src/sdk/src/merkle.rs
  41. 4 4
      src/sdk/src/util.rs
  42. 2 5
      src/wallet/walletdb.rs
  43. 1 2
      tests/burn_proof.rs

+ 4 - 4
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<T> = std::result::Result<T, Error>;
@@ -191,7 +191,7 @@ pub fn state_transition(
     // 3. get the ProposalVote from DAO::State
     let state =
         states.lookup::<dao::State>(*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::<dao::State>(*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();
     }
 }

+ 2 - 2
bin/dao/daod/src/contract/dao/exec/wallet.rs

@@ -16,14 +16,14 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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},
 };
 

+ 2 - 2
bin/dao/daod/src/contract/dao/mint/wallet.rs

@@ -16,13 +16,13 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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},
 };
 

+ 4 - 2
bin/dao/daod/src/contract/dao/propose/wallet.rs

@@ -16,7 +16,9 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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},
 };
 

+ 8 - 7
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<pallas::Base>,
     pub proposal_tree: MerkleTree,
     pub proposal_roots: Vec<MerkleNode>,
-    pub proposal_votes: HashMap<HashableBase, ProposalVotes>,
+    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 {

+ 3 - 2
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},
 };
 

+ 28 - 22
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<PublicKey, MoneyWallet>,
+    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::State>(*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::State>(*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()
             ))?;

+ 3 - 3
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();

+ 5 - 15
bin/dao/daod/src/util.rs

@@ -16,7 +16,7 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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<H: Hasher>(&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<dyn Any + Send>;
 
 pub struct StateRegistry {
-    pub states: HashMap<HashableBase, GenericContractState>,
+    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())
     }
 }
 

+ 1 - 1
bin/darkotc/src/main.rs

@@ -551,7 +551,7 @@ async fn sign_tx(endpoint: Url, data: &str) -> Result<Transaction> {
         exit(1);
     }
 
-    tx.inputs[idx_to_sign].signature = signature.clone();
+    tx.inputs[idx_to_sign].signature = signature;
     Ok(tx)
 }
 

+ 4 - 4
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<T> = std::result::Result<T, Error>;
@@ -189,7 +189,7 @@ pub fn state_transition(
     // 3. get the ProposalVote from DAO::State
     let state =
         states.lookup::<dao::State>(*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::<dao::State>(*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();
     }
 }

+ 2 - 2
example/dao/src/contract/dao/exec/wallet.rs

@@ -16,14 +16,14 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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},
 };
 

+ 2 - 2
example/dao/src/contract/dao/mint/wallet.rs

@@ -16,13 +16,13 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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},
 };
 

+ 4 - 2
example/dao/src/contract/dao/propose/wallet.rs

@@ -16,7 +16,9 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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},
 };
 

+ 8 - 7
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<pallas::Base>,
     pub proposal_tree: MerkleTree,
     pub proposal_roots: Vec<MerkleNode>,
-    pub proposal_votes: HashMap<HashableBase, ProposalVotes>,
+    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 {

+ 3 - 2
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},
 };
 

+ 8 - 3
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) }

+ 5 - 15
example/dao/src/util.rs

@@ -16,7 +16,7 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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<H: Hasher>(&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<dyn Any + Send>;
 
 pub struct StateRegistry {
-    pub states: HashMap<HashableBase, GenericContractState>,
+    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())
     }
 }
 

+ 2 - 2
example/dao2/src/contract/dao/exec/wallet.rs

@@ -16,14 +16,14 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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},
 };
 

+ 2 - 2
example/dao2/src/contract/dao/mint/wallet.rs

@@ -16,13 +16,13 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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},
 };
 

+ 4 - 2
example/dao2/src/contract/dao/propose/wallet.rs

@@ -16,7 +16,9 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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},
 };
 

+ 3 - 2
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},
 };
 

+ 2 - 3
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,
 };

+ 2 - 3
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,

+ 1 - 2
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::{

+ 1 - 1
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,

+ 3 - 2
src/consensus/ouroboros/state.rs

@@ -16,7 +16,9 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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},
 };

+ 4 - 7
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,

+ 2 - 2
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.

+ 1 - 2
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,

+ 0 - 1
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;

+ 0 - 47
src/crypto/util.rs

@@ -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 <https://www.gnu.org/licenses/>.
- */
-
-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<const N: usize>(messages: [pallas::Base; N]) -> pallas::Base {
-    poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<N>, 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<const NUM_BITS: usize>(int: u64) -> [bool; NUM_BITS] {
-    assert!(NUM_BITS <= 64);
-    gen_const_array(|mask: usize| (int & (1 << mask)) != 0)
-}

+ 3 - 2
src/node/state.rs

@@ -16,7 +16,9 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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,

+ 43 - 8
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<Self, ContractError> {
+        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<pallas::Base> 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<Self, Self::Error> {
+        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()))
+            }
+        }
+    }
+}

+ 6 - 8
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<pallas::Point> for PublicKey {
     }
 }
 
-impl core::hash::Hash for PublicKey {
-    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
-        let bytes = self.0.to_affine().to_bytes();
-        bytes.hash(state);
-    }
-}
-
 impl FromStr for PublicKey {
     type Err = ContractError;
 

+ 4 - 0
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};

+ 96 - 0
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 <https://www.gnu.org/licenses/>.
+ */
+
+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<Self, ContractError> {
+        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<pallas::Base> 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<Self, Self::Error> {
+        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())),
+        }
+    }
+}

+ 3 - 3
src/sdk/src/db.rs

@@ -49,7 +49,7 @@ pub fn db_init(contract_id: ContractId, db_name: &str) -> GenericResult<DbHandle
             }
         }
 
-        return Ok(ret as u32)
+        Ok(ret as u32)
     }
 }
 
@@ -70,7 +70,7 @@ pub fn db_lookup(contract_id: ContractId, db_name: &str) -> GenericResult<DbHand
             }
         }
 
-        return Ok(ret as u32)
+        Ok(ret as u32)
     }
 }
 
@@ -118,7 +118,7 @@ pub fn db_set(db_handle: DbHandle, key: &[u8], value: &[u8]) -> 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),

+ 7 - 5
src/sdk/src/entrypoint.rs

@@ -16,7 +16,7 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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::<u64>();
     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)
 }

+ 2 - 1
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),

+ 4 - 4
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" {

+ 2 - 5
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;

+ 1 - 2
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;