client.rs 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2022 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. //! This module implements the client-side of this contract's interaction.
  19. //! What we basically do here is implement an API that creates the necessary
  20. //! structures and is able to export them to create a DarkFi Transaction
  21. //! object that can be broadcasted to the network when we want to make a
  22. //! payment with some coins in our wallet.
  23. //! Note that this API doesn't involve any wallet interaction, but only
  24. //! takes the necessary objects provided by the caller. This is so we can
  25. //! abstract away the wallet interface to client implementations.
  26. use chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, KeyInit};
  27. use darkfi::{
  28. consensus::leadcoin::LeadCoin,
  29. zk::{
  30. proof::{Proof, ProvingKey},
  31. vm::ZkCircuit,
  32. vm_stack::Witness,
  33. },
  34. zkas::ZkBinary,
  35. ClientFailed, Error, Result,
  36. };
  37. use darkfi_sdk::{
  38. crypto::{
  39. constants::MERKLE_DEPTH,
  40. diffie_hellman::{kdf_sapling, sapling_ka_agree},
  41. pedersen::{pedersen_commitment_base, pedersen_commitment_u64, ValueBlind, ValueCommit},
  42. poseidon_hash, Keypair, MerkleNode, Nullifier, PublicKey, SecretKey, TokenId,
  43. },
  44. incrementalmerkletree,
  45. incrementalmerkletree::{bridgetree::BridgeTree, Hashable, Tree},
  46. pasta::{
  47. arithmetic::CurveAffine,
  48. group::{ff::PrimeField, Curve},
  49. pallas,
  50. },
  51. };
  52. use darkfi_serial::{serialize, Decodable, Encodable, SerialDecodable, SerialEncodable};
  53. use halo2_proofs::{arithmetic::Field, circuit::Value};
  54. use log::{debug, error, info};
  55. use rand::rngs::OsRng;
  56. use crate::state::{
  57. ClearInput, Input, MoneyStakeParams, MoneyTransferParams, MoneyUnstakeParams, Output,
  58. StakedInput, StakedOutput,
  59. };
  60. // Wallet SQL table constant names. These have to represent the SQL schema.
  61. // TODO: They should also ideally be prefixed with the contract ID to avoid
  62. // collisions.
  63. pub const MONEY_INFO_TABLE: &str = "money_info";
  64. pub const MONEY_INFO_COL_LAST_SCANNED_SLOT: &str = "last_scanned_slot";
  65. pub const MONEY_TREE_TABLE: &str = "money_tree";
  66. pub const MONEY_TREE_COL_TREE: &str = "tree";
  67. pub const MONEY_KEYS_TABLE: &str = "money_keys";
  68. pub const MONEY_KEYS_COL_KEY_ID: &str = "key_id";
  69. pub const MONEY_KEYS_COL_IS_DEFAULT: &str = "is_default";
  70. pub const MONEY_KEYS_COL_PUBLIC: &str = "public";
  71. pub const MONEY_KEYS_COL_SECRET: &str = "secret";
  72. pub const MONEY_COINS_TABLE: &str = "money_coins";
  73. pub const MONEY_COINS_COL_COIN: &str = "coin";
  74. pub const MONEY_COINS_COL_IS_SPENT: &str = "is_spent";
  75. pub const MONEY_COINS_COL_SERIAL: &str = "serial";
  76. pub const MONEY_COINS_COL_VALUE: &str = "value";
  77. pub const MONEY_COINS_COL_TOKEN_ID: &str = "token_id";
  78. pub const MONEY_COINS_COL_COIN_BLIND: &str = "coin_blind";
  79. pub const MONEY_COINS_COL_VALUE_BLIND: &str = "value_blind";
  80. pub const MONEY_COINS_COL_TOKEN_BLIND: &str = "token_blind";
  81. pub const MONEY_COINS_COL_SECRET: &str = "secret";
  82. pub const MONEY_COINS_COL_NULLIFIER: &str = "nullifier";
  83. pub const MONEY_COINS_COL_LEAF_POSITION: &str = "leaf_position";
  84. pub const MONEY_COINS_COL_MEMO: &str = "memo";
  85. /// Byte length of the AEAD tag of the chacha20 cipher used for note encryption
  86. pub const AEAD_TAG_SIZE: usize = 16;
  87. /// The `Coin` is represented as a base field element.
  88. #[derive(Debug, Clone, Copy, Eq, PartialEq, SerialEncodable, SerialDecodable)]
  89. pub struct Coin(pallas::Base);
  90. impl Coin {
  91. /// Reference the raw inner base field element
  92. pub fn inner(&self) -> pallas::Base {
  93. self.0
  94. }
  95. /// Try to create a `Coin` type from the given 32 bytes.
  96. /// Returns an error if the bytes don't fit in the base field.
  97. pub fn from_bytes(bytes: [u8; 32]) -> Result<Self> {
  98. match pallas::Base::from_repr(bytes).into() {
  99. Some(v) => Ok(Self(v)),
  100. None => Err(Error::CoinFromBytes),
  101. }
  102. }
  103. }
  104. impl From<pallas::Base> for Coin {
  105. fn from(x: pallas::Base) -> Self {
  106. Self(x)
  107. }
  108. }
  109. /// The `OwnCoin` is a representation of `Coin` with its respective metadata.
  110. #[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
  111. pub struct OwnCoin {
  112. /// The coin hash
  113. pub coin: Coin,
  114. /// The attached Note
  115. pub note: Note,
  116. /// Coin's secret key
  117. pub secret: SecretKey,
  118. /// Coin's nullifier,
  119. pub nullifier: Nullifier,
  120. /// Coin's leaf position in the Merkle tree of coins
  121. pub leaf_position: incrementalmerkletree::Position,
  122. }
  123. /// The `Note` holds the inner attributes of a `Coin`
  124. #[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
  125. pub struct Note {
  126. /// Serial number of the coin, used for the nullifier
  127. pub serial: pallas::Base,
  128. /// Value of the coin
  129. pub value: u64,
  130. /// Token ID of the coin
  131. pub token_id: TokenId,
  132. /// Blinding factor for the coin bulla
  133. pub coin_blind: pallas::Base,
  134. /// Blinding factor for the value pedersen commitment
  135. pub value_blind: ValueBlind,
  136. /// Blinding factor for the token ID pedersen commitment
  137. pub token_blind: ValueBlind,
  138. /// Attached memo (arbitrary data)
  139. pub memo: Vec<u8>,
  140. }
  141. impl Note {
  142. /// Encrypt the note to some given `PublicKey` using an AEAD cipher.
  143. pub fn encrypt(&self, public_key: &PublicKey) -> Result<EncryptedNote> {
  144. let ephem_keypair = Keypair::random(&mut OsRng);
  145. let shared_secret = sapling_ka_agree(&ephem_keypair.secret, public_key);
  146. let key = kdf_sapling(&shared_secret, &ephem_keypair.public);
  147. let mut input = vec![];
  148. self.encode(&mut input)?;
  149. let input_len = input.len();
  150. let mut ciphertext = vec![0_u8; input_len + AEAD_TAG_SIZE];
  151. ciphertext[..input_len].copy_from_slice(&input);
  152. ChaCha20Poly1305::new(key.as_ref().into())
  153. .encrypt_in_place([0u8; 12][..].into(), &[], &mut ciphertext)
  154. .unwrap();
  155. Ok(EncryptedNote { ciphertext, ephem_public: ephem_keypair.public })
  156. }
  157. }
  158. /// The `EncryptedNote` represents a structure holding the ciphertext (which is
  159. /// an encryption of the `Note` object, and the ephemeral `PublicKey` created at
  160. /// the time when the encryption was done
  161. #[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
  162. pub struct EncryptedNote {
  163. /// Ciphertext of the encrypted `Note`
  164. pub ciphertext: Vec<u8>,
  165. /// Ephemeral public key created at the time of encrypting the note
  166. pub ephem_public: PublicKey,
  167. }
  168. impl EncryptedNote {
  169. /// Attempt to decrypt an `EncryptedNote` given a secret key.
  170. pub fn decrypt(&self, secret: &SecretKey) -> Result<Note> {
  171. let shared_secret = sapling_ka_agree(secret, &self.ephem_public);
  172. let key = kdf_sapling(&shared_secret, &self.ephem_public);
  173. let ciphertext_len = self.ciphertext.len();
  174. let mut plaintext = vec![0_u8; ciphertext_len];
  175. plaintext.copy_from_slice(&self.ciphertext);
  176. match ChaCha20Poly1305::new(key.as_ref().into()).decrypt_in_place(
  177. [0u8; 12][..].into(),
  178. &[],
  179. &mut plaintext,
  180. ) {
  181. Ok(()) => Ok(Note::decode(&plaintext[..ciphertext_len - AEAD_TAG_SIZE])?),
  182. Err(e) => Err(Error::NoteDecryptionFailed(e.to_string())),
  183. }
  184. }
  185. }
  186. struct TransactionBuilderClearInputInfo {
  187. pub value: u64,
  188. pub token_id: TokenId,
  189. pub signature_secret: SecretKey,
  190. }
  191. struct TransactionBuilderInputInfo {
  192. pub leaf_position: incrementalmerkletree::Position,
  193. pub merkle_path: Vec<MerkleNode>,
  194. pub secret: SecretKey,
  195. pub note: Note,
  196. }
  197. struct TransactionBuilderOutputInfo {
  198. pub value: u64,
  199. pub token_id: TokenId,
  200. pub public_key: PublicKey,
  201. }
  202. struct TransferBurnRevealed {
  203. pub value_commit: ValueCommit,
  204. pub token_commit: ValueCommit,
  205. pub nullifier: Nullifier,
  206. pub merkle_root: MerkleNode,
  207. pub spend_hook: pallas::Base,
  208. pub user_data_enc: pallas::Base,
  209. pub signature_public: PublicKey,
  210. }
  211. impl TransferBurnRevealed {
  212. #[allow(clippy::too_many_arguments)]
  213. pub fn compute(
  214. value: u64,
  215. token_id: TokenId,
  216. value_blind: ValueBlind,
  217. token_blind: ValueBlind,
  218. serial: pallas::Base,
  219. spend_hook: pallas::Base,
  220. user_data: pallas::Base,
  221. user_data_blind: pallas::Base,
  222. coin_blind: pallas::Base,
  223. secret_key: SecretKey,
  224. leaf_position: incrementalmerkletree::Position,
  225. merkle_path: Vec<MerkleNode>,
  226. signature_secret: SecretKey,
  227. ) -> Self {
  228. let nullifier = Nullifier::from(poseidon_hash([secret_key.inner(), serial]));
  229. let public_key = PublicKey::from_secret(secret_key);
  230. let (pub_x, pub_y) = public_key.xy();
  231. let coin = poseidon_hash([
  232. pub_x,
  233. pub_y,
  234. pallas::Base::from(value),
  235. token_id.inner(),
  236. serial,
  237. spend_hook,
  238. user_data,
  239. coin_blind,
  240. ]);
  241. let merkle_root = {
  242. let position: u64 = leaf_position.into();
  243. let mut current = MerkleNode::from(coin);
  244. for (level, sibling) in merkle_path.iter().enumerate() {
  245. let level = level as u8;
  246. current = if position & (1 << level) == 0 {
  247. MerkleNode::combine(level.into(), &current, sibling)
  248. } else {
  249. MerkleNode::combine(level.into(), sibling, &current)
  250. };
  251. }
  252. current
  253. };
  254. let user_data_enc = poseidon_hash([user_data, user_data_blind]);
  255. let value_commit = pedersen_commitment_u64(value, value_blind);
  256. let token_commit = pedersen_commitment_base(token_id.inner(), token_blind);
  257. Self {
  258. value_commit,
  259. token_commit,
  260. nullifier,
  261. merkle_root,
  262. spend_hook,
  263. user_data_enc,
  264. signature_public: PublicKey::from_secret(signature_secret),
  265. }
  266. }
  267. pub fn to_vec(&self) -> Vec<pallas::Base> {
  268. let valcom_coords = self.value_commit.to_affine().coordinates().unwrap();
  269. let tokcom_coords = self.token_commit.to_affine().coordinates().unwrap();
  270. let sigpub_coords = self.signature_public.inner().to_affine().coordinates().unwrap();
  271. // NOTE: It's important to keep this order the same as the `constrain_instance`
  272. // calls in the zkas code.
  273. vec![
  274. self.nullifier.inner(),
  275. *valcom_coords.x(),
  276. *valcom_coords.y(),
  277. *tokcom_coords.x(),
  278. *tokcom_coords.y(),
  279. self.merkle_root.inner(),
  280. self.user_data_enc,
  281. *sigpub_coords.x(),
  282. *sigpub_coords.y(),
  283. // TODO: Why is spend_hook in the struct but not here?
  284. ]
  285. }
  286. }
  287. struct TransferMintRevealed {
  288. pub coin: Coin,
  289. pub value_commit: ValueCommit,
  290. pub token_commit: ValueCommit,
  291. }
  292. impl TransferMintRevealed {
  293. #[allow(clippy::too_many_arguments)]
  294. pub fn compute(
  295. value: u64,
  296. token_id: TokenId,
  297. value_blind: ValueBlind,
  298. token_blind: ValueBlind,
  299. serial: pallas::Base,
  300. spend_hook: pallas::Base,
  301. user_data: pallas::Base,
  302. coin_blind: pallas::Base,
  303. public_key: PublicKey,
  304. ) -> Self {
  305. let value_commit = pedersen_commitment_u64(value, value_blind);
  306. let token_commit = pedersen_commitment_base(token_id.inner(), token_blind);
  307. let (pub_x, pub_y) = public_key.xy();
  308. let coin = Coin::from(poseidon_hash([
  309. pub_x,
  310. pub_y,
  311. pallas::Base::from(value),
  312. token_id.inner(),
  313. serial,
  314. spend_hook,
  315. user_data,
  316. coin_blind,
  317. ]));
  318. Self { coin, value_commit, token_commit }
  319. }
  320. pub fn to_vec(&self) -> Vec<pallas::Base> {
  321. let valcom_coords = self.value_commit.to_affine().coordinates().unwrap();
  322. let tokcom_coords = self.token_commit.to_affine().coordinates().unwrap();
  323. // NOTE: It's important to keep this order the same as the `constrain_instance`
  324. // calls in the zkas code.
  325. vec![
  326. self.coin.inner(),
  327. *valcom_coords.x(),
  328. *valcom_coords.y(),
  329. *tokcom_coords.x(),
  330. *tokcom_coords.y(),
  331. ]
  332. }
  333. }
  334. #[allow(clippy::too_many_arguments)]
  335. fn create_transfer_mint_proof(
  336. zkbin: &ZkBinary,
  337. pk: &ProvingKey,
  338. value: u64,
  339. token_id: TokenId,
  340. value_blind: ValueBlind,
  341. token_blind: ValueBlind,
  342. serial: pallas::Base,
  343. spend_hook: pallas::Base,
  344. user_data: pallas::Base,
  345. coin_blind: pallas::Base,
  346. public_key: PublicKey,
  347. ) -> Result<(Proof, TransferMintRevealed)> {
  348. let revealed = TransferMintRevealed::compute(
  349. value,
  350. token_id,
  351. value_blind,
  352. token_blind,
  353. serial,
  354. spend_hook,
  355. user_data,
  356. coin_blind,
  357. public_key,
  358. );
  359. let (pub_x, pub_y) = public_key.xy();
  360. // NOTE: It's important to keep these in the same order as the zkas code.
  361. let prover_witnesses = vec![
  362. Witness::Base(Value::known(pub_x)),
  363. Witness::Base(Value::known(pub_y)),
  364. Witness::Base(Value::known(pallas::Base::from(value))),
  365. Witness::Base(Value::known(token_id.inner())),
  366. Witness::Base(Value::known(serial)),
  367. Witness::Base(Value::known(coin_blind)),
  368. Witness::Base(Value::known(spend_hook)),
  369. Witness::Base(Value::known(user_data)),
  370. Witness::Scalar(Value::known(value_blind)),
  371. Witness::Scalar(Value::known(token_blind)),
  372. ];
  373. let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
  374. let proof = Proof::create(pk, &[circuit], &revealed.to_vec(), &mut OsRng)?;
  375. Ok((proof, revealed))
  376. }
  377. #[allow(clippy::too_many_arguments)]
  378. fn create_transfer_burn_proof(
  379. zkbin: &ZkBinary,
  380. pk: &ProvingKey,
  381. value: u64,
  382. token_id: TokenId,
  383. value_blind: ValueBlind,
  384. token_blind: ValueBlind,
  385. serial: pallas::Base,
  386. spend_hook: pallas::Base,
  387. user_data: pallas::Base,
  388. user_data_blind: pallas::Base,
  389. coin_blind: pallas::Base,
  390. secret_key: SecretKey,
  391. leaf_position: incrementalmerkletree::Position,
  392. merkle_path: Vec<MerkleNode>,
  393. signature_secret: SecretKey,
  394. ) -> Result<(Proof, TransferBurnRevealed)> {
  395. let revealed = TransferBurnRevealed::compute(
  396. value,
  397. token_id,
  398. value_blind,
  399. token_blind,
  400. serial,
  401. spend_hook,
  402. user_data,
  403. user_data_blind,
  404. coin_blind,
  405. secret_key,
  406. leaf_position,
  407. merkle_path.clone(),
  408. signature_secret,
  409. );
  410. // NOTE: It's important to keep these in the same order as the zkas code.
  411. let prover_witnesses = vec![
  412. Witness::Base(Value::known(pallas::Base::from(value))),
  413. Witness::Base(Value::known(token_id.inner())),
  414. Witness::Scalar(Value::known(value_blind)),
  415. Witness::Scalar(Value::known(token_blind)),
  416. Witness::Base(Value::known(serial)),
  417. Witness::Base(Value::known(spend_hook)),
  418. Witness::Base(Value::known(user_data)),
  419. Witness::Base(Value::known(user_data_blind)),
  420. Witness::Base(Value::known(coin_blind)),
  421. Witness::Base(Value::known(secret_key.inner())),
  422. Witness::Uint32(Value::known(u64::from(leaf_position).try_into().unwrap())),
  423. Witness::MerklePath(Value::known(merkle_path.try_into().unwrap())),
  424. Witness::Base(Value::known(signature_secret.inner())),
  425. ];
  426. let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
  427. let proof = Proof::create(pk, &[circuit], &revealed.to_vec(), &mut OsRng)?;
  428. Ok((proof, revealed))
  429. }
  430. struct StakeLeadMintRevealed {
  431. pub value_commit: ValueCommit,
  432. pub pk: pallas::Base,
  433. pub commitment_x: pallas::Base,
  434. pub commitment_y: pallas::Base,
  435. }
  436. impl StakeLeadMintRevealed {
  437. pub fn compute(
  438. value: pallas::Base,
  439. pk: pallas::Base,
  440. value_blind: pallas::Scalar,
  441. commitment: pallas::Point,
  442. ) -> Self {
  443. let value_commit = pedersen_commitment_base(value, value_blind);
  444. let coord = commitment.to_affine().coordinates().unwrap();
  445. Self { value_commit, pk, commitment_x: *coord.x(), commitment_y: *coord.y() }
  446. }
  447. pub fn to_vec(&self) -> Vec<pallas::Base> {
  448. let value_coord = self.value_commit.to_affine().coordinates().unwrap();
  449. let value_cm_x = *value_coord.x();
  450. let value_cm_y = *value_coord.y();
  451. vec![value_cm_x, value_cm_y, self.pk, self.commitment_x, self.commitment_y]
  452. }
  453. }
  454. fn create_stake_mint_proof(
  455. zkbin: &ZkBinary, // LeadMint contract binary
  456. pk: &ProvingKey,
  457. public_key: pallas::Base,
  458. coin_commitment: pallas::Point,
  459. value: pallas::Base,
  460. value_blind: ValueBlind,
  461. coin_blind: ValueBlind,
  462. sk: pallas::Base,
  463. sk_root: pallas::Base,
  464. tau: pallas::Base,
  465. nonce: pallas::Base, // rho
  466. ) -> Result<(Proof, StakeLeadMintRevealed)> {
  467. let revealed = StakeLeadMintRevealed::compute(value, public_key, value_blind, coin_commitment);
  468. let prover_witnesses = vec![
  469. Witness::Base(Value::known(sk)),
  470. Witness::Base(Value::known(sk_root)),
  471. Witness::Base(Value::known(tau)),
  472. Witness::Base(Value::known(nonce)),
  473. Witness::Scalar(Value::known(coin_blind)),
  474. Witness::Base(Value::known(value)),
  475. Witness::Scalar(Value::known(value_blind)),
  476. ];
  477. let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
  478. let proof = Proof::create(pk, &[circuit], &revealed.to_vec(), &mut OsRng)?;
  479. Ok((proof, revealed))
  480. }
  481. struct UnstakeLeadBurnRevealed {
  482. pub value_commit: ValueCommit,
  483. pub pk: pallas::Base,
  484. pub commitment_x: pallas::Base,
  485. pub commitment_y: pallas::Base,
  486. pub commitment_root: pallas::Base,
  487. pub sk_root: pallas::Base,
  488. pub nullifier: pallas::Base,
  489. }
  490. impl UnstakeLeadBurnRevealed {
  491. pub fn compute(
  492. value: pallas::Base,
  493. value_blind: ValueBlind,
  494. pk: pallas::Base,
  495. commitment: pallas::Point,
  496. commitment_root: pallas::Base,
  497. sk_root: pallas::Base,
  498. nullifier: pallas::Base,
  499. ) -> Self {
  500. let value_commit = pedersen_commitment_base(value, value_blind);
  501. let coord = commitment.to_affine().coordinates().unwrap();
  502. let commitment_x = *coord.x();
  503. let commitment_y = *coord.y();
  504. Self { value_commit, pk, commitment_x, commitment_y, commitment_root, sk_root, nullifier }
  505. }
  506. pub fn to_vec(&self) -> Vec<pallas::Base> {
  507. let coord = self.value_commit.to_affine().coordinates().unwrap();
  508. let value_cm_x = *coord.x();
  509. let value_cm_y = *coord.y();
  510. vec![
  511. value_cm_x,
  512. value_cm_y,
  513. self.pk,
  514. self.commitment_x,
  515. self.commitment_y,
  516. self.commitment_root,
  517. self.sk_root,
  518. self.nullifier,
  519. ]
  520. }
  521. }
  522. fn create_unstake_burn_proof(
  523. zkbin: &ZkBinary,
  524. pk: &ProvingKey,
  525. value: pallas::Base,
  526. value_blind: ValueBlind,
  527. coin_blind: ValueBlind,
  528. public_key: pallas::Base,
  529. sk: pallas::Base,
  530. sk_root: pallas::Base,
  531. sk_pos: incrementalmerkletree::Position,
  532. sk_path: Vec<MerkleNode>,
  533. commitment_merkle_path: Vec<MerkleNode>,
  534. commitment: pallas::Point,
  535. commitment_root: pallas::Base,
  536. commitment_pos: incrementalmerkletree::Position,
  537. tau: pallas::Base,
  538. nonce: pallas::Base,
  539. nullifier: pallas::Base,
  540. ) -> Result<(Proof, UnstakeLeadBurnRevealed)> {
  541. let revealed = UnstakeLeadBurnRevealed::compute(
  542. value,
  543. value_blind,
  544. public_key,
  545. commitment,
  546. commitment_root,
  547. sk_root,
  548. nullifier,
  549. );
  550. let prover_witnesses = vec![
  551. Witness::MerklePath(Value::known(commitment_merkle_path.try_into().unwrap())),
  552. Witness::Uint32(Value::known(u64::from(commitment_pos).try_into().unwrap())), // u32
  553. Witness::Uint32(Value::known(u64::from(sk_pos).try_into().unwrap())), // u32
  554. Witness::Base(Value::known(sk)),
  555. Witness::Base(Value::known(sk_root)),
  556. Witness::MerklePath(Value::known(sk_path.try_into().unwrap())),
  557. Witness::Base(Value::known(tau)),
  558. Witness::Base(Value::known(nonce)),
  559. Witness::Scalar(Value::known(coin_blind)),
  560. Witness::Base(Value::known(value)),
  561. Witness::Scalar(Value::known(value_blind)),
  562. ];
  563. let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
  564. let proof = Proof::create(pk, &[circuit], &revealed.to_vec(), &mut OsRng)?;
  565. Ok((proof, revealed))
  566. }
  567. /// Build half of the money contract OTC swap transaction parameters with the given data:
  568. /// * `value_send` - Amount to send
  569. /// * `token_id_send` - Token ID to send
  570. /// * `value_recv` - Amount to receive
  571. /// * `token_id_recv` - Token ID to receive
  572. /// * `value_blinds` - Value blinds to use if we're the second half
  573. /// * `token_blinds` - Token blinds to use if we're the second half
  574. /// * `coins` - Set of coins we're able to spend
  575. /// * `tree` - Current Merkle tree of coins
  576. /// * `mint_zkbin` - ZkBinary of the mint circuit
  577. /// * `mint_pk` - Proving key for the ZK mint proof
  578. /// * `burn_zkbin` - ZkBinary of the burn circuit
  579. /// * `burn_pk` - Proving key for the ZK burn proof
  580. #[allow(clippy::too_many_arguments)]
  581. #[allow(clippy::type_complexity)]
  582. pub fn build_half_swap_tx(
  583. pubkey: &PublicKey,
  584. value_send: u64,
  585. token_id_send: TokenId,
  586. value_recv: u64,
  587. token_id_recv: TokenId,
  588. value_blinds: &[ValueBlind],
  589. token_blinds: &[ValueBlind],
  590. coins: &[OwnCoin],
  591. tree: &BridgeTree<MerkleNode, MERKLE_DEPTH>,
  592. mint_zkbin: &ZkBinary,
  593. mint_pk: &ProvingKey,
  594. burn_zkbin: &ZkBinary,
  595. burn_pk: &ProvingKey,
  596. ) -> Result<(
  597. MoneyTransferParams,
  598. Vec<Proof>,
  599. Vec<SecretKey>,
  600. Vec<OwnCoin>,
  601. Vec<ValueBlind>,
  602. Vec<ValueBlind>,
  603. )> {
  604. debug!("Building OTC swap transaction half");
  605. assert!(value_send != 0);
  606. assert!(value_recv != 0);
  607. assert!(!coins.is_empty());
  608. debug!("Money::build_half_swap_tx(): Building anonymous inputs");
  609. // We'll take any coin that has correct value
  610. let Some(coin) = coins.iter().find(|x| x.note.value == value_send && x.note.token_id == token_id_send) else {
  611. error!("Money::build_half_swap_tx(): Did not find a coin with enough value to swap");
  612. return Err(ClientFailed::NotEnoughValue(value_send).into())
  613. };
  614. let leaf_position = coin.leaf_position;
  615. let root = tree.root(0).unwrap();
  616. let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
  617. let input = TransactionBuilderInputInfo {
  618. leaf_position,
  619. merkle_path,
  620. secret: coin.secret,
  621. note: coin.note.clone(),
  622. };
  623. let spent_coins = vec![coin.clone()];
  624. let output = TransactionBuilderOutputInfo {
  625. value: value_recv,
  626. token_id: token_id_recv,
  627. public_key: *pubkey,
  628. };
  629. // We now fill this with necessary stuff
  630. let mut params = MoneyTransferParams { clear_inputs: vec![], inputs: vec![], outputs: vec![] };
  631. let val_blinds: Vec<ValueBlind>;
  632. let tok_blinds: Vec<ValueBlind>;
  633. // If we got non-empty `value_blinds` passed into this function, we use them here.
  634. // They should be sent to the second party by the swap initiator.
  635. let (value_send_blind, value_recv_blind) = {
  636. if value_blinds.is_empty() {
  637. let value_send_blind = ValueBlind::random(&mut OsRng);
  638. let value_recv_blind = ValueBlind::random(&mut OsRng);
  639. val_blinds = vec![value_send_blind, value_recv_blind];
  640. (value_send_blind, value_recv_blind)
  641. } else {
  642. val_blinds = vec![value_blinds[1], value_blinds[0]];
  643. (value_blinds[1], value_blinds[0])
  644. }
  645. };
  646. // The same goes for token blinds
  647. let (token_send_blind, token_recv_blind) = {
  648. if token_blinds.is_empty() {
  649. let token_send_blind = ValueBlind::random(&mut OsRng);
  650. let token_recv_blind = ValueBlind::random(&mut OsRng);
  651. tok_blinds = vec![token_send_blind, token_recv_blind];
  652. (token_send_blind, token_recv_blind)
  653. } else {
  654. tok_blinds = vec![token_blinds[1], token_blinds[0]];
  655. (token_blinds[1], token_blinds[0])
  656. }
  657. };
  658. // The ephemeral secret key we're using here.
  659. let signature_secret = SecretKey::random(&mut OsRng);
  660. // Disable composability for this old obsolete API
  661. let spend_hook = pallas::Base::zero();
  662. let user_data = pallas::Base::zero();
  663. let user_data_blind = pallas::Base::random(&mut OsRng);
  664. let mut zk_proofs = vec![];
  665. info!("Creating swap burn proof for input 0");
  666. let (proof, revealed) = create_transfer_burn_proof(
  667. burn_zkbin,
  668. burn_pk,
  669. input.note.value,
  670. input.note.token_id,
  671. value_send_blind,
  672. token_send_blind,
  673. input.note.serial,
  674. spend_hook,
  675. user_data,
  676. user_data_blind,
  677. input.note.coin_blind,
  678. input.secret,
  679. input.leaf_position,
  680. input.merkle_path,
  681. signature_secret,
  682. )?;
  683. params.inputs.push(Input {
  684. value_commit: revealed.value_commit,
  685. token_commit: revealed.token_commit,
  686. nullifier: revealed.nullifier,
  687. merkle_root: revealed.merkle_root,
  688. spend_hook: revealed.spend_hook,
  689. user_data_enc: revealed.user_data_enc,
  690. signature_public: revealed.signature_public,
  691. });
  692. zk_proofs.push(proof);
  693. let serial = pallas::Base::random(&mut OsRng);
  694. let coin_blind = pallas::Base::random(&mut OsRng);
  695. // Disable composability for this old obsolete API
  696. let spend_hook = pallas::Base::zero();
  697. let user_data = pallas::Base::zero();
  698. info!("Creating swap mint proof for output 0");
  699. let (proof, revealed) = create_transfer_mint_proof(
  700. mint_zkbin,
  701. mint_pk,
  702. output.value,
  703. output.token_id,
  704. value_recv_blind,
  705. token_recv_blind,
  706. serial,
  707. spend_hook,
  708. user_data,
  709. coin_blind,
  710. output.public_key,
  711. )?;
  712. zk_proofs.push(proof);
  713. // Encrypted note
  714. let note = Note {
  715. serial,
  716. value: output.value,
  717. token_id: output.token_id,
  718. coin_blind,
  719. value_blind: value_recv_blind,
  720. token_blind: token_recv_blind,
  721. // Here we store our secret key we use for signing
  722. memo: serialize(&signature_secret),
  723. };
  724. let encrypted_note = note.encrypt(&output.public_key)?;
  725. params.outputs.push(Output {
  726. value_commit: revealed.value_commit,
  727. token_commit: revealed.token_commit,
  728. coin: revealed.coin.inner(),
  729. ciphertext: encrypted_note.ciphertext,
  730. ephem_public: encrypted_note.ephem_public,
  731. });
  732. // Now we should have all the params, zk proofs, and signature secrets.
  733. // We return it all and let the caller deal with it.
  734. Ok((params, zk_proofs, vec![signature_secret], spent_coins, val_blinds, tok_blinds))
  735. }
  736. /// Build money contract transfer transaction parameters with the given data:
  737. /// * `keypair` - Caller's keypair
  738. /// * `pubkey` - Public key of the recipient
  739. /// * `value` - Value of the transfer
  740. /// * `token_id` - Token ID to transfer
  741. /// * `coins` - Set of coins we're able to spend
  742. /// * `tree` - Current Merkle tree of coins
  743. /// * `mint_zkbin` - ZkBinary of the mint circuit
  744. /// * `mint_pk` - Proving key for the ZK mint proof
  745. /// * `burn_zkbin` - ZkBinary of the burn circuit
  746. /// * `burn_pk` - Proving key for the ZK burn proof
  747. /// * `clear_input` - Marks if we're creating clear or anonymous inputs
  748. #[allow(clippy::too_many_arguments)]
  749. #[allow(clippy::type_complexity)]
  750. pub fn build_transfer_tx(
  751. keypair: &Keypair,
  752. pubkey: &PublicKey,
  753. value: u64,
  754. token_id: TokenId,
  755. coins: &[OwnCoin],
  756. tree: &BridgeTree<MerkleNode, MERKLE_DEPTH>,
  757. mint_zkbin: &ZkBinary,
  758. mint_pk: &ProvingKey,
  759. burn_zkbin: &ZkBinary,
  760. burn_pk: &ProvingKey,
  761. clear_input: bool,
  762. ) -> Result<(MoneyTransferParams, Vec<Proof>, Vec<SecretKey>, Vec<OwnCoin>)> {
  763. debug!("Building money contract transfer transaction");
  764. assert!(value != 0);
  765. if !clear_input {
  766. assert!(!coins.is_empty());
  767. }
  768. // Ensure the coins given to us are all of the same token_id.
  769. // The money contract base transfer doesn't allow conversions.
  770. for coin in coins.iter() {
  771. assert_eq!(token_id, coin.note.token_id);
  772. }
  773. let mut clear_inputs = vec![];
  774. let mut inputs = vec![];
  775. let mut outputs = vec![];
  776. let mut spent_coins = vec![];
  777. if clear_input {
  778. debug!("Money::build_transfer_tx(): Building clear input");
  779. let input =
  780. TransactionBuilderClearInputInfo { value, token_id, signature_secret: keypair.secret };
  781. clear_inputs.push(input);
  782. } else {
  783. debug!("Money::build_transfer_tx(): Building anonymous inputs");
  784. let mut inputs_value = 0;
  785. for coin in coins.iter() {
  786. if inputs_value >= value {
  787. debug!("inputs_value >= value");
  788. break
  789. }
  790. let leaf_position = coin.leaf_position;
  791. let root = tree.root(0).unwrap();
  792. let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
  793. inputs_value += coin.note.value;
  794. let input = TransactionBuilderInputInfo {
  795. leaf_position,
  796. merkle_path,
  797. secret: coin.secret,
  798. note: coin.note.clone(),
  799. };
  800. inputs.push(input);
  801. spent_coins.push(coin.clone());
  802. }
  803. if inputs_value < value {
  804. error!("Money::build_transfer_tx(): Not enough value to build tx inputs");
  805. return Err(ClientFailed::NotEnoughValue(inputs_value).into())
  806. }
  807. if inputs_value > value {
  808. let return_value = inputs_value - value;
  809. outputs.push(TransactionBuilderOutputInfo {
  810. value: return_value,
  811. token_id,
  812. public_key: keypair.public,
  813. });
  814. }
  815. debug!("Money::build_transfer_tx(): Finished building inputs");
  816. }
  817. outputs.push(TransactionBuilderOutputInfo { value, token_id, public_key: *pubkey });
  818. assert!(clear_inputs.len() + inputs.len() > 0);
  819. // We now fill this with necessary stuff
  820. let mut params = MoneyTransferParams { clear_inputs: vec![], inputs: vec![], outputs: vec![] };
  821. // I assumed this vec will contain a secret key for each clear input and anonymous input.
  822. let mut signature_secrets = vec![];
  823. let token_blind = ValueBlind::random(&mut OsRng);
  824. for input in clear_inputs {
  825. // TODO: FIXME: What to do with this signature secret?
  826. let signature_public = PublicKey::from_secret(input.signature_secret);
  827. signature_secrets.push(input.signature_secret);
  828. let value_blind = ValueBlind::random(&mut OsRng);
  829. params.clear_inputs.push(ClearInput {
  830. value: input.value,
  831. token_id: input.token_id,
  832. value_blind,
  833. token_blind,
  834. signature_public,
  835. });
  836. }
  837. let mut input_blinds = vec![];
  838. let mut output_blinds = vec![];
  839. let mut zk_proofs = vec![];
  840. for (i, input) in inputs.iter().enumerate() {
  841. let value_blind = ValueBlind::random(&mut OsRng);
  842. input_blinds.push(value_blind);
  843. let signature_secret = SecretKey::random(&mut OsRng);
  844. signature_secrets.push(signature_secret);
  845. // Disable composability for this old obsolete API
  846. let spend_hook = pallas::Base::zero();
  847. let user_data = pallas::Base::zero();
  848. let user_data_blind = pallas::Base::random(&mut OsRng);
  849. info!("Creating transfer burn proof for input {}", i);
  850. let (proof, revealed) = create_transfer_burn_proof(
  851. burn_zkbin,
  852. burn_pk,
  853. input.note.value,
  854. input.note.token_id,
  855. value_blind,
  856. token_blind,
  857. input.note.serial,
  858. spend_hook,
  859. user_data,
  860. user_data_blind,
  861. input.note.coin_blind,
  862. input.secret,
  863. input.leaf_position,
  864. input.merkle_path.clone(),
  865. signature_secret,
  866. )?;
  867. params.inputs.push(Input {
  868. value_commit: revealed.value_commit,
  869. token_commit: revealed.token_commit,
  870. nullifier: revealed.nullifier,
  871. merkle_root: revealed.merkle_root,
  872. spend_hook: revealed.spend_hook,
  873. user_data_enc: revealed.user_data_enc,
  874. signature_public: revealed.signature_public,
  875. });
  876. zk_proofs.push(proof);
  877. }
  878. // This value_blind calc assumes there will always be at least a single output
  879. assert!(!outputs.is_empty());
  880. for (i, output) in outputs.iter().enumerate() {
  881. let value_blind = if i == outputs.len() - 1 {
  882. compute_remainder_blind(&params.clear_inputs, &input_blinds, &output_blinds)
  883. } else {
  884. ValueBlind::random(&mut OsRng)
  885. };
  886. output_blinds.push(value_blind);
  887. let serial = pallas::Base::random(&mut OsRng);
  888. let coin_blind = pallas::Base::random(&mut OsRng);
  889. // Disable composability for this old obsolete API
  890. let spend_hook = pallas::Base::zero();
  891. let user_data = pallas::Base::zero();
  892. info!("Creating transfer mint proof for output {}", i);
  893. let (proof, revealed) = create_transfer_mint_proof(
  894. mint_zkbin,
  895. mint_pk,
  896. output.value,
  897. output.token_id,
  898. value_blind,
  899. token_blind,
  900. serial,
  901. spend_hook,
  902. user_data,
  903. coin_blind,
  904. output.public_key,
  905. )?;
  906. zk_proofs.push(proof);
  907. // Encrypted note
  908. let note = Note {
  909. serial,
  910. value: output.value,
  911. token_id: output.token_id,
  912. coin_blind,
  913. value_blind,
  914. token_blind,
  915. // NOTE: Perhaps pass in memos to this entire function with
  916. // VecDeque and then pop front to add here.
  917. memo: vec![],
  918. };
  919. let encrypted_note = note.encrypt(&output.public_key)?;
  920. params.outputs.push(Output {
  921. value_commit: revealed.value_commit,
  922. token_commit: revealed.token_commit,
  923. coin: revealed.coin.inner(),
  924. ciphertext: encrypted_note.ciphertext,
  925. ephem_public: encrypted_note.ephem_public,
  926. })
  927. }
  928. // Now we should have all the params, zk proofs, and signature secrets.
  929. // We return it all and let the caller deal with it.
  930. Ok((params, zk_proofs, signature_secrets, spent_coins))
  931. }
  932. pub fn build_stake_tx(
  933. //pubkey: &PublicKey,
  934. coins: &[OwnCoin],
  935. tx_tree: &mut BridgeTree<MerkleNode, MERKLE_DEPTH>,
  936. cm_tree: &mut BridgeTree<MerkleNode, MERKLE_DEPTH>,
  937. sk_tree: &mut BridgeTree<MerkleNode, MERKLE_DEPTH>,
  938. mint_zkbin: &ZkBinary,
  939. mint_pk: &ProvingKey,
  940. burn_zkbin: &ZkBinary,
  941. burn_pk: &ProvingKey,
  942. slot_index: u64,
  943. eta: pallas::Base,
  944. ) -> Result<(MoneyStakeParams, Vec<Proof>, Vec<LeadCoin>, Vec<ValueBlind>, Vec<ValueBlind>)> {
  945. // convert owncoins to leadcoins.
  946. // TODO: verify this token blind usage
  947. let token_blind = ValueBlind::random(&mut OsRng);
  948. let mut leadcoins: Vec<LeadCoin> = vec![];
  949. let mut params = MoneyStakeParams { inputs: vec![], outputs: vec![], token_blind };
  950. let mut proofs = vec![];
  951. let mut own_blinds = vec![];
  952. let mut lead_blinds = vec![];
  953. for coin in coins.iter() {
  954. // burn the coin
  955. let value_blind = ValueBlind::random(&mut OsRng);
  956. own_blinds.push(value_blind);
  957. let spend_hook = pallas::Base::zero();
  958. let user_data = pallas::Base::zero();
  959. let user_data_blind = pallas::Base::random(&mut OsRng);
  960. let tx_leaf_position = coin.leaf_position;
  961. let tx_root = tx_tree.root(0).unwrap();
  962. let tx_merkle_path = tx_tree.authentication_path(tx_leaf_position, &tx_root).unwrap();
  963. let signature_secret = SecretKey::random(&mut OsRng);
  964. //signature_secrets.push(signature_secret);
  965. let (own_proof, own_revealed) = create_transfer_burn_proof(
  966. burn_zkbin,
  967. burn_pk,
  968. coin.note.value,
  969. coin.note.token_id,
  970. coin.note.value_blind,
  971. coin.note.token_blind,
  972. coin.note.serial,
  973. spend_hook,
  974. user_data,
  975. user_data_blind,
  976. coin.note.coin_blind,
  977. coin.secret,
  978. coin.leaf_position,
  979. tx_merkle_path.clone(),
  980. signature_secret,
  981. )?;
  982. params.inputs.push(Input {
  983. value_commit: own_revealed.value_commit,
  984. token_commit: own_revealed.token_commit,
  985. nullifier: own_revealed.nullifier,
  986. merkle_root: own_revealed.merkle_root,
  987. spend_hook: own_revealed.spend_hook,
  988. user_data_enc: own_revealed.user_data_enc,
  989. signature_public: own_revealed.signature_public,
  990. });
  991. proofs.push(own_proof);
  992. let lead_value_blind = ValueBlind::random(&mut OsRng);
  993. lead_blinds.push(lead_value_blind);
  994. sk_tree.append(&MerkleNode::from(coin.secret.inner()));
  995. let sk_pos = sk_tree.witness().unwrap();
  996. let sk_root = sk_tree.root(0).unwrap();
  997. let sk_merkle_path = sk_tree.authentication_path(sk_pos, &sk_root).unwrap();
  998. let leadcoin = LeadCoin::new(
  999. eta, // randomness from last finalized block.
  1000. coin.note.value,
  1001. slot_index, // tau
  1002. coin.secret.inner(), // coin secret key
  1003. sk_root,
  1004. sk_pos.try_into().unwrap(),
  1005. sk_merkle_path.try_into().unwrap(),
  1006. coin.note.serial,
  1007. cm_tree,
  1008. );
  1009. leadcoins.push(leadcoin);
  1010. let lead_coin_blind = ValueBlind::random(&mut OsRng);
  1011. let public_key = leadcoin.pk();
  1012. let (lead_proof, lead_revealed) = create_stake_mint_proof(
  1013. mint_zkbin,
  1014. mint_pk,
  1015. public_key,
  1016. leadcoin.coin1_commitment,
  1017. pallas::Base::from(coin.note.value),
  1018. lead_value_blind,
  1019. lead_coin_blind,
  1020. coin.secret.inner(),
  1021. sk_root.inner(),
  1022. pallas::Base::from(slot_index), // tau
  1023. coin.note.serial, // nonce
  1024. )?;
  1025. let coin_commit_coords = [lead_revealed.commitment_x, lead_revealed.commitment_y];
  1026. let coin_commit_hash = poseidon_hash(coin_commit_coords);
  1027. params.outputs.push(StakedOutput {
  1028. value_commit: lead_revealed.value_commit,
  1029. coin_commit_hash,
  1030. coin_pk_hash: public_key,
  1031. });
  1032. proofs.push(lead_proof);
  1033. }
  1034. Ok((params, proofs, leadcoins, own_blinds, lead_blinds))
  1035. }
  1036. pub fn build_unstake_tx(
  1037. pubkey: &PublicKey, //recepient of owncoin public key
  1038. token_id_recv: TokenId,
  1039. coins: &[LeadCoin],
  1040. mint_zkbin: &ZkBinary, // stake own mint binary
  1041. mint_pk: &ProvingKey,
  1042. burn_zkbin: &ZkBinary, // unstake lead burn binary
  1043. burn_pk: &ProvingKey,
  1044. ) -> Result<(MoneyUnstakeParams, Vec<Proof>, Vec<SecretKey>, Vec<ValueBlind>, Vec<ValueBlind>)> {
  1045. // convert leadcoin to owncoin
  1046. // TODO: verify this token blind usage
  1047. let token_blind = ValueBlind::random(&mut OsRng);
  1048. //let owncoins : Vec<OwnCoin>= vec![];
  1049. let mut params = MoneyUnstakeParams { inputs: vec![], outputs: vec![], token_blind };
  1050. let mut proofs = vec![];
  1051. let mut own_blinds = vec![];
  1052. let mut lead_blinds = vec![];
  1053. for coin in coins.iter() {
  1054. // burn lead coin
  1055. let value_blind = ValueBlind::random(&mut OsRng);
  1056. lead_blinds.push(value_blind);
  1057. let pk = coin.pk();
  1058. let nullifier = coin.sn();
  1059. let (unstake_proof, unstake_revealed) = create_unstake_burn_proof(
  1060. burn_zkbin,
  1061. burn_pk,
  1062. pallas::Base::from(coin.value),
  1063. value_blind,
  1064. coin.coin1_blind,
  1065. pk,
  1066. coin.coin1_sk,
  1067. coin.coin1_sk_root.inner(),
  1068. incrementalmerkletree::Position::from(coin.coin1_sk_pos as usize),
  1069. coin.coin1_sk_merkle_path.to_vec(),
  1070. coin.coin1_commitment_merkle_path.to_vec(),
  1071. coin.coin1_commitment,
  1072. coin.coin1_commitment_root.inner(),
  1073. incrementalmerkletree::Position::from(coin.coin1_commitment_pos as usize),
  1074. coin.tau,
  1075. coin.nonce,
  1076. nullifier,
  1077. )?;
  1078. let commitment_coord = [unstake_revealed.commitment_x, unstake_revealed.commitment_y];
  1079. let coin_commitment_hash = poseidon_hash(commitment_coord);
  1080. params.inputs.push(StakedInput {
  1081. nullifier: nullifier.into(),
  1082. value_commit: unstake_revealed.value_commit,
  1083. coin_commit_hash: coin_commitment_hash,
  1084. coin_pk_hash: unstake_revealed.pk,
  1085. coin_commit_root: unstake_revealed.commitment_root.into(),
  1086. sk_root: unstake_revealed.sk_root.into(),
  1087. });
  1088. proofs.push(unstake_proof);
  1089. let own_value_blind = ValueBlind::random(&mut OsRng);
  1090. own_blinds.push(own_value_blind);
  1091. // mint own coin
  1092. let serial = pallas::Base::random(&mut OsRng);
  1093. let coin_blind = pallas::Base::random(&mut OsRng);
  1094. let token_recv_blind = ValueBlind::random(&mut OsRng);
  1095. // Disable composability for this old obsolete API
  1096. let spend_hook = pallas::Base::zero();
  1097. let user_data = pallas::Base::zero();
  1098. let (proof, revealed) = create_transfer_mint_proof(
  1099. mint_zkbin,
  1100. mint_pk,
  1101. coin.value,
  1102. token_id_recv,
  1103. own_value_blind,
  1104. token_recv_blind,
  1105. serial,
  1106. spend_hook,
  1107. user_data,
  1108. coin_blind,
  1109. *pubkey, //receipient public_key
  1110. )?;
  1111. proofs.push(proof);
  1112. // Encrypted note
  1113. let note = Note {
  1114. serial,
  1115. value: coin.value,
  1116. token_id: token_id_recv,
  1117. coin_blind,
  1118. value_blind,
  1119. token_blind: token_recv_blind,
  1120. // Here we store our secret key we use for signing
  1121. memo: vec![],
  1122. };
  1123. let encrypted_note = note.encrypt(&pubkey)?;
  1124. params.outputs.push(Output {
  1125. value_commit: revealed.value_commit,
  1126. token_commit: revealed.token_commit,
  1127. coin: revealed.coin.inner(),
  1128. ciphertext: encrypted_note.ciphertext,
  1129. ephem_public: encrypted_note.ephem_public,
  1130. });
  1131. }
  1132. Ok((params, proofs, vec![], lead_blinds, own_blinds))
  1133. }
  1134. fn compute_remainder_blind(
  1135. clear_inputs: &[ClearInput],
  1136. input_blinds: &[ValueBlind],
  1137. output_blinds: &[ValueBlind],
  1138. ) -> ValueBlind {
  1139. let mut total = ValueBlind::zero();
  1140. for input in clear_inputs {
  1141. total += input.value_blind;
  1142. }
  1143. for input_blind in input_blinds {
  1144. total += input_blind
  1145. }
  1146. for output_blind in output_blinds {
  1147. total -= output_blind;
  1148. }
  1149. total
  1150. }
  1151. #[cfg(test)]
  1152. mod tests {
  1153. use darkfi_sdk::pasta::group::ff::Field;
  1154. use super::*;
  1155. #[test]
  1156. fn test_note_encdec() {
  1157. let note = Note {
  1158. serial: pallas::Base::random(&mut OsRng),
  1159. value: 100,
  1160. token_id: TokenId::from(pallas::Base::random(&mut OsRng)),
  1161. coin_blind: pallas::Base::random(&mut OsRng),
  1162. value_blind: pallas::Scalar::random(&mut OsRng),
  1163. token_blind: pallas::Scalar::random(&mut OsRng),
  1164. memo: vec![32, 223, 231, 3, 1, 1],
  1165. };
  1166. let keypair = Keypair::random(&mut OsRng);
  1167. let encrypted_note = note.encrypt(&keypair.public).unwrap();
  1168. let note2 = encrypted_note.decrypt(&keypair.secret).unwrap();
  1169. assert_eq!(note.serial, note2.serial);
  1170. assert_eq!(note.value, note2.value);
  1171. assert_eq!(note.token_id, note2.token_id);
  1172. assert_eq!(note.coin_blind, note2.coin_blind);
  1173. assert_eq!(note.value_blind, note2.value_blind);
  1174. assert_eq!(note.token_blind, note2.token_blind);
  1175. assert_eq!(note.memo, note2.memo);
  1176. assert_eq!(note, note2);
  1177. }
  1178. }