Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Murisi/namada integration #44

Merged
merged 15 commits into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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