Skip to content

Commit

Permalink
Merge branch 'murisi/namada-integration'
Browse files Browse the repository at this point in the history
  • Loading branch information
Murisi Tarusenga committed May 25, 2023
2 parents d331c4e + cfea8c9 commit 0d7dc07
Show file tree
Hide file tree
Showing 17 changed files with 391 additions and 102 deletions.
3 changes: 0 additions & 3 deletions masp_primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@ lazy_static = "1"
# - Test dependencies
proptest = { version = "1.0.0", optional = true }

# - Transparent inputs
secp256k1 = { version = "0.24.1", features = [ "rand" ] }

# - ZIP 339
bip0039 = { version = "0.9", features = ["std", "all-languages"] }

Expand Down
3 changes: 2 additions & 1 deletion masp_primitives/src/consensus.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Consensus logic and parameters.

use borsh::{BorshDeserialize, BorshSerialize};
use memuse::DynamicUsage;
use std::cmp::{Ord, Ordering};
use std::convert::TryFrom;
Expand All @@ -9,7 +10,7 @@ use std::ops::{Add, Bound, RangeBounds, Sub};
/// A wrapper type representing blockchain heights. Safe conversion from
/// various integer types, as well as addition and subtraction, are provided.
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, BorshSerialize, BorshDeserialize)]
pub struct BlockHeight(u32);

memuse::impl_no_dynamic_usage!(BlockHeight);
Expand Down
5 changes: 5 additions & 0 deletions masp_primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,10 @@ pub mod sapling;
pub mod transaction;
pub mod zip32;

pub use bls12_381;
pub use ff;
pub use group;
pub use jubjub;

#[cfg(test)]
mod test_vectors;
8 changes: 4 additions & 4 deletions masp_primitives/src/merkle_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,10 @@ impl<Node: Hashable> BorshDeserialize for MerklePath<Node> {
// Begin to construct the authentication path
// Do not use any data in the witness after the expected depth
let iter = witness[..33 * depth + 8].chunks_exact(33);
*witness = iter.remainder();
// Update the witness to its final position
*witness = &witness[33 * depth + 8..];
// Read the position from the witness
let position = iter.remainder().read_u64::<LittleEndian>()?;

// The vector works in reverse
let mut auth_path = iter
Expand All @@ -798,9 +801,6 @@ impl<Node: Hashable> BorshDeserialize for MerklePath<Node> {
return Err(std::io::Error::from(std::io::ErrorKind::InvalidData));
}

// Read the position from the witness
let position = witness.read_u64::<LittleEndian>()?;

// Given the position, let's finish constructing the authentication
// path
let mut tmp = position;
Expand Down
9 changes: 5 additions & 4 deletions masp_primitives/src/sapling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ pub struct Node {
}

impl Node {
#[cfg(test)]
pub(crate) fn new(repr: [u8; 32]) -> Self {
pub fn new(repr: [u8; 32]) -> Self {
Node { repr }
}

Expand Down Expand Up @@ -506,7 +505,9 @@ pub enum Rseed {
}

/// Typesafe wrapper for nullifier values.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(
Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, BorshSerialize, BorshDeserialize,
)]
pub struct Nullifier(pub [u8; 32]);

impl Nullifier {
Expand Down Expand Up @@ -551,7 +552,7 @@ impl From<NoteValue> for u64 {
}
}

#[derive(Clone, Debug)]
#[derive(Clone, Debug, Copy)]
pub struct Note {
/// The asset type that the note represents
pub asset_type: AssetType,
Expand Down
3 changes: 2 additions & 1 deletion masp_primitives/src/sapling/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
constants::{PROOF_GENERATION_KEY_GENERATOR, SPENDING_KEY_GENERATOR},
keys::prf_expand,
};
use borsh::{BorshDeserialize, BorshSerialize};
use ff::PrimeField;
use group::{Group, GroupEncoding};
use std::{
Expand All @@ -31,7 +32,7 @@ pub enum DecodingError {
}

/// An outgoing viewing key
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, BorshSerialize, BorshDeserialize)]
pub struct OutgoingViewingKey(pub [u8; 32]);

/// A Sapling expanded spending key
Expand Down
36 changes: 32 additions & 4 deletions masp_primitives/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use blake2b_simd::Hash as Blake2bHash;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use ff::PrimeField;
use memuse::DynamicUsage;
pub use secp256k1::PublicKey as TransparentAddress;
use std::{
fmt::{self, Debug},
hash::Hash,
Expand All @@ -35,6 +34,9 @@ use self::{
txid::{to_txid, BlockTxCommitmentDigester, TxIdDigester},
};

#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)]
pub struct TransparentAddress(pub [u8; 20]);

pub const GROTH_PROOF_SIZE: usize = 48 + 96 + 48;
pub type GrothProofBytes = [u8; GROTH_PROOF_SIZE];

Expand Down Expand Up @@ -147,7 +149,7 @@ pub trait Authorization {
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Unproven;
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Authorized;

impl Authorization for Authorized {
Expand All @@ -163,7 +165,7 @@ impl Authorization for Unauthorized {
}

/// A MASP transaction.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Transaction {
txid: TxId,
data: TransactionData<Authorized>,
Expand All @@ -183,7 +185,7 @@ impl PartialEq for Transaction {
}
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
pub struct TransactionData<A: Authorization> {
version: TxVersion,
consensus_branch_id: BranchId,
Expand Down Expand Up @@ -280,6 +282,32 @@ impl TransactionData<Authorized> {
}
}

impl BorshSerialize for Transaction {
fn serialize<W: Write>(&self, writer: &mut W) -> borsh::maybestd::io::Result<()> {
self.write(writer)
}
}

impl BorshDeserialize for Transaction {
fn deserialize(buf: &mut &[u8]) -> borsh::maybestd::io::Result<Self> {
Self::read(buf, BranchId::MASP)
}
}

impl borsh::BorshSchema for Transaction {
fn add_definitions_recursively(
_definitions: &mut std::collections::HashMap<
borsh::schema::Declaration,
borsh::schema::Definition,
>,
) {
}

fn declaration() -> borsh::schema::Declaration {
"Transaction".into()
}
}

impl Transaction {
fn from_data(data: TransactionData<Authorized>) -> io::Result<Self> {
match data.version {
Expand Down
86 changes: 65 additions & 21 deletions masp_primitives/src/transaction/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ use std::error;
use std::fmt;
use std::sync::mpsc::Sender;

use secp256k1::PublicKey as TransparentAddress;
use borsh::{BorshDeserialize, BorshSerialize};

use rand::{rngs::OsRng, CryptoRng, RngCore};

use crate::{
asset_type::AssetType,
consensus::{self, BlockHeight, BranchId},
convert::AllowedConversion,
keys::OutgoingViewingKey,
memo::MemoBytes,
merkle_tree::MerklePath,
Expand All @@ -28,7 +29,7 @@ use crate::{
fees::FeeRule,
sighash::{signature_hash, SignableInput},
txid::TxIdDigester,
Transaction, TransactionData, TxVersion, Unauthorized,
Transaction, TransactionData, TransparentAddress, TxVersion, Unauthorized,
},
zip32::ExtendedSpendingKey,
};
Expand Down Expand Up @@ -115,17 +116,19 @@ impl Progress {
}

/// Generates a [`Transaction`] from its inputs and outputs.
pub struct Builder<P, R> {
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)]
pub struct Builder<P, R, Key = ExtendedSpendingKey, Notifier = Sender<Progress>> {
params: P,
rng: R,
target_height: BlockHeight,
expiry_height: BlockHeight,
transparent_builder: TransparentBuilder,
sapling_builder: SaplingBuilder<P>,
progress_notifier: Option<Sender<Progress>>,
sapling_builder: SaplingBuilder<P, Key>,
#[borsh_skip]
progress_notifier: Option<Notifier>,
}

impl<P, R> Builder<P, R> {
impl<P, R, K, N> Builder<P, R, K, N> {
/// Returns the network parameters that the builder has been configured for.
pub fn params(&self) -> &P {
&self.params
Expand All @@ -150,7 +153,7 @@ impl<P, R> Builder<P, R> {

/// Returns the set of Sapling inputs currently committed to be consumed
/// by the transaction.
pub fn sapling_inputs(&self) -> &[impl sapling::fees::InputView<()>] {
pub fn sapling_inputs(&self) -> &[impl sapling::fees::InputView<(), K>] {
self.sapling_builder.inputs()
}

Expand All @@ -159,6 +162,12 @@ impl<P, R> Builder<P, R> {
pub fn sapling_outputs(&self) -> &[impl sapling::fees::OutputView] {
self.sapling_builder.outputs()
}

/// Returns the set of Sapling converts currently set to be produced by
/// the transaction.
pub fn sapling_converts(&self) -> &[impl sapling::fees::ConvertView] {
self.sapling_builder.converts()
}
}

impl<P: consensus::Parameters> Builder<P, OsRng> {
Expand Down Expand Up @@ -219,6 +228,20 @@ impl<P: consensus::Parameters, R: RngCore> Builder<P, R> {
.add_spend(&mut self.rng, extsk, diversifier, note, merkle_path)
}

/// Adds a Sapling note to be spent in this transaction.
///
/// Returns an error if the given Merkle path does not have the same anchor as the
/// paths for previous Sapling notes.
pub fn add_sapling_convert(
&mut self,
allowed: AllowedConversion,
value: u64,
merkle_path: MerklePath<Node>,
) -> Result<(), sapling::builder::Error> {
self.sapling_builder
.add_convert(allowed, value, merkle_path)
}

/// Adds a Sapling address to send funds to.
pub fn add_sapling_output(
&mut self,
Expand Down Expand Up @@ -270,7 +293,7 @@ impl<P: consensus::Parameters, R: RngCore> Builder<P, R> {
}

/// Returns the sum of the transparent, Sapling, and TZE value balances.
fn value_balance(&self) -> Result<Amount, BalanceError> {
pub fn value_balance(&self) -> Result<Amount, BalanceError> {
let value_balances = [
self.transparent_builder.value_balance()?,
self.sapling_builder.value_balance(),
Expand Down Expand Up @@ -388,6 +411,30 @@ impl<P: consensus::Parameters, R: RngCore> Builder<P, R> {
}
}

pub trait MapBuilder<P1, R1, K1, N1, P2, R2, K2, N2>:
sapling::builder::MapBuilder<P1, K1, P2, K2>
{
fn map_rng(&self, s: R1) -> R2;
fn map_notifier(&self, s: N1) -> N2;
}

impl<P1, R1, K1, N1> Builder<P1, R1, K1, N1> {
pub fn map_builder<P2, R2, K2, N2, F: MapBuilder<P1, R1, K1, N1, P2, R2, K2, N2>>(
self,
f: F,
) -> Builder<P2, R2, K2, N2> {
Builder::<P2, R2, K2, N2> {
params: f.map_params(self.params),
rng: f.map_rng(self.rng),
target_height: self.target_height,
expiry_height: self.expiry_height,
transparent_builder: self.transparent_builder,
progress_notifier: self.progress_notifier.map(|x| f.map_notifier(x)),
sapling_builder: self.sapling_builder.map_builder(f),
}
}
}

#[cfg(any(test, feature = "test-dependencies"))]
mod testing {
use rand::RngCore;
Expand Down Expand Up @@ -423,8 +470,8 @@ mod testing {
#[cfg(test)]
mod tests {
use ff::Field;
use rand::Rng;
use rand_core::OsRng;
use secp256k1::Secp256k1;

use crate::{
asset_type::AssetType,
Expand All @@ -436,6 +483,7 @@ mod tests {
components::amount::{Amount, DEFAULT_FEE, MAX_MONEY},
sapling::builder::{self as build_s},
transparent::builder::{self as build_t},
TransparentAddress,
},
zip32::ExtendedSpendingKey,
};
Expand Down Expand Up @@ -473,7 +521,9 @@ mod tests {

#[test]
fn binding_sig_present_if_shielded_spend() {
let (_, transparent_address) = Secp256k1::new().generate_keypair(&mut OsRng);
let mut rng = OsRng;

let transparent_address = TransparentAddress(rng.gen::<[u8; 20]>());

let extsk = ExtendedSpendingKey::master(&[]);
let dfvk = extsk.to_diversifiable_full_viewing_key();
Expand Down Expand Up @@ -517,10 +567,9 @@ mod tests {

#[test]
fn fails_on_negative_transparent_output() {
let secret_key =
secp256k1::SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order");
let transparent_address =
secp256k1::PublicKey::from_secret_key(&secp256k1::Secp256k1::new(), &secret_key);
let mut rng = OsRng;

let transparent_address = TransparentAddress(rng.gen::<[u8; 20]>());
let tx_height = TEST_NETWORK
.activation_height(NetworkUpgrade::MASP)
.unwrap();
Expand All @@ -535,7 +584,7 @@ mod tests {
fn fails_on_negative_change() {
let mut rng = OsRng;

let (_, transparent_address) = Secp256k1::new().generate_keypair(&mut OsRng);
let transparent_address = TransparentAddress(rng.gen::<[u8; 20]>());
// Just use the master key as the ExtendedSpendingKey for this test
let extsk = ExtendedSpendingKey::master(&[]);
let tx_height = TEST_NETWORK
Expand Down Expand Up @@ -603,12 +652,7 @@ mod tests {
{
let mut builder = Builder::new(TEST_NETWORK, tx_height);
builder
.add_sapling_spend(
extsk,
*to.diversifier(),
note1.clone(),
witness1.path().unwrap(),
)
.add_sapling_spend(extsk, *to.diversifier(), note1, witness1.path().unwrap())
.unwrap();
builder
.add_sapling_output(ovk, to, zec(), 30000, MemoBytes::empty())
Expand Down
2 changes: 1 addition & 1 deletion masp_primitives/src/transaction/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub mod sapling;
pub mod transparent;
pub use self::{
amount::Amount,
sapling::{OutputDescription, SpendDescription},
sapling::{ConvertDescription, OutputDescription, SpendDescription},
transparent::{TxIn, TxOut},
};

Expand Down
Loading

0 comments on commit 0d7dc07

Please sign in to comment.