Jelajahi Sumber

add a Blind type to the SDK, which is used in all bullas as the explicit blinding factor.

zero 2 tahun lalu
induk
melakukan
2094274851
39 mengubah file dengan 318 tambahan dan 235 penghapusan
  1. 13 13
      bin/drk/src/dao.rs
  2. 5 5
      bin/drk/src/money.rs
  3. 14 14
      bin/drk/src/swap.rs
  4. 2 3
      bin/drk/src/token.rs
  5. 14 11
      src/contract/dao/src/client/auth_xfer.rs
  6. 11 9
      src/contract/dao/src/client/exec.rs
  7. 1 1
      src/contract/dao/src/client/mint.rs
  8. 13 13
      src/contract/dao/src/client/propose.rs
  9. 13 12
      src/contract/dao/src/client/vote.rs
  10. 5 5
      src/contract/dao/src/model.rs
  11. 7 7
      src/contract/dao/tests/integration.rs
  12. 6 6
      src/contract/money/src/client/auth_token_mint_v1.rs
  13. 23 23
      src/contract/money/src/client/fee_v1.rs
  14. 5 5
      src/contract/money/src/client/genesis_mint_v1.rs
  15. 11 11
      src/contract/money/src/client/mod.rs
  16. 6 5
      src/contract/money/src/client/pow_reward_v1.rs
  17. 9 6
      src/contract/money/src/client/swap_v1.rs
  18. 1 1
      src/contract/money/src/client/token_freeze_v1.rs
  19. 2 2
      src/contract/money/src/client/token_mint_v1.rs
  20. 11 8
      src/contract/money/src/client/transfer_v1/builder.rs
  21. 4 4
      src/contract/money/src/client/transfer_v1/mod.rs
  22. 17 17
      src/contract/money/src/client/transfer_v1/proof.rs
  23. 1 1
      src/contract/money/src/entrypoint/fee_v1.rs
  24. 1 1
      src/contract/money/src/entrypoint/genesis_mint_v1.rs
  25. 1 1
      src/contract/money/src/entrypoint/pow_reward_v1.rs
  26. 1 1
      src/contract/money/src/entrypoint/transfer_v1.rs
  27. 11 10
      src/contract/money/src/model/mod.rs
  28. 7 8
      src/contract/test-harness/src/dao_exec.rs
  29. 2 2
      src/contract/test-harness/src/dao_propose.rs
  30. 7 7
      src/contract/test-harness/src/lib.rs
  31. 2 2
      src/contract/test-harness/src/money_airdrop.rs
  32. 7 7
      src/contract/test-harness/src/money_otc_swap.rs
  33. 2 2
      src/contract/test-harness/src/money_token.rs
  34. 2 2
      src/sdk/python/src/crypto.rs
  35. 66 0
      src/sdk/src/crypto/blind.rs
  36. 4 0
      src/sdk/src/crypto/mod.rs
  37. 5 4
      src/sdk/src/crypto/pedersen.rs
  38. 3 3
      tests/halo2_vk_ser.rs
  39. 3 3
      tests/zkvm_opcodes.rs

+ 13 - 13
bin/drk/src/dao.rs

@@ -42,8 +42,8 @@ use darkfi_sdk::{
     crypto::{
         poseidon_hash,
         util::{fp_mod_fv, fp_to_u64},
-        FuncId, FuncRef, Keypair, MerkleNode, MerkleTree, PublicKey, SecretKey, DAO_CONTRACT_ID,
-        MONEY_CONTRACT_ID,
+        BaseBlind, Blind, FuncId, FuncRef, Keypair, MerkleNode, MerkleTree, PublicKey, ScalarBlind,
+        SecretKey, DAO_CONTRACT_ID, MONEY_CONTRACT_ID,
     },
     pasta::pallas,
     ContractCall,
@@ -120,7 +120,7 @@ pub struct DaoProposalInfo {
     pub dest: PublicKey,
     pub amount: u64,
     pub token_id: TokenId,
-    pub blind: pallas::Base,
+    pub blind: BaseBlind,
 }
 
 #[derive(SerialEncodable, SerialDecodable)]
@@ -193,7 +193,7 @@ pub struct Dao {
     /// Secret key for the DAO
     pub secret_key: SecretKey,
     /// DAO bulla blind
-    pub bulla_blind: pallas::Base,
+    pub bulla_blind: BaseBlind,
     /// Leaf position of the DAO in the Merkle tree of DAOs
     pub leaf_position: Option<bridgetree::Position>,
     /// The transaction hash where the DAO was deployed
@@ -214,7 +214,7 @@ impl Dao {
             self.gov_token_id.inner(),
             x,
             y,
-            self.bulla_blind,
+            self.bulla_blind.inner(),
         ]))
     }
 
@@ -276,7 +276,7 @@ pub struct DaoProposal {
     /// Token ID to be sent
     pub token_id: TokenId,
     /// Proposal's bulla blind
-    pub bulla_blind: pallas::Base,
+    pub bulla_blind: BaseBlind,
     /// Leaf position of this proposal in the Merkle tree of proposals
     pub leaf_position: Option<bridgetree::Position>,
     /// Snapshotted Money Merkle tree
@@ -299,7 +299,7 @@ impl DaoProposal {
             pallas::Base::from(self.amount),
             self.token_id.inner(),
             self.dao_bulla.inner(),
-            self.bulla_blind,
+            self.bulla_blind.inner(),
         ])
     }
 }
@@ -346,11 +346,11 @@ pub struct DaoVote {
     /// The vote
     pub vote_option: bool,
     /// Blinding factor for the yes vote
-    pub yes_vote_blind: pallas::Scalar,
+    pub yes_vote_blind: ScalarBlind,
     /// Value of all votes
     pub all_vote_value: u64,
     /// Blinding facfor of all votes
-    pub all_vote_blind: pallas::Scalar,
+    pub all_vote_blind: ScalarBlind,
     /// Transaction hash where this vote was casted
     pub tx_hash: Option<blake3::Hash>,
     /// call index in the transaction where this vote was casted
@@ -819,9 +819,9 @@ impl Drk {
                     let vote_option = fp_to_u64(note[0]).unwrap();
                     assert!(vote_option == 0 || vote_option == 1);
                     let vote_option = vote_option != 0;
-                    let yes_vote_blind = fp_mod_fv(note[1]);
+                    let yes_vote_blind = Blind(fp_mod_fv(note[1]));
                     let all_vote_value = fp_to_u64(note[2]).unwrap();
-                    let all_vote_blind = fp_mod_fv(note[3]);
+                    let all_vote_blind = Blind(fp_mod_fv(note[3]));
 
                     let v = DaoVote {
                         id: 0,
@@ -1545,7 +1545,7 @@ impl Drk {
             duration_days: 30,
             user_data: pallas::Base::ZERO,
             dao_bulla: dao.bulla(),
-            blind: pallas::Base::random(&mut OsRng),
+            blind: Blind::random(&mut OsRng),
         };
 
         // TODO: Simplify this model struct import once
@@ -1658,7 +1658,7 @@ impl Drk {
             duration_days: 30,
             user_data: pallas::Base::ZERO,
             dao_bulla: dao.bulla(),
-            blind: pallas::Base::random(&mut OsRng),
+            blind: Blind::random(&mut OsRng),
         };
 
         // TODO: Simplify this model struct import once

+ 5 - 5
bin/drk/src/money.rs

@@ -34,8 +34,8 @@ use darkfi_money_contract::{
 use darkfi_sdk::{
     bridgetree,
     crypto::{
-        note::AeadEncryptedNote, poseidon_hash, FuncId, Keypair, MerkleNode, MerkleTree, PublicKey,
-        SecretKey, MONEY_CONTRACT_ID,
+        note::AeadEncryptedNote, poseidon_hash, BaseBlind, FuncId, Keypair, MerkleNode, MerkleTree,
+        PublicKey, ScalarBlind, SecretKey, MONEY_CONTRACT_ID,
     },
     pasta::pallas,
 };
@@ -436,17 +436,17 @@ impl Drk {
             let Value::Blob(ref coin_blind_bytes) = row[6] else {
                 return Err(Error::ParseFailed("[get_coins] Coin blind bytes parsing failed"))
             };
-            let coin_blind: pallas::Base = deserialize(coin_blind_bytes)?;
+            let coin_blind: BaseBlind = deserialize(coin_blind_bytes)?;
 
             let Value::Blob(ref value_blind_bytes) = row[7] else {
                 return Err(Error::ParseFailed("[get_coins] Value blind bytes parsing failed"))
             };
-            let value_blind: pallas::Scalar = deserialize(value_blind_bytes)?;
+            let value_blind: ScalarBlind = deserialize(value_blind_bytes)?;
 
             let Value::Blob(ref token_blind_bytes) = row[8] else {
                 return Err(Error::ParseFailed("[get_coins] Token blind bytes parsing failed"))
             };
-            let token_blind: pallas::Base = deserialize(token_blind_bytes)?;
+            let token_blind: BaseBlind = deserialize(token_blind_bytes)?;
 
             let Value::Blob(ref secret_bytes) = row[9] else {
                 return Err(Error::ParseFailed("[get_coins] Secret bytes parsing failed"))

+ 14 - 14
bin/drk/src/swap.rs

@@ -33,8 +33,8 @@ use darkfi_money_contract::{
 };
 use darkfi_sdk::{
     crypto::{
-        contract_id::MONEY_CONTRACT_ID, pedersen::pedersen_commitment_u64, poseidon_hash, FuncId,
-        PublicKey, SecretKey,
+        contract_id::MONEY_CONTRACT_ID, pedersen::pedersen_commitment_u64, poseidon_hash,
+        BaseBlind, Blind, FuncId, PublicKey, ScalarBlind, SecretKey,
     },
     pasta::pallas,
     tx::ContractCall,
@@ -51,8 +51,8 @@ pub struct PartialSwapData {
     proofs: Vec<Proof>,
     value_pair: (u64, u64),
     token_pair: (TokenId, TokenId),
-    value_blinds: Vec<pallas::Scalar>,
-    token_blinds: Vec<pallas::Base>,
+    value_blinds: Vec<ScalarBlind>,
+    token_blinds: Vec<BaseBlind>,
 }
 
 impl fmt::Display for PartialSwapData {
@@ -125,8 +125,8 @@ impl Drk {
         let burn_circuit = ZkCircuit::new(empty_witnesses(&burn_zkbin)?, &burn_zkbin);
 
         // Since we're creating the first half, we generate the blinds.
-        let value_blinds = [pallas::Scalar::random(&mut OsRng), pallas::Scalar::random(&mut OsRng)];
-        let token_blinds = [pallas::Base::random(&mut OsRng), pallas::Base::random(&mut OsRng)];
+        let value_blinds = [Blind::random(&mut OsRng), Blind::random(&mut OsRng)];
+        let token_blinds = [Blind::random(&mut OsRng), Blind::random(&mut OsRng)];
 
         // Now we should have everything we need to build the swap half
         eprintln!("Creating Mint and Burn circuit proving keys");
@@ -138,9 +138,9 @@ impl Drk {
             token_id_send: token_send,
             value_recv,
             token_id_recv: token_recv,
-            user_data_blind_send: pallas::Base::random(&mut OsRng), // <-- FIXME: Perhaps should be passed in
-            spend_hook_recv: FuncId::none(), // <-- FIXME: Should be passed in
-            user_data_recv: pallas::Base::zero(), // <-- FIXME: Should be passed in
+            user_data_blind_send: Blind::random(&mut OsRng), // <-- FIXME: Perhaps should be passed in
+            spend_hook_recv: FuncId::none(),                 // <-- FIXME: Should be passed in
+            user_data_recv: pallas::Base::ZERO,              // <-- FIXME: Should be passed in
             value_blinds,
             token_blinds,
             coin: burn_coin,
@@ -228,9 +228,9 @@ impl Drk {
             token_id_send: partial.token_pair.1,
             value_recv: partial.value_pair.0,
             token_id_recv: partial.token_pair.0,
-            user_data_blind_send: pallas::Base::random(&mut OsRng), // <-- FIXME: Perhaps should be passed in
-            spend_hook_recv: FuncId::none(), // <-- FIXME: Should be passed in
-            user_data_recv: pallas::Base::ZERO, // <-- FIXME: Should be passed in
+            user_data_blind_send: Blind::random(&mut OsRng), // <-- FIXME: Perhaps should be passed in
+            spend_hook_recv: FuncId::none(),                 // <-- FIXME: Should be passed in
+            user_data_recv: pallas::Base::ZERO,              // <-- FIXME: Should be passed in
             value_blinds: [partial.value_blinds[1], partial.value_blinds[0]],
             token_blinds: [partial.token_blinds[1], partial.token_blinds[0]],
             coin: burn_coin,
@@ -361,7 +361,7 @@ impl Drk {
                 pub_y,
                 pallas::Base::from(note.value),
                 note.token_id.inner(),
-                note.coin_blind,
+                note.coin_blind.inner(),
             ]));
 
             if coin == params.outputs[output_idx].coin {
@@ -372,7 +372,7 @@ impl Drk {
             }
 
             let valcom = pedersen_commitment_u64(note.value, note.value_blind);
-            let tokcom = poseidon_hash([note.token_id.inner(), note.token_blind]);
+            let tokcom = poseidon_hash([note.token_id.inner(), note.token_blind.inner()]);
 
             if valcom != params.outputs[output_idx].value_commit {
                 eprintln!(

+ 2 - 3
bin/drk/src/token.rs

@@ -37,8 +37,7 @@ use darkfi_money_contract::{
 };
 use darkfi_sdk::{
     crypto::{
-        contract_id::MONEY_CONTRACT_ID, pasta_prelude::*, FuncId, FuncRef, Keypair, PublicKey,
-        SecretKey,
+        contract_id::MONEY_CONTRACT_ID, Blind, FuncId, FuncRef, Keypair, PublicKey, SecretKey,
     },
     dark_tree::DarkLeaf,
     pasta::pallas,
@@ -225,7 +224,7 @@ impl Drk {
             token_id,
             spend_hook,
             user_data,
-            blind: pallas::Base::random(&mut OsRng),
+            blind: Blind::random(&mut OsRng),
         };
 
         let builder = TokenMintCallBuilder {

+ 14 - 11
src/contract/dao/src/client/auth_xfer.rs

@@ -18,7 +18,7 @@
 
 use darkfi_money_contract::model::CoinAttributes;
 use darkfi_sdk::{
-    crypto::{note::ElGamalEncryptedNote, poseidon_hash, PublicKey, SecretKey},
+    crypto::{note::ElGamalEncryptedNote, poseidon_hash, BaseBlind, PublicKey, SecretKey},
     pasta::pallas,
 };
 
@@ -36,7 +36,7 @@ pub struct DaoAuthMoneyTransferCall {
     pub proposal: DaoProposal,
     pub proposal_coinattrs: Vec<CoinAttributes>,
     pub dao: Dao,
-    pub input_user_data_blind: pallas::Base,
+    pub input_user_data_blind: BaseBlind,
     pub dao_coin_attrs: CoinAttributes,
 }
 
@@ -69,7 +69,7 @@ impl DaoAuthMoneyTransferCall {
                 coin_attrs.token_id.inner(),
                 coin_attrs.spend_hook.inner(),
                 coin_attrs.user_data,
-                coin_attrs.blind,
+                coin_attrs.blind.inner(),
             ];
             let enc_note =
                 ElGamalEncryptedNote::encrypt(note, &ephem_secret, &coin_attrs.public_key);
@@ -80,7 +80,7 @@ impl DaoAuthMoneyTransferCall {
                 Witness::Base(Value::known(coin_attrs.token_id.inner())),
                 Witness::Base(Value::known(coin_attrs.spend_hook.inner())),
                 Witness::Base(Value::known(coin_attrs.user_data)),
-                Witness::Base(Value::known(coin_attrs.blind)),
+                Witness::Base(Value::known(coin_attrs.blind.inner())),
                 Witness::Base(Value::known(ephem_secret.inner())),
             ];
 
@@ -112,8 +112,11 @@ impl DaoAuthMoneyTransferCall {
         let dao_public_key = self.dao.public_key.inner();
         let dao_change_value = pallas::Base::from(self.dao_coin_attrs.value);
 
-        let note =
-            [dao_change_value, self.dao_coin_attrs.token_id.inner(), self.dao_coin_attrs.blind];
+        let note = [
+            dao_change_value,
+            self.dao_coin_attrs.token_id.inner(),
+            self.dao_coin_attrs.blind.inner(),
+        ];
         let dao_change_attrs =
             ElGamalEncryptedNote::encrypt(note, &ephem_secret, &self.dao.public_key);
 
@@ -125,7 +128,7 @@ impl DaoAuthMoneyTransferCall {
         let dao_approval_ratio_base = pallas::Base::from(self.dao.approval_ratio_base);
 
         let input_user_data_enc =
-            poseidon_hash([self.dao.to_bulla().inner(), self.input_user_data_blind]);
+            poseidon_hash([self.dao.to_bulla().inner(), self.input_user_data_blind.inner()]);
 
         let prover_witnesses = vec![
             // proposal params
@@ -133,7 +136,7 @@ impl DaoAuthMoneyTransferCall {
             Witness::Base(Value::known(pallas::Base::from(self.proposal.creation_day))),
             Witness::Base(Value::known(pallas::Base::from(self.proposal.duration_days))),
             Witness::Base(Value::known(self.proposal.user_data)),
-            Witness::Base(Value::known(self.proposal.blind)),
+            Witness::Base(Value::known(self.proposal.blind.inner())),
             // DAO params
             Witness::Base(Value::known(dao_proposer_limit)),
             Witness::Base(Value::known(dao_quorum)),
@@ -141,13 +144,13 @@ impl DaoAuthMoneyTransferCall {
             Witness::Base(Value::known(dao_approval_ratio_base)),
             Witness::Base(Value::known(self.dao.gov_token_id.inner())),
             Witness::EcNiPoint(Value::known(dao_public_key)),
-            Witness::Base(Value::known(self.dao.bulla_blind)),
+            Witness::Base(Value::known(self.dao.bulla_blind.inner())),
             // Dao input user data blind
-            Witness::Base(Value::known(self.input_user_data_blind)),
+            Witness::Base(Value::known(self.input_user_data_blind.inner())),
             // Dao output coin attrs
             Witness::Base(Value::known(dao_change_value)),
             Witness::Base(Value::known(self.dao_coin_attrs.token_id.inner())),
-            Witness::Base(Value::known(self.dao_coin_attrs.blind)),
+            Witness::Base(Value::known(self.dao_coin_attrs.blind.inner())),
             // DAO::exec() func ID
             Witness::Base(Value::known(self.dao_coin_attrs.spend_hook.inner())),
             // Encrypted change DAO output

+ 11 - 9
src/contract/dao/src/client/exec.rs

@@ -17,7 +17,9 @@
  */
 
 use darkfi_sdk::{
-    crypto::{pasta_prelude::*, pedersen_commitment_u64, PublicKey, SecretKey},
+    crypto::{
+        pasta_prelude::*, pedersen_commitment_u64, BaseBlind, PublicKey, ScalarBlind, SecretKey,
+    },
     pasta::pallas,
 };
 
@@ -37,11 +39,11 @@ pub struct DaoExecCall {
     pub dao: Dao,
     pub yes_vote_value: u64,
     pub all_vote_value: u64,
-    pub yes_vote_blind: pallas::Scalar,
-    pub all_vote_blind: pallas::Scalar,
+    pub yes_vote_blind: ScalarBlind,
+    pub all_vote_blind: ScalarBlind,
     pub input_value: u64,
-    pub input_value_blind: pallas::Scalar,
-    pub input_user_data_blind: pallas::Base,
+    pub input_value_blind: ScalarBlind,
+    pub input_user_data_blind: BaseBlind,
     pub hook_dao_exec: pallas::Base,
     pub signature_secret: SecretKey,
 }
@@ -82,7 +84,7 @@ impl DaoExecCall {
             Witness::Base(Value::known(pallas::Base::from(self.proposal.creation_day))),
             Witness::Base(Value::known(pallas::Base::from(self.proposal.duration_days))),
             Witness::Base(Value::known(self.proposal.user_data)),
-            Witness::Base(Value::known(self.proposal.blind)),
+            Witness::Base(Value::known(self.proposal.blind.inner())),
             // DAO params
             Witness::Base(Value::known(dao_proposer_limit)),
             Witness::Base(Value::known(dao_quorum)),
@@ -91,12 +93,12 @@ impl DaoExecCall {
             Witness::Base(Value::known(self.dao.gov_token_id.inner())),
             Witness::Base(Value::known(dao_pub_x)),
             Witness::Base(Value::known(dao_pub_y)),
-            Witness::Base(Value::known(self.dao.bulla_blind)),
+            Witness::Base(Value::known(self.dao.bulla_blind.inner())),
             // votes
             Witness::Base(Value::known(pallas::Base::from(self.yes_vote_value))),
             Witness::Base(Value::known(pallas::Base::from(self.all_vote_value))),
-            Witness::Scalar(Value::known(self.yes_vote_blind)),
-            Witness::Scalar(Value::known(self.all_vote_blind)),
+            Witness::Scalar(Value::known(self.yes_vote_blind.inner())),
+            Witness::Scalar(Value::known(self.all_vote_blind.inner())),
             // signature secret
             Witness::Base(Value::known(self.signature_secret.inner())),
         ];

+ 1 - 1
src/contract/dao/src/client/mint.rs

@@ -64,7 +64,7 @@ pub fn make_mint_call(
         Witness::Base(halo2::Value::known(dao_approval_ratio_base)),
         Witness::Base(halo2::Value::known(dao.gov_token_id.inner())),
         Witness::Base(halo2::Value::known(dao_secret_key.inner())),
-        Witness::Base(halo2::Value::known(dao.bulla_blind)),
+        Witness::Base(halo2::Value::known(dao.bulla_blind.inner())),
     ];
 
     let (pub_x, pub_y) = dao.public_key.xy();

+ 13 - 13
src/contract/dao/src/client/propose.rs

@@ -22,7 +22,7 @@ use darkfi_sdk::{
     bridgetree::Hashable,
     crypto::{
         note::AeadEncryptedNote, pasta_prelude::*, pedersen::pedersen_commitment_u64,
-        poseidon_hash, FuncId, MerkleNode, PublicKey, SecretKey,
+        poseidon_hash, Blind, FuncId, MerkleNode, PublicKey, ScalarBlind, SecretKey,
     },
     pasta::pallas,
 };
@@ -63,14 +63,14 @@ impl DaoProposeCall {
     ) -> Result<(DaoProposeParams, Vec<Proof>)> {
         let mut proofs = vec![];
 
-        let gov_token_blind = pallas::Base::random(&mut OsRng);
+        let gov_token_blind = Blind::random(&mut OsRng);
 
         let mut inputs = vec![];
         let mut total_funds = 0;
-        let mut total_funds_blinds = pallas::Scalar::from(0);
+        let mut total_funds_blinds = ScalarBlind::ZERO;
 
         for input in self.inputs {
-            let funds_blind = pallas::Scalar::random(&mut OsRng);
+            let funds_blind = Blind::random(&mut OsRng);
             total_funds += input.note.value;
             total_funds_blinds += funds_blind;
 
@@ -86,9 +86,9 @@ impl DaoProposeCall {
                 Witness::Base(Value::known(note.token_id.inner())),
                 Witness::Base(Value::known(pallas::Base::ZERO)),
                 Witness::Base(Value::known(pallas::Base::ZERO)),
-                Witness::Base(Value::known(note.coin_blind)),
-                Witness::Scalar(Value::known(funds_blind)),
-                Witness::Base(Value::known(gov_token_blind)),
+                Witness::Base(Value::known(note.coin_blind.inner())),
+                Witness::Scalar(Value::known(funds_blind.inner())),
+                Witness::Base(Value::known(gov_token_blind.inner())),
                 Witness::Uint32(Value::known(leaf_pos.try_into().unwrap())),
                 Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
                 Witness::Base(Value::known(input.signature_secret.inner())),
@@ -123,7 +123,7 @@ impl DaoProposeCall {
 
             let nullifier: Nullifier = poseidon_hash([input.secret.inner(), coin.inner()]).into();
 
-            let token_commit = poseidon_hash([note.token_id.inner(), gov_token_blind]);
+            let token_commit = poseidon_hash([note.token_id.inner(), gov_token_blind.inner()]);
             assert_eq!(self.dao.gov_token_id, note.token_id);
 
             let value_commit = pedersen_commitment_u64(note.value, funds_blind);
@@ -155,7 +155,7 @@ impl DaoProposeCall {
         let total_funds_coords = total_funds_commit.to_affine().coordinates().unwrap();
         let total_funds = pallas::Base::from(total_funds);
 
-        let token_commit = poseidon_hash([self.dao.gov_token_id.inner(), gov_token_blind]);
+        let token_commit = poseidon_hash([self.dao.gov_token_id.inner(), gov_token_blind.inner()]);
 
         let dao_proposer_limit = pallas::Base::from(self.dao.proposer_limit);
         let dao_quorum = pallas::Base::from(self.dao.quorum);
@@ -171,15 +171,15 @@ impl DaoProposeCall {
         let prover_witnesses = vec![
             // Proposers total number of gov tokens
             Witness::Base(Value::known(total_funds)),
-            Witness::Scalar(Value::known(total_funds_blinds)),
+            Witness::Scalar(Value::known(total_funds_blinds.inner())),
             // Used for blinding exported gov token ID
-            Witness::Base(Value::known(gov_token_blind)),
+            Witness::Base(Value::known(gov_token_blind.inner())),
             // proposal params
             Witness::Base(Value::known(self.proposal.auth_calls.commit())),
             Witness::Base(Value::known(pallas::Base::from(self.proposal.creation_day))),
             Witness::Base(Value::known(pallas::Base::from(self.proposal.duration_days))),
             Witness::Base(Value::known(self.proposal.user_data)),
-            Witness::Base(Value::known(self.proposal.blind)),
+            Witness::Base(Value::known(self.proposal.blind.inner())),
             // DAO params
             Witness::Base(Value::known(dao_proposer_limit)),
             Witness::Base(Value::known(dao_quorum)),
@@ -188,7 +188,7 @@ impl DaoProposeCall {
             Witness::Base(Value::known(self.dao.gov_token_id.inner())),
             Witness::Base(Value::known(dao_pub_x)),
             Witness::Base(Value::known(dao_pub_y)),
-            Witness::Base(Value::known(self.dao.bulla_blind)),
+            Witness::Base(Value::known(self.dao.bulla_blind.inner())),
             Witness::Uint32(Value::known(dao_leaf_position.try_into().unwrap())),
             Witness::MerklePath(Value::known(self.dao_merkle_path.try_into().unwrap())),
         ];

+ 13 - 12
src/contract/dao/src/client/vote.rs

@@ -22,7 +22,7 @@ use darkfi_sdk::{
     bridgetree::Hashable,
     crypto::{
         note::ElGamalEncryptedNote, pasta_prelude::*, pedersen_commitment_u64, poseidon_hash,
-        util::fv_mod_fp_unsafe, FuncId, Keypair, MerkleNode, PublicKey, SecretKey,
+        util::fv_mod_fp_unsafe, Blind, FuncId, Keypair, MerkleNode, PublicKey, SecretKey,
     },
     pasta::pallas,
 };
@@ -111,7 +111,7 @@ impl DaoVoteCall {
                 Witness::Base(Value::known(note.token_id.inner())),
                 Witness::Base(Value::known(pallas::Base::ZERO)),
                 Witness::Base(Value::known(pallas::Base::ZERO)),
-                Witness::Base(Value::known(note.coin_blind)),
+                Witness::Base(Value::known(note.coin_blind.inner())),
                 Witness::Scalar(Value::known(value_blind)),
                 Witness::Base(Value::known(gov_token_blind)),
                 Witness::Uint32(Value::known(leaf_pos.try_into().unwrap())),
@@ -149,7 +149,7 @@ impl DaoVoteCall {
 
             let nullifier = poseidon_hash([input.secret.inner(), coin.inner()]);
 
-            let vote_commit = pedersen_commitment_u64(note.value, value_blind);
+            let vote_commit = pedersen_commitment_u64(note.value, Blind(value_blind));
             let vote_commit_coords = vote_commit.to_affine().coordinates().unwrap();
 
             let (sig_x, sig_y) = signature_public.xy();
@@ -196,17 +196,18 @@ impl DaoVoteCall {
                 break blind
             }
         };
-        let yes_vote_commit = pedersen_commitment_u64(vote_option * all_vote_value, yes_vote_blind);
+        let yes_vote_commit =
+            pedersen_commitment_u64(vote_option * all_vote_value, Blind(yes_vote_blind));
         let yes_vote_commit_coords = yes_vote_commit.to_affine().coordinates().unwrap();
 
-        let all_vote_commit = pedersen_commitment_u64(all_vote_value, all_vote_blind);
+        let all_vote_commit = pedersen_commitment_u64(all_vote_value, Blind(all_vote_blind));
         assert_eq!(all_vote_commit, inputs.iter().map(|i| i.vote_commit).sum());
         let all_vote_commit_coords = all_vote_commit.to_affine().coordinates().unwrap();
 
         // Convert blinds to 𝔽ₚ, which should work fine since we selected them
         // to be convertable.
-        let yes_vote_blind = fv_mod_fp_unsafe(yes_vote_blind).unwrap();
-        let all_vote_blind = fv_mod_fp_unsafe(all_vote_blind).unwrap();
+        let yes_vote_blind = Blind(fv_mod_fp_unsafe(yes_vote_blind).unwrap());
+        let all_vote_blind = Blind(fv_mod_fp_unsafe(all_vote_blind).unwrap());
 
         let vote_option = pallas::Base::from(vote_option);
         let all_vote_value_fp = pallas::Base::from(all_vote_value);
@@ -221,7 +222,7 @@ impl DaoVoteCall {
             Witness::Base(Value::known(pallas::Base::from(self.proposal.creation_day))),
             Witness::Base(Value::known(pallas::Base::from(self.proposal.duration_days))),
             Witness::Base(Value::known(self.proposal.user_data)),
-            Witness::Base(Value::known(self.proposal.blind)),
+            Witness::Base(Value::known(self.proposal.blind.inner())),
             // DAO params
             Witness::Base(Value::known(dao_proposer_limit)),
             Witness::Base(Value::known(dao_quorum)),
@@ -229,13 +230,13 @@ impl DaoVoteCall {
             Witness::Base(Value::known(dao_approval_ratio_base)),
             Witness::Base(Value::known(self.dao.gov_token_id.inner())),
             Witness::EcNiPoint(Value::known(dao_public_key)),
-            Witness::Base(Value::known(self.dao.bulla_blind)),
+            Witness::Base(Value::known(self.dao.bulla_blind.inner())),
             // Vote
             Witness::Base(Value::known(vote_option)),
-            Witness::Base(Value::known(yes_vote_blind)),
+            Witness::Base(Value::known(yes_vote_blind.inner())),
             // Total number of gov tokens allocated
             Witness::Base(Value::known(all_vote_value_fp)),
-            Witness::Base(Value::known(all_vote_blind)),
+            Witness::Base(Value::known(all_vote_blind.inner())),
             // gov token
             Witness::Base(Value::known(gov_token_blind)),
             // time checks
@@ -247,7 +248,7 @@ impl DaoVoteCall {
         assert_eq!(self.dao.to_bulla(), self.proposal.dao_bulla);
         let proposal_bulla = self.proposal.to_bulla();
 
-        let note = [vote_option, yes_vote_blind, all_vote_value_fp, all_vote_blind];
+        let note = [vote_option, yes_vote_blind.inner(), all_vote_value_fp, all_vote_blind.inner()];
         let enc_note = ElGamalEncryptedNote::encrypt(note, &ephem_secret, &self.dao_keypair.public);
 
         let public_inputs = vec![

+ 5 - 5
src/contract/dao/src/model.rs

@@ -23,7 +23,7 @@ use darkfi_sdk::{
     crypto::{
         note::{AeadEncryptedNote, ElGamalEncryptedNote},
         pasta_prelude::*,
-        poseidon_hash, MerkleNode, PublicKey,
+        poseidon_hash, BaseBlind, MerkleNode, PublicKey,
     },
     error::ContractError,
     pasta::pallas,
@@ -43,7 +43,7 @@ pub struct Dao {
     pub approval_ratio_base: u64,
     pub gov_token_id: TokenId,
     pub public_key: PublicKey,
-    pub bulla_blind: pallas::Base,
+    pub bulla_blind: BaseBlind,
 }
 // ANCHOR_END: dao
 
@@ -62,7 +62,7 @@ impl Dao {
             self.gov_token_id.inner(),
             pub_x,
             pub_y,
-            self.bulla_blind,
+            self.bulla_blind.inner(),
         ]);
         DaoBulla(bulla)
     }
@@ -148,7 +148,7 @@ pub struct DaoProposal {
     /// Arbitrary data provided by the user. We don't use this.
     pub user_data: pallas::Base,
     pub dao_bulla: DaoBulla,
-    pub blind: pallas::Base,
+    pub blind: BaseBlind,
 }
 // ANCHOR_END: dao-proposal
 
@@ -160,7 +160,7 @@ impl DaoProposal {
             pallas::Base::from(self.duration_days),
             self.user_data,
             self.dao_bulla.inner(),
-            self.blind,
+            self.blind.inner(),
         ]);
         DaoProposalBulla(bulla)
     }

+ 7 - 7
src/contract/dao/tests/integration.rs

@@ -31,7 +31,7 @@ use darkfi_sdk::{
         pasta_prelude::*,
         pedersen_commitment_u64, poseidon_hash,
         util::{fp_mod_fv, fp_to_u64},
-        FuncId, FuncRef, DAO_CONTRACT_ID, MONEY_CONTRACT_ID,
+        Blind, FuncId, FuncRef, DAO_CONTRACT_ID, MONEY_CONTRACT_ID,
     },
     pasta::pallas,
 };
@@ -98,7 +98,7 @@ fn integration_test() -> Result<()> {
             approval_ratio_quot: 1,
             gov_token_id,
             public_key: dao_keypair.public,
-            bulla_blind: pallas::Base::random(&mut OsRng),
+            bulla_blind: Blind::random(&mut OsRng),
         };
 
         // ====================
@@ -249,7 +249,7 @@ fn integration_test() -> Result<()> {
             token_id: drk_token_id,
             spend_hook: FuncId::none(),
             user_data: pallas::Base::ZERO,
-            blind: pallas::Base::random(&mut OsRng),
+            blind: Blind::random(&mut OsRng),
         }];
         // We can add whatever we want in here, even arbitrary text
         // It's up to the auth module to decide what to do with it.
@@ -342,8 +342,8 @@ fn integration_test() -> Result<()> {
         let mut total_yes_vote_value = 0;
         let mut total_all_vote_value = 0;
         let mut blind_total_vote = DaoBlindAggregateVote::default();
-        let mut total_yes_vote_blind = pallas::Scalar::ZERO;
-        let mut total_all_vote_blind = pallas::Scalar::ZERO;
+        let mut total_yes_vote_blind = Blind::ZERO;
+        let mut total_all_vote_blind = Blind::ZERO;
 
         for (i, (note, params)) in [
             (vote_note_1, alice_vote_params),
@@ -360,9 +360,9 @@ fn integration_test() -> Result<()> {
             //   all_vote_blind,
             // ]
             let vote_option = fp_to_u64(note[0]).unwrap();
-            let yes_vote_blind = fp_mod_fv(note[1]);
+            let yes_vote_blind = Blind(fp_mod_fv(note[1]));
             let all_vote_value = fp_to_u64(note[2]).unwrap();
-            let all_vote_blind = fp_mod_fv(note[3]);
+            let all_vote_blind = Blind(fp_mod_fv(note[3]));
             assert!(vote_option == 0 || vote_option == 1);
 
             total_yes_vote_blind += yes_vote_blind;

+ 6 - 6
src/contract/money/src/client/auth_token_mint_v1.rs

@@ -22,7 +22,7 @@ use darkfi::{
     Result,
 };
 use darkfi_sdk::{
-    crypto::{note::AeadEncryptedNote, pasta_prelude::*, pedersen_commitment_u64, Keypair},
+    crypto::{note::AeadEncryptedNote, pasta_prelude::*, pedersen_commitment_u64, Blind, Keypair},
     pasta::pallas,
 };
 use log::info;
@@ -56,7 +56,7 @@ impl AuthTokenMintCallBuilder {
     pub fn build(&self) -> Result<AuthTokenMintCallDebris> {
         info!("Building Money::AuthTokenMintV1 contract call");
 
-        let value_blind = pallas::Scalar::random(&mut OsRng);
+        let value_blind = Blind::random(&mut OsRng);
         let value_commit = pedersen_commitment_u64(self.coin_attrs.value, value_blind);
 
         // Create the proof
@@ -70,14 +70,14 @@ impl AuthTokenMintCallBuilder {
             Witness::Base(Value::known(pallas::Base::from(self.coin_attrs.value))),
             Witness::Base(Value::known(self.coin_attrs.spend_hook.inner())),
             Witness::Base(Value::known(self.coin_attrs.user_data)),
-            Witness::Base(Value::known(self.coin_attrs.blind)),
+            Witness::Base(Value::known(self.coin_attrs.blind.inner())),
             // Token attributes
             Witness::Base(Value::known(self.token_attrs.auth_parent.inner())),
-            Witness::Base(Value::known(self.token_attrs.blind)),
+            Witness::Base(Value::known(self.token_attrs.blind.inner())),
             // Secret key used by mint
             Witness::Base(Value::known(self.mint_keypair.secret.inner())),
             // Random blinding factor for the value commitment
-            Witness::Scalar(Value::known(value_blind)),
+            Witness::Scalar(Value::known(value_blind.inner())),
         ];
 
         let mint_pubkey = self.mint_keypair.public;
@@ -104,7 +104,7 @@ impl AuthTokenMintCallBuilder {
             user_data: self.coin_attrs.user_data,
             coin_blind: self.coin_attrs.blind,
             value_blind,
-            token_blind: pallas::Base::ZERO,
+            token_blind: Blind::ZERO,
             memo: vec![],
         };
 

+ 23 - 23
src/contract/money/src/client/fee_v1.rs

@@ -31,8 +31,8 @@ use darkfi_sdk::{
     crypto::{
         note::AeadEncryptedNote,
         pasta_prelude::{Curve, CurveAffine, Field},
-        pedersen_commitment_u64, poseidon_hash, FuncId, Keypair, MerkleNode, MerkleTree, PublicKey,
-        SecretKey,
+        pedersen_commitment_u64, poseidon_hash, BaseBlind, Blind, FuncId, Keypair, MerkleNode,
+        MerkleTree, PublicKey, ScalarBlind, SecretKey,
     },
     pasta::pallas,
 };
@@ -109,7 +109,7 @@ pub async fn append_fee_call(
         merkle_path: tree.witness(coin.leaf_position, 0).unwrap(),
         secret: coin.secret,
         note: coin.note.clone(),
-        user_data_blind: pallas::Base::random(&mut OsRng),
+        user_data_blind: Blind::random(&mut OsRng),
     };
 
     let output = FeeCallOutput {
@@ -118,13 +118,13 @@ pub async fn append_fee_call(
         token_id: coin.note.token_id,
         spend_hook: FuncId::none(),
         user_data: pallas::Base::ZERO,
-        blind: pallas::Base::random(&mut OsRng),
+        blind: Blind::random(&mut OsRng),
     };
 
-    let token_blind = pallas::Base::random(&mut OsRng);
+    let token_blind = Blind::random(&mut OsRng);
 
-    let input_value_blind = pallas::Scalar::random(&mut OsRng);
-    let fee_value_blind = pallas::Scalar::random(&mut OsRng);
+    let input_value_blind = Blind::random(&mut OsRng);
+    let fee_value_blind = Blind::random(&mut OsRng);
     let output_value_blind = compute_remainder_blind(&[], &[input_value_blind], &[fee_value_blind]);
 
     let signature_secret = SecretKey::random(&mut OsRng);
@@ -194,9 +194,9 @@ pub struct FeeCallSecrets {
     /// Decrypted note associated with the output
     pub note: MoneyNote,
     /// The value blind created for the input
-    pub input_value_blind: pallas::Scalar,
+    pub input_value_blind: ScalarBlind,
     /// The value blind created for the output
-    pub output_value_blind: pallas::Scalar,
+    pub output_value_blind: ScalarBlind,
 }
 
 /// Revealed public inputs of the `Fee_V1` ZK proof
@@ -253,7 +253,7 @@ struct FeeCallInput {
     merkle_path: Vec<MerkleNode>,
     secret: SecretKey,
     note: MoneyNote,
-    user_data_blind: pallas::Base,
+    user_data_blind: BaseBlind,
 }
 
 type FeeCallOutput = CoinAttributes;
@@ -264,13 +264,13 @@ fn create_fee_proof(
     zkbin: &ZkBinary,
     pk: &ProvingKey,
     input: &FeeCallInput,
-    input_value_blind: pallas::Scalar,
+    input_value_blind: ScalarBlind,
     output: &FeeCallOutput,
-    output_value_blind: pallas::Scalar,
+    output_value_blind: ScalarBlind,
     output_spend_hook: FuncId,
     output_user_data: pallas::Base,
-    output_coin_blind: pallas::Base,
-    token_blind: pallas::Base,
+    output_coin_blind: BaseBlind,
+    token_blind: BaseBlind,
     signature_secret: SecretKey,
 ) -> Result<(Proof, FeeRevealed)> {
     let public_key = PublicKey::from_secret(input.secret);
@@ -304,10 +304,10 @@ fn create_fee_proof(
         current
     };
 
-    let input_user_data_enc = poseidon_hash([input.note.user_data, input.user_data_blind]);
+    let input_user_data_enc = poseidon_hash([input.note.user_data, input.user_data_blind.inner()]);
     let input_value_commit = pedersen_commitment_u64(input.note.value, input_value_blind);
     let output_value_commit = pedersen_commitment_u64(output.value, output_value_blind);
-    let token_commit = poseidon_hash([input.note.token_id.inner(), token_blind]);
+    let token_commit = poseidon_hash([input.note.token_id.inner(), token_blind.inner()]);
 
     // Create output coin
     let output_coin = CoinAttributes {
@@ -316,7 +316,7 @@ fn create_fee_proof(
         token_id: output.token_id,
         spend_hook: output_spend_hook,
         user_data: output_user_data,
-        blind: output_coin_blind,
+        blind: output_coin_blind.clone(),
     }
     .to_coin();
 
@@ -338,18 +338,18 @@ fn create_fee_proof(
         Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
         Witness::Base(Value::known(signature_secret.inner())),
         Witness::Base(Value::known(pallas::Base::from(input.note.value))),
-        Witness::Scalar(Value::known(input_value_blind)),
+        Witness::Scalar(Value::known(input_value_blind.inner())),
         Witness::Base(Value::known(input.note.spend_hook.inner())),
         Witness::Base(Value::known(input.note.user_data)),
-        Witness::Base(Value::known(input.note.coin_blind)),
-        Witness::Base(Value::known(input.user_data_blind)),
+        Witness::Base(Value::known(input.note.coin_blind.inner())),
+        Witness::Base(Value::known(input.user_data_blind.inner())),
         Witness::Base(Value::known(pallas::Base::from(output.value))),
         Witness::Base(Value::known(output_spend_hook.inner())),
         Witness::Base(Value::known(output_user_data)),
-        Witness::Scalar(Value::known(output_value_blind)),
-        Witness::Base(Value::known(output_coin_blind)),
+        Witness::Scalar(Value::known(output_value_blind.inner())),
+        Witness::Base(Value::known(output_coin_blind.inner())),
         Witness::Base(Value::known(input.note.token_id.inner())),
-        Witness::Base(Value::known(token_blind)),
+        Witness::Base(Value::known(token_blind.inner())),
     ];
 
     let circuit = ZkCircuit::new(prover_witnesses, zkbin);

+ 5 - 5
src/contract/money/src/client/genesis_mint_v1.rs

@@ -22,7 +22,7 @@ use darkfi::{
     Result,
 };
 use darkfi_sdk::{
-    crypto::{note::AeadEncryptedNote, pasta_prelude::*, FuncId, Keypair, PublicKey},
+    crypto::{note::AeadEncryptedNote, pasta_prelude::*, Blind, FuncId, Keypair, PublicKey},
     pasta::pallas,
 };
 use log::{debug, info};
@@ -96,14 +96,14 @@ impl GenesisMintCallBuilder {
             token_id,
             spend_hook: FuncId::none(),
             user_data: pallas::Base::ZERO,
-            blind: pallas::Base::random(&mut OsRng),
+            blind: Blind::random(&mut OsRng),
         };
 
         // We just create the commitment blinds here. We simply encofce
         // that the clear input and the anon output have the same commitments.
         // Not sure if this can be avoided, but also is it really necessary to avoid?
-        let value_blind = pallas::Scalar::random(&mut OsRng);
-        let token_blind = pallas::Base::random(&mut OsRng);
+        let value_blind = Blind::random(&mut OsRng);
+        let token_blind = Blind::random(&mut OsRng);
 
         let c_input = ClearInput {
             value: input.value,
@@ -113,7 +113,7 @@ impl GenesisMintCallBuilder {
             signature_public: PublicKey::from_secret(input.signature_secret),
         };
 
-        let coin_blind = pallas::Base::random(&mut OsRng);
+        let coin_blind = Blind::random(&mut OsRng);
 
         info!("Creating token mint proof for output");
         let (proof, public_inputs) = create_transfer_mint_proof(

+ 11 - 11
src/contract/money/src/client/mod.rs

@@ -28,7 +28,7 @@
 
 use darkfi_sdk::{
     bridgetree,
-    crypto::{FuncId, SecretKey},
+    crypto::{BaseBlind, Blind, FuncId, ScalarBlind, SecretKey},
     pasta::pallas,
 };
 use darkfi_serial::{async_trait, SerialDecodable, SerialEncodable};
@@ -75,12 +75,12 @@ pub struct MoneyNote {
     /// User data used by protocol when spend hook is enabled
     pub user_data: pallas::Base,
     /// Blinding factor for the coin
-    pub coin_blind: pallas::Base,
+    pub coin_blind: BaseBlind,
     // TODO: look into removing these fields. We potentially don't need them [
     /// Blinding factor for the value pedersen commitment
-    pub value_blind: pallas::Scalar,
+    pub value_blind: ScalarBlind,
     /// Blinding factor for the token ID pedersen commitment
-    pub token_blind: pallas::Base,
+    pub token_blind: BaseBlind,
     // ] ^ the receiver is not interested in the value commit / token commits.
     // we just want to examine the coins in the outputs. The money::transfer() contract
     // should ensure everything else is correct.
@@ -105,22 +105,22 @@ pub struct OwnCoin {
 
 pub fn compute_remainder_blind(
     clear_inputs: &[crate::model::ClearInput],
-    input_blinds: &[pallas::Scalar],
-    output_blinds: &[pallas::Scalar],
-) -> pallas::Scalar {
+    input_blinds: &[ScalarBlind],
+    output_blinds: &[ScalarBlind],
+) -> ScalarBlind {
     let mut total = pallas::Scalar::zero();
 
     for input in clear_inputs {
-        total += input.value_blind;
+        total += input.value_blind.inner();
     }
 
     for input_blind in input_blinds {
-        total += input_blind;
+        total += input_blind.inner();
     }
 
     for output_blind in output_blinds {
-        total -= output_blind;
+        total -= output_blind.inner();
     }
 
-    total
+    Blind(total)
 }

+ 6 - 5
src/contract/money/src/client/pow_reward_v1.rs

@@ -24,7 +24,8 @@ use darkfi::{
 use darkfi_sdk::{
     blockchain::expected_reward,
     crypto::{
-        ecvrf::VrfProof, note::AeadEncryptedNote, pasta_prelude::*, FuncId, PublicKey, SecretKey,
+        ecvrf::VrfProof, note::AeadEncryptedNote, pasta_prelude::*, Blind, FuncId, PublicKey,
+        SecretKey,
     },
     pasta::pallas,
 };
@@ -101,14 +102,14 @@ impl PoWRewardCallBuilder {
             token_id,
             spend_hook: FuncId::none(),
             user_data: pallas::Base::ZERO,
-            blind: pallas::Base::random(&mut OsRng),
+            blind: Blind::random(&mut OsRng),
         };
 
         // We just create the commitment blinds here. We simply encofce
         // that the clear input and the anon output have the same commitments.
         // Not sure if this can be avoided, but also is it really necessary to avoid?
-        let value_blind = pallas::Scalar::random(&mut OsRng);
-        let token_blind = pallas::Base::random(&mut OsRng);
+        let value_blind = Blind::random(&mut OsRng);
+        let token_blind = Blind::random(&mut OsRng);
 
         let c_input = ClearInput {
             value: input.value,
@@ -118,7 +119,7 @@ impl PoWRewardCallBuilder {
             signature_public: PublicKey::from_secret(input.signature_secret),
         };
 
-        let coin_blind = pallas::Base::random(&mut OsRng);
+        let coin_blind = Blind::random(&mut OsRng);
 
         info!("Creating token mint proof for output");
         let (proof, public_inputs) = create_transfer_mint_proof(

+ 9 - 6
src/contract/money/src/client/swap_v1.rs

@@ -24,7 +24,10 @@ use darkfi::{
     ClientFailed, Result,
 };
 use darkfi_sdk::{
-    crypto::{note::AeadEncryptedNote, pasta_prelude::*, FuncId, MerkleTree, PublicKey, SecretKey},
+    crypto::{
+        note::AeadEncryptedNote, pasta_prelude::*, BaseBlind, Blind, FuncId, MerkleTree, PublicKey,
+        ScalarBlind, SecretKey,
+    },
     pasta::pallas,
 };
 use darkfi_serial::serialize;
@@ -63,7 +66,7 @@ pub struct SwapCallBuilder {
     /// The token ID of the party's output to receive
     pub token_id_recv: TokenId,
     /// User data blind for the party's input
-    pub user_data_blind_send: pallas::Base,
+    pub user_data_blind_send: BaseBlind,
     /// Spend hook for the party's output
     pub spend_hook_recv: FuncId,
     /// User data for the party's output
@@ -72,9 +75,9 @@ pub struct SwapCallBuilder {
     /// `[0]` is used for input 0 and output 1, and `[1]` is
     /// used for input 1 and output 0. The same applies to
     /// `token_blinds`.
-    pub value_blinds: [pallas::Scalar; 2],
+    pub value_blinds: [ScalarBlind; 2],
     /// The blinds to be used for token ID pedersen commitments
-    pub token_blinds: [pallas::Base; 2],
+    pub token_blinds: [BaseBlind; 2],
     /// The coin to be used as the input to the swap
     pub coin: OwnCoin,
     /// Merkle tree of coins used to create inclusion proofs
@@ -122,7 +125,7 @@ impl SwapCallBuilder {
             token_id: self.token_id_recv,
             spend_hook: FuncId::none(),
             user_data: pallas::Base::ZERO,
-            blind: pallas::Base::random(&mut OsRng),
+            blind: Blind::random(&mut OsRng),
         };
 
         // Now we fill this with necessary stuff
@@ -155,7 +158,7 @@ impl SwapCallBuilder {
         proofs.push(proof);
 
         // For the output, we create a new coin blind
-        let coin_blind = pallas::Base::random(&mut OsRng);
+        let coin_blind = Blind::random(&mut OsRng);
 
         info!("Creating mint proof for output");
         let (proof, public_inputs) = create_transfer_mint_proof(

+ 1 - 1
src/contract/money/src/client/token_freeze_v1.rs

@@ -52,7 +52,7 @@ impl TokenFreezeCallBuilder {
         let prover_witnesses = vec![
             // Token attributes
             Witness::Base(Value::known(self.token_attrs.auth_parent.inner())),
-            Witness::Base(Value::known(self.token_attrs.blind)),
+            Witness::Base(Value::known(self.token_attrs.blind.inner())),
             // Secret key used by mint
             Witness::Base(Value::known(self.mint_keypair.secret.inner())),
         ];

+ 2 - 2
src/contract/money/src/client/token_mint_v1.rs

@@ -55,11 +55,11 @@ impl TokenMintCallBuilder {
             Witness::Base(Value::known(pallas::Base::from(self.coin_attrs.value))),
             Witness::Base(Value::known(self.coin_attrs.spend_hook.inner())),
             Witness::Base(Value::known(self.coin_attrs.user_data)),
-            Witness::Base(Value::known(self.coin_attrs.blind)),
+            Witness::Base(Value::known(self.coin_attrs.blind.inner())),
             // Token attributes
             Witness::Base(Value::known(self.token_attrs.auth_parent.inner())),
             Witness::Base(Value::known(self.token_attrs.user_data)),
-            Witness::Base(Value::known(self.token_attrs.blind)),
+            Witness::Base(Value::known(self.token_attrs.blind.inner())),
         ];
 
         let coin = self.coin_attrs.to_coin();

+ 11 - 8
src/contract/money/src/client/transfer_v1/builder.rs

@@ -22,7 +22,10 @@ use darkfi::{
 };
 use darkfi_sdk::{
     bridgetree,
-    crypto::{note::AeadEncryptedNote, pasta_prelude::*, MerkleNode, PublicKey, SecretKey},
+    crypto::{
+        note::AeadEncryptedNote, pasta_prelude::*, BaseBlind, Blind, MerkleNode, PublicKey,
+        ScalarBlind, SecretKey,
+    },
     pasta::pallas,
 };
 use log::{debug, info};
@@ -65,7 +68,7 @@ pub struct TransferCallInput {
     pub note: MoneyNote,
     // In the DAO all inputs must have the same user_data_enc and use the same blind
     // So support allowing the user to set their own blind.
-    pub user_data_blind: pallas::Base,
+    pub user_data_blind: BaseBlind,
 }
 
 pub type TransferCallOutput = CoinAttributes;
@@ -80,12 +83,12 @@ impl TransferCallBuilder {
         let mut signature_secrets = vec![];
         let mut proofs = vec![];
 
-        let token_blind = pallas::Base::random(&mut OsRng);
+        let token_blind = Blind::random(&mut OsRng);
         debug!("Building clear inputs");
         for input in self.clear_inputs {
             signature_secrets.push(input.signature_secret);
             let signature_public = PublicKey::from_secret(input.signature_secret);
-            let value_blind = pallas::Scalar::random(&mut OsRng);
+            let value_blind = Blind::random(&mut OsRng);
 
             params.clear_inputs.push(ClearInput {
                 value: input.value,
@@ -101,7 +104,7 @@ impl TransferCallBuilder {
 
         debug!("Building anonymous inputs");
         for (i, input) in self.inputs.iter().enumerate() {
-            let value_blind = pallas::Scalar::random(&mut OsRng);
+            let value_blind = Blind::random(&mut OsRng);
             input_blinds.push(value_blind);
 
             let signature_secret = SecretKey::random(&mut OsRng);
@@ -138,7 +141,7 @@ impl TransferCallBuilder {
             let value_blind = if i == self.outputs.len() - 1 {
                 compute_remainder_blind(&params.clear_inputs, &input_blinds, &output_blinds)
             } else {
-                pallas::Scalar::random(&mut OsRng)
+                Blind::random(&mut OsRng)
             };
 
             output_blinds.push(value_blind);
@@ -203,9 +206,9 @@ pub struct TransferCallSecrets {
     pub output_notes: Vec<MoneyNote>,
 
     /// The value blinds created for the inputs
-    pub input_value_blinds: Vec<pallas::Scalar>,
+    pub input_value_blinds: Vec<ScalarBlind>,
     /// The value blinds created for the outputs
-    pub output_value_blinds: Vec<pallas::Scalar>,
+    pub output_value_blinds: Vec<ScalarBlind>,
 }
 
 impl TransferCallSecrets {

+ 4 - 4
src/contract/money/src/client/transfer_v1/mod.rs

@@ -17,7 +17,7 @@
  */
 use darkfi::{zk::ProvingKey, zkas::ZkBinary, ClientFailed, Result};
 use darkfi_sdk::{
-    crypto::{pasta_prelude::*, FuncId, Keypair, MerkleTree, PublicKey},
+    crypto::{pasta_prelude::*, Blind, FuncId, Keypair, MerkleTree, PublicKey},
     pasta::pallas,
 };
 use log::{debug, error};
@@ -118,7 +118,7 @@ pub fn make_transfer_call(
             merkle_path,
             secret: coin.secret,
             note: coin.note.clone(),
-            user_data_blind: pallas::Base::random(&mut OsRng),
+            user_data_blind: Blind::random(&mut OsRng),
         };
 
         inputs.push(input);
@@ -131,7 +131,7 @@ pub fn make_transfer_call(
         token_id,
         spend_hook: FuncId::none(),
         user_data: pallas::Base::ZERO,
-        blind: pallas::Base::random(&mut OsRng),
+        blind: Blind::random(&mut OsRng),
     });
 
     if change_value > 0 {
@@ -141,7 +141,7 @@ pub fn make_transfer_call(
             token_id,
             spend_hook: FuncId::none(),
             user_data: pallas::Base::ZERO,
-            blind: pallas::Base::random(&mut OsRng),
+            blind: Blind::random(&mut OsRng),
         });
     }
 

+ 17 - 17
src/contract/money/src/client/transfer_v1/proof.rs

@@ -24,8 +24,8 @@ use darkfi::{
 use darkfi_sdk::{
     bridgetree::Hashable,
     crypto::{
-        pasta_prelude::*, pedersen_commitment_u64, poseidon_hash, FuncId, MerkleNode, PublicKey,
-        SecretKey,
+        pasta_prelude::*, pedersen_commitment_u64, poseidon_hash, BaseBlind, FuncId, MerkleNode,
+        PublicKey, ScalarBlind, SecretKey,
     },
     pasta::pallas,
 };
@@ -85,8 +85,8 @@ pub fn create_transfer_burn_proof(
     zkbin: &ZkBinary,
     pk: &ProvingKey,
     input: &TransferCallInput,
-    value_blind: pallas::Scalar,
-    token_blind: pallas::Base,
+    value_blind: ScalarBlind,
+    token_blind: BaseBlind,
     signature_secret: SecretKey,
 ) -> Result<(Proof, TransferBurnRevealed)> {
     let public_key = PublicKey::from_secret(input.secret);
@@ -118,9 +118,9 @@ pub fn create_transfer_burn_proof(
         current
     };
 
-    let user_data_enc = poseidon_hash([input.note.user_data, input.user_data_blind]);
+    let user_data_enc = poseidon_hash([input.note.user_data, input.user_data_blind.inner()]);
     let value_commit = pedersen_commitment_u64(input.note.value, value_blind);
-    let token_commit = poseidon_hash([input.note.token_id.inner(), token_blind]);
+    let token_commit = poseidon_hash([input.note.token_id.inner(), token_blind.inner()]);
 
     let public_inputs = TransferBurnRevealed {
         value_commit,
@@ -138,10 +138,10 @@ pub fn create_transfer_burn_proof(
         Witness::Base(Value::known(input.note.token_id.inner())),
         Witness::Base(Value::known(input.note.spend_hook.inner())),
         Witness::Base(Value::known(input.note.user_data)),
-        Witness::Base(Value::known(input.note.coin_blind)),
-        Witness::Scalar(Value::known(value_blind)),
-        Witness::Base(Value::known(token_blind)),
-        Witness::Base(Value::known(input.user_data_blind)),
+        Witness::Base(Value::known(input.note.coin_blind.inner())),
+        Witness::Scalar(Value::known(value_blind.inner())),
+        Witness::Base(Value::known(token_blind.inner())),
+        Witness::Base(Value::known(input.user_data_blind.inner())),
         Witness::Uint32(Value::known(u64::from(input.leaf_position).try_into().unwrap())),
         Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
         Witness::Base(Value::known(signature_secret.inner())),
@@ -158,14 +158,14 @@ pub fn create_transfer_mint_proof(
     zkbin: &ZkBinary,
     pk: &ProvingKey,
     output: &TransferCallOutput,
-    value_blind: pallas::Scalar,
-    token_blind: pallas::Base,
+    value_blind: ScalarBlind,
+    token_blind: BaseBlind,
     spend_hook: FuncId,
     user_data: pallas::Base,
-    coin_blind: pallas::Base,
+    coin_blind: BaseBlind,
 ) -> Result<(Proof, TransferMintRevealed)> {
     let value_commit = pedersen_commitment_u64(output.value, value_blind);
-    let token_commit = poseidon_hash([output.token_id.inner(), token_blind]);
+    let token_commit = poseidon_hash([output.token_id.inner(), token_blind.inner()]);
     let (pub_x, pub_y) = output.public_key.xy();
 
     let coin = CoinAttributes {
@@ -188,9 +188,9 @@ pub fn create_transfer_mint_proof(
         Witness::Base(Value::known(output.token_id.inner())),
         Witness::Base(Value::known(spend_hook.inner())),
         Witness::Base(Value::known(user_data)),
-        Witness::Base(Value::known(coin_blind)),
-        Witness::Scalar(Value::known(value_blind)),
-        Witness::Base(Value::known(token_blind)),
+        Witness::Base(Value::known(coin_blind.inner())),
+        Witness::Scalar(Value::known(value_blind.inner())),
+        Witness::Base(Value::known(token_blind.inner())),
     ];
 
     let circuit = ZkCircuit::new(prover_witnesses, zkbin);

+ 1 - 1
src/contract/money/src/entrypoint/fee_v1.rs

@@ -108,7 +108,7 @@ pub(crate) fn money_fee_process_instruction_v1(
 
     // Fees can only be paid using the native token, so we'll compare
     // the token commitments with this one:
-    let native_token_commit = poseidon_hash([DARK_TOKEN_ID.inner(), params.token_blind]);
+    let native_token_commit = poseidon_hash([DARK_TOKEN_ID.inner(), params.token_blind.inner()]);
 
     // ===================================
     // Perform the actual state transition

+ 1 - 1
src/contract/money/src/entrypoint/genesis_mint_v1.rs

@@ -116,7 +116,7 @@ pub(crate) fn money_genesis_mint_process_instruction_v1(
         return Err(MoneyError::ValueMismatch.into())
     }
 
-    if poseidon_hash([params.input.token_id.inner(), params.input.token_blind]) !=
+    if poseidon_hash([params.input.token_id.inner(), params.input.token_blind.inner()]) !=
         params.output.token_commit
     {
         msg!("[GenesisMintV1] Error: Token commitment mismatch");

+ 1 - 1
src/contract/money/src/entrypoint/pow_reward_v1.rs

@@ -155,7 +155,7 @@ pub(crate) fn money_pow_reward_process_instruction_v1(
         return Err(MoneyError::ValueMismatch.into())
     }
 
-    if poseidon_hash([params.input.token_id.inner(), params.input.token_blind]) !=
+    if poseidon_hash([params.input.token_id.inner(), params.input.token_blind.inner()]) !=
         params.output.token_commit
     {
         msg!("[PoWRewardV1] Error: Token commitment mismatch");

+ 1 - 1
src/contract/money/src/entrypoint/transfer_v1.rs

@@ -237,7 +237,7 @@ pub(crate) fn money_transfer_process_instruction_v1(
         params
             .clear_inputs
             .iter()
-            .any(|x| poseidon_hash([x.token_id.inner(), x.token_blind]) != tokcom);
+            .any(|x| poseidon_hash([x.token_id.inner(), x.token_blind.inner()]) != tokcom);
 
     if failed_tokcom {
         msg!("[TransferV1] Error: Token commitments do not match");

+ 11 - 10
src/contract/money/src/model/mod.rs

@@ -18,8 +18,8 @@
 
 use darkfi_sdk::{
     crypto::{
-        ecvrf::VrfProof, note::AeadEncryptedNote, pasta_prelude::PrimeField, poseidon_hash, FuncId,
-        MerkleNode, PublicKey, SecretKey,
+        ecvrf::VrfProof, note::AeadEncryptedNote, pasta_prelude::PrimeField, poseidon_hash,
+        BaseBlind, FuncId, MerkleNode, PublicKey, ScalarBlind, SecretKey,
     },
     error::ContractError,
     pasta::pallas,
@@ -78,7 +78,7 @@ pub struct CoinAttributes {
     pub spend_hook: FuncId,
     pub user_data: pallas::Base,
     /// Simultaneously blinds the coin and ensures uniqueness
-    pub blind: pallas::Base,
+    pub blind: BaseBlind,
 }
 // ANCHOR_END: coin-attributes
 
@@ -92,7 +92,7 @@ impl CoinAttributes {
             self.token_id.inner(),
             self.spend_hook.inner(),
             self.user_data,
-            self.blind,
+            self.blind.inner(),
         ]);
         Coin(coin)
     }
@@ -102,12 +102,13 @@ impl CoinAttributes {
 pub struct TokenAttributes {
     pub auth_parent: FuncId,
     pub user_data: pallas::Base,
-    pub blind: pallas::Base,
+    pub blind: BaseBlind,
 }
 
 impl TokenAttributes {
     pub fn to_token_id(&self) -> TokenId {
-        let token_id = poseidon_hash([self.auth_parent.inner(), self.user_data, self.blind]);
+        let token_id =
+            poseidon_hash([self.auth_parent.inner(), self.user_data, self.blind.inner()]);
         TokenId::from(token_id)
     }
 }
@@ -137,9 +138,9 @@ pub struct ClearInput {
     /// Input's token ID
     pub token_id: TokenId,
     /// Blinding factor for `value`
-    pub value_blind: pallas::Scalar,
+    pub value_blind: ScalarBlind,
     /// Blinding factor for `token_id`
-    pub token_blind: pallas::Base,
+    pub token_blind: BaseBlind,
     /// Public key for the signature
     pub signature_public: PublicKey,
 }
@@ -189,9 +190,9 @@ pub struct MoneyFeeParamsV1 {
     /// Anonymous outputs
     pub output: Output,
     /// Fee value blind
-    pub fee_value_blind: pallas::Scalar,
+    pub fee_value_blind: ScalarBlind,
     /// Token ID blind
-    pub token_blind: pallas::Base,
+    pub token_blind: BaseBlind,
 }
 
 /// State update for `Money::Fee`

+ 7 - 8
src/contract/test-harness/src/dao_exec.rs

@@ -32,11 +32,10 @@ use darkfi_money_contract::{
 };
 use darkfi_sdk::{
     crypto::{
-        pasta_prelude::Field, pedersen_commitment_u64, FuncRef, MerkleNode, SecretKey,
+        pedersen_commitment_u64, Blind, FuncRef, MerkleNode, ScalarBlind, SecretKey,
         DAO_CONTRACT_ID, MONEY_CONTRACT_ID,
     },
     dark_tree::DarkLeaf,
-    pasta::pallas,
     ContractCall,
 };
 use darkfi_serial::{serialize, Encodable};
@@ -54,8 +53,8 @@ impl TestHarness {
         proposal_coinattrs: Vec<CoinAttributes>,
         yes_vote_value: u64,
         all_vote_value: u64,
-        yes_vote_blind: pallas::Scalar,
-        all_vote_blind: pallas::Scalar,
+        yes_vote_blind: ScalarBlind,
+        all_vote_blind: ScalarBlind,
     ) -> Result<(Transaction, MoneyTransferParamsV1, DaoExecParams)> {
         let dao_wallet = self.holders.get(&Holder::Dao).unwrap();
 
@@ -77,7 +76,7 @@ impl TestHarness {
         let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::DaoExec).unwrap();
         let timer = Instant::now();
 
-        let input_user_data_blind = pallas::Base::random(&mut OsRng);
+        let input_user_data_blind = Blind::random(&mut OsRng);
         let exec_signature_secret = SecretKey::random(&mut OsRng);
 
         assert!(!proposal_coinattrs.is_empty());
@@ -124,7 +123,7 @@ impl TestHarness {
             token_id: proposal_token_id,
             spend_hook,
             user_data: dao_bulla.inner(),
-            blind: pallas::Base::random(&mut OsRng),
+            blind: Blind::random(&mut OsRng),
         };
         outputs.push(dao_coin_attrs.clone());
 
@@ -146,10 +145,10 @@ impl TestHarness {
         // We need to extract stuff from the inputs and outputs that we'll also
         // use in the DAO::Exec call. This DAO API needs to be better.
         let mut input_value = 0;
-        let mut input_value_blind = pallas::Scalar::ZERO;
+        let mut input_value_blind = Blind::ZERO;
         for (input, blind) in spent_coins.iter().zip(xfer_secrets.input_value_blinds.iter()) {
             input_value += input.note.value;
-            input_value_blind += blind;
+            input_value_blind += *blind;
         }
         assert_eq!(
             pedersen_commitment_u64(input_value, input_value_blind),

+ 2 - 2
src/contract/test-harness/src/dao_propose.rs

@@ -30,7 +30,7 @@ use darkfi_dao_contract::{
 };
 use darkfi_money_contract::{client::OwnCoin, model::CoinAttributes, MoneyFunction};
 use darkfi_sdk::{
-    crypto::{pasta_prelude::Field, MerkleNode, SecretKey, DAO_CONTRACT_ID, MONEY_CONTRACT_ID},
+    crypto::{Blind, MerkleNode, SecretKey, DAO_CONTRACT_ID, MONEY_CONTRACT_ID},
     pasta::pallas,
     ContractCall,
 };
@@ -106,7 +106,7 @@ impl TestHarness {
             duration_days: 30,
             user_data,
             dao_bulla: dao.to_bulla(),
-            blind: pallas::Base::random(&mut OsRng),
+            blind: Blind::random(&mut OsRng),
         };
 
         let call = DaoProposeCall {

+ 7 - 7
src/contract/test-harness/src/lib.rs

@@ -35,8 +35,8 @@ use darkfi_money_contract::{
 use darkfi_sdk::{
     bridgetree,
     crypto::{
-        note::AeadEncryptedNote, pasta_prelude::Field, poseidon_hash, ContractId, Keypair,
-        MerkleNode, MerkleTree, PublicKey, SecretKey,
+        note::AeadEncryptedNote, pasta_prelude::Field, poseidon_hash, BaseBlind, Blind, ContractId,
+        Keypair, MerkleNode, MerkleTree, PublicKey, SecretKey,
     },
     pasta::pallas,
 };
@@ -64,13 +64,13 @@ mod money_transfer;
 pub fn init_logger() {
     let mut cfg = simplelog::ConfigBuilder::new();
     cfg.add_filter_ignore("sled".to_string());
-    cfg.set_target_level(simplelog::LevelFilter::Error);
+    //cfg.set_target_level(simplelog::LevelFilter::Error);
 
     // We check this error so we can execute same file tests in parallel,
     // otherwise second one fails to init logger here.
     if simplelog::TermLogger::init(
-        //simplelog::LevelFilter::Info,
-        simplelog::LevelFilter::Debug,
+        simplelog::LevelFilter::Info,
+        //simplelog::LevelFilter::Debug,
         //simplelog::LevelFilter::Trace,
         cfg.build(),
         simplelog::TerminalMode::Mixed,
@@ -112,7 +112,7 @@ pub enum TxAction {
 pub struct Wallet {
     pub keypair: Keypair,
     pub token_mint_authority: Keypair,
-    pub token_blind: pallas::Base,
+    pub token_blind: BaseBlind,
     pub contract_deploy_authority: Keypair,
     pub validator: ValidatorPtr,
     pub money_merkle_tree: MerkleTree,
@@ -162,7 +162,7 @@ impl Wallet {
         let spent_money_coins = vec![];
 
         let token_mint_authority = Keypair::random(&mut OsRng);
-        let token_blind = pallas::Base::random(&mut OsRng);
+        let token_blind = Blind::random(&mut OsRng);
         let contract_deploy_authority = Keypair::random(&mut OsRng);
 
         Ok(Self {

+ 2 - 2
src/contract/test-harness/src/money_airdrop.rs

@@ -29,7 +29,7 @@ use darkfi_money_contract::{
     MoneyFunction, MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
 };
 use darkfi_sdk::{
-    crypto::{FuncId, MerkleNode, MONEY_CONTRACT_ID},
+    crypto::{Blind, FuncId, MerkleNode, MONEY_CONTRACT_ID},
     pasta::pallas,
     ContractCall,
 };
@@ -74,7 +74,7 @@ impl TestHarness {
                 token_id: *DARK_TOKEN_ID,
                 spend_hook: rcpt_spend_hook.unwrap_or(FuncId::none()),
                 user_data: rcpt_user_data.unwrap_or(pallas::Base::ZERO),
-                blind: pallas::Base::random(&mut OsRng),
+                blind: Blind::random(&mut OsRng),
             }],
             mint_zkbin: mint_zkbin.clone(),
             mint_pk: mint_pk.clone(),

+ 7 - 7
src/contract/test-harness/src/money_otc_swap.rs

@@ -29,7 +29,7 @@ use darkfi_money_contract::{
     MoneyFunction, MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
 };
 use darkfi_sdk::{
-    crypto::{FuncId, MerkleNode, MONEY_CONTRACT_ID},
+    crypto::{Blind, FuncId, MerkleNode, MONEY_CONTRACT_ID},
     pasta::pallas,
     ContractCall,
 };
@@ -62,14 +62,14 @@ impl TestHarness {
 
         // We're just going to be using a zero spend-hook and user-data
         let rcpt_spend_hook = FuncId::none();
-        let rcpt_user_data = pallas::Base::zero();
-        let rcpt_user_data_blind = pallas::Base::random(&mut OsRng);
+        let rcpt_user_data = pallas::Base::ZERO;
+        let rcpt_user_data_blind = Blind::random(&mut OsRng);
 
         // Generating  swap blinds
-        let value_send_blind = pallas::Scalar::random(&mut OsRng);
-        let value_recv_blind = pallas::Scalar::random(&mut OsRng);
-        let token_send_blind = pallas::Base::random(&mut OsRng);
-        let token_recv_blind = pallas::Base::random(&mut OsRng);
+        let value_send_blind = Blind::random(&mut OsRng);
+        let value_recv_blind = Blind::random(&mut OsRng);
+        let token_send_blind = Blind::random(&mut OsRng);
+        let token_recv_blind = Blind::random(&mut OsRng);
 
         // Builder first holder part
         let builder = SwapCallBuilder {

+ 2 - 2
src/contract/test-harness/src/money_token.rs

@@ -36,7 +36,7 @@ use darkfi_money_contract::{
     MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1,
 };
 use darkfi_sdk::{
-    crypto::{poseidon_hash, FuncId, FuncRef, MerkleNode, MONEY_CONTRACT_ID},
+    crypto::{poseidon_hash, Blind, FuncId, FuncRef, MerkleNode, MONEY_CONTRACT_ID},
     dark_tree::DarkLeaf,
     pasta::pallas,
     ContractCall,
@@ -96,7 +96,7 @@ impl TestHarness {
             token_id,
             spend_hook: spend_hook.unwrap_or(FuncId::none()),
             user_data: user_data.unwrap_or(pallas::Base::ZERO),
-            blind: pallas::Base::random(&mut OsRng),
+            blind: Blind::random(&mut OsRng),
         };
 
         let builder = TokenMintCallBuilder {

+ 2 - 2
src/sdk/python/src/crypto.rs

@@ -51,7 +51,7 @@ pub fn poseidon_hash(messages: Vec<&PyCell<Fp>>) -> Fp {
 /// Calculate a Pedersen commitment with an u64 value.
 #[pyfunction]
 pub fn pedersen_commitment_u64(value: u64, blind: &PyCell<Fq>) -> Ep {
-    Ep(crypto::pedersen::pedersen_commitment_u64(value, blind.borrow().deref().0))
+    Ep(crypto::pedersen::pedersen_commitment_u64(value, crypto::Blind(blind.borrow().deref().0)))
 }
 
 /// Calculate a Pedersen commitment with an Fp value.
@@ -59,7 +59,7 @@ pub fn pedersen_commitment_u64(value: u64, blind: &PyCell<Fq>) -> Ep {
 pub fn pedersen_commitment_base(value: &PyCell<Fp>, blind: &PyCell<Fq>) -> Ep {
     Ep(crypto::pedersen::pedersen_commitment_base(
         value.borrow().deref().0,
-        blind.borrow().deref().0,
+        crypto::Blind(blind.borrow().deref().0),
     ))
 }
 

+ 66 - 0
src/sdk/src/crypto/blind.rs

@@ -0,0 +1,66 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2024 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/>.
+ */
+
+#[cfg(feature = "async")]
+use darkfi_serial::{async_trait, AsyncDecodable, AsyncEncodable};
+use darkfi_serial::{Decodable, Encodable, SerialDecodable, SerialEncodable};
+
+use pasta_curves::{group::ff::Field, pallas};
+
+#[cfg(feature = "async")]
+pub trait EncDecode: Encodable + Decodable + AsyncEncodable + AsyncDecodable {}
+#[cfg(not(feature = "async"))]
+pub trait EncDecode: Encodable + Decodable {}
+
+impl EncDecode for pallas::Base {}
+impl EncDecode for pallas::Scalar {}
+
+/// Blinding factor used in bullas. Every bulla should contain one.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
+pub struct Blind<F: Field + EncDecode>(pub F);
+
+impl<F: Field + EncDecode> Blind<F> {
+    pub const ZERO: Self = Self(F::ZERO);
+
+    pub fn random<RngCore: rand_core::RngCore>(rng: &mut RngCore) -> Self {
+        Self(F::random(rng))
+    }
+
+    pub fn inner(&self) -> F {
+        self.0
+    }
+}
+
+impl<'a, 'b, F: Field + EncDecode> std::ops::Add<&'b Blind<F>> for &'a Blind<F> {
+    type Output = Blind<F>;
+
+    #[inline]
+    fn add(self, rhs: &'b Blind<F>) -> Blind<F> {
+        Blind(self.0.add(rhs.0))
+    }
+}
+
+impl<F: Field + EncDecode> std::ops::AddAssign for Blind<F> {
+    #[inline]
+    fn add_assign(&mut self, other: Self) {
+        self.0.add_assign(other.0)
+    }
+}
+
+pub type BaseBlind = Blind<pallas::Base>;
+pub type ScalarBlind = Blind<pallas::Scalar>;

+ 4 - 0
src/sdk/src/crypto/mod.rs

@@ -16,6 +16,10 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+/// Blinding factors
+pub mod blind;
+pub use blind::{BaseBlind, Blind, ScalarBlind};
+
 /// Cryptographic constants
 pub mod constants;
 

+ 5 - 4
src/sdk/src/crypto/pedersen.rs

@@ -20,6 +20,7 @@ use halo2_gadgets::ecc::chip::FixedPoint;
 use pasta_curves::{arithmetic::CurveExt, pallas};
 
 use super::{
+    blind::ScalarBlind,
     constants::{
         fixed_bases::{
             VALUE_COMMITMENT_PERSONALIZATION, VALUE_COMMITMENT_R_BYTES, VALUE_COMMITMENT_V_BYTES,
@@ -31,20 +32,20 @@ use super::{
 
 /// Pedersen commitment for a full-width base field element.
 #[allow(non_snake_case)]
-pub fn pedersen_commitment_base(value: pallas::Base, blind: pallas::Scalar) -> pallas::Point {
+pub fn pedersen_commitment_base(value: pallas::Base, blind: ScalarBlind) -> pallas::Point {
     let hasher = pallas::Point::hash_to_curve(VALUE_COMMITMENT_PERSONALIZATION);
     let V = NullifierK.generator();
     let R = hasher(&VALUE_COMMITMENT_R_BYTES);
 
-    V * fp_mod_fv(value) + R * blind
+    V * fp_mod_fv(value) + R * blind.inner()
 }
 
 /// Pedersen commitment for a 64-bit value, in the base field.
 #[allow(non_snake_case)]
-pub fn pedersen_commitment_u64(value: u64, blind: pallas::Scalar) -> pallas::Point {
+pub fn pedersen_commitment_u64(value: u64, blind: ScalarBlind) -> pallas::Point {
     let hasher = pallas::Point::hash_to_curve(VALUE_COMMITMENT_PERSONALIZATION);
     let V = hasher(&VALUE_COMMITMENT_V_BYTES);
     let R = hasher(&VALUE_COMMITMENT_R_BYTES);
 
-    V * fp_mod_fv(pallas::Base::from(value)) + R * blind
+    V * fp_mod_fv(pallas::Base::from(value)) + R * blind.inner()
 }

+ 3 - 3
tests/halo2_vk_ser.rs

@@ -18,7 +18,7 @@
 use std::io::Cursor;
 
 use darkfi_sdk::crypto::{
-    pedersen::pedersen_commitment_u64, util::fp_mod_fv, MerkleNode, MerkleTree, PublicKey,
+    pedersen::pedersen_commitment_u64, util::fp_mod_fv, Blind, MerkleNode, MerkleTree, PublicKey,
     SecretKey,
 };
 use halo2_gadgets::poseidon::{
@@ -88,7 +88,7 @@ fn halo2_vk_ser() -> Result<()> {
     let pk = ProvingKey::build(zkbin.k, &circuit);
 
     let value = 666_u64;
-    let value_blind = pallas::Scalar::random(&mut OsRng);
+    let value_blind = Blind::random(&mut OsRng);
     let blind = pallas::Base::random(&mut OsRng);
     let secret = pallas::Base::random(&mut OsRng);
     let a = pallas::Base::from(42);
@@ -120,7 +120,7 @@ fn halo2_vk_ser() -> Result<()> {
     let (ephem_x, ephem_y) = PublicKey::from(pubkey * fp_mod_fv(ephem_secret.inner())).xy();
     let prover_witnesses = vec![
         Witness::Base(Value::known(pallas::Base::from(value))),
-        Witness::Scalar(Value::known(value_blind)),
+        Witness::Scalar(Value::known(value_blind.inner())),
         Witness::Base(Value::known(blind)),
         Witness::Base(Value::known(a)),
         Witness::Base(Value::known(b)),

+ 3 - 3
tests/zkvm_opcodes.rs

@@ -17,7 +17,7 @@
  */
 
 use darkfi_sdk::crypto::{
-    pedersen::pedersen_commitment_u64, util::fp_mod_fv, MerkleNode, MerkleTree, PublicKey,
+    pedersen::pedersen_commitment_u64, util::fp_mod_fv, Blind, MerkleNode, MerkleTree, PublicKey,
     SecretKey,
 };
 use halo2_gadgets::poseidon::{
@@ -50,7 +50,7 @@ fn zkvm_opcodes() -> Result<()> {
 
     // Values for the proof
     let value = 666_u64;
-    let value_blind = pallas::Scalar::random(&mut OsRng);
+    let value_blind = Blind::random(&mut OsRng);
     let blind = pallas::Base::random(&mut OsRng);
     let secret = pallas::Base::random(&mut OsRng);
     let a = pallas::Base::from(42);
@@ -83,7 +83,7 @@ fn zkvm_opcodes() -> Result<()> {
 
     let prover_witnesses = vec![
         Witness::Base(Value::known(pallas::Base::from(value))),
-        Witness::Scalar(Value::known(value_blind)),
+        Witness::Scalar(Value::known(value_blind.inner())),
         Witness::Base(Value::known(blind)),
         Witness::Base(Value::known(a)),
         Witness::Base(Value::known(b)),