darkfi_money_contract/client/
burn_v1.rs1use darkfi::{
20 zk::{Proof, ProvingKey},
21 zkas::ZkBinary,
22 ClientFailed, Result,
23};
24use darkfi_sdk::crypto::{BaseBlind, Blind, MerkleTree, ScalarBlind, SecretKey};
25use rand::rngs::OsRng;
26use tracing::debug;
27
28use crate::{
29 client::{
30 transfer_v1::{proof::create_transfer_burn_proof, TransferCallInput},
31 OwnCoin,
32 },
33 error::MoneyError,
34 model::{Input, MoneyBurnParamsV1},
35};
36
37pub struct BurnCallBuilder {
40 pub inputs: Vec<TransferCallInput>,
42 pub burn_zkbin: ZkBinary,
44 pub burn_pk: ProvingKey,
46}
47
48impl BurnCallBuilder {
49 pub fn build(self) -> Result<(MoneyBurnParamsV1, BurnCallDebris)> {
50 debug!(target: "contract::money::client::burn::build", "Building Money::BurnV1 contract call");
51 if self.inputs.is_empty() {
52 return Err(ClientFailed::VerifyError(MoneyError::BurnMissingInputs.to_string()).into())
53 }
54
55 let mut params = MoneyBurnParamsV1 { inputs: vec![] };
56 let mut signature_secrets = vec![];
57 let mut proofs = vec![];
58
59 let token_blind = BaseBlind::random(&mut OsRng);
60 let mut input_value_blinds = vec![];
61
62 debug!(target: "contract::money::client::burn::build", "Building anonymous inputs");
63 for (i, input) in self.inputs.iter().enumerate() {
64 let value_blind = Blind::random(&mut OsRng);
65 input_value_blinds.push(value_blind);
66
67 let signature_secret = SecretKey::random(&mut OsRng);
68 signature_secrets.push(signature_secret);
69
70 debug!(target: "contract::money::client::burn::build", "Creating burn proof for input {i}");
71 let (proof, public_inputs) = create_transfer_burn_proof(
72 &self.burn_zkbin,
73 &self.burn_pk,
74 input,
75 value_blind,
76 token_blind,
77 signature_secret,
78 )?;
79
80 params.inputs.push(Input {
81 value_commit: public_inputs.value_commit,
82 token_commit: public_inputs.token_commit,
83 nullifier: public_inputs.nullifier,
84 merkle_root: public_inputs.merkle_root,
85 user_data_enc: public_inputs.user_data_enc,
86 signature_public: public_inputs.signature_public,
87 });
88
89 proofs.push(proof);
90 }
91
92 let secrets = BurnCallDebris { proofs, signature_secrets, input_value_blinds, token_blind };
93 Ok((params, secrets))
94 }
95}
96
97pub struct BurnCallDebris {
98 pub proofs: Vec<Proof>,
100 pub signature_secrets: Vec<SecretKey>,
102 pub input_value_blinds: Vec<ScalarBlind>,
104 pub token_blind: BaseBlind,
106}
107
108pub fn make_burn_call(
121 coins: Vec<OwnCoin>,
122 tree: MerkleTree,
123 burn_zkbin: ZkBinary,
124 burn_pk: ProvingKey,
125) -> Result<(MoneyBurnParamsV1, BurnCallDebris, Vec<OwnCoin>)> {
126 debug!(target: "contract::money::client::burn", "Building Money::BurnV1 contract call");
127
128 if coins.is_empty() {
129 return Err(ClientFailed::VerifyError(MoneyError::BurnMissingInputs.to_string()).into())
130 }
131
132 let token_id = coins[0].note.token_id;
134 for coin in &coins {
135 if coin.note.token_id != token_id {
136 return Err(ClientFailed::InvalidTokenId(coin.note.token_id.to_string()).into())
137 }
138 }
139
140 let mut inputs = vec![];
141 for coin in coins.iter() {
142 let input = TransferCallInput {
143 coin: coin.clone(),
144 merkle_path: tree.witness(coin.leaf_position, 0).unwrap(),
145 user_data_blind: Blind::random(&mut OsRng),
146 };
147
148 inputs.push(input);
149 }
150
151 let burn_builder = BurnCallBuilder { inputs, burn_zkbin, burn_pk };
152
153 let (params, secrets) = burn_builder.build()?;
154
155 Ok((params, secrets, coins))
156}