mirror of https://github.com/zcash/orchard.git
Use builder to generate "valid" bundles via proptest.
This commit is contained in:
parent
4d89d45332
commit
f91088d35b
|
@ -46,6 +46,7 @@ rev = "f1e76dbc9abf2b68cc609e874fe39f2a15b75b12"
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = "0.3"
|
criterion = "0.3"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
proptest = "1.0.0"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
bench = false
|
bench = false
|
||||||
|
|
|
@ -49,7 +49,7 @@ pub mod testing {
|
||||||
use super::Address;
|
use super::Address;
|
||||||
|
|
||||||
prop_compose! {
|
prop_compose! {
|
||||||
/// Generate an arbitrary random seed
|
/// Generates an arbitrary payment address.
|
||||||
pub(crate) fn arb_address()(sk in arb_spending_key()) -> Address {
|
pub(crate) fn arb_address()(sk in arb_spending_key()) -> Address {
|
||||||
let fvk = FullViewingKey::from(&sk);
|
let fvk = FullViewingKey::from(&sk);
|
||||||
fvk.default_address()
|
fvk.default_address()
|
||||||
|
|
129
src/builder.rs
129
src/builder.rs
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
use nonempty::NonEmpty;
|
use nonempty::NonEmpty;
|
||||||
|
@ -17,16 +16,21 @@ use crate::{
|
||||||
},
|
},
|
||||||
primitives::redpallas::{self, Binding, SpendAuth},
|
primitives::redpallas::{self, Binding, SpendAuth},
|
||||||
tree::{Anchor, MerklePath},
|
tree::{Anchor, MerklePath},
|
||||||
value::{self, NoteValue, ValueCommitTrapdoor, ValueCommitment, ValueSum},
|
value::{self, NoteValue, OverflowError, ValueCommitTrapdoor, ValueCommitment, ValueSum},
|
||||||
Address, Note, TransmittedNoteCiphertext,
|
Address, Note, TransmittedNoteCiphertext,
|
||||||
};
|
};
|
||||||
|
|
||||||
const MIN_ACTIONS: usize = 2;
|
const MIN_ACTIONS: usize = 2;
|
||||||
|
|
||||||
|
/// An error type for the kinds of errors that can occur during bundle construction.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
/// A bundle could not be built because required signatures were missing.
|
||||||
MissingSignatures,
|
MissingSignatures,
|
||||||
|
/// An error occurred in the process of producing a proof for a bundle.
|
||||||
Proof(halo2::plonk::Error),
|
Proof(halo2::plonk::Error),
|
||||||
|
/// An overflow error occurred while attempting to construct the value
|
||||||
|
/// for a bundle.
|
||||||
ValueSum(value::OverflowError),
|
ValueSum(value::OverflowError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +125,7 @@ impl ActionInfo {
|
||||||
/// Defined in [Zcash Protocol Spec § 4.7.3: Sending Notes (Orchard)][orchardsend].
|
/// Defined in [Zcash Protocol Spec § 4.7.3: Sending Notes (Orchard)][orchardsend].
|
||||||
///
|
///
|
||||||
/// [orchardsend]: https://zips.z.cash/protocol/nu5.pdf#orchardsend
|
/// [orchardsend]: https://zips.z.cash/protocol/nu5.pdf#orchardsend
|
||||||
fn build<V: TryFrom<i64>(self, mut rng: impl RngCore) -> (Action<SigningMetadata>, Circuit) {
|
fn build(self, mut rng: impl RngCore) -> (Action<SigningMetadata>, Circuit) {
|
||||||
let v_net = self.value_sum().expect("already checked this");
|
let v_net = self.value_sum().expect("already checked this");
|
||||||
let cv_net = ValueCommitment::derive(v_net, self.rcv);
|
let cv_net = ValueCommitment::derive(v_net, self.rcv);
|
||||||
|
|
||||||
|
@ -164,6 +168,7 @@ impl ActionInfo {
|
||||||
|
|
||||||
/// A builder that constructs a [`Bundle`] from a set of notes to be spent, and recipients
|
/// A builder that constructs a [`Bundle`] from a set of notes to be spent, and recipients
|
||||||
/// to receive funds.
|
/// to receive funds.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
spends: Vec<SpendInfo>,
|
spends: Vec<SpendInfo>,
|
||||||
recipients: Vec<RecipientInfo>,
|
recipients: Vec<RecipientInfo>,
|
||||||
|
@ -172,6 +177,7 @@ pub struct Builder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Builder {
|
impl Builder {
|
||||||
|
/// Construct a new empty builder for an Orchard bundle.
|
||||||
pub fn new(flags: Flags, anchor: Anchor) -> Self {
|
pub fn new(flags: Flags, anchor: Anchor) -> Self {
|
||||||
Builder {
|
Builder {
|
||||||
spends: vec![],
|
spends: vec![],
|
||||||
|
@ -282,7 +288,8 @@ impl Builder {
|
||||||
.iter()
|
.iter()
|
||||||
.fold(Some(ValueSum::zero()), |acc, action| {
|
.fold(Some(ValueSum::zero()), |acc, action| {
|
||||||
acc? + action.value_sum()?
|
acc? + action.value_sum()?
|
||||||
}).ok_or(Error::ValueSum(value::OverflowError))?;
|
})
|
||||||
|
.ok_or(OverflowError)?;
|
||||||
|
|
||||||
// Compute the transaction binding signing key.
|
// Compute the transaction binding signing key.
|
||||||
let bsk = pre_actions
|
let bsk = pre_actions
|
||||||
|
@ -292,10 +299,8 @@ impl Builder {
|
||||||
.into_bsk();
|
.into_bsk();
|
||||||
|
|
||||||
// Create the actions.
|
// Create the actions.
|
||||||
let (actions, circuits): (Vec<_>, Vec<_>) = pre_actions
|
let (actions, circuits): (Vec<_>, Vec<_>) =
|
||||||
.into_iter()
|
pre_actions.into_iter().map(|a| a.build(&mut rng)).unzip();
|
||||||
.map(|a| a.build(&mut rng, PhantomData::<V>))
|
|
||||||
.unzip();
|
|
||||||
|
|
||||||
// Verify that bsk and bvk are consistent.
|
// Verify that bsk and bvk are consistent.
|
||||||
let bvk = (actions.iter().map(|a| a.cv_net()).sum::<ValueCommitment>()
|
let bvk = (actions.iter().map(|a| a.cv_net()).sum::<ValueCommitment>()
|
||||||
|
@ -310,7 +315,9 @@ impl Builder {
|
||||||
.collect();
|
.collect();
|
||||||
let proof = Proof::create(pk, &circuits, &instances)?;
|
let proof = Proof::create(pk, &circuits, &instances)?;
|
||||||
|
|
||||||
let value_balance: V = i64::try_from(value_balance).map_err(Error::ValueSum).and_then(|i| V::try_from(i).map_err(|_| Error::ValueSum(value::OverflowError)))?;
|
let value_balance: V = i64::try_from(value_balance)
|
||||||
|
.map_err(Error::ValueSum)
|
||||||
|
.and_then(|i| V::try_from(i).map_err(|_| Error::ValueSum(value::OverflowError)))?;
|
||||||
|
|
||||||
Ok(Bundle::from_parts(
|
Ok(Bundle::from_parts(
|
||||||
NonEmpty::from_vec(actions).unwrap(),
|
NonEmpty::from_vec(actions).unwrap(),
|
||||||
|
@ -453,27 +460,80 @@ impl<V> Bundle<PartiallyAuthorized, V> {
|
||||||
#[cfg(any(test, feature = "test-dependencies"))]
|
#[cfg(any(test, feature = "test-dependencies"))]
|
||||||
pub mod testing {
|
pub mod testing {
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use proptest::collection::vec;
|
use proptest::collection::vec;
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
|
|
||||||
//use pasta_curves::{pallas};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
address::testing::arb_address,
|
address::testing::arb_address,
|
||||||
bundle::{Authorized, Bundle, Flags},
|
bundle::{Authorized, Bundle, Flags},
|
||||||
circuit::ProvingKey,
|
circuit::ProvingKey,
|
||||||
keys::{FullViewingKey, OutgoingViewingKey, SpendingKey},
|
keys::{
|
||||||
|
testing::arb_spending_key, FullViewingKey, OutgoingViewingKey, SpendAuthorizingKey,
|
||||||
|
SpendingKey,
|
||||||
|
},
|
||||||
note::testing::arb_note,
|
note::testing::arb_note,
|
||||||
tree::{Anchor, MerklePath},
|
tree::{Anchor, MerklePath},
|
||||||
value::testing::{arb_positive_note_value, MAX_MONEY},
|
value::{
|
||||||
|
testing::{arb_positive_note_value, MAX_MONEY},
|
||||||
|
NoteValue,
|
||||||
|
},
|
||||||
|
Address, Note,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Builder;
|
use super::Builder;
|
||||||
|
|
||||||
|
/// An intermediate type used for construction of arbitrary
|
||||||
|
/// bundle values. This type is required because of a limitation
|
||||||
|
/// of the proptest prop_compose! macro which does not correctly
|
||||||
|
/// handle polymorphic generator functions. Instead of generating
|
||||||
|
/// a bundle directly, we generate the bundle inputs, and then
|
||||||
|
/// are able to use the `build` function to construct the bundle
|
||||||
|
/// from these inputs, but using a `ValueBalance` implementation that
|
||||||
|
/// is defined by the end user.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct ArbitraryBundleInputs {
|
||||||
|
sk: SpendingKey,
|
||||||
|
anchor: Anchor,
|
||||||
|
notes: Vec<Note>,
|
||||||
|
recipient_amounts: Vec<(Address, NoteValue)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArbitraryBundleInputs {
|
||||||
|
/// Create a bundle from the set of arbitrary bundle inputs.
|
||||||
|
fn into_bundle<V: TryFrom<i64>>(self) -> Bundle<Authorized, V> {
|
||||||
|
let fvk = FullViewingKey::from(&self.sk);
|
||||||
|
let ovk = OutgoingViewingKey::from(&fvk);
|
||||||
|
let flags = Flags::from_parts(true, true);
|
||||||
|
let mut builder = Builder::new(flags, self.anchor);
|
||||||
|
|
||||||
|
for note in self.notes.into_iter() {
|
||||||
|
builder.add_spend(fvk.clone(), note, MerklePath).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (addr, value) in self.recipient_amounts.into_iter() {
|
||||||
|
builder
|
||||||
|
.add_recipient(Some(ovk.clone()), addr, value, None)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rng = OsRng;
|
||||||
|
let pk = ProvingKey::build();
|
||||||
|
builder
|
||||||
|
.build(&mut rng, &pk)
|
||||||
|
.unwrap()
|
||||||
|
.prepare(rand_7::rngs::OsRng, [0; 32])
|
||||||
|
.sign(rand_7::rngs::OsRng, &SpendAuthorizingKey::from(&self.sk))
|
||||||
|
.finalize()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
prop_compose! {
|
prop_compose! {
|
||||||
/// Produce a random valid Orchard bundle.
|
/// Produce a random valid Orchard bundle.
|
||||||
pub fn arb_bundle(sk: SpendingKey)(
|
fn arb_bundle_inputs(sk: SpendingKey)(
|
||||||
anchor in prop::array::uniform32(prop::num::u8::ANY).prop_map(Anchor),
|
anchor in prop::array::uniform32(prop::num::u8::ANY).prop_map(Anchor),
|
||||||
// generate note values that we're certain won't exceed MAX_MONEY in total
|
// generate note values that we're certain won't exceed MAX_MONEY in total
|
||||||
notes in vec(arb_positive_note_value(MAX_MONEY as u64 / 10000).prop_flat_map(arb_note), 1..30),
|
notes in vec(arb_positive_note_value(MAX_MONEY as u64 / 10000).prop_flat_map(arb_note), 1..30),
|
||||||
|
@ -483,30 +543,29 @@ pub mod testing {
|
||||||
),
|
),
|
||||||
1..30
|
1..30
|
||||||
),
|
),
|
||||||
) -> Bundle<Authorized, i64> {
|
) -> ArbitraryBundleInputs {
|
||||||
let fvk = FullViewingKey::from(&sk);
|
ArbitraryBundleInputs {
|
||||||
let ovk = OutgoingViewingKey::from(&fvk);
|
sk: sk.clone(),
|
||||||
let flags = Flags::from_parts(true, true);
|
anchor,
|
||||||
let mut builder = Builder::new(flags, anchor);
|
notes,
|
||||||
|
recipient_amounts
|
||||||
for note in notes.into_iter() {
|
|
||||||
builder.add_spend(fvk.clone(), note, MerklePath).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (addr, value) in recipient_amounts.into_iter() {
|
|
||||||
builder.add_recipient(Some(ovk.clone()), addr, value, None).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut rng = OsRng;
|
|
||||||
let pk = ProvingKey::build();
|
|
||||||
builder
|
|
||||||
.build(&mut rng, &pk)
|
|
||||||
.unwrap()
|
|
||||||
.prepare(rand_7::rngs::OsRng, [0; 32])
|
|
||||||
.finalize()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produce an arbitrary valid Orchard bundle using a random spending key.
|
||||||
|
pub fn arb_bundle<V: TryFrom<i64> + Debug>() -> impl Strategy<Value = Bundle<Authorized, V>> {
|
||||||
|
arb_spending_key()
|
||||||
|
.prop_flat_map(arb_bundle_inputs)
|
||||||
|
.prop_map(|inputs| inputs.into_bundle::<V>())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Produce an arbitrary valid Orchard bundle using a specified spending key.
|
||||||
|
pub fn arb_bundle_with_key<V: TryFrom<i64> + Debug>(
|
||||||
|
k: SpendingKey,
|
||||||
|
) -> impl Strategy<Value = Bundle<Authorized, V>> {
|
||||||
|
arb_bundle_inputs(k).prop_map(|inputs| inputs.into_bundle::<V>())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -172,37 +172,6 @@ pub trait Authorization {
|
||||||
type SpendAuth;
|
type SpendAuth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Authorizing data for a bundle of actions, ready to be committed to the ledger.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Authorized {
|
|
||||||
proof: Proof,
|
|
||||||
binding_signature: redpallas::Signature<Binding>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Authorized {
|
|
||||||
/// Construct a new value with authorizing data.
|
|
||||||
pub fn new(proof: Proof, binding_signature: redpallas::Signature<Binding>) -> Self {
|
|
||||||
Authorized {
|
|
||||||
proof,
|
|
||||||
binding_signature,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the proof component of the authorizing data.
|
|
||||||
pub fn proof(&self) -> &Proof {
|
|
||||||
&self.proof
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the binding signature.
|
|
||||||
pub fn binding_signature(&self) -> &redpallas::Signature<Binding> {
|
|
||||||
&self.binding_signature
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Authorization for Authorized {
|
|
||||||
type SpendAuth = redpallas::Signature<SpendAuth>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A bundle of actions to be applied to the ledger.
|
/// A bundle of actions to be applied to the ledger.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Bundle<T: Authorization, V> {
|
pub struct Bundle<T: Authorization, V> {
|
||||||
|
@ -318,58 +287,15 @@ impl<T: Authorization, V> Bundle<T, V> {
|
||||||
|
|
||||||
/// Authorizing data for a bundle of actions, ready to be committed to the ledger.
|
/// Authorizing data for a bundle of actions, ready to be committed to the ledger.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BundleAuth {
|
pub struct Authorized {
|
||||||
/// The authorizing data for the actions in a bundle
|
proof: Proof,
|
||||||
pub action_authorizations: NonEmpty<<Authorized as Authorization>::SpendAuth>,
|
binding_signature: redpallas::Signature<Binding>,
|
||||||
/// The authorizing data that covers the bundle as a whole
|
|
||||||
pub authorization: Authorized,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors that may be generated in the process of constructing bundle authorizing data.
|
impl Authorization for Authorized {
|
||||||
#[derive(Debug)]
|
type SpendAuth = redpallas::Signature<SpendAuth>;
|
||||||
pub enum BundleAuthError<E> {
|
|
||||||
/// An error produced by the underlying computation of authorizing data for a bundle
|
|
||||||
Wrapped(E),
|
|
||||||
/// Authorizing data for the bundle could not be matched to bundle contents.
|
|
||||||
AuthLengthMismatch(usize, usize),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//impl<V> Bundle<Unauthorized, V> {
|
|
||||||
// /// Compute the authorizing data for a bundle and apply it to the bundle, returning the
|
|
||||||
// /// authorized result.
|
|
||||||
// pub fn with_auth<E, F: FnOnce(&Self) -> Result<BundleAuth, E>>(
|
|
||||||
// self,
|
|
||||||
// f: F,
|
|
||||||
// ) -> Result<Bundle<Authorized, V>, BundleAuthError<E>> {
|
|
||||||
// let auth = f(&self).map_err(BundleAuthError::Wrapped)?;
|
|
||||||
// let actions_len = self.actions.len();
|
|
||||||
//
|
|
||||||
// if actions_len != auth.action_authorizations.len() {
|
|
||||||
// Err(BundleAuthError::AuthLengthMismatch(
|
|
||||||
// actions_len,
|
|
||||||
// auth.action_authorizations.len(),
|
|
||||||
// ))
|
|
||||||
// } else {
|
|
||||||
// let actions = NonEmpty::from_vec(
|
|
||||||
// self.actions
|
|
||||||
// .into_iter()
|
|
||||||
// .zip(auth.action_authorizations.into_iter())
|
|
||||||
// .map(|(act, a)| act.map(|_| a))
|
|
||||||
// .collect(),
|
|
||||||
// )
|
|
||||||
// .ok_or(BundleAuthError::AuthLengthMismatch(actions_len, 0))?;
|
|
||||||
//
|
|
||||||
// Ok(Bundle {
|
|
||||||
// actions,
|
|
||||||
// flags: self.flags,
|
|
||||||
// value_balance: self.value_balance,
|
|
||||||
// anchor: self.anchor,
|
|
||||||
// authorization: auth.authorization,
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
impl Authorized {
|
impl Authorized {
|
||||||
/// Constructs the authorizing data for a bundle of actions from its constituent parts.
|
/// Constructs the authorizing data for a bundle of actions from its constituent parts.
|
||||||
pub fn from_parts(proof: Proof, binding_signature: redpallas::Signature<Binding>) -> Self {
|
pub fn from_parts(proof: Proof, binding_signature: redpallas::Signature<Binding>) -> Self {
|
||||||
|
@ -378,6 +304,16 @@ impl Authorized {
|
||||||
binding_signature,
|
binding_signature,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the proof component of the authorizing data.
|
||||||
|
pub fn proof(&self) -> &Proof {
|
||||||
|
&self.proof
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the binding signature.
|
||||||
|
pub fn binding_signature(&self) -> &redpallas::Signature<Binding> {
|
||||||
|
&self.binding_signature
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> Bundle<Authorized, V> {
|
impl<V> Bundle<Authorized, V> {
|
||||||
|
@ -417,8 +353,7 @@ pub mod testing {
|
||||||
},
|
},
|
||||||
primitives::redpallas::testing::arb_spendauth_verification_key,
|
primitives::redpallas::testing::arb_spendauth_verification_key,
|
||||||
value::{
|
value::{
|
||||||
testing::{arb_note_value},
|
testing::arb_note_value, NoteValue, ValueCommitTrapdoor, ValueCommitment, ValueSum,
|
||||||
NoteValue, ValueCommitTrapdoor, ValueCommitment, ValueSum,
|
|
||||||
},
|
},
|
||||||
Anchor,
|
Anchor,
|
||||||
};
|
};
|
||||||
|
@ -489,7 +424,7 @@ pub mod testing {
|
||||||
NonEmpty::from_vec(actions).unwrap(),
|
NonEmpty::from_vec(actions).unwrap(),
|
||||||
flags,
|
flags,
|
||||||
values.into_iter().fold(
|
values.into_iter().fold(
|
||||||
ValueSum::zero(),
|
ValueSum::zero(),
|
||||||
|acc, cv| (acc + (cv - NoteValue::zero()).unwrap()).unwrap()
|
|acc, cv| (acc + (cv - NoteValue::zero()).unwrap()).unwrap()
|
||||||
),
|
),
|
||||||
anchor,
|
anchor,
|
||||||
|
|
|
@ -25,7 +25,7 @@ use crate::{
|
||||||
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
|
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
|
||||||
///
|
///
|
||||||
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
|
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SpendingKey([u8; 32]);
|
pub struct SpendingKey([u8; 32]);
|
||||||
|
|
||||||
impl SpendingKey {
|
impl SpendingKey {
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
|
|
||||||
mod address;
|
mod address;
|
||||||
mod builder;
|
pub mod builder;
|
||||||
pub mod bundle;
|
pub mod bundle;
|
||||||
mod circuit;
|
mod circuit;
|
||||||
mod constants;
|
mod constants;
|
||||||
|
|
|
@ -10,7 +10,6 @@ pub struct MerklePath;
|
||||||
impl MerklePath {
|
impl MerklePath {
|
||||||
/// Generates a dummy Merkle path for use in dummy spent notes.
|
/// Generates a dummy Merkle path for use in dummy spent notes.
|
||||||
pub(crate) fn dummy(_rng: &mut impl RngCore) -> Self {
|
pub(crate) fn dummy(_rng: &mut impl RngCore) -> Self {
|
||||||
// TODO
|
|
||||||
MerklePath
|
MerklePath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
11
src/value.rs
11
src/value.rs
|
@ -72,7 +72,9 @@ impl Sub for NoteValue {
|
||||||
fn sub(self, rhs: Self) -> Self::Output {
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
let a = self.0 as i128;
|
let a = self.0 as i128;
|
||||||
let b = rhs.0 as i128;
|
let b = rhs.0 as i128;
|
||||||
a.checked_sub(b).filter(|v| v > &(-(std::u64::MAX as i128))).map(ValueSum)
|
a.checked_sub(b)
|
||||||
|
.filter(|v| v > &(-(std::u64::MAX as i128)))
|
||||||
|
.map(ValueSum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +101,10 @@ impl Add for ValueSum {
|
||||||
type Output = Option<ValueSum>;
|
type Output = Option<ValueSum>;
|
||||||
|
|
||||||
fn add(self, rhs: Self) -> Self::Output {
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
self.0.checked_add(rhs.0).filter(|v| v < &(std::u64::MAX as i128)).map(ValueSum)
|
self.0
|
||||||
|
.checked_add(rhs.0)
|
||||||
|
.filter(|v| v < &(std::u64::MAX as i128))
|
||||||
|
.map(ValueSum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,7 +289,7 @@ mod tests {
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
testing::{arb_trapdoor, arb_value_sum, MAX_MONEY},
|
testing::{arb_trapdoor, arb_value_sum, MAX_MONEY},
|
||||||
OverflowError, ValueCommitTrapdoor, ValueCommitment, ValueSum
|
OverflowError, ValueCommitTrapdoor, ValueCommitment, ValueSum,
|
||||||
};
|
};
|
||||||
use crate::primitives::redpallas;
|
use crate::primitives::redpallas;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue