| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- use darkfi_sdk::crypto::MerkleNode;
- use darkfi_serial::{SerialDecodable, SerialEncodable};
- use pasta_curves::group::ff::Field;
- use rand::rngs::OsRng;
- use darkfi::{
- crypto::{
- burn_proof::create_burn_proof,
- keypair::{PublicKey, SecretKey},
- mint_proof::create_mint_proof,
- types::{
- DrkCoinBlind, DrkSerial, DrkSpendHook, DrkTokenId, DrkUserData, DrkUserDataBlind,
- DrkValueBlind,
- },
- },
- Result,
- };
- use crate::{
- contract::money_contract::{
- transfer::validate::{CallData, ClearInput, Input, Output},
- CONTRACT_ID,
- },
- note,
- util::{FuncCall, ZkContractInfo, ZkContractTable},
- };
- #[derive(Clone, SerialEncodable, SerialDecodable)]
- pub struct Note {
- pub serial: DrkSerial,
- pub value: u64,
- pub token_id: DrkTokenId,
- pub spend_hook: DrkSpendHook,
- pub user_data: DrkUserData,
- pub coin_blind: DrkCoinBlind,
- pub value_blind: DrkValueBlind,
- pub token_blind: DrkValueBlind,
- }
- pub struct Builder {
- pub clear_inputs: Vec<BuilderClearInputInfo>,
- pub inputs: Vec<BuilderInputInfo>,
- pub outputs: Vec<BuilderOutputInfo>,
- }
- pub struct BuilderClearInputInfo {
- pub value: u64,
- pub token_id: DrkTokenId,
- pub signature_secret: SecretKey,
- }
- pub struct BuilderInputInfo {
- pub leaf_position: incrementalmerkletree::Position,
- pub merkle_path: Vec<MerkleNode>,
- pub secret: SecretKey,
- pub note: Note,
- pub user_data_blind: DrkUserDataBlind,
- pub value_blind: DrkValueBlind,
- pub signature_secret: SecretKey,
- }
- pub struct BuilderOutputInfo {
- pub value: u64,
- pub token_id: DrkTokenId,
- pub public: PublicKey,
- pub serial: DrkSerial,
- pub coin_blind: DrkCoinBlind,
- pub spend_hook: DrkSpendHook,
- pub user_data: DrkUserData,
- }
- impl Builder {
- fn compute_remainder_blind(
- clear_inputs: &[ClearInput],
- input_blinds: &[DrkValueBlind],
- output_blinds: &[DrkValueBlind],
- ) -> DrkValueBlind {
- let mut total = DrkValueBlind::zero();
- for input in clear_inputs {
- total += input.value_blind;
- }
- for input_blind in input_blinds {
- total += input_blind;
- }
- for output_blind in output_blinds {
- total -= output_blind;
- }
- total
- }
- pub fn build(self, zk_bins: &ZkContractTable) -> Result<FuncCall> {
- assert!(self.clear_inputs.len() + self.inputs.len() > 0);
- let mut clear_inputs = vec![];
- let token_blind = DrkValueBlind::random(&mut OsRng);
- for input in &self.clear_inputs {
- let signature_public = PublicKey::from_secret(input.signature_secret);
- let value_blind = DrkValueBlind::random(&mut OsRng);
- let clear_input = ClearInput {
- value: input.value,
- token_id: input.token_id,
- value_blind,
- token_blind,
- signature_public,
- };
- clear_inputs.push(clear_input);
- }
- let mut proofs = vec![];
- let mut inputs = vec![];
- let mut input_blinds = vec![];
- for input in self.inputs {
- let value_blind = input.value_blind;
- input_blinds.push(value_blind);
- let zk_info = zk_bins.lookup(&"money-transfer-burn".to_string()).unwrap();
- let zk_info = if let ZkContractInfo::Native(info) = zk_info {
- info
- } else {
- panic!("Not native info")
- };
- let burn_pk = &zk_info.proving_key;
- // Note from the previous output
- let note = input.note.clone();
- let (burn_proof, revealed) = create_burn_proof(
- burn_pk,
- note.value,
- note.token_id,
- value_blind,
- token_blind,
- note.serial,
- note.spend_hook,
- note.user_data,
- input.user_data_blind,
- note.coin_blind,
- input.secret,
- input.leaf_position,
- input.merkle_path.clone(),
- input.signature_secret,
- )?;
- proofs.push(burn_proof);
- let input = Input { revealed };
- inputs.push(input);
- }
- let mut outputs = vec![];
- let mut output_blinds = vec![];
- // This value_blind calc assumes there will always be at least a single output
- assert!(!self.outputs.is_empty());
- for (i, output) in self.outputs.iter().enumerate() {
- let value_blind = if i == self.outputs.len() - 1 {
- Self::compute_remainder_blind(&clear_inputs, &input_blinds, &output_blinds)
- } else {
- DrkValueBlind::random(&mut OsRng)
- };
- output_blinds.push(value_blind);
- let serial = output.serial;
- let coin_blind = output.coin_blind;
- let zk_info = zk_bins.lookup(&"money-transfer-mint".to_string()).unwrap();
- let zk_info = if let ZkContractInfo::Native(info) = zk_info {
- info
- } else {
- panic!("Not native info")
- };
- let mint_pk = &zk_info.proving_key;
- let (mint_proof, revealed) = create_mint_proof(
- mint_pk,
- output.value,
- output.token_id,
- value_blind,
- token_blind,
- serial,
- output.spend_hook,
- output.user_data,
- coin_blind,
- output.public,
- )?;
- proofs.push(mint_proof);
- let note = Note {
- serial,
- value: output.value,
- token_id: output.token_id,
- spend_hook: output.spend_hook,
- user_data: output.user_data,
- coin_blind,
- value_blind,
- token_blind,
- };
- let encrypted_note = note::encrypt(¬e, &output.public)?;
- let output = Output { revealed, enc_note: encrypted_note };
- outputs.push(output);
- }
- let call_data = CallData { clear_inputs, inputs, outputs };
- Ok(FuncCall {
- contract_id: *CONTRACT_ID,
- func_id: *super::FUNC_ID,
- call_data: Box::new(call_data),
- proofs,
- })
- }
- }
|