Skip to content
Closed
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
18 changes: 16 additions & 2 deletions src/bundle/batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use pasta_curves::vesta;
use rand::{CryptoRng, RngCore};
use tracing::debug;

use super::{Authorized, Bundle};
use super::{burn_validation::validate_bundle_burn, Authorized, Bundle};
use crate::{
circuit::VerifyingKey,
note::AssetBase,
primitives::redpallas::{self, Binding, SpendAuth},
};

Expand All @@ -23,6 +24,7 @@ struct BundleSignature {
pub struct BatchValidator {
proofs: plonk::BatchVerifier<vesta::Affine>,
signatures: Vec<BundleSignature>,
burns: Vec<(AssetBase, i64)>,
}

impl BatchValidator {
Expand All @@ -31,10 +33,11 @@ impl BatchValidator {
BatchValidator {
proofs: plonk::BatchVerifier::new(),
signatures: vec![],
burns: vec![],
}
}

/// Adds the proof and RedPallas signatures from the given bundle to the validator.
/// Adds the proof, RedPallas signatures and burn mechanism values from the given bundle to the validator.
pub fn add_bundle<V: Copy + Into<i64>>(
&mut self,
bundle: &Bundle<Authorized, V>,
Expand All @@ -58,6 +61,13 @@ impl BatchValidator {
.authorization()
.proof()
.add_to_batch(&mut self.proofs, bundle.to_instances());

self.burns.extend(
bundle
.burn
.iter()
.map(|(asset, amount)| (*asset, (*amount).into())),
);
}

/// Batch-validates the accumulated bundles.
Expand All @@ -67,6 +77,10 @@ impl BatchValidator {
/// figure out which of the accumulated bundles might be invalid; if that information
/// is desired, construct separate [`BatchValidator`]s for sub-batches of the bundles.
pub fn validate<R: RngCore + CryptoRng>(self, vk: &VerifyingKey, rng: R) -> bool {
if validate_bundle_burn(&self.burns).is_err() {
return false;
}

if self.signatures.is_empty() {
// An empty batch is always valid, but is not free to run; skip it.
// Note that a transaction has at least a binding signature, so if
Expand Down
53 changes: 53 additions & 0 deletions src/issuance.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Structs related to issuance bundles and the associated logic.
use blake2b_simd::Hash as Blake2bHash;
use group::Group;
use memuse::DynamicUsage;
use nonempty::NonEmpty;
use rand::{CryptoRng, RngCore};
use std::collections::HashSet;
Expand All @@ -25,6 +26,10 @@ use crate::{

use crate::supply_info::{AssetSupply, SupplyInfo};

mod batch;

pub use batch::BatchValidator;

/// A bundle of actions to be applied to the ledger.
#[derive(Debug, Clone)]
pub struct IssueBundle<T: IssueAuth> {
Expand All @@ -49,6 +54,24 @@ pub struct IssueAction {
finalize: bool,
}

impl DynamicUsage for IssueAction {
#[inline(always)]
fn dynamic_usage(&self) -> usize {
self.asset_desc.dynamic_usage() + self.notes.dynamic_usage()
}

#[inline(always)]
fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
let asset_desc_bounds = self.asset_desc.dynamic_usage_bounds();
let note_bounds = self.notes.dynamic_usage_bounds();

(
asset_desc_bounds.0 + note_bounds.0,
asset_desc_bounds.1.zip(note_bounds.1).map(|(a, b)| a + b),
)
}
}

/// The parameters required to add a Note into an IssueAction.
#[derive(Debug)]
pub struct IssueInfo {
Expand Down Expand Up @@ -202,6 +225,15 @@ impl IssueAuth for Unauthorized {}
impl IssueAuth for Prepared {}
impl IssueAuth for Signed {}

impl DynamicUsage for Signed {
fn dynamic_usage(&self) -> usize {
0
}
fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
(0, Some(0))
}
}

impl<T: IssueAuth> IssueBundle<T> {
/// Returns the issuer verification key for the bundle.
pub fn ik(&self) -> &IssuanceValidatingKey {
Expand Down Expand Up @@ -460,6 +492,27 @@ impl IssueBundle<Signed> {
}
}

impl DynamicUsage for IssueBundle<Signed> {
fn dynamic_usage(&self) -> usize {
self.actions.dynamic_usage() + self.ik.dynamic_usage() + self.authorization.dynamic_usage()
}

fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
let action_bounds = self.actions.dynamic_usage_bounds();
let ik_bounds = self.ik.dynamic_usage_bounds();
let authorization_bounds = self.authorization.dynamic_usage_bounds();

(
action_bounds.0 + ik_bounds.0 + authorization_bounds.0,
action_bounds
.1
.zip(ik_bounds.1)
.zip(authorization_bounds.1)
.map(|((a, b), c)| a + b + c),
)
}
}

/// Validation for Orchard IssueBundles
///
/// A set of previously finalized asset types must be provided in `finalized` argument.
Expand Down
36 changes: 36 additions & 0 deletions src/issuance/batch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use std::collections::HashSet;

use super::{verify_issue_bundle, AssetBase, IssueBundle, Signed};

/// Batch validation context for Issuance.
///
#[derive(Debug, Default)]
pub struct BatchValidator {
bundles: Vec<(IssueBundle<Signed>, [u8; 32])>,
}

impl BatchValidator {
/// Constructs a new batch validation context.
pub fn new() -> Self {
BatchValidator { bundles: vec![] }
}

/// Adds bundle to the validator.
pub fn add_bundle(&mut self, bundle: &IssueBundle<Signed>, sighash: [u8; 32]) {
self.bundles.push((bundle.clone(), sighash))
}

/// Batch-validates the accumulated bundles.
///
/// Returns `true` if every bundle added to the batch validator is valid, or `false`
/// if one or more are invalid.
pub fn validate(self) -> bool {
// FIXME: take/save finalization set from/to the global state
let finalized = HashSet::<AssetBase>::new();

// FIXME: process resulting supply_info
self.bundles
.into_iter()
.all(|(bundle, sighash)| verify_issue_bundle(&bundle, sighash, &finalized).is_ok())
}
}
13 changes: 13 additions & 0 deletions src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use group::{
prime::PrimeCurveAffine,
Curve, GroupEncoding,
};
use memuse::DynamicUsage;
use pasta_curves::{pallas, pallas::Scalar};
use rand::{CryptoRng, RngCore};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
Expand Down Expand Up @@ -349,6 +350,18 @@ impl PartialEq for IssuanceValidatingKey {

impl Eq for IssuanceValidatingKey {}

impl DynamicUsage for IssuanceValidatingKey {
#[inline(always)]
fn dynamic_usage(&self) -> usize {
0
}

#[inline(always)]
fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
(0, Some(0))
}
}

impl IssuanceValidatingKey {
/// Converts this spend validating key to its serialized form,
/// I2LEOSP_256(ik).
Expand Down
13 changes: 13 additions & 0 deletions src/note.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use core::fmt;

use group::GroupEncoding;
use memuse::DynamicUsage;
use pasta_curves::pallas;
use rand::RngCore;
use subtle::{Choice, ConditionallySelectable, CtOption};
Expand Down Expand Up @@ -306,6 +307,18 @@ impl Note {
}
}

impl DynamicUsage for Note {
#[inline(always)]
fn dynamic_usage(&self) -> usize {
0
}

#[inline(always)]
fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
(0, Some(0))
}
}

/// An encrypted note.
#[derive(Clone)]
pub struct TransmittedNoteCiphertext {
Expand Down