Skip to content

Commit

Permalink
transparent ptx (#230)
Browse files Browse the repository at this point in the history
  • Loading branch information
XuyangSong authored Oct 24, 2023
1 parent df9410c commit 9801cdb
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 91 deletions.
10 changes: 10 additions & 0 deletions taiga_halo2/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ pub enum TransactionError {
InconsistentOwnedNotePubID,
/// IO error
IoError(std::io::Error),
/// Transparent resource nullifier key is missing
MissingTransparentResourceNullifierKey,
/// Transparent resource merkle path is missing
MissingTransparentResourceMerklePath,
}

impl Display for TransactionError {
Expand All @@ -37,6 +41,12 @@ impl Display for TransactionError {
f.write_str("Owned note public id is not consistent between the action and the vp")
}
IoError(e) => f.write_str(&format!("IoError error: {e}")),
MissingTransparentResourceNullifierKey => {
f.write_str("Transparent resource nullifier key is missing")
}
MissingTransparentResourceMerklePath => {
f.write_str("Transparent resource merkle path is missing")
}
}
}
}
Expand Down
14 changes: 4 additions & 10 deletions taiga_halo2/src/taiga_api.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
#[cfg(feature = "borsh")]
use crate::{
action::ActionInfo,
circuit::vp_bytecode::ApplicationByteCode,
error::TransactionError,
transaction::{ShieldedResult, TransparentResult},
action::ActionInfo, circuit::vp_bytecode::ApplicationByteCode, error::TransactionError,
transaction::TransactionResult,
};
use crate::{
note::{Note, RandomSeed},
Expand Down Expand Up @@ -203,7 +201,7 @@ pub fn create_transaction(

/// Verify a transaction and return the results
///
/// ShieldedResult layout:
/// TransactionResult layout:
/// | Parameters | type | size(bytes)|
/// | - | - | - |
/// | anchor num | u32 | 4 |
Expand All @@ -213,12 +211,8 @@ pub fn create_transaction(
/// | output cm num | u32 | 4 |
/// | output cms | pallas::Base | 32 * num |
///
/// Note: TransparentResult is empty
///
#[cfg(feature = "borsh")]
pub fn verify_transaction(
tx_bytes: Vec<u8>,
) -> Result<(ShieldedResult, TransparentResult), TransactionError> {
pub fn verify_transaction(tx_bytes: Vec<u8>) -> Result<TransactionResult, TransactionError> {
// Decode the tx
let tx = transaction_deserialize(tx_bytes)?;

Expand Down
99 changes: 49 additions & 50 deletions taiga_halo2/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::merkle_tree::Anchor;
use crate::note::NoteCommitment;
use crate::nullifier::Nullifier;
use crate::shielded_ptx::ShieldedPartialTransaction;
use crate::transparent_ptx::{OutputResource, TransparentPartialTransaction};
use crate::transparent_ptx::TransparentPartialTransaction;
use crate::value_commitment::ValueCommitment;
use blake2b_simd::Params as Blake2bParams;
use pasta_curves::{group::Group, pallas};
Expand All @@ -32,35 +32,28 @@ pub struct Transaction {
signature: BindingSignature,
}

#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "nif", derive(NifRecord))]
#[cfg_attr(feature = "nif", tag = "bundle")]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ShieldedPartialTxBundle(Vec<ShieldedPartialTransaction>);

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "nif", derive(NifStruct))]
#[cfg_attr(feature = "nif", module = "Taiga.Transaction.Result")]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ShieldedResult {
pub struct TransactionResult {
pub anchors: Vec<Anchor>,
pub nullifiers: Vec<Nullifier>,
pub output_cms: Vec<NoteCommitment>,
}

#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "nif", derive(NifRecord))]
#[cfg_attr(feature = "nif", tag = "bundle")]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TransparentPartialTxBundle(Vec<TransparentPartialTransaction>);
pub struct ShieldedPartialTxBundle(Vec<ShieldedPartialTransaction>);

// TODO: add other outputs if needed.
#[derive(Debug, Clone)]
pub struct TransparentResult {
pub nullifiers: Vec<Nullifier>,
pub outputs: Vec<OutputResource>,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TransparentPartialTxBundle(Vec<TransparentPartialTransaction>);

impl Transaction {
// Generate the transaction
Expand All @@ -71,8 +64,7 @@ impl Transaction {
) -> Self {
assert!(!(shielded_ptx_bundle.is_empty() && transparent_ptx_bundle.is_empty()));
let shielded_sk = shielded_ptx_bundle.get_bindig_sig_r();
let transparent_sk = transparent_ptx_bundle.get_bindig_sig_r();
let binding_sk = BindingSigningKey::from(shielded_sk + transparent_sk);
let binding_sk = BindingSigningKey::from(shielded_sk);
let sig_hash = Self::digest(&shielded_ptx_bundle, &transparent_ptx_bundle);
let signature = binding_sk.sign(rng, &sig_hash);

Expand All @@ -84,14 +76,15 @@ impl Transaction {
}

#[allow(clippy::type_complexity)]
pub fn execute(&self) -> Result<(ShieldedResult, TransparentResult), TransactionError> {
let shielded_result = self.shielded_ptx_bundle.execute()?;
let transparent_result = self.transparent_ptx_bundle.execute()?;
pub fn execute(&self) -> Result<TransactionResult, TransactionError> {
let mut result = self.shielded_ptx_bundle.execute()?;
let mut transparent_result = self.transparent_ptx_bundle.execute()?;
result.append(&mut transparent_result);

// check balance
self.verify_binding_sig()?;

Ok((shielded_result, transparent_result))
Ok(result)
}

fn verify_binding_sig(&self) -> Result<(), TransactionError> {
Expand Down Expand Up @@ -210,6 +203,14 @@ impl<'a> Decoder<'a> for Transaction {
}
}

impl TransactionResult {
pub fn append(&mut self, result: &mut TransactionResult) {
self.anchors.append(&mut result.anchors);
self.nullifiers.append(&mut result.nullifiers);
self.output_cms.append(&mut result.output_cms);
}
}

impl ShieldedPartialTxBundle {
pub fn is_empty(&self) -> bool {
self.0.is_empty()
Expand All @@ -230,13 +231,13 @@ impl ShieldedPartialTxBundle {
}

#[allow(clippy::type_complexity)]
pub fn execute(&self) -> Result<ShieldedResult, TransactionError> {
pub fn execute(&self) -> Result<TransactionResult, TransactionError> {
for partial_tx in self.0.iter() {
partial_tx.execute()?;
}

// Return Nullifiers to check double-spent, NoteCommitments to store, anchors to check the root-existence
Ok(ShieldedResult {
Ok(TransactionResult {
nullifiers: self.get_nullifiers(),
output_cms: self.get_output_cms(),
anchors: self.get_anchors(),
Expand All @@ -261,15 +262,6 @@ impl ShieldedPartialTxBundle {
pub fn get_anchors(&self) -> Vec<Anchor> {
self.0.iter().flat_map(|ptx| ptx.get_anchors()).collect()
}

fn get_binding_vk(&self) -> BindingVerificationKey {
let vk = self
.get_value_commitments()
.iter()
.fold(pallas::Point::identity(), |acc, cv| acc + cv.inner());

BindingVerificationKey::from(vk)
}
}

impl TransparentPartialTxBundle {
Expand All @@ -285,20 +277,23 @@ impl TransparentPartialTxBundle {
self.0.push(ptx);
}

pub fn execute(&self) -> Result<TransparentResult, TransactionError> {
pub fn execute(&self) -> Result<TransactionResult, TransactionError> {
for partial_tx in self.0.iter() {
partial_tx.execute()?;
}

Ok(TransparentResult {
nullifiers: vec![],
outputs: vec![],
Ok(TransactionResult {
nullifiers: self.get_nullifiers(),
output_cms: self.get_output_cms(),
anchors: self.get_anchors(),
})
}

pub fn get_value_commitments(&self) -> Vec<ValueCommitment> {
// TODO: add the real value commitments
vec![]
self.0
.iter()
.flat_map(|ptx| ptx.get_value_commitments())
.collect()
}

pub fn get_nullifiers(&self) -> Vec<Nullifier> {
Expand All @@ -312,17 +307,13 @@ impl TransparentPartialTxBundle {
pub fn get_anchors(&self) -> Vec<Anchor> {
self.0.iter().flat_map(|ptx| ptx.get_anchors()).collect()
}

pub fn get_bindig_sig_r(&self) -> pallas::Scalar {
// TODO: add the real r
pallas::Scalar::zero()
}
}

#[cfg(test)]
pub mod testing {
use crate::shielded_ptx::testing::create_shielded_ptx;
use crate::transaction::ShieldedPartialTxBundle;
use crate::transaction::{ShieldedPartialTxBundle, TransparentPartialTxBundle};
use crate::transparent_ptx::testing::create_transparent_ptx;

pub fn create_shielded_ptx_bundle(num: usize) -> ShieldedPartialTxBundle {
let mut bundle = vec![];
Expand All @@ -333,6 +324,15 @@ pub mod testing {
ShieldedPartialTxBundle::new(bundle)
}

pub fn create_transparent_ptx_bundle(num: usize) -> TransparentPartialTxBundle {
let mut bundle = vec![];
for _ in 0..num {
let ptx = create_transparent_ptx();
bundle.push(ptx);
}
TransparentPartialTxBundle::new(bundle)
}

#[test]
fn test_halo2_transaction() {
use super::*;
Expand All @@ -341,17 +341,16 @@ pub mod testing {
let rng = OsRng;

let shielded_ptx_bundle = create_shielded_ptx_bundle(1);
// TODO: add transparent_ptx_bundle test
let transparent_ptx_bundle = TransparentPartialTxBundle::default();
let transparent_ptx_bundle = create_transparent_ptx_bundle(1);
let tx = Transaction::build(rng, shielded_ptx_bundle, transparent_ptx_bundle);
let (_shielded_ret, _) = tx.execute().unwrap();
let _ret = tx.execute().unwrap();

#[cfg(feature = "borsh")]
{
let borsh = borsh::to_vec(&tx).unwrap();
let de_tx: Transaction = BorshDeserialize::deserialize(&mut borsh.as_ref()).unwrap();
let (de_shielded_ret, _) = de_tx.execute().unwrap();
assert_eq!(_shielded_ret, de_shielded_ret);
let de_ret = de_tx.execute().unwrap();
assert_eq!(_ret, de_ret);
}
}
}
Loading

0 comments on commit 9801cdb

Please sign in to comment.