Skip to content

Commit

Permalink
taiga data format and api (#222)
Browse files Browse the repository at this point in the history
* basic taiga data format and layout
* simplified Taiga APIs for external
* add hints to the partial transaction
* add a new partial transaction creation API to support concrete circuit presentation instead of dynamic one.
  • Loading branch information
XuyangSong authored Oct 11, 2023
1 parent e9a4aed commit fe2e920
Show file tree
Hide file tree
Showing 14 changed files with 616 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ pub fn create_transaction<R: RngCore + CryptoRng>(mut rng: R) -> Transaction {
ShieldedPartialTransaction::build(
[input_note_1_proving_info, input_note_2_proving_info],
[output_note_1_proving_info, intent_note_proving_info],
vec![],
&mut rng,
)
};
Expand Down Expand Up @@ -183,12 +184,13 @@ pub fn create_transaction<R: RngCore + CryptoRng>(mut rng: R) -> Transaction {
ShieldedPartialTransaction::build(
[intent_note_proving_info, input_note_3_proving_info],
[output_note_2_proving_info, output_note_3_proving_info],
vec![],
&mut rng,
)
};

// Create the final transaction
let shielded_tx_bundle = ShieldedPartialTxBundle::build(vec![ptx_1, ptx_2]);
let shielded_tx_bundle = ShieldedPartialTxBundle::new(vec![ptx_1, ptx_2]);
let transparent_ptx_bundle = TransparentPartialTxBundle::default();
Transaction::build(&mut rng, shielded_tx_bundle, transparent_ptx_bundle)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ pub fn create_token_intent_ptx<R: RngCore>(
let ptx = ShieldedPartialTransaction::build(
[input_note_proving_info, padding_input_note_proving_info],
[intent_note_proving_info, padding_output_note_proving_info],
vec![],
&mut rng,
);

Expand Down Expand Up @@ -243,6 +244,7 @@ pub fn consume_token_intent_ptx<R: RngCore>(
ShieldedPartialTransaction::build(
[intent_note_proving_info, padding_input_note_proving_info],
[bought_note_proving_info, returned_note_proving_info],
vec![],
&mut rng,
)
}
Expand Down Expand Up @@ -298,7 +300,7 @@ pub fn create_token_swap_transaction<R: RngCore + CryptoRng>(mut rng: R) -> Tran
);

// Solver creates the final transaction
let shielded_tx_bundle = ShieldedPartialTxBundle::build(vec![alice_ptx, bob_ptx, solver_ptx]);
let shielded_tx_bundle = ShieldedPartialTxBundle::new(vec![alice_ptx, bob_ptx, solver_ptx]);
let transparent_ptx_bundle = TransparentPartialTxBundle::default();
Transaction::build(&mut rng, shielded_tx_bundle, transparent_ptx_bundle)
}
Expand Down
1 change: 1 addition & 0 deletions taiga_halo2/examples/tx_examples/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ pub fn create_token_swap_ptx<R: RngCore>(
ShieldedPartialTransaction::build(
[input_note_proving_info, padding_input_note_proving_info],
[output_note_proving_info, padding_output_note_proving_info],
vec![],
&mut rng,
)
}
4 changes: 3 additions & 1 deletion taiga_halo2/examples/tx_examples/token_swap_with_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ pub fn create_token_intent_ptx<R: RngCore>(
let ptx = ShieldedPartialTransaction::build(
[input_note_proving_info, padding_input_note_proving_info],
[intent_note_proving_info, padding_output_note_proving_info],
vec![],
&mut rng,
);

Expand Down Expand Up @@ -239,6 +240,7 @@ pub fn consume_token_intent_ptx<R: RngCore>(
ShieldedPartialTransaction::build(
[intent_note_proving_info, padding_input_note_proving_info],
[output_note_proving_info, padding_output_note_proving_info],
vec![],
&mut rng,
)
}
Expand Down Expand Up @@ -302,7 +304,7 @@ pub fn create_token_swap_intent_transaction<R: RngCore + CryptoRng>(mut rng: R)
);

// Solver creates the final transaction
let shielded_tx_bundle = ShieldedPartialTxBundle::build(vec![alice_ptx, bob_ptx, solver_ptx]);
let shielded_tx_bundle = ShieldedPartialTxBundle::new(vec![alice_ptx, bob_ptx, solver_ptx]);
let transparent_ptx_bundle = TransparentPartialTxBundle::default();
Transaction::build(&mut rng, shielded_tx_bundle, transparent_ptx_bundle)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub fn create_token_swap_transaction<R: RngCore + CryptoRng>(mut rng: R) -> Tran
);

// Solver creates the final transaction
let shielded_tx_bundle = ShieldedPartialTxBundle::build(vec![alice_ptx, bob_ptx, carol_ptx]);
let shielded_tx_bundle = ShieldedPartialTxBundle::new(vec![alice_ptx, bob_ptx, carol_ptx]);
let transparent_ptx_bundle = TransparentPartialTxBundle::default();
Transaction::build(&mut rng, shielded_tx_bundle, transparent_ptx_bundle)
}
Expand Down
2 changes: 2 additions & 0 deletions taiga_halo2/src/circuit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ pub mod curve;
pub mod hash_to_curve;
pub mod note_encryption_circuit;
mod vamp_ir_utils;
#[cfg(feature = "borsh")]
pub mod vp_bytecode;
pub mod vp_examples;
84 changes: 84 additions & 0 deletions taiga_halo2/src/circuit/vp_bytecode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use crate::circuit::{
vp_circuit::{VPVerifyingInfo, ValidityPredicateVerifyingInfo, VampIRValidityPredicateCircuit},
vp_examples::TrivialValidityPredicateCircuit,
};
use crate::shielded_ptx::NoteVPVerifyingInfoSet;
use borsh::{BorshDeserialize, BorshSerialize};
#[cfg(feature = "serde")]
use serde;
use std::path::PathBuf;

#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ValidityPredicateRepresentation {
// vampir has a unified circuit representation.
VampIR(Vec<u8>),
// Native halo2 circuits don't have a unified representatioin, enumerate the vp circuit examples for the moment.
// TODO: figure out if we can have a unified circuit presentation. In theory, it's possible to separate the circuit system and proving system.
Trivial,
// TODO: add other vp types here if needed
}

#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ValidityPredicateByteCode {
circuit: ValidityPredicateRepresentation,
inputs: Vec<u8>,
}

#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ApplicationByteCode {
app_vp_bytecode: ValidityPredicateByteCode,
dynamic_vp_bytecode: Vec<ValidityPredicateByteCode>,
}

impl ValidityPredicateByteCode {
pub fn new(circuit: ValidityPredicateRepresentation, inputs: Vec<u8>) -> Self {
Self { circuit, inputs }
}

pub fn generate_proof(self) -> VPVerifyingInfo {
match self.circuit {
ValidityPredicateRepresentation::VampIR(circuit) => {
// TDDO: use the file_name api atm,
// request vamp_ir to provide a api to generate circuit from bytes.
let vamp_ir_circuit_file =
PathBuf::from(String::from_utf8_lossy(&circuit).to_string());
let inputs_file = PathBuf::from(String::from_utf8_lossy(&self.inputs).to_string());
let vp_circuit = VampIRValidityPredicateCircuit::from_vamp_ir_file(
&vamp_ir_circuit_file,
&inputs_file,
);
vp_circuit.get_verifying_info()
}
ValidityPredicateRepresentation::Trivial => {
let vp = TrivialValidityPredicateCircuit::from_bytes(self.inputs);
vp.get_verifying_info()
}
}
}
}

impl ApplicationByteCode {
pub fn new(
app_vp_bytecode: ValidityPredicateByteCode,
dynamic_vp_bytecode: Vec<ValidityPredicateByteCode>,
) -> Self {
Self {
app_vp_bytecode,
dynamic_vp_bytecode,
}
}

pub fn generate_proofs(self) -> NoteVPVerifyingInfoSet {
let app_vp_verifying_info = self.app_vp_bytecode.generate_proof();

let app_dynamic_vp_verifying_info = self
.dynamic_vp_bytecode
.into_iter()
.map(|bytecode| bytecode.generate_proof())
.collect();
NoteVPVerifyingInfoSet::new(app_vp_verifying_info, app_dynamic_vp_verifying_info)
}
}
64 changes: 64 additions & 0 deletions taiga_halo2/src/circuit/vp_examples.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[cfg(feature = "borsh")]
use crate::circuit::vp_bytecode::{ValidityPredicateByteCode, ValidityPredicateRepresentation};
use crate::{
circuit::vp_circuit::{
VPVerifyingInfo, ValidityPredicateCircuit, ValidityPredicateConfig,
Expand All @@ -9,6 +11,8 @@ use crate::{
vp_commitment::ValidityPredicateCommitment,
vp_vk::ValidityPredicateVerifyingKey,
};
#[cfg(feature = "borsh")]
use borsh::{BorshDeserialize, BorshSerialize};
use halo2_proofs::plonk::{keygen_pk, keygen_vk, ProvingKey};
use halo2_proofs::{
circuit::{floor_planner, Layouter},
Expand Down Expand Up @@ -82,6 +86,24 @@ impl TrivialValidityPredicateCircuit {
}
}

// Only for test
#[cfg(feature = "borsh")]
pub fn to_bytecode(&self) -> ValidityPredicateByteCode {
ValidityPredicateByteCode::new(ValidityPredicateRepresentation::Trivial, self.to_bytes())
}

// Only for test
#[cfg(feature = "borsh")]
pub fn to_bytes(&self) -> Vec<u8> {
borsh::to_vec(&self).unwrap()
}

// Only for test
#[cfg(feature = "borsh")]
pub fn from_bytes(bytes: Vec<u8>) -> Self {
BorshDeserialize::deserialize(&mut bytes.as_ref()).unwrap()
}

fn to_proxy(&self) -> TrivialValidtyPredicateCircuitProxy {
TrivialValidtyPredicateCircuitProxy {
owned_note_pub_id: self.owned_note_pub_id,
Expand All @@ -91,6 +113,48 @@ impl TrivialValidityPredicateCircuit {
}
}

#[cfg(feature = "borsh")]
impl BorshSerialize for TrivialValidityPredicateCircuit {
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
use ff::PrimeField;
writer.write_all(&self.owned_note_pub_id.to_repr())?;
for input in self.input_notes.iter() {
input.serialize(writer)?;
}

for output in self.output_notes.iter() {
output.serialize(writer)?;
}
Ok(())
}
}

#[cfg(feature = "borsh")]
impl BorshDeserialize for TrivialValidityPredicateCircuit {
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
use ff::PrimeField;
let owned_note_pub_id_bytes = <[u8; 32]>::deserialize_reader(reader)?;
let owned_note_pub_id = Option::from(pallas::Base::from_repr(owned_note_pub_id_bytes))
.ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
"owned_note_pub_id not in field",
)
})?;
let input_notes: Vec<_> = (0..NUM_NOTE)
.map(|_| Note::deserialize_reader(reader))
.collect::<Result<_, _>>()?;
let output_notes: Vec<_> = (0..NUM_NOTE)
.map(|_| Note::deserialize_reader(reader))
.collect::<Result<_, _>>()?;
Ok(Self {
owned_note_pub_id,
input_notes: input_notes.try_into().unwrap(),
output_notes: output_notes.try_into().unwrap(),
})
}
}

impl TrivialValidtyPredicateCircuitProxy {
fn to_concrete(&self) -> Option<TrivialValidityPredicateCircuit> {
let input_notes = self.input_notes.clone().try_into().ok()?;
Expand Down
9 changes: 9 additions & 0 deletions taiga_halo2/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ pub enum TransactionError {
InconsistentOutputNoteCommitment,
/// Owned note public id is not consistent between the action and the vp.
InconsistentOwnedNotePubID,
/// IO error
IoError(std::io::Error),
}

impl Display for TransactionError {
Expand All @@ -34,6 +36,7 @@ impl Display for TransactionError {
InconsistentOwnedNotePubID => {
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}")),
}
}
}
Expand All @@ -43,3 +46,9 @@ impl From<PlonkError> for TransactionError {
TransactionError::Proof(e)
}
}

impl From<std::io::Error> for TransactionError {
fn from(e: std::io::Error) -> Self {
TransactionError::IoError(e)
}
}
1 change: 1 addition & 0 deletions taiga_halo2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod note_encryption;
pub mod nullifier;
pub mod proof;
pub mod shielded_ptx;
pub mod taiga_api;
pub mod transaction;
pub mod transparent_ptx;
pub mod utils;
Expand Down
20 changes: 20 additions & 0 deletions taiga_halo2/src/merkle_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,26 @@ impl Hash for Anchor {
}
}

#[cfg(feature = "borsh")]
impl BorshSerialize for Anchor {
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_all(&self.0.to_repr())?;
Ok(())
}
}

#[cfg(feature = "borsh")]
impl BorshDeserialize for Anchor {
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
let mut repr = [0u8; 32];
reader.read_exact(&mut repr)?;
let value = Option::from(pallas::Base::from_repr(repr)).ok_or_else(|| {
std::io::Error::new(std::io::ErrorKind::InvalidData, "Anchor not in field")
})?;
Ok(Self(value))
}
}

#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Default)]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand Down
Loading

0 comments on commit fe2e920

Please sign in to comment.