Просмотр исходного кода

drk: Initial swap inspection stub.

parazyd 3 лет назад
Родитель
Сommit
805b9b82e9
2 измененных файлов с 173 добавлено и 2 удалено
  1. 12 0
      bin/drk/src/main.rs
  2. 161 2
      bin/drk/src/rpc_swap.rs

+ 12 - 0
bin/drk/src/main.rs

@@ -205,6 +205,9 @@ enum OtcSubcmd {
     /// Build entire swap tx given the first half from stdin
     Join,
 
+    /// Inspect a swap half or the full swap tx from stdin
+    Inspect,
+
     /// Sign a transaction given from stdin as the first-half
     Sign,
 }
@@ -487,6 +490,15 @@ async fn main() -> Result<()> {
                     Ok(())
                 }
 
+                OtcSubcmd::Inspect => {
+                    let mut buf = String::new();
+                    stdin().read_to_string(&mut buf)?;
+                    let bytes = bs58::decode(&buf.trim()).into_vec()?;
+
+                    drk.inspect_swap(bytes).await.with_context(|| "Failed to inspect swap")?;
+                    Ok(())
+                }
+
                 OtcSubcmd::Sign => {
                     let mut buf = String::new();
                     stdin().read_to_string(&mut buf)?;

+ 161 - 2
bin/drk/src/rpc_swap.rs

@@ -19,16 +19,20 @@
 use anyhow::{anyhow, Result};
 use darkfi::{
     tx::Transaction,
+    util::parse::encode_base10,
     zk::{proof::ProvingKey, vm::ZkCircuit, vm_stack::empty_witnesses, Proof},
     zkas::ZkBinary,
 };
 use darkfi_money_contract::{
-    client::{build_half_swap_tx, EncryptedNote},
+    client::{build_half_swap_tx, EncryptedNote, Note},
     state::MoneyTransferParams,
     MoneyFunction, ZKAS_BURN_NS, ZKAS_MINT_NS,
 };
 use darkfi_sdk::{
-    crypto::{pedersen::ValueBlind, ContractId, SecretKey, TokenId},
+    crypto::{
+        pedersen::{pedersen_commitment_base, pedersen_commitment_u64, ValueBlind},
+        poseidon_hash, ContractId, PublicKey, SecretKey, TokenId,
+    },
     pasta::pallas,
     tx::ContractCall,
 };
@@ -242,6 +246,161 @@ impl Drk {
         Ok(tx)
     }
 
+    /// Inspect and verify a given swap (half or full) transaction
+    pub async fn inspect_swap(&self, bytes: Vec<u8>) -> Result<()> {
+        let mut full: Option<Transaction> = None;
+        let mut _half: Option<PartialSwapData> = None;
+
+        match deserialize(&bytes) {
+            Ok(v) => full = Some(v),
+            Err(_) => {}
+        }
+
+        match deserialize(&bytes) {
+            Ok(v) => _half = Some(v),
+            Err(_) => {
+                if full.is_none() {
+                    return Err(anyhow!("Failed to deserialize to Transaction or PartialSwapData"))
+                }
+            }
+        }
+
+        if let Some(tx) = full {
+            // We're inspecting a full transaction
+            if tx.calls.len() != 1 {
+                eprintln!(
+                    "Found {} contract calls in the transaction, there should be 1",
+                    tx.calls.len()
+                );
+                return Err(anyhow!("Inspection failed"))
+            }
+
+            let params: MoneyTransferParams = deserialize(&tx.calls[0].data[1..])?;
+            eprintln!("Parameters:\n{:#?}", params);
+
+            if params.inputs.len() != 2 {
+                eprintln!("Found {} inputs, there should be 2", params.inputs.len());
+                return Err(anyhow!("Inspection failed"))
+            }
+
+            if params.outputs.len() != 2 {
+                eprintln!("Found {} outputs, there should be 2", params.outputs.len());
+                return Err(anyhow!("Inspection failed"))
+            }
+
+            // Try to decrypt one of the outputs.
+            let secret_keys = self.wallet_secrets().await?;
+            let mut skey: Option<SecretKey> = None;
+            let mut note: Option<Note> = None;
+            let mut output_idx = 0;
+
+            for output in &params.outputs {
+                let ciphertext = output.ciphertext.clone();
+                let ephem_public = output.ephem_public;
+                let e_note = EncryptedNote { ciphertext, ephem_public };
+                eprintln!("Trying to decrypt note in output {}", output_idx);
+
+                for secret in &secret_keys {
+                    if let Ok(d_note) = e_note.decrypt(secret) {
+                        let s: SecretKey = deserialize(&d_note.memo)?;
+                        skey = Some(s);
+                        note = Some(d_note);
+                        eprintln!("Successfully decrypted and found an ephemeral secret");
+                        break
+                    }
+                }
+
+                if note.is_some() {
+                    break
+                }
+
+                output_idx += 1;
+            }
+
+            let Some(note) = note else {
+                eprintln!("Error: Could not decrypt notes of either output");
+                return Err(anyhow!("Inspection failed"))
+            };
+
+            eprintln!(
+                "Output[{}] value: {} ({})",
+                output_idx,
+                note.value,
+                encode_base10(note.value, 8)
+            );
+            eprintln!("Output[{}] token ID: {}", output_idx, note.token_id);
+
+            let skey = skey.unwrap();
+            let (pub_x, pub_y) = PublicKey::from_secret(skey).xy();
+            let coin = poseidon_hash([
+                pub_x,
+                pub_y,
+                pallas::Base::from(note.value),
+                note.token_id.inner(),
+                note.serial,
+                note.coin_blind,
+            ]);
+
+            if coin == params.outputs[output_idx].coin {
+                eprintln!("Output[{}] coin matches decrypted note metadata", output_idx);
+            } else {
+                eprintln!("Error: Output[{}] coin does not match note metadata", output_idx);
+                return Err(anyhow!("Inspection failed"))
+            }
+
+            let valcom = pedersen_commitment_u64(note.value, note.value_blind);
+            let tokcom = pedersen_commitment_base(note.token_id.inner(), note.token_blind);
+
+            if valcom != params.outputs[output_idx].value_commit {
+                eprintln!(
+                    "Error: Output[{}] value commitment does not match note metadata",
+                    output_idx
+                );
+                return Err(anyhow!("Inspection failed"))
+            }
+
+            if tokcom != params.outputs[output_idx].token_commit {
+                eprintln!(
+                    "Error: Output[{}] token commitment does not match note metadata",
+                    output_idx
+                );
+                return Err(anyhow!("Inspection failed"))
+            }
+
+            eprintln!("Value and token commitments match decrypted note metadata");
+
+            // Verify that the output commitments match the other input commitments
+            match output_idx {
+                0 => {
+                    if valcom != params.inputs[1].value_commit ||
+                        tokcom != params.inputs[1].token_commit
+                    {
+                        eprintln!("Error: Value/Token commits of output[0] do not match input[1]");
+                        return Err(anyhow!("Inspection failed"))
+                    }
+                }
+                1 => {
+                    if valcom != params.inputs[0].value_commit ||
+                        tokcom != params.inputs[0].token_commit
+                    {
+                        eprintln!("Error: Value/Token commits of output[1] do not match input[0]");
+                        return Err(anyhow!("Inspection failed"))
+                    }
+                }
+                _ => unreachable!(),
+            }
+
+            eprintln!("Found matching pedersen commitments for outputs and inputs");
+
+            // TODO: Verify signature
+            // TODO: Verify ZK proofs
+            return Ok(())
+        }
+
+        // TODO: Inspect PartialSwapData
+        todo!("Inspect PartialSwapData");
+    }
+
     /// Sign a given transaction by retrieving the secret key from the encrypted
     /// note and prepending it to the transaction's signatures.
     pub async fn sign_swap(&self, tx: &mut Transaction) -> Result<()> {