darkfi_money_contract/client/
fee_v1.rs
1use darkfi::{
20 zk::{halo2::Value, Proof, ProvingKey, Witness, ZkCircuit},
21 zkas::ZkBinary,
22 Result,
23};
24use darkfi_sdk::{
25 bridgetree::Hashable,
26 crypto::{
27 pasta_prelude::{Curve, CurveAffine},
28 pedersen_commitment_u64, poseidon_hash, BaseBlind, FuncId, MerkleNode, PublicKey,
29 ScalarBlind, SecretKey,
30 },
31 pasta::pallas,
32};
33use rand::rngs::OsRng;
34
35use crate::{
36 client::{Coin, MoneyNote, OwnCoin},
37 model::{CoinAttributes, Nullifier},
38};
39
40pub const FEE_CALL_GAS: u64 = 42_000_000;
43
44pub struct FeeCallSecrets {
46 pub proof: Proof,
48 pub signature_secret: SecretKey,
50 pub note: MoneyNote,
52 pub input_value_blind: ScalarBlind,
54 pub output_value_blind: ScalarBlind,
56}
57
58pub struct FeeRevealed {
60 pub nullifier: Nullifier,
62 pub input_value_commit: pallas::Point,
64 pub token_commit: pallas::Base,
66 pub merkle_root: MerkleNode,
68 pub input_user_data_enc: pallas::Base,
70 pub signature_public: PublicKey,
72 pub output_coin: Coin,
74 pub output_value_commit: pallas::Point,
76}
77
78impl FeeRevealed {
79 pub fn to_vec(&self) -> Vec<pallas::Base> {
82 let input_vc_coords = self.input_value_commit.to_affine().coordinates().unwrap();
83 let output_vc_coords = self.output_value_commit.to_affine().coordinates().unwrap();
84 let sigpub_coords = self.signature_public.inner().to_affine().coordinates().unwrap();
85
86 vec![
89 self.nullifier.inner(),
90 *input_vc_coords.x(),
91 *input_vc_coords.y(),
92 self.token_commit,
93 self.merkle_root.inner(),
94 self.input_user_data_enc,
95 *sigpub_coords.x(),
96 *sigpub_coords.y(),
97 self.output_coin.inner(),
98 *output_vc_coords.x(),
99 *output_vc_coords.y(),
100 ]
101 }
102}
103
104pub struct FeeCallInput {
105 pub coin: OwnCoin,
107 pub merkle_path: Vec<MerkleNode>,
109 pub user_data_blind: BaseBlind,
111}
112
113pub type FeeCallOutput = CoinAttributes;
114
115#[allow(clippy::too_many_arguments)]
117pub fn create_fee_proof(
118 zkbin: &ZkBinary,
119 pk: &ProvingKey,
120 input: &FeeCallInput,
121 input_value_blind: ScalarBlind,
122 output: &FeeCallOutput,
123 output_value_blind: ScalarBlind,
124 output_spend_hook: FuncId,
125 output_user_data: pallas::Base,
126 output_coin_blind: BaseBlind,
127 token_blind: BaseBlind,
128 signature_secret: SecretKey,
129) -> Result<(Proof, FeeRevealed)> {
130 let public_key = PublicKey::from_secret(input.coin.secret);
131 let signature_public = PublicKey::from_secret(signature_secret);
132
133 let input_coin = CoinAttributes {
135 public_key,
136 value: input.coin.note.value,
137 token_id: input.coin.note.token_id,
138 spend_hook: input.coin.note.spend_hook,
139 user_data: input.coin.note.user_data,
140 blind: input.coin.note.coin_blind,
141 }
142 .to_coin();
143
144 let merkle_root = {
145 let position: u64 = input.coin.leaf_position.into();
146 let mut current = MerkleNode::from(input_coin.inner());
147 for (level, sibling) in input.merkle_path.iter().enumerate() {
148 let level = level as u8;
149 current = if position & (1 << level) == 0 {
150 MerkleNode::combine(level.into(), ¤t, sibling)
151 } else {
152 MerkleNode::combine(level.into(), sibling, ¤t)
153 };
154 }
155 current
156 };
157
158 let input_user_data_enc =
159 poseidon_hash([input.coin.note.user_data, input.user_data_blind.inner()]);
160 let input_value_commit = pedersen_commitment_u64(input.coin.note.value, input_value_blind);
161 let output_value_commit = pedersen_commitment_u64(output.value, output_value_blind);
162 let token_commit = poseidon_hash([input.coin.note.token_id.inner(), token_blind.inner()]);
163
164 let output_coin = CoinAttributes {
166 public_key: output.public_key,
167 value: output.value,
168 token_id: output.token_id,
169 spend_hook: output_spend_hook,
170 user_data: output_user_data,
171 blind: output_coin_blind,
172 }
173 .to_coin();
174
175 let public_inputs = FeeRevealed {
176 nullifier: input.coin.nullifier(),
177 input_value_commit,
178 token_commit,
179 merkle_root,
180 input_user_data_enc,
181 signature_public,
182 output_coin,
183 output_value_commit,
184 };
185
186 let prover_witnesses = vec![
187 Witness::Base(Value::known(input.coin.secret.inner())),
188 Witness::Uint32(Value::known(u64::from(input.coin.leaf_position).try_into().unwrap())),
189 Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
190 Witness::Base(Value::known(signature_secret.inner())),
191 Witness::Base(Value::known(pallas::Base::from(input.coin.note.value))),
192 Witness::Scalar(Value::known(input_value_blind.inner())),
193 Witness::Base(Value::known(input.coin.note.spend_hook.inner())),
194 Witness::Base(Value::known(input.coin.note.user_data)),
195 Witness::Base(Value::known(input.coin.note.coin_blind.inner())),
196 Witness::Base(Value::known(input.user_data_blind.inner())),
197 Witness::Base(Value::known(pallas::Base::from(output.value))),
198 Witness::Base(Value::known(output_spend_hook.inner())),
199 Witness::Base(Value::known(output_user_data)),
200 Witness::Scalar(Value::known(output_value_blind.inner())),
201 Witness::Base(Value::known(output_coin_blind.inner())),
202 Witness::Base(Value::known(input.coin.note.token_id.inner())),
203 Witness::Base(Value::known(token_blind.inner())),
204 ];
205
206 let circuit = ZkCircuit::new(prover_witnesses, zkbin);
208 let proof = Proof::create(pk, &[circuit], &public_inputs.to_vec(), &mut OsRng)?;
209
210 Ok((proof, public_inputs))
211}