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

daod/ money: moved CallData into validate.rs

lunar-mining 4 лет назад
Родитель
Сommit
4064cf4423

+ 6 - 6
bin/daod/src/money_contract/transfer/builder.rs

@@ -1,12 +1,6 @@
 use pasta_curves::group::ff::Field;
 use rand::rngs::OsRng;
 
-use super::{
-    partial::{Partial, PartialClearInput, PartialInput},
-    CallData, ClearInput, Input, Output,
-};
-use crate::demo::FuncCall;
-
 use darkfi::{
     crypto::{
         burn_proof::create_burn_proof,
@@ -22,6 +16,12 @@ use darkfi::{
     Result,
 };
 
+use super::partial::{Partial, PartialClearInput, PartialInput};
+use crate::{
+    demo::FuncCall,
+    money_contract::transfer::validate::{CallData, ClearInput, Input, Output},
+};
+
 pub struct Builder {
     pub clear_inputs: Vec<BuilderClearInputInfo>,
     pub inputs: Vec<BuilderInputInfo>,

+ 0 - 265
bin/daod/src/money_contract/transfer/mod.rs

@@ -1,268 +1,3 @@
-use std::{any::Any, io};
-
-use log::error;
-use pasta_curves::group::Group;
-
-use darkfi::{
-    crypto::{
-        burn_proof::verify_burn_proof,
-        keypair::PublicKey,
-        mint_proof::verify_mint_proof,
-        note::EncryptedNote,
-        proof::VerifyingKey,
-        schnorr,
-        schnorr::SchnorrPublic,
-        types::{DrkCircuitField, DrkTokenId, DrkValueBlind, DrkValueCommit},
-        util::{pedersen_commitment_base, pedersen_commitment_u64},
-        BurnRevealedValues, MintRevealedValues, Proof,
-    },
-    util::serial::{Encodable, SerialDecodable, SerialEncodable, VarInt},
-    Result, VerifyFailed, VerifyResult,
-};
-
-use crate::demo::CallDataBase;
-
 pub mod builder;
 pub mod partial;
 pub mod validate;
-
-/// A DarkFi transaction
-#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
-pub struct CallData {
-    /// Clear inputs
-    pub clear_inputs: Vec<ClearInput>,
-    /// Anonymous inputs
-    pub inputs: Vec<Input>,
-    /// Anonymous outputs
-    pub outputs: Vec<Output>,
-}
-
-impl CallDataBase for CallData {
-    fn zk_public_values(&self) -> Vec<Vec<DrkCircuitField>> {
-        let mut public_values = Vec::new();
-        for input in &self.inputs {
-            public_values.push(input.revealed.make_outputs());
-        }
-        for output in &self.outputs {
-            public_values.push(output.revealed.make_outputs());
-        }
-        public_values
-    }
-
-    fn zk_proof_addrs(&self) -> Vec<String> {
-        let mut result = Vec::new();
-        for _ in &self.inputs {
-            result.push("money-transfer-burn".to_string());
-        }
-        for _ in &self.outputs {
-            result.push("money-transfer-mint".to_string());
-        }
-        result
-    }
-
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
-}
-
-/// A transaction's clear input
-#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
-pub struct ClearInput {
-    /// Input's value (amount)
-    pub value: u64,
-    /// Input's token ID
-    pub token_id: DrkTokenId,
-    /// Blinding factor for `value`
-    pub value_blind: DrkValueBlind,
-    /// Blinding factor for `token_id`
-    pub token_blind: DrkValueBlind,
-    /// Public key for the signature
-    pub signature_public: PublicKey,
-    ///  signature
-    pub signature: schnorr::Signature,
-}
-
-/// A transaction's anonymous input
-#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
-pub struct Input {
-    /// Zero-knowledge proof for the input
-    pub burn_proof: Proof,
-    /// Public inputs for the zero-knowledge proof
-    pub revealed: BurnRevealedValues,
-    /// Input's signature
-    pub signature: schnorr::Signature,
-}
-
-/// A transaction's anonymous output
-#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
-pub struct Output {
-    /// Zero-knowledge proof for the output
-    pub mint_proof: Proof,
-    /// Public inputs for the zero-knowledge proof
-    pub revealed: MintRevealedValues,
-    /// The encrypted note
-    pub enc_note: EncryptedNote,
-}
-
-impl CallData {
-    /// Verify the transaction
-    pub fn verify(&self, mint_vk: &VerifyingKey, burn_vk: &VerifyingKey) -> VerifyResult<()> {
-        //  must have minimum 1 clear or anon input, and 1 output
-        if self.clear_inputs.len() + self.inputs.len() == 0 {
-            error!("tx::verify(): Missing inputs");
-            return Err(VerifyFailed::LackingInputs)
-        }
-        if self.outputs.len() == 0 {
-            error!("tx::verify(): Missing outputs");
-            return Err(VerifyFailed::LackingOutputs)
-        }
-
-        // Accumulator for the value commitments
-        let mut valcom_total = DrkValueCommit::identity();
-
-        // Add values from the clear inputs
-        for input in &self.clear_inputs {
-            valcom_total += pedersen_commitment_u64(input.value, input.value_blind);
-        }
-
-        // Add values from the inputs
-        for (i, input) in self.inputs.iter().enumerate() {
-            match verify_burn_proof(burn_vk, &input.burn_proof, &input.revealed) {
-                Ok(()) => valcom_total += &input.revealed.value_commit,
-                Err(e) => {
-                    error!("tx::verify(): Failed to verify burn proof {}: {}", i, e);
-                    return Err(VerifyFailed::BurnProof(i))
-                }
-            }
-        }
-
-        // Subtract values from the outputs
-        for (i, output) in self.outputs.iter().enumerate() {
-            match verify_mint_proof(mint_vk, &output.mint_proof, &output.revealed) {
-                Ok(()) => valcom_total -= &output.revealed.value_commit,
-                Err(e) => {
-                    error!("tx::verify(): Failed to verify mint proof {}: {}", i, e);
-                    return Err(VerifyFailed::MintProof(i))
-                }
-            }
-        }
-
-        // If the accumulator is not back in its initial state,
-        // there's a value mismatch.
-        if valcom_total != DrkValueCommit::identity() {
-            error!("tx::verify(): Missing funds");
-            return Err(VerifyFailed::MissingFunds)
-        }
-
-        // Verify that the token commitments match
-        if !self.verify_token_commitments() {
-            error!("tx::verify(): Token ID mismatch");
-            return Err(VerifyFailed::TokenMismatch)
-        }
-
-        // Verify the available signatures
-        let mut unsigned_tx_data = vec![];
-        self.encode_without_signature(&mut unsigned_tx_data)?;
-
-        for (i, input) in self.clear_inputs.iter().enumerate() {
-            let public = &input.signature_public;
-            if !public.verify(&unsigned_tx_data[..], &input.signature) {
-                error!("tx::verify(): Failed to verify Clear Input signature {}", i);
-                return Err(VerifyFailed::ClearInputSignature(i))
-            }
-        }
-
-        for (i, input) in self.inputs.iter().enumerate() {
-            let public = &input.revealed.signature_public;
-            if !public.verify(&unsigned_tx_data[..], &input.signature) {
-                error!("tx::verify(): Failed to verify Input signature {}", i);
-                return Err(VerifyFailed::InputSignature(i))
-            }
-        }
-
-        Ok(())
-    }
-
-    pub fn encode_without_signature<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        let mut len = 0;
-        len += self.clear_inputs.encode_without_signature(&mut s)?;
-        len += self.inputs.encode_without_signature(&mut s)?;
-        len += self.outputs.encode(s)?;
-        Ok(len)
-    }
-
-    fn verify_token_commitments(&self) -> bool {
-        assert_ne!(self.outputs.len(), 0);
-        let token_commit_value = self.outputs[0].revealed.token_commit;
-
-        let mut failed =
-            self.inputs.iter().any(|input| input.revealed.token_commit != token_commit_value);
-
-        failed = failed ||
-            self.outputs.iter().any(|output| output.revealed.token_commit != token_commit_value);
-
-        failed = failed ||
-            self.clear_inputs.iter().any(|input| {
-                pedersen_commitment_base(input.token_id, input.token_blind) != token_commit_value
-            });
-        !failed
-    }
-}
-
-impl ClearInput {
-    fn from_partial(partial: partial::PartialClearInput, signature: schnorr::Signature) -> Self {
-        Self {
-            value: partial.value,
-            token_id: partial.token_id,
-            value_blind: partial.value_blind,
-            token_blind: partial.token_blind,
-            signature_public: partial.signature_public,
-            signature,
-        }
-    }
-
-    fn encode_without_signature<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        let mut len = 0;
-        len += self.value.encode(&mut s)?;
-        len += self.token_id.encode(&mut s)?;
-        len += self.value_blind.encode(&mut s)?;
-        len += self.token_blind.encode(&mut s)?;
-        len += self.signature_public.encode(s)?;
-        Ok(len)
-    }
-}
-
-impl Input {
-    pub fn from_partial(partial: partial::PartialInput, signature: schnorr::Signature) -> Self {
-        Self { burn_proof: partial.burn_proof, revealed: partial.revealed, signature }
-    }
-
-    fn encode_without_signature<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        let mut len = 0;
-        len += self.burn_proof.encode(&mut s)?;
-        len += self.revealed.encode(&mut s)?;
-        Ok(len)
-    }
-}
-
-trait EncodableWithoutSignature {
-    fn encode_without_signature<S: io::Write>(&self, s: S) -> Result<usize>;
-}
-
-macro_rules! impl_vec_without_signature {
-    ($type: ty) => {
-        impl EncodableWithoutSignature for Vec<$type> {
-            #[inline]
-            fn encode_without_signature<S: io::Write>(&self, mut s: S) -> Result<usize> {
-                let mut len = 0;
-                len += VarInt(self.len() as u64).encode(&mut s)?;
-                for c in self.iter() {
-                    len += c.encode_without_signature(&mut s)?;
-                }
-                Ok(len)
-            }
-        }
-    };
-}
-impl_vec_without_signature!(ClearInput);
-impl_vec_without_signature!(Input);

+ 2 - 1
bin/daod/src/money_contract/transfer/partial.rs

@@ -1,4 +1,3 @@
-use super::Output;
 use darkfi::{
     crypto::{
         keypair::PublicKey,
@@ -8,6 +7,8 @@ use darkfi::{
     util::serial::{SerialDecodable, SerialEncodable},
 };
 
+use crate::money_contract::transfer::validate::Output;
+
 #[derive(Clone, SerialEncodable, SerialDecodable)]
 pub struct Partial {
     pub clear_inputs: Vec<PartialClearInput>,

+ 279 - 4
bin/daod/src/money_contract/transfer/validate.rs

@@ -1,16 +1,40 @@
-use std::any::TypeId;
+use std::{
+    any::{Any, TypeId},
+    io,
+};
 
 use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
 use log::{debug, error};
 
+use pasta_curves::group::Group;
+
 use darkfi::{
-    crypto::{coin::Coin, merkle_node::MerkleNode, note::EncryptedNote, nullifier::Nullifier},
+    crypto::{
+        burn_proof::verify_burn_proof,
+        coin::Coin,
+        keypair::PublicKey,
+        merkle_node::MerkleNode,
+        mint_proof::verify_mint_proof,
+        note::EncryptedNote,
+        nullifier::Nullifier,
+        proof::VerifyingKey,
+        schnorr,
+        schnorr::SchnorrPublic,
+        types::{DrkCircuitField, DrkTokenId, DrkValueBlind, DrkValueCommit},
+        util::{pedersen_commitment_base, pedersen_commitment_u64},
+        BurnRevealedValues, MintRevealedValues, Proof,
+    },
     node::state::ProgramState,
+    util::serial::{Encodable, SerialDecodable, SerialEncodable, VarInt},
+    Error as DarkFiError,
 };
 
 use crate::{
-    demo::{StateRegistry, Transaction},
-    money_contract::{state::State, transfer::CallData},
+    demo::{CallDataBase, StateRegistry, Transaction},
+    money_contract::{
+        state::State,
+        transfer::partial::{PartialClearInput, PartialInput},
+    },
 };
 
 /// A struct representing a state update.
@@ -126,10 +150,253 @@ pub fn state_transition(
     Ok(Update { nullifiers, coins, enc_notes })
 }
 
+/// A DarkFi transaction
+#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
+pub struct CallData {
+    /// Clear inputs
+    pub clear_inputs: Vec<ClearInput>,
+    /// Anonymous inputs
+    pub inputs: Vec<Input>,
+    /// Anonymous outputs
+    pub outputs: Vec<Output>,
+}
+
+impl CallDataBase for CallData {
+    fn zk_public_values(&self) -> Vec<Vec<DrkCircuitField>> {
+        let mut public_values = Vec::new();
+        for input in &self.inputs {
+            public_values.push(input.revealed.make_outputs());
+        }
+        for output in &self.outputs {
+            public_values.push(output.revealed.make_outputs());
+        }
+        public_values
+    }
+
+    fn zk_proof_addrs(&self) -> Vec<String> {
+        let mut result = Vec::new();
+        for _ in &self.inputs {
+            result.push("money-transfer-burn".to_string());
+        }
+        for _ in &self.outputs {
+            result.push("money-transfer-mint".to_string());
+        }
+        result
+    }
+
+    fn as_any(&self) -> &dyn Any {
+        self
+    }
+}
+impl CallData {
+    /// Verify the transaction
+    pub fn verify(&self, mint_vk: &VerifyingKey, burn_vk: &VerifyingKey) -> VerifyResult<()> {
+        //  must have minimum 1 clear or anon input, and 1 output
+        if self.clear_inputs.len() + self.inputs.len() == 0 {
+            error!("tx::verify(): Missing inputs");
+            return Err(VerifyFailed::LackingInputs)
+        }
+        if self.outputs.len() == 0 {
+            error!("tx::verify(): Missing outputs");
+            return Err(VerifyFailed::LackingOutputs)
+        }
+
+        // Accumulator for the value commitments
+        let mut valcom_total = DrkValueCommit::identity();
+
+        // Add values from the clear inputs
+        for input in &self.clear_inputs {
+            valcom_total += pedersen_commitment_u64(input.value, input.value_blind);
+        }
+
+        // Add values from the inputs
+        for (i, input) in self.inputs.iter().enumerate() {
+            match verify_burn_proof(burn_vk, &input.burn_proof, &input.revealed) {
+                Ok(()) => valcom_total += &input.revealed.value_commit,
+                Err(e) => {
+                    error!("tx::verify(): Failed to verify burn proof {}: {}", i, e);
+                    return Err(VerifyFailed::BurnProof(i))
+                }
+            }
+        }
+
+        // Subtract values from the outputs
+        for (i, output) in self.outputs.iter().enumerate() {
+            match verify_mint_proof(mint_vk, &output.mint_proof, &output.revealed) {
+                Ok(()) => valcom_total -= &output.revealed.value_commit,
+                Err(e) => {
+                    error!("tx::verify(): Failed to verify mint proof {}: {}", i, e);
+                    return Err(VerifyFailed::MintProof(i))
+                }
+            }
+        }
+
+        // If the accumulator is not back in its initial state,
+        // there's a value mismatch.
+        if valcom_total != DrkValueCommit::identity() {
+            error!("tx::verify(): Missing funds");
+            return Err(VerifyFailed::MissingFunds)
+        }
+
+        // Verify that the token commitments match
+        if !self.verify_token_commitments() {
+            error!("tx::verify(): Token ID mismatch");
+            return Err(VerifyFailed::TokenMismatch)
+        }
+
+        // Verify the available signatures
+        let mut unsigned_tx_data = vec![];
+        self.encode_without_signature(&mut unsigned_tx_data)?;
+
+        for (i, input) in self.clear_inputs.iter().enumerate() {
+            let public = &input.signature_public;
+            if !public.verify(&unsigned_tx_data[..], &input.signature) {
+                error!("tx::verify(): Failed to verify Clear Input signature {}", i);
+                return Err(VerifyFailed::ClearInputSignature(i))
+            }
+        }
+
+        for (i, input) in self.inputs.iter().enumerate() {
+            let public = &input.revealed.signature_public;
+            if !public.verify(&unsigned_tx_data[..], &input.signature) {
+                error!("tx::verify(): Failed to verify Input signature {}", i);
+                return Err(VerifyFailed::InputSignature(i))
+            }
+        }
+
+        Ok(())
+    }
+
+    pub fn encode_without_signature<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.clear_inputs.encode_without_signature(&mut s)?;
+        len += self.inputs.encode_without_signature(&mut s)?;
+        len += self.outputs.encode(s)?;
+        Ok(len)
+    }
+
+    fn verify_token_commitments(&self) -> bool {
+        assert_ne!(self.outputs.len(), 0);
+        let token_commit_value = self.outputs[0].revealed.token_commit;
+
+        let mut failed =
+            self.inputs.iter().any(|input| input.revealed.token_commit != token_commit_value);
+
+        failed = failed ||
+            self.outputs.iter().any(|output| output.revealed.token_commit != token_commit_value);
+
+        failed = failed ||
+            self.clear_inputs.iter().any(|input| {
+                pedersen_commitment_base(input.token_id, input.token_blind) != token_commit_value
+            });
+        !failed
+    }
+}
+
+/// A transaction's clear input
+#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
+pub struct ClearInput {
+    /// Input's value (amount)
+    pub value: u64,
+    /// Input's token ID
+    pub token_id: DrkTokenId,
+    /// Blinding factor for `value`
+    pub value_blind: DrkValueBlind,
+    /// Blinding factor for `token_id`
+    pub token_blind: DrkValueBlind,
+    /// Public key for the signature
+    pub signature_public: PublicKey,
+    ///  signature
+    pub signature: schnorr::Signature,
+}
+
+/// A transaction's anonymous input
+#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
+pub struct Input {
+    /// Zero-knowledge proof for the input
+    pub burn_proof: Proof,
+    /// Public inputs for the zero-knowledge proof
+    pub revealed: BurnRevealedValues,
+    /// Input's signature
+    pub signature: schnorr::Signature,
+}
+
+/// A transaction's anonymous output
+#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
+pub struct Output {
+    /// Zero-knowledge proof for the output
+    pub mint_proof: Proof,
+    /// Public inputs for the zero-knowledge proof
+    pub revealed: MintRevealedValues,
+    /// The encrypted note
+    pub enc_note: EncryptedNote,
+}
+
+impl ClearInput {
+    pub fn from_partial(partial: PartialClearInput, signature: schnorr::Signature) -> Self {
+        Self {
+            value: partial.value,
+            token_id: partial.token_id,
+            value_blind: partial.value_blind,
+            token_blind: partial.token_blind,
+            signature_public: partial.signature_public,
+            signature,
+        }
+    }
+
+    fn encode_without_signature<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.value.encode(&mut s)?;
+        len += self.token_id.encode(&mut s)?;
+        len += self.value_blind.encode(&mut s)?;
+        len += self.token_blind.encode(&mut s)?;
+        len += self.signature_public.encode(s)?;
+        Ok(len)
+    }
+}
+
+impl Input {
+    pub fn from_partial(partial: PartialInput, signature: schnorr::Signature) -> Self {
+        Self { burn_proof: partial.burn_proof, revealed: partial.revealed, signature }
+    }
+
+    fn encode_without_signature<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.burn_proof.encode(&mut s)?;
+        len += self.revealed.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+trait EncodableWithoutSignature {
+    fn encode_without_signature<S: io::Write>(&self, s: S) -> Result<usize>;
+}
+
+macro_rules! impl_vec_without_signature {
+    ($type: ty) => {
+        impl EncodableWithoutSignature for Vec<$type> {
+            #[inline]
+            fn encode_without_signature<S: io::Write>(&self, mut s: S) -> Result<usize> {
+                let mut len = 0;
+                len += VarInt(self.len() as u64).encode(&mut s)?;
+                for c in self.iter() {
+                    len += c.encode_without_signature(&mut s)?;
+                }
+                Ok(len)
+            }
+        }
+    };
+}
+impl_vec_without_signature!(ClearInput);
+impl_vec_without_signature!(Input);
+
 #[derive(Debug, Clone, thiserror::Error)]
 pub enum Error {
     #[error(transparent)]
     VerifyFailed(#[from] VerifyFailed),
+
+    #[error("DarkFi error: {0}")]
+    DarkFiError(String),
 }
 
 /// Transaction verification errors
@@ -182,3 +449,11 @@ impl From<Error> for VerifyFailed {
         Self::InternalError(err.to_string())
     }
 }
+
+impl From<DarkFiError> for Error {
+    fn from(err: DarkFiError) -> Self {
+        Self::DarkFiError(err.to_string())
+    }
+}
+/// Result type used in transaction verifications
+pub type VerifyResult<T> = std::result::Result<T, VerifyFailed>;