diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 05ed21067..7c5f9a4a5 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -1,9 +1,6 @@ name: Audit on: - pull_request: - push: - schedule: - - cron: '0 */12 * * *' + workflow_dispatch: jobs: audit: runs-on: ubuntu-latest diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 013678635..e501ab982 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -1,5 +1,8 @@ name: Benchmark on: + push: + branches: + - 'main' workflow_dispatch: env: CARGO_TERM_COLOR: always diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 400622a32..f7a5d0fc6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,7 @@ on: - 'main' schedule: - cron: '0 0 * * */2' + workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 1eea8b658..4f0a29444 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Added - [\#206](https://github.com/Manta-Network/manta-rs/pull/206) Move Poseidon sage script to test the hardcoded round constant values. - [\#172](https://github.com/Manta-Network/manta-rs/pull/172) Add abstract Phase 2 for Groth16 trusted setup +- [\#197](https://github.com/Manta-Network/manta-rs/pull/197) Add ECLAIR utilities for next circuit upgrade ### Changed - [\#180](https://github.com/Manta-Network/manta-rs/pull/180) Start moving to new `arkworks` backend for `manta-crypto` diff --git a/manta-accounting/src/transfer/mod.rs b/manta-accounting/src/transfer/mod.rs index 75f89d558..904023a90 100644 --- a/manta-accounting/src/transfer/mod.rs +++ b/manta-accounting/src/transfer/mod.rs @@ -34,7 +34,7 @@ use alloc::vec::Vec; use core::{fmt::Debug, hash::Hash, marker::PhantomData, ops::Deref}; use manta_crypto::{ accumulator::{self, AssertValidVerification, MembershipProof, Model}, - constraint::{ProofSystem, ProofSystemInput}, + constraint::{HasInput, ProofSystem}, eclair::{ self, alloc::{ @@ -236,12 +236,12 @@ pub trait Configuration { /// Proof System Type type ProofSystem: ProofSystem - + ProofSystemInput - + ProofSystemInput - + ProofSystemInput> - + ProofSystemInput> - + ProofSystemInput> - + ProofSystemInput>; + + HasInput + + HasInput + + HasInput> + + HasInput> + + HasInput> + + HasInput>; /// Note Base Encryption Scheme Type type NoteEncryptionScheme: encryption::Encrypt< @@ -297,8 +297,7 @@ pub type UtxoAccumulatorOutput = pub type UtxoMembershipProof = MembershipProof<::UtxoAccumulatorModel>; /// UTXO Membership Proof Variable Type -pub type UtxoMembershipProofVar = - MembershipProof<::UtxoAccumulatorModelVar, Compiler>; +pub type UtxoMembershipProofVar = MembershipProof<::UtxoAccumulatorModelVar>; /// Encrypted Note Type pub type EncryptedNote = EncryptedMessage< diff --git a/manta-accounting/src/transfer/receiver.rs b/manta-accounting/src/transfer/receiver.rs index 251b0b1f6..c7b4a813a 100644 --- a/manta-accounting/src/transfer/receiver.rs +++ b/manta-accounting/src/transfer/receiver.rs @@ -25,8 +25,7 @@ use crate::{ }; use core::{fmt::Debug, hash::Hash, iter}; use manta_crypto::{ - accumulator::Accumulator, - constraint::ProofSystemInput, + constraint::HasInput, eclair::{ alloc::{ mode::{Derived, Public}, @@ -97,16 +96,6 @@ where self.encrypted_note.ephemeral_public_key() } - /// Returns `true` whenever `self.utxo` and `rhs.utxo` can be inserted in any order into the - /// `utxo_accumulator`. - #[inline] - pub fn is_independent_from(&self, rhs: &Self, utxo_accumulator: &A) -> bool - where - A: Accumulator, Model = C::UtxoAccumulatorModel>, - { - utxo_accumulator.are_independent(&self.utxo, &rhs.utxo) - } - /// Extracts the ledger posting data from `self`. #[inline] pub fn into_post(self) -> ReceiverPost { diff --git a/manta-accounting/src/transfer/sender.rs b/manta-accounting/src/transfer/sender.rs index e438ccd65..7a4ba0ffd 100644 --- a/manta-accounting/src/transfer/sender.rs +++ b/manta-accounting/src/transfer/sender.rs @@ -27,7 +27,7 @@ use crate::{ use core::{fmt::Debug, hash::Hash, iter}; use manta_crypto::{ accumulator::Accumulator, - constraint::ProofSystemInput, + constraint::HasInput, eclair::{ alloc::{mode::Derived, Allocate, Allocator, Variable}, bool::AssertEq, @@ -142,16 +142,6 @@ where None } } - - /// Returns `true` whenever `self.utxo` and `rhs.utxo` can be inserted in any order into the - /// `utxo_accumulator`. - #[inline] - pub fn is_independent_from(&self, rhs: &Self, utxo_accumulator: &A) -> bool - where - A: Accumulator, Model = C::UtxoAccumulatorModel>, - { - utxo_accumulator.are_independent(&self.utxo, &rhs.utxo) - } } /// Sender Proof @@ -211,16 +201,6 @@ where self.asset.value } - /// Returns `true` whenever `self.utxo` and `rhs.utxo` can be inserted in any order into the - /// `utxo_accumulator`. - #[inline] - pub fn is_independent_from(&self, rhs: &Self, utxo_accumulator: &A) -> bool - where - A: Accumulator, Model = C::UtxoAccumulatorModel>, - { - utxo_accumulator.are_independent(&self.utxo, &rhs.utxo) - } - /// Reverts `self` back into a [`PreSender`]. /// /// This method should be called if the [`Utxo`] membership proof attached to `self` was deemed diff --git a/manta-crypto/Cargo.toml b/manta-crypto/Cargo.toml index 05738b9b0..9d3a4c41a 100644 --- a/manta-crypto/Cargo.toml +++ b/manta-crypto/Cargo.toml @@ -59,4 +59,5 @@ rand_core = { version = "0.6.3", default-features = false } workspace-hack = { version = "0.1.0", path = "../workspace-hack" } [dev-dependencies] -rand = "0.8.4" +ark-bn254 = { version = "0.3.0", default-features = false, features = ["scalar_field"] } +manta-crypto = { path = ".", default-features = false, features = ["getrandom"] } diff --git a/manta-crypto/src/accumulator.rs b/manta-crypto/src/accumulator.rs index 1e31d3358..f14381523 100644 --- a/manta-crypto/src/accumulator.rs +++ b/manta-crypto/src/accumulator.rs @@ -17,7 +17,7 @@ //! Dynamic Cryptographic Accumulators use crate::eclair::alloc::{mode::Derived, Allocate, Allocator, Constant, Variable}; -use core::marker::PhantomData; +use core::{fmt::Debug, hash::Hash}; /// Accumulator Membership Model Types pub trait Types { @@ -31,6 +31,33 @@ pub trait Types { type Output; } +impl Types for &T +where + T: Types + ?Sized, +{ + type Item = T::Item; + type Witness = T::Witness; + type Output = T::Output; +} + +impl Types for &mut T +where + T: Types + ?Sized, +{ + type Item = T::Item; + type Witness = T::Witness; + type Output = T::Output; +} + +/// Accumulator Item Type +pub type Item = ::Item; + +/// Accumulator Witness Type +pub type Witness = ::Witness; + +/// Accumulator Output Type +pub type Output = ::Output; + /// Accumulator Membership Model pub trait Model: Types { /// Verification Type @@ -80,19 +107,10 @@ pub trait AssertValidVerification: Model { ); } -/// Accumulator Witness Type -pub type Witness = <::Model as Types>::Witness; - -/// Accumulator Output Type -pub type Output = <::Model as Types>::Output; - /// Accumulator -pub trait Accumulator { - /// Item Type - type Item: ?Sized; - +pub trait Accumulator: Types { /// Model Type - type Model: Model + ?Sized; + type Model: Model + ?Sized; /// Returns the model associated with `self`. fn model(&self) -> &Self::Model; @@ -102,15 +120,6 @@ pub trait Accumulator { /// `false` if the maximum capacity of the accumulator would be exceeded by inserting `item`. fn insert(&mut self, item: &Self::Item) -> bool; - /// Returns `true` whenever `fst` and `snd` can be inserted in any order into the accumulator. - /// This method should return `false`, the worst-case result, in the case that the insertion - /// order is unknown or unspecified. - #[inline] - fn are_independent(&self, fst: &Self::Item, snd: &Self::Item) -> bool { - let _ = (fst, snd); - false - } - /// Returns a membership proof for `item` if it is contained in `self`. fn prove(&self, item: &Self::Item) -> Option>; @@ -132,7 +141,6 @@ impl Accumulator for &mut A where A: Accumulator + ?Sized, { - type Item = A::Item; type Model = A::Model; #[inline] @@ -212,129 +220,36 @@ pub trait OptimizedAccumulator: Accumulator { } } -/// Item Hash Accumulator Model -pub struct ItemHashAccumulatorModel -where - H: ItemHashFunction, - A: Accumulator, -{ - /// Item Hash Function - item_hash_function: H, - - /// Accumulator - accumulator: A, - - /// Type Parameter Marker - __: PhantomData, -} - -impl Types for ItemHashAccumulatorModel -where - H: ItemHashFunction, - A: Accumulator, -{ - type Item = T; - type Witness = Witness; - type Output = Output; -} - -impl Model for ItemHashAccumulatorModel -where - H: ItemHashFunction, - A: Accumulator, -{ - type Verification = ::Verification; - - #[inline] - fn verify( - &self, - item: &Self::Item, - witness: &Self::Witness, - output: &Self::Output, - compiler: &mut (), - ) -> Self::Verification { - self.accumulator.model().verify( - &self.item_hash_function.item_hash(item, compiler), - witness, - output, - compiler, - ) - } -} - -/// Item Hash Accumulator -pub struct ItemHashAccumulator -where - H: ItemHashFunction, - A: Accumulator, -{ - /// Item Hash Accumulator Model - model: ItemHashAccumulatorModel, -} - -impl Accumulator for ItemHashAccumulator -where - H: ItemHashFunction, - A: Accumulator, -{ - type Item = T; - type Model = ItemHashAccumulatorModel; - - #[inline] - fn model(&self) -> &Self::Model { - &self.model - } - - #[inline] - fn insert(&mut self, item: &Self::Item) -> bool { - self.model - .accumulator - .insert(&self.model.item_hash_function.item_hash(item, &mut ())) - } - - #[inline] - fn prove(&self, item: &Self::Item) -> Option> { - self.model - .accumulator - .prove(&self.model.item_hash_function.item_hash(item, &mut ())) - .map(MembershipProof::into) - } - - #[inline] - fn contains(&self, item: &Self::Item) -> bool { - self.model - .accumulator - .contains(&self.model.item_hash_function.item_hash(item, &mut ())) - } -} - /// Accumulator Membership Proof -pub struct MembershipProof +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = "M::Witness: Clone, M::Output: Clone"), + Copy(bound = "M::Witness: Copy, M::Output: Copy"), + Debug(bound = "M::Witness: Debug, M::Output: Debug"), + Default(bound = "M::Witness: Default, M::Output: Default"), + Eq(bound = "M::Witness: Eq, M::Output: Eq"), + Hash(bound = "M::Witness: Hash, M::Output: Hash"), + PartialEq(bound = "M::Witness: PartialEq, M::Output: PartialEq") +)] +pub struct MembershipProof where - M: Model + ?Sized, + M: Types + ?Sized, { /// Secret Membership Witness witness: M::Witness, /// Accumulator Output output: M::Output, - - /// Type Parameter Marker - __: PhantomData, } -impl MembershipProof +impl MembershipProof where - M: Model + ?Sized, + M: Types + ?Sized, { /// Builds a new [`MembershipProof`] from `witness` and `output`. #[inline] pub fn new(witness: M::Witness, output: M::Output) -> Self { - Self { - witness, - output, - __: PhantomData, - } + Self { witness, output } } /// Returns the accumulated output part of `self`, dropping the [`M::Witness`](Types::Witness). @@ -351,13 +266,16 @@ where /// Verifies that `item` is stored in a known accumulator using `model`. #[inline] - pub fn verify(&self, model: &M, item: &M::Item, compiler: &mut COM) -> M::Verification { + pub fn verify(&self, model: &M, item: &M::Item, compiler: &mut COM) -> M::Verification + where + M: Model, + { model.verify(item, &self.witness, &self.output, compiler) } /// Asserts that the verification of the storage of `item` in the known accumulator is valid. #[inline] - pub fn assert_valid(&self, model: &M, item: &M::Item, compiler: &mut COM) + pub fn assert_valid(&self, model: &M, item: &M::Item, compiler: &mut COM) where M: AssertValidVerification, { @@ -371,9 +289,9 @@ where /// This function cannot guarantee that the point-wise conversion of the witness and output /// preserves the membership proof validity. #[inline] - pub fn into(self) -> MembershipProof + pub fn into(self) -> MembershipProof where - N: Model + ?Sized, + N: Types + ?Sized, M::Witness: Into, M::Output: Into, { @@ -381,9 +299,9 @@ where } } -impl Variable, COM> for MembershipProof +impl Variable, COM> for MembershipProof where - M: Model + Constant, + M: Constant + Model, M::Type: Model, M::Witness: Variable::Witness>, M::Output: Variable::Output>, diff --git a/manta-crypto/src/algebra.rs b/manta-crypto/src/algebra.rs index f661f4aa5..eb86ed326 100644 --- a/manta-crypto/src/algebra.rs +++ b/manta-crypto/src/algebra.rs @@ -27,25 +27,42 @@ use manta_util::codec::{Decode, DecodeError, Encode, Read, Write}; #[cfg(feature = "serde")] use manta_util::serde::{Deserialize, Serialize}; -/// Ring of Scalars -pub trait Scalar { - /// Adds `rhs` to `self` in the ring. +/// Group +pub trait Group { + /// Adds `rhs` to `self` in the group. fn add(&self, rhs: &Self, compiler: &mut COM) -> Self; +} +/// Ring +pub trait Ring: Group { /// Multiplies `self` by `rhs` in the ring. fn mul(&self, rhs: &Self, compiler: &mut COM) -> Self; } -/// Group -pub trait Group { - /// Ring of Scalars - type Scalar: Scalar; - - /// Adds `rhs` to `self` in the group. - fn add(&self, rhs: &Self, compiler: &mut COM) -> Self; +/// Scalar Multiplication +pub trait ScalarMul { + /// Output Type + type Output; /// Multiplies `self` by `scalar` in the group. - fn mul(&self, scalar: &Self::Scalar, compiler: &mut COM) -> Self; + fn scalar_mul(&self, scalar: &S, compiler: &mut COM) -> Self::Output; +} + +/// Group with a Scalar Multiplication +pub trait ScalarMulGroup: Group + ScalarMul {} + +impl ScalarMulGroup for G where G: Group + ScalarMul {} + +/// Group Generator +pub trait HasGenerator +where + G: Group, +{ + /// Generator Type + type Generator; + + /// Returns a generator of `G`. + fn generator(&self) -> &Self::Generator; } /// Diffie-Hellman Key Agreement Scheme @@ -56,18 +73,18 @@ pub trait Group { )] #[derive(derivative::Derivative)] #[derivative(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct DiffieHellman { +pub struct DiffieHellman { /// Group Generator - pub generator: G, + pub generator: GEN, /// Type Parameter Marker - __: PhantomData, + __: PhantomData<(S, G)>, } -impl DiffieHellman { +impl DiffieHellman { /// Builds a new [`DiffieHellman`] key agreement scheme from the given `generator`. #[inline] - pub fn new(generator: G) -> Self { + pub fn new(generator: GEN) -> Self { Self { generator, __: PhantomData, @@ -76,45 +93,56 @@ impl DiffieHellman { /// Converts `self` into the group generator. #[inline] - pub fn into_inner(self) -> G { + pub fn into_inner(self) -> GEN { self.generator } } -impl Constant for DiffieHellman +impl HasGenerator for DiffieHellman where - G: Constant, + G: Group, { - type Type = DiffieHellman; + type Generator = GEN; #[inline] - fn new_constant(value: &Self::Type, compiler: &mut COM) -> Self { - Self::new(G::new_constant(&value.generator, compiler)) + fn generator(&self) -> &Self::Generator { + &self.generator } } -impl key::agreement::Types for DiffieHellman +impl Constant for DiffieHellman where - G: Group + security::ComputationalDiffieHellmanHardness, + S: Constant, + G: Constant, + GEN: Constant, { - type SecretKey = G::Scalar; + type Type = DiffieHellman; + + #[inline] + fn new_constant(value: &Self::Type, compiler: &mut COM) -> Self { + Self::new(Constant::new_constant(&value.generator, compiler)) + } +} + +impl key::agreement::Types for DiffieHellman { + type SecretKey = S; type PublicKey = G; type SharedSecret = G; } -impl key::agreement::Derive for DiffieHellman +impl key::agreement::Derive for DiffieHellman where - G: Group + security::ComputationalDiffieHellmanHardness, + GEN: ScalarMul + security::ComputationalDiffieHellmanHardness, { #[inline] fn derive(&self, secret_key: &Self::SecretKey, compiler: &mut COM) -> Self::PublicKey { - self.generator.mul(secret_key, compiler) + self.generator.scalar_mul(secret_key, compiler) } } -impl key::agreement::Agree for DiffieHellman +impl key::agreement::Agree for DiffieHellman where - G: Group + security::ComputationalDiffieHellmanHardness, + G: ScalarMul + security::ComputationalDiffieHellmanHardness, { #[inline] fn agree( @@ -123,15 +151,15 @@ where secret_key: &Self::SecretKey, compiler: &mut COM, ) -> Self::SharedSecret { - public_key.mul(secret_key, compiler) + public_key.scalar_mul(secret_key, compiler) } } -impl Decode for DiffieHellman +impl Decode for DiffieHellman where - G: Decode, + GEN: Decode, { - type Error = G::Error; + type Error = GEN::Error; #[inline] fn decode(mut reader: R) -> Result> @@ -142,9 +170,9 @@ where } } -impl Encode for DiffieHellman +impl Encode for DiffieHellman where - G: Encode, + GEN: Encode, { #[inline] fn encode(&self, mut writer: W) -> Result<(), W::Error> @@ -156,9 +184,9 @@ where } } -impl Sample for DiffieHellman +impl Sample for DiffieHellman where - G: Sample, + GEN: Sample, { #[inline] fn sample(distribution: D, rng: &mut R) -> Self @@ -172,52 +200,62 @@ where /// Security Assumptions /// /// The following outlines some standard security assumptions for cryptographic protocols built on -/// [`Group`] types. These security properties can be attached to instances of [`Group`] which we -/// assume to have these hardness properties. +/// types that implement [`ScalarMul`] for some set of scalars. These security properties can be +/// attached to instances of [`ScalarMul`] which we assume to have these hardness properties. pub mod security { /// Discrete Logarithm Hardness Assumption /// - /// For a [`Group`](super::Group) `G`, it should be infeasible to find a procedure `f` that - /// makes this function return `true`: + /// For a type `G`, it should be infeasible to find a procedure `f` that makes this function + /// return `true`: /// /// ```text - /// fn solve(g: G, y: G, f: F) -> bool + /// fn solve(g: G, y: S, f: F) -> bool /// where - /// F: FnOnce(G, G) -> G::Scalar, + /// G: ScalarMul, + /// F: FnOnce(G, G) -> S, /// { - /// y == g.mul(f(g, y)) + /// y == g.scalar_mul(f(g, y)) /// } /// ``` pub trait DiscreteLogarithmHardness {} /// Computational Diffie-Hellman Hardness Assumption /// - /// For a [`Group`](super::Group) `G`, it should be infeasible to find a procedure `f` that - /// makes this function return `true`: + /// For a type `G`, it should be infeasible to find a procedure `f` that makes this function + /// return `true`: /// /// ```text - /// fn solve(g: G, a: G::Scalar, b: G::Scalar, f: F) -> bool + /// fn solve(g: G, a: S, b: S, f: F) -> bool /// where + /// G: ScalarMul, + /// S: Ring, /// F: FnOnce(G, G, G) -> G, /// { - /// f(g, g.mul(a), g.mul(b)) == g.mul(a.mul(b)) + /// f(g, g.scalar_mul(a), g.scalar_mul(b)) == g.scalar_mul(a.mul(b)) /// } /// ``` pub trait ComputationalDiffieHellmanHardness: DiscreteLogarithmHardness {} /// Decisional Diffie-Hellman Hardness Assumption /// - /// For a [`Group`](super::Group) `G`, it should be infeasible to distinguish the probability - /// distributions over the following two functions when [`G::Scalar](super::Group::Scalar) - /// inputs are sampled uniformly from their domain (and `g` the generator is fixed): + /// For a type `G`, it should be infeasible to distinguish the probability distributions over + /// the following two functions when scalar inputs are sampled uniformly from their domain (and + /// `g` the generator is fixed): /// /// ```text - /// fn dh_triple(g: G, a: G::Scalar, b: G::Scalar) -> (G, G, G) { - /// (g.mul(a), g.mul(b), g.mul(a.mul(b))) + /// fn dh_triple(g: G, a: S, b: S) -> (G, G, G) + /// where + /// G: ScalarMul, + /// S: Ring, + /// { + /// (g.scalar_mul(a), g.scalar_mul(b), g.scalar_mul(a.mul(b))) /// } /// - /// fn random_triple(g: G, a: G::Scalar, b: G::Scalar, c: G::Scalar) -> (G, G, G) { - /// (g.mul(a), g.mul(b), g.mul(c)) + /// fn random_triple(g: G, a: S, b: S, c: S) -> (G, G, G) + /// where + /// G: ScalarMul, + /// { + /// (g.scalar_mul(a), g.scalar_mul(b), g.scalar_mul(c)) /// } /// ``` pub trait DecisionalDiffieHellmanHardness: ComputationalDiffieHellmanHardness {} diff --git a/manta-crypto/src/arkworks/ff.rs b/manta-crypto/src/arkworks/ff.rs new file mode 100644 index 000000000..e9096bbd3 --- /dev/null +++ b/manta-crypto/src/arkworks/ff.rs @@ -0,0 +1,118 @@ +// Copyright 2019-2022 Manta Network. +// This file is part of manta-rs. +// +// manta-rs is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// manta-rs is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with manta-rs. If not, see . + +//! Arkworks Finite Field Backend + +use manta_util::{byte_count, into_array_unchecked}; + +#[doc(inline)] +pub use ark_ff::*; + +/// Implements a fallible conversion from `F` to `$type`. +macro_rules! field_try_into { + ($($name:ident => $type:tt),* $(,)?) => { + $( + #[doc = "Tries to convert a field element `x` into an integer of type `"] + #[doc = stringify!($type)] + #[doc = "`."] + #[inline] + pub fn $name(x: F) -> Option<$type> + where + F: PrimeField, + { + if x < F::from(2u8).pow([$type::BITS as u64]) { + let mut bytes = x.into_repr().to_bytes_le(); + bytes.truncate(byte_count($type::BITS) as usize); + Some($type::from_le_bytes(into_array_unchecked(bytes))) + } else { + None + } + } + )* + }; +} + +field_try_into! { + try_into_u8 => u8, + try_into_u16 => u16, + try_into_u32 => u32, + try_into_u64 => u64, + try_into_u128 => u128, +} + +/// Testing Suite +#[cfg(test)] +mod test { + use super::*; + use crate::rand::{OsRng, Rand, RngCore, Sample}; + use alloc::vec::Vec; + use core::fmt::Debug; + + /// Asserts that a single conversion of `value` specified by `convert` is correct. + #[inline] + pub fn assert_valid_integer_conversion(convert: C, value: T) + where + F: PrimeField, + T: Copy + Debug + Into + PartialEq, + C: Fn(F) -> Option, + { + assert_eq!( + convert(value.into()), + Some(value), + "Conversion should have been the inverse of the `F::into` function." + ); + } + + /// Asserts that the conversions specified by `convert` are valid. + #[inline] + pub fn assert_valid_integer_conversions( + convert: C, + test_vector: Vec, + rng: &mut R, + ) where + F: PrimeField, + T: Copy + Debug + Into + PartialEq + Sample, + C: Fn(F) -> Option, + R: RngCore + ?Sized, + { + for element in test_vector { + assert_valid_integer_conversion(&convert, element); + } + for _ in 0..ROUNDS { + assert_valid_integer_conversion(&convert, rng.gen()); + } + } + + /// Generates the conversion test for `$type` against the BN254 Curve. + macro_rules! generate_test { + ($name:ident, $convert:ident, $type:tt) => { + #[test] + fn $name() { + assert_valid_integer_conversions::( + $convert, + vec![0, 1, 2, $type::MAX - 2, $type::MAX - 1, $type::MAX], + &mut OsRng, + ); + } + }; + } + + generate_test!(u8_has_valid_conversions, try_into_u8, u8); + generate_test!(u16_has_valid_conversions, try_into_u16, u16); + generate_test!(u32_has_valid_conversions, try_into_u32, u32); + generate_test!(u64_has_valid_conversions, try_into_u64, u64); + generate_test!(u128_has_valid_conversions, try_into_u128, u128); +} diff --git a/manta-crypto/src/arkworks/mod.rs b/manta-crypto/src/arkworks/mod.rs index 228994f98..454070ac3 100644 --- a/manta-crypto/src/arkworks/mod.rs +++ b/manta-crypto/src/arkworks/mod.rs @@ -17,12 +17,12 @@ //! Arkworks Backend pub use ark_ec as ec; -pub use ark_ff as ff; pub use ark_r1cs_std as r1cs_std; pub use ark_relations as relations; pub use ark_serialize as serialize; pub mod algebra; pub mod constraint; +pub mod ff; pub mod pairing; pub mod rand; diff --git a/manta-crypto/src/constraint.rs b/manta-crypto/src/constraint.rs index 25f70d11c..536b4f1b7 100644 --- a/manta-crypto/src/constraint.rs +++ b/manta-crypto/src/constraint.rs @@ -84,12 +84,35 @@ pub trait ProofSystem { } /// Proof System Input -pub trait ProofSystemInput: ProofSystem +pub trait Input

+where + P: ProofSystem + ?Sized, +{ + /// Extends the `input` buffer with data from `self`. + fn extend(&self, input: &mut P::Input); +} + +/// Proof System Input Introspection +/// +/// This `trait` is automatically implemented for all [`T: Input`](Input) and cannot be +/// implemented manually. +pub trait HasInput: ProofSystem where T: ?Sized, { - /// Extend the `input` with the `next` element. - fn extend(input: &mut Self::Input, next: &T); + /// Extends the `input` buffer with data from `value`. + fn extend(input: &mut Self::Input, value: &T); +} + +impl HasInput for P +where + P: ProofSystem + ?Sized, + T: Input

+ ?Sized, +{ + #[inline] + fn extend(input: &mut Self::Input, value: &T) { + value.extend(input) + } } /// Constraint System Measurement @@ -114,6 +137,8 @@ pub mod measure { } } + impl Count for () {} + /// Constraint System Measurement pub trait Measure: Count + Count + Count { /// Returns the number of constraints stored in `self`. @@ -154,6 +179,13 @@ pub mod measure { } } + impl Measure for () { + #[inline] + fn constraint_count(&self) -> usize { + 0 + } + } + /// Constraint System Size Measurement #[cfg_attr( feature = "serde", @@ -242,6 +274,29 @@ pub mod measure { } } + /// Prints the measurement of the call to `f` with the given `label`. + #[cfg(feature = "std")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] + #[inline] + pub fn print_measurement(label: D, f: F, compiler: &mut COM) -> T + where + D: Display, + F: FnOnce(&mut COM) -> T, + COM: Measure, + { + let before = compiler.measure(); + let value = f(compiler); + println!( + "{}: {:?}", + label, + compiler + .measure() + .checked_sub(before) + .expect("Measurements should increase when adding more constraints.") + ); + value + } + /// Measurement Instrument pub struct Instrument<'c, COM> where diff --git a/manta-crypto/src/eclair/alloc.rs b/manta-crypto/src/eclair/alloc.rs index d2000924c..7c0129717 100644 --- a/manta-crypto/src/eclair/alloc.rs +++ b/manta-crypto/src/eclair/alloc.rs @@ -27,7 +27,9 @@ //! abstractions inside of compilers, like heap allocation. Allocation only refers to lifting //! constants and variables from one compiler to another. -use core::marker::PhantomData; +use alloc::{boxed::Box, vec::Vec}; +use core::{iter, marker::PhantomData}; +use manta_util::{into_array_unchecked, Array, BoxArray}; /// Constant Type Alias pub type Const = >::Type; @@ -38,7 +40,7 @@ pub type Const = >::Type; /// _compilation time_. In this case, we take an explicit value of the underlying type and directly /// return an allocated value in the `COM` compiler. Contrast this with [`Variable`] types whose /// values are not known at _compilation time_ and are only known at _execution time_. -pub trait Constant +pub trait Constant where COM: ?Sized, { @@ -49,6 +51,15 @@ where fn new_constant(this: &Self::Type, compiler: &mut COM) -> Self; } +impl Constant for bool { + type Type = bool; + + #[inline] + fn new_constant(this: &Self::Type, _: &mut ()) -> Self { + *this + } +} + impl Constant for () where COM: ?Sized, @@ -74,6 +85,75 @@ where } } +impl Constant for [T; N] +where + COM: ?Sized, + T: Constant, +{ + type Type = [T::Type; N]; + + #[inline] + fn new_constant(this: &Self::Type, compiler: &mut COM) -> Self { + into_array_unchecked( + this.iter() + .map(|this| this.as_constant(compiler)) + .collect::>(), + ) + } +} + +impl Constant for Vec +where + COM: ?Sized, + T: Constant, +{ + type Type = Vec; + + #[inline] + fn new_constant(this: &Self::Type, compiler: &mut COM) -> Self { + this.iter().map(|this| this.as_constant(compiler)).collect() + } +} + +impl Constant for Box<[T]> +where + COM: ?Sized, + T: Constant, +{ + type Type = Box<[T::Type]>; + + #[inline] + fn new_constant(this: &Self::Type, compiler: &mut COM) -> Self { + this.iter().map(|this| this.as_constant(compiler)).collect() + } +} + +impl Constant for Array +where + COM: ?Sized, + T: Constant, +{ + type Type = Array; + + #[inline] + fn new_constant(this: &Self::Type, compiler: &mut COM) -> Self { + this.iter().map(|this| this.as_constant(compiler)).collect() + } +} + +impl Constant for BoxArray +where + COM: ?Sized, + T: Constant, +{ + type Type = Array; + + #[inline] + fn new_constant(this: &Self::Type, compiler: &mut COM) -> Self { + this.iter().map(|this| this.as_constant(compiler)).collect() + } +} + /// Variable Type Alias pub type Var = >::Type; @@ -90,7 +170,7 @@ pub type Var = >::Type; /// The tag `M` in the type parameters of this trait refers to the [`Variable`]'s allocation mode. /// See the [`mode`] module for more details on why allocation modes are necessary and useful and /// how to use them. -pub trait Variable +pub trait Variable where COM: ?Sized, { @@ -144,6 +224,90 @@ where } } +impl Variable for Box +where + COM: ?Sized, + T: Variable, +{ + type Type = Box; + + #[inline] + fn new_unknown(compiler: &mut COM) -> Self { + Self::new(compiler.allocate_unknown()) + } + + #[inline] + fn new_known(this: &Self::Type, compiler: &mut COM) -> Self { + Self::new(T::new_known(this, compiler)) + } +} + +impl Variable for [T; N] +where + COM: ?Sized, + T: Variable, +{ + type Type = [T::Type; N]; + + #[inline] + fn new_unknown(compiler: &mut COM) -> Self { + into_array_unchecked( + iter::repeat_with(|| compiler.allocate_unknown()) + .take(N) + .collect::>(), + ) + } + + #[inline] + fn new_known(this: &Self::Type, compiler: &mut COM) -> Self { + into_array_unchecked( + this.iter() + .map(|this| this.as_known(compiler)) + .collect::>(), + ) + } +} + +impl Variable for Array +where + COM: ?Sized, + T: Variable, +{ + type Type = Array; + + #[inline] + fn new_unknown(compiler: &mut COM) -> Self { + iter::repeat_with(|| compiler.allocate_unknown()) + .take(N) + .collect() + } + + #[inline] + fn new_known(this: &Self::Type, compiler: &mut COM) -> Self { + this.iter().map(|this| this.as_known(compiler)).collect() + } +} + +impl Variable for BoxArray +where + COM: ?Sized, + T: Variable, +{ + type Type = BoxArray; + + #[inline] + fn new_unknown(compiler: &mut COM) -> Self { + iter::repeat_with(|| compiler.allocate_unknown()) + .take(N) + .collect() + } + + #[inline] + fn new_known(this: &Self::Type, compiler: &mut COM) -> Self { + this.iter().map(|this| this.as_known(compiler)).collect() + } +} + /// Allocation Auto-`trait` /// /// Allocation schemes are built up from the individual variables which can be allocated into a @@ -153,7 +317,7 @@ where /// /// See [`Constant`] and [`Variable`] for more details on including a specific variable in the /// allocation scheme for a compiler. -pub trait Allocate +pub trait Allocate where COM: ?Sized, { @@ -191,7 +355,12 @@ where } } -impl Allocate for T where T: ?Sized {} +impl Allocate for T +where + COM: ?Sized, + T: ?Sized, +{ +} /// Allocator Auto-`trait` /// diff --git a/manta-crypto/src/eclair/bool.rs b/manta-crypto/src/eclair/bool.rs index c0050bd17..582ac9adc 100644 --- a/manta-crypto/src/eclair/bool.rs +++ b/manta-crypto/src/eclair/bool.rs @@ -20,10 +20,10 @@ //! types. In this module, we define the access interfaces needed to simulate the [`bool`] type with //! [`Bool`]. -use crate::eclair::{cmp::PartialEq, Has}; +use crate::eclair::{cmp::PartialEq, Has, Type}; /// Boolean Type Inside of the Compiler -pub type Bool = >::Type; +pub type Bool = Type; /// Assertion pub trait Assert: Has { @@ -42,6 +42,13 @@ pub trait Assert: Has { } } +impl Assert for () { + #[inline] + fn assert(&mut self, bit: &bool) { + assert!(bit) + } +} + /// Equality Assertion pub trait AssertEq: Assert { /// Asserts that `lhs` and `rhs` are equal. @@ -91,6 +98,26 @@ where fn select(bit: &Bool, true_value: &Self, false_value: &Self, compiler: &mut COM) -> Self; } +/// Implements [`ConditionalSelect`] for the given `$type`. +macro_rules! impl_conditional_select { + ($($type:tt),* $(,)?) => { + $( + impl ConditionalSelect for $type { + #[inline] + fn select(bit: &Bool, true_value: &Self, false_value: &Self, _: &mut ()) -> Self { + if *bit { + true_value.clone() + } else { + false_value.clone() + } + } + } + )* + } +} + +impl_conditional_select!(bool, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128); + /// Conditional Swap pub trait ConditionalSwap: Sized where diff --git a/manta-crypto/src/eclair/cmp.rs b/manta-crypto/src/eclair/cmp.rs index 66ece418d..31aeae3c8 100644 --- a/manta-crypto/src/eclair/cmp.rs +++ b/manta-crypto/src/eclair/cmp.rs @@ -17,10 +17,14 @@ //! Comparison use crate::eclair::{ - bool::{Assert, Bool}, - ops::Not, + alloc::{Allocate, Constant}, + bool::{Assert, AssertEq, Bool}, + ops::{BitAnd, Not}, Has, }; +use alloc::{boxed::Box, vec::Vec}; +use core::cmp; +use manta_util::{Array, BoxArray}; /// Partial Equivalence Relations pub trait PartialEq @@ -56,22 +60,151 @@ where } } -/* TODO: -impl PartialEq for T +/// Implements [`PartialEq`] for the given `$type`. +macro_rules! impl_partial_eq { + ($($type:tt),* $(,)?) => { + $( + impl PartialEq for $type + where + $type: cmp::PartialEq, + { + #[inline] + fn eq(&self, rhs: &Rhs, _: &mut ()) -> bool { + cmp::PartialEq::eq(self, rhs) + } + + #[inline] + fn ne(&self, rhs: &Rhs, _: &mut ()) -> bool { + cmp::PartialEq::ne(self, rhs) + } + } + )* + }; +} + +impl_partial_eq!(bool, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128); + +impl PartialEq, COM> for Vec +where + COM: Has, + Bool: Constant + BitAnd, COM, Output = Bool>, + T: PartialEq, +{ + #[inline] + fn eq(&self, rhs: &Vec, compiler: &mut COM) -> Bool { + if self.len() != rhs.len() { + false.as_constant(compiler) + } else { + let mut are_equal = true.as_constant::>(compiler); + for (lhs, rhs) in self.iter().zip(rhs) { + are_equal = are_equal.bitand(lhs.eq(rhs, compiler), compiler); + } + are_equal + } + } + + #[inline] + fn assert_equal(&self, rhs: &Vec, compiler: &mut COM) + where + COM: Assert, + { + if self.len() != rhs.len() { + let not_equal = false.as_constant(compiler); + compiler.assert(¬_equal); + } else { + for (lhs, rhs) in self.iter().zip(rhs) { + compiler.assert_eq(lhs, rhs); + } + } + } +} + +impl PartialEq, COM> for Box<[T]> +where + COM: Has, + Bool: Constant + BitAnd, COM, Output = Bool>, + T: PartialEq, +{ + #[inline] + fn eq(&self, rhs: &Box<[Rhs]>, compiler: &mut COM) -> Bool { + if self.len() != rhs.len() { + false.as_constant(compiler) + } else { + let mut are_equal = true.as_constant::>(compiler); + for (lhs, rhs) in self.iter().zip(rhs.iter()) { + are_equal = are_equal.bitand(lhs.eq(rhs, compiler), compiler); + } + are_equal + } + } + + #[inline] + fn assert_equal(&self, rhs: &Box<[Rhs]>, compiler: &mut COM) + where + COM: Assert, + { + if self.len() != rhs.len() { + let not_equal = false.as_constant(compiler); + compiler.assert(¬_equal); + } else { + for (lhs, rhs) in self.iter().zip(rhs.iter()) { + compiler.assert_eq(lhs, rhs); + } + } + } +} + +impl PartialEq, COM> for Array +where + COM: Has, + Bool: Constant + BitAnd, COM, Output = Bool>, + T: PartialEq, +{ + #[inline] + fn eq(&self, rhs: &Array, compiler: &mut COM) -> Bool { + let mut are_equal = true.as_constant::>(compiler); + for (lhs, rhs) in self.iter().zip(rhs) { + are_equal = are_equal.bitand(lhs.eq(rhs, compiler), compiler); + } + are_equal + } + + #[inline] + fn assert_equal(&self, rhs: &Array, compiler: &mut COM) + where + COM: Assert, + { + for (lhs, rhs) in self.iter().zip(rhs) { + compiler.assert_eq(lhs, rhs); + } + } +} + +impl PartialEq, COM> for BoxArray where - T: cmp::PartialEq, + COM: Has, + Bool: Constant + BitAnd, COM, Output = Bool>, + T: PartialEq, { #[inline] - fn eq(&self, rhs: &Rhs, _: &mut ()) -> bool { - self.eq(rhs) + fn eq(&self, rhs: &BoxArray, compiler: &mut COM) -> Bool { + let mut are_equal = true.as_constant::>(compiler); + for (lhs, rhs) in self.iter().zip(rhs) { + are_equal = are_equal.bitand(lhs.eq(rhs, compiler), compiler); + } + are_equal } #[inline] - fn ne(&self, rhs: &Rhs, _: &mut ()) -> bool { - self.ne(rhs) + fn assert_equal(&self, rhs: &BoxArray, compiler: &mut COM) + where + COM: Assert, + { + for (lhs, rhs) in self.iter().zip(rhs) { + compiler.assert_eq(lhs, rhs); + } } } -*/ /// Equality pub trait Eq: PartialEq @@ -79,7 +212,3 @@ where COM: Has, { } - -/* TODO: -impl Eq for T where T: cmp::Eq {} -*/ diff --git a/manta-crypto/src/eclair/mod.rs b/manta-crypto/src/eclair/mod.rs index bdbc2c2d7..db9df8ab9 100644 --- a/manta-crypto/src/eclair/mod.rs +++ b/manta-crypto/src/eclair/mod.rs @@ -46,6 +46,22 @@ impl Native for () { /// This `trait` is explicitly not implemented for `()`, the default native compiler. This marker /// can be used to write explicitly different implementations for native and non-native compilers /// where otherwise a generic implementation would have to exist. +/// +/// # Limitations +/// +/// This is an emulation of an unimplemented feature of rust called ["negative trait bounds"]. As it +/// currently stands, the compiler will make instances of [`NonNative`] outside of the ECLAIR crate +/// unusable as you'll run into [error 0119] which has the following notice: +/// +/// ```text +/// note: upstream crates may add a new impl of trait `NonNative` for type `()` in future versions +/// ``` +/// +/// Even though this trait will never be implemented for `()`, there's no way the Rust compiler can +/// know this. As of right now, we can only use this `trait` internally to this crate. +/// +/// ["negative trait bounds"]: https://doc.rust-lang.org/beta/unstable-book/language-features/negative-impls.html +/// [error 0119]: https://doc.rust-lang.org/error-index.html#E0119 pub trait NonNative {} /// Compiler Type Introspection @@ -67,3 +83,6 @@ pub trait Has { impl Has for () { type Type = T; } + +/// Compiler Introspected Type +pub type Type = >::Type; diff --git a/manta-crypto/src/eclair/num.rs b/manta-crypto/src/eclair/num.rs index 507bec67f..5e04426a7 100644 --- a/manta-crypto/src/eclair/num.rs +++ b/manta-crypto/src/eclair/num.rs @@ -16,7 +16,13 @@ //! Numeric Types and Traits -use crate::eclair::ops::{Add, AddAssign, Mul, MulAssign}; +use crate::eclair::{ + alloc::{Allocator, Variable}, + bool::{Assert, Bool, ConditionalSelect, ConditionalSwap}, + cmp::PartialEq, + ops::{Add, AddAssign, Mul, MulAssign, Not}, + Has, +}; use core::{borrow::Borrow, ops::Deref}; /// Additive Identity @@ -24,22 +30,99 @@ pub trait Zero { /// Verification Type type Verification; + /// Returns the additive identity for `Self`. + fn zero(compiler: &mut COM) -> Self; + /// Returns a truthy value if `self` is equal to the additive identity. fn is_zero(&self, compiler: &mut COM) -> Self::Verification; } +impl Zero for bool { + type Verification = bool; + + #[inline] + fn zero(_: &mut ()) -> Self { + false + } + + #[inline] + fn is_zero(&self, _: &mut ()) -> Self::Verification { + !(*self) + } +} + /// Multiplicative Identity pub trait One { /// Verification Type type Verification; + /// Returns the multiplicative identity for `Self`. + fn one(compiler: &mut COM) -> Self; + /// Returns a truthy value if `self` is equal to the multiplicative identity. fn is_one(&self, compiler: &mut COM) -> Self::Verification; } +impl One for bool { + type Verification = bool; + + #[inline] + fn one(_: &mut ()) -> Self { + true + } + + #[inline] + fn is_one(&self, _: &mut ()) -> Self::Verification { + *self + } +} + +/// Defines an implementation for [`Zero`] and [`One`] for integers. +macro_rules! define_zero_one { + ($($type:tt),* $(,)?) => { + $( + impl Zero for $type { + type Verification = bool; + + #[inline] + fn zero(_: &mut ()) -> Self { + 0 + } + + #[inline] + fn is_zero(&self, compiler: &mut ()) -> Self::Verification { + *self == Self::zero(compiler) + } + } + + impl One for $type { + type Verification = bool; + + #[inline] + fn one(_: &mut ()) -> Self { + 1 + } + + #[inline] + fn is_one(&self, compiler: &mut ()) -> Self::Verification { + *self == Self::one(compiler) + } + } + )* + } +} + +define_zero_one!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128); + /// Within-Bit-Range Assertion +/// +/// # Restrictions +/// +/// This `trait` assumes that `BITS > 0` and does not currently support `BITS = 0`. In this case +/// we would have an assertion that `x < 2^0 = 1` which is just that `x = 0` in most systems. For +/// this usecase, the [`Zero`] `trait` should be considered instead. pub trait AssertWithinBitRange { - /// Asserts that `value` is smaller than `2^BITS` + /// Asserts that `value` is smaller than `2^BITS`. fn assert_within_range(&mut self, value: &T); } @@ -180,6 +263,90 @@ where } } +impl Zero for UnsignedInteger +where + T: Zero, +{ + type Verification = T::Verification; + + #[inline] + fn zero(compiler: &mut COM) -> Self { + Self::new_unchecked(T::zero(compiler)) + } + + #[inline] + fn is_zero(&self, compiler: &mut COM) -> Self::Verification { + self.0.is_zero(compiler) + } +} + +impl One for UnsignedInteger +where + T: One, +{ + type Verification = T::Verification; + + #[inline] + fn one(compiler: &mut COM) -> Self { + Self::new_unchecked(T::one(compiler)) + } + + #[inline] + fn is_one(&self, compiler: &mut COM) -> Self::Verification { + self.0.is_one(compiler) + } +} + +impl PartialEq for UnsignedInteger +where + COM: Has, + T: PartialEq, +{ + #[inline] + fn eq(&self, rhs: &Self, compiler: &mut COM) -> Bool { + self.0.eq(&rhs.0, compiler) + } + + #[inline] + fn ne(&self, rhs: &Self, compiler: &mut COM) -> Bool + where + Bool: Not>, + { + self.0.ne(&rhs.0, compiler) + } + + #[inline] + fn assert_equal(&self, rhs: &Self, compiler: &mut COM) + where + COM: Assert, + { + self.0.assert_equal(&rhs.0, compiler) + } +} + +impl ConditionalSelect for UnsignedInteger +where + COM: Has, + T: ConditionalSelect, +{ + #[inline] + fn select(bit: &Bool, true_value: &Self, false_value: &Self, compiler: &mut COM) -> Self { + Self::new_unchecked(T::select(bit, &true_value.0, &false_value.0, compiler)) + } +} + +impl ConditionalSwap for UnsignedInteger +where + COM: Has, + T: ConditionalSwap, +{ + #[inline] + fn swap(bit: &Bool, lhs: &Self, rhs: &Self, compiler: &mut COM) -> (Self, Self) { + let (lhs, rhs) = T::swap(bit, &lhs.0, &rhs.0, compiler); + (Self::new_unchecked(lhs), Self::new_unchecked(rhs)) + } +} + /// Defines [`UnsignedInteger`] types for the given number of `$bits`. macro_rules! define_uint { ($($name:ident, $bits:expr),* $(,)?) => { @@ -202,3 +369,32 @@ define_uint!( U190, 190, U200, 200, U210, 210, U220, 220, U230, 230, U240, 240, U250, 250, U251, 251, U252, 252, U253, 253, U254, 254, U255, 255, U256, 256, ); + +/// Defines [`Variable`] allocation implementation for [`UnsignedInteger`] whenever it has a native +/// Rust counterpart. +macro_rules! define_uint_allocation { + ($($type:tt, $bits:expr),* $(,)?) => { + $( + impl Variable for UnsignedInteger + where + COM: AssertWithinBitRange, + T: Variable, + T::Type: From<$type>, + { + type Type = $type; + + #[inline] + fn new_unknown(compiler: &mut COM) -> Self { + Self::new(compiler.allocate_unknown(), compiler) + } + + #[inline] + fn new_known(this: &Self::Type, compiler: &mut COM) -> Self { + Self::new(compiler.allocate_known(&(*this).into()), compiler) + } + } + )* + }; +} + +define_uint_allocation!(u8, 8, u16, 16, u32, 32, u64, 64, u128, 128); diff --git a/manta-crypto/src/encryption/hybrid.rs b/manta-crypto/src/encryption/hybrid.rs index a6308fd69..1141f794a 100644 --- a/manta-crypto/src/encryption/hybrid.rs +++ b/manta-crypto/src/encryption/hybrid.rs @@ -21,9 +21,13 @@ //! encryption scheme inlines this complexity into the encryption interfaces. use crate::{ + constraint::{HasInput, Input}, eclair::{ self, - alloc::{mode::Derived, Allocate, Allocator, Constant, Var, Variable}, + alloc::{ + mode::{Derived, Public, Secret}, + Allocate, Allocator, Constant, Var, Variable, + }, bool::{Assert, AssertEq, Bool}, ops::BitAnd, Has, @@ -118,6 +122,28 @@ where } } +impl Variable for Randomness +where + K: key::agreement::Types + Constant, + E: Constant + RandomnessType, + K::SecretKey: Variable, + E::Randomness: Variable, + K::Type: key::agreement::Types>, + E::Type: RandomnessType>, +{ + type Type = Randomness; + + #[inline] + fn new_unknown(compiler: &mut COM) -> Self { + Variable::, COM>::new_unknown(compiler) + } + + #[inline] + fn new_known(this: &Self::Type, compiler: &mut COM) -> Self { + Variable::, COM>::new_known(this, compiler) + } +} + impl Variable, COM> for Randomness where K: key::agreement::Types + Constant, @@ -228,6 +254,28 @@ where } } +impl Variable for Ciphertext +where + K: key::agreement::Types + Constant, + E: CiphertextType + Constant, + K::PublicKey: Variable, + E::Ciphertext: Variable, + K::Type: key::agreement::Types>, + E::Type: CiphertextType>, +{ + type Type = Ciphertext; + + #[inline] + fn new_unknown(compiler: &mut COM) -> Self { + Variable::, COM>::new_unknown(compiler) + } + + #[inline] + fn new_known(this: &Self::Type, compiler: &mut COM) -> Self { + Variable::, COM>::new_known(this, compiler) + } +} + impl Variable, COM> for Ciphertext where K: key::agreement::Types + Constant, @@ -253,6 +301,37 @@ where } } +impl Encode for Ciphertext +where + K: key::agreement::Types, + K::PublicKey: Encode, + E: CiphertextType, + E::Ciphertext: Encode, +{ + #[inline] + fn encode(&self, mut writer: W) -> Result<(), W::Error> + where + W: Write, + { + self.ephemeral_public_key.encode(&mut writer)?; + self.ciphertext.encode(&mut writer)?; + Ok(()) + } +} + +impl Input

for Ciphertext +where + K: key::agreement::Types, + E: CiphertextType, + P: HasInput + HasInput + ?Sized, +{ + #[inline] + fn extend(&self, input: &mut P::Input) { + P::extend(input, &self.ephemeral_public_key); + P::extend(input, &self.ciphertext); + } +} + /// Hybrid Encryption Scheme #[cfg_attr( feature = "serde", diff --git a/manta-crypto/src/encryption/mod.rs b/manta-crypto/src/encryption/mod.rs index 5e4a5039b..0eafb300b 100644 --- a/manta-crypto/src/encryption/mod.rs +++ b/manta-crypto/src/encryption/mod.rs @@ -21,6 +21,7 @@ //! [`Decrypt`] `trait`s for more. use crate::{ + constraint::{HasInput, Input, ProofSystem}, eclair::{ self, alloc::{ @@ -33,7 +34,8 @@ use crate::{ }, rand::{Rand, RngCore, Sample}, }; -use core::{fmt::Debug, hash::Hash}; +use core::{fmt::Debug, hash::Hash, marker::PhantomData}; +use manta_util::codec::{Encode, Write}; #[cfg(feature = "serde")] use manta_util::serde::{Deserialize, Serialize}; @@ -67,6 +69,81 @@ where /// Header Type pub type Header = ::Header; +/// Empty Header +#[derive(derivative::Derivative)] +#[derivative(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct EmptyHeader(PhantomData); + +impl Constant for EmptyHeader { + type Type = EmptyHeader; + + #[inline] + fn new_constant(this: &Self::Type, compiler: &mut COM) -> Self { + let _ = (this, compiler); + Self::default() + } +} + +impl Variable for EmptyHeader { + type Type = EmptyHeader; + + #[inline] + fn new_unknown(compiler: &mut COM) -> Self { + let _ = compiler; + Self::default() + } + + #[inline] + fn new_known(this: &Self::Type, compiler: &mut COM) -> Self { + let _ = (this, compiler); + Self::default() + } +} + +impl eclair::cmp::PartialEq for EmptyHeader +where + COM: Has, + Bool: Constant, +{ + #[inline] + fn eq(&self, rhs: &Self, compiler: &mut COM) -> Bool { + let _ = rhs; + Bool::::new_constant(&true, compiler) + } + + #[inline] + fn ne(&self, rhs: &Self, compiler: &mut COM) -> Bool { + let _ = rhs; + Bool::::new_constant(&false, compiler) + } + + #[inline] + fn assert_equal(&self, rhs: &Self, compiler: &mut COM) { + let _ = (rhs, compiler); + } +} + +impl Encode for EmptyHeader { + #[inline] + fn encode(&self, writer: W) -> Result<(), W::Error> + where + W: Write, + { + let _ = writer; + Ok(()) + } +} + +impl

Input

for EmptyHeader +where + P: ProofSystem + ?Sized, +{ + #[inline] + fn extend(&self, input: &mut P::Input) { + let _ = input; + } +} + /// Ciphertext /// /// The ciphertext type represents the piece of the encrypt-decrypt interface that contains the @@ -526,21 +603,6 @@ where { } -impl Sample<(H, C)> for EncryptedMessage -where - E: CiphertextType + HeaderType, - E::Header: Sample, - E::Ciphertext: Sample, -{ - #[inline] - fn sample(distribution: (H, C), rng: &mut R) -> Self - where - R: RngCore + ?Sized, - { - Self::new(rng.sample(distribution.0), rng.sample(distribution.1)) - } -} - impl Variable, COM> for EncryptedMessage where E: CiphertextType + HeaderType + Constant, @@ -577,15 +639,56 @@ where #[inline] fn new_unknown(compiler: &mut COM) -> Self { - Self::new(compiler.allocate_unknown(), compiler.allocate_unknown()) + Variable::, _>::new_unknown(compiler) } #[inline] fn new_known(this: &Self::Type, compiler: &mut COM) -> Self { - Self::new( - this.header.as_known(compiler), - this.ciphertext.as_known(compiler), - ) + Variable::, _>::new_known(this, compiler) + } +} + +impl Sample<(H, C)> for EncryptedMessage +where + E: CiphertextType + HeaderType, + E::Header: Sample, + E::Ciphertext: Sample, +{ + #[inline] + fn sample(distribution: (H, C), rng: &mut R) -> Self + where + R: RngCore + ?Sized, + { + Self::new(rng.sample(distribution.0), rng.sample(distribution.1)) + } +} + +impl Encode for EncryptedMessage +where + E: CiphertextType + HeaderType, + E::Header: Encode, + E::Ciphertext: Encode, +{ + #[inline] + fn encode(&self, mut writer: W) -> Result<(), W::Error> + where + W: Write, + { + self.header.encode(&mut writer)?; + self.ciphertext.encode(&mut writer)?; + Ok(()) + } +} + +impl Input

for EncryptedMessage +where + E: CiphertextType + HeaderType, + P: HasInput + HasInput + ?Sized, +{ + #[inline] + fn extend(&self, input: &mut P::Input) { + P::extend(input, &self.header); + P::extend(input, &self.ciphertext); } } diff --git a/manta-crypto/src/key.rs b/manta-crypto/src/key.rs index 0eb147c63..288d85cdc 100644 --- a/manta-crypto/src/key.rs +++ b/manta-crypto/src/key.rs @@ -117,9 +117,11 @@ pub mod agreement { /// Key Derivation Functions pub mod kdf { use crate::rand::{RngCore, Sample}; - use alloc::vec::Vec; use core::marker::PhantomData; - use manta_util::codec::{Decode, DecodeError, Encode, Read, Write}; + use manta_util::{ + codec::{Decode, DecodeError, Encode, Read, Write}, + AsBytes, + }; #[cfg(feature = "serde")] use manta_util::serde::{Deserialize, Serialize}; @@ -175,12 +177,6 @@ pub mod kdf { } } - /// Byte Conversion Trait - pub trait AsBytes { - /// Returns an owned byte representation of `self`. - fn as_bytes(&self) -> Vec; - } - /// From Byte Vector Adapter #[cfg_attr( feature = "serde", diff --git a/manta-crypto/src/merkle_tree/forest.rs b/manta-crypto/src/merkle_tree/forest.rs index de2d946b5..975dce3b0 100644 --- a/manta-crypto/src/merkle_tree/forest.rs +++ b/manta-crypto/src/merkle_tree/forest.rs @@ -24,13 +24,14 @@ use crate::{ accumulator::{ - Accumulator, ConstantCapacityAccumulator, ExactSizeAccumulator, MembershipProof, + self, Accumulator, ConstantCapacityAccumulator, ExactSizeAccumulator, MembershipProof, OptimizedAccumulator, }, merkle_tree::{ fork::ForkedTree, inner_tree::InnerMap, - tree::{self, Leaf, Parameters, Tree}, + path::Path, + tree::{self, Leaf, Parameters, Root, Tree}, InnerDigest, LeafDigest, WithProofs, }, }; @@ -288,6 +289,16 @@ where } } +impl accumulator::Types for MerkleForest +where + C: Configuration + ?Sized, + F: Forest, +{ + type Item = Leaf; + type Witness = Path; + type Output = Root; +} + impl Accumulator for MerkleForest where C: Configuration + ?Sized, @@ -295,7 +306,6 @@ where F::Tree: WithProofs, InnerDigest: Clone + PartialEq, { - type Item = Leaf; type Model = Parameters; #[inline] @@ -310,11 +320,6 @@ where .push_provable(&self.parameters, item) } - #[inline] - fn are_independent(&self, fst: &Self::Item, snd: &Self::Item) -> bool { - C::tree_index(fst) != C::tree_index(snd) - } - #[inline] fn prove(&self, item: &Self::Item) -> Option> { let tree = self.forest.get_tree(item); diff --git a/manta-crypto/src/merkle_tree/tree.rs b/manta-crypto/src/merkle_tree/tree.rs index be468b41b..e8fc877ac 100644 --- a/manta-crypto/src/merkle_tree/tree.rs +++ b/manta-crypto/src/merkle_tree/tree.rs @@ -1046,13 +1046,22 @@ where } } +impl accumulator::Types for MerkleTree +where + C: Configuration + ?Sized, + T: Tree, +{ + type Item = Leaf; + type Witness = Path; + type Output = Root; +} + impl Accumulator for MerkleTree where C: Configuration + ?Sized, T: Tree + WithProofs, InnerDigest: Clone + PartialEq, { - type Item = Leaf; type Model = Parameters; #[inline] diff --git a/manta-crypto/src/permutation/duplex.rs b/manta-crypto/src/permutation/duplex.rs index 68b66afd0..90844a7fb 100644 --- a/manta-crypto/src/permutation/duplex.rs +++ b/manta-crypto/src/permutation/duplex.rs @@ -20,6 +20,14 @@ // dropping it on decryption. use crate::{ + constraint::{HasInput, Input}, + eclair::{ + self, + alloc::{mode::Public, Allocate, Allocator, Constant, Variable}, + bool::{Assert, AssertEq, Bool}, + ops::BitAnd, + Has, + }, encryption::{ CiphertextType, Decrypt, DecryptedPlaintextType, DecryptionKeyType, Encrypt, EncryptionKeyType, HeaderType, PlaintextType, RandomnessType, @@ -28,9 +36,14 @@ use crate::{ sponge::{Read, Sponge, Write}, PseudorandomPermutation, }, + rand::{Rand, RngCore, Sample}, }; use alloc::vec::Vec; use core::marker::PhantomData; +use manta_util::{ + codec::{self, Encode}, + iter::{BorrowIterator, Iterable}, +}; #[cfg(feature = "serde")] use manta_util::serde::{Deserialize, Serialize}; @@ -58,9 +71,15 @@ where /// Plaintext Block Type type PlaintextBlock: Write; + /// Plaintext Type + type Plaintext: FromIterator + BorrowIterator; + /// Ciphertext Block Type type CiphertextBlock: Write; + /// Ciphertext Type + type Ciphertext: FromIterator + BorrowIterator; + /// Authentication Tag Type type Tag: Read; } @@ -116,6 +135,83 @@ pub struct Ciphertext { pub message: C, } +impl Ciphertext { + /// Builds a new [`Ciphertext`] from `tag` and `message`. + #[inline] + pub fn new(tag: T, message: C) -> Self { + Self { tag, message } + } +} + +impl eclair::cmp::PartialEq for Ciphertext +where + COM: Has, + Bool: BitAnd, COM, Output = Bool>, + T: eclair::cmp::PartialEq, + C: eclair::cmp::PartialEq, +{ + #[inline] + fn eq(&self, rhs: &Self, compiler: &mut COM) -> Bool { + self.tag + .eq(&rhs.tag, compiler) + .bitand(self.message.eq(&rhs.message, compiler), compiler) + } + + #[inline] + fn assert_equal(&self, rhs: &Self, compiler: &mut COM) + where + COM: Assert, + { + compiler.assert_eq(&self.tag, &rhs.tag); + compiler.assert_eq(&self.message, &rhs.message); + } +} + +impl Variable for Ciphertext +where + T: Variable, + C: Variable, +{ + type Type = Ciphertext; + + #[inline] + fn new_unknown(compiler: &mut COM) -> Self { + Self::new(compiler.allocate_unknown(), compiler.allocate_unknown()) + } + + #[inline] + fn new_known(this: &Self::Type, compiler: &mut COM) -> Self { + Self::new(this.tag.as_known(compiler), this.message.as_known(compiler)) + } +} + +impl Encode for Ciphertext +where + T: Encode, + C: Encode, +{ + #[inline] + fn encode(&self, mut writer: W) -> Result<(), W::Error> + where + W: codec::Write, + { + self.tag.encode(&mut writer)?; + self.message.encode(&mut writer)?; + Ok(()) + } +} + +impl Input

for Ciphertext +where + P: HasInput + HasInput + ?Sized, +{ + #[inline] + fn extend(&self, input: &mut P::Input) { + P::extend(input, &self.tag); + P::extend(input, &self.message); + } +} + /// Duplex Sponge Authenticated Encryption Scheme #[cfg_attr( feature = "serde", @@ -174,14 +270,15 @@ where &self, key: &C::Key, header: &C::Header, - plaintext: &[C::PlaintextBlock], + plaintext: &C::Plaintext, compiler: &mut COM, - ) -> (C::Tag, Vec) + ) -> (C::Tag, C::Ciphertext) where C: Setup, { let mut state = self.setup(key, header, compiler); - let ciphertext = Sponge::new(&self.permutation, &mut state).absorb_all(plaintext, compiler); + let ciphertext = + Sponge::new(&self.permutation, &mut state).absorb_all(plaintext.iter(), compiler); (C::Tag::read(&state, compiler), ciphertext) } @@ -192,18 +289,51 @@ where &self, key: &C::Key, header: &C::Header, - ciphertext: &[C::CiphertextBlock], + ciphertext: &C::Ciphertext, compiler: &mut COM, - ) -> (C::Tag, Vec) + ) -> (C::Tag, C::Plaintext) where C: Setup, { let mut state = self.setup(key, header, compiler); - let plaintext = Sponge::new(&self.permutation, &mut state).absorb_all(ciphertext, compiler); + let plaintext = + Sponge::new(&self.permutation, &mut state).absorb_all(ciphertext.iter(), compiler); (C::Tag::read(&state, compiler), plaintext) } } +impl Constant for Duplexer +where + P: PseudorandomPermutation + Constant, + C: Types + Constant, + P::Type: PseudorandomPermutation, + C::Type: Types, +{ + type Type = Duplexer; + + #[inline] + fn new_constant(this: &Self::Type, compiler: &mut COM) -> Self { + Self::new( + this.permutation.as_constant(compiler), + this.configuration.as_constant(compiler), + ) + } +} + +impl Sample<(DP, DC)> for Duplexer +where + P: PseudorandomPermutation + Sample, + C: Sample + Types

, +{ + #[inline] + fn sample(distribution: (DP, DC), rng: &mut R) -> Self + where + R: RngCore + ?Sized, + { + Self::new(rng.sample(distribution.0), rng.sample(distribution.1)) + } +} + impl HeaderType for Duplexer where P: PseudorandomPermutation, @@ -217,7 +347,7 @@ where P: PseudorandomPermutation, C: Types, { - type Ciphertext = Ciphertext>; + type Ciphertext = Ciphertext; } impl EncryptionKeyType for Duplexer @@ -241,7 +371,7 @@ where P: PseudorandomPermutation, C: Types, { - type Plaintext = Vec; + type Plaintext = C::Plaintext; } impl RandomnessType for Duplexer @@ -261,7 +391,7 @@ where P: PseudorandomPermutation, C: Verify, { - type DecryptedPlaintext = (C::Verification, Vec); + type DecryptedPlaintext = (C::Verification, C::Plaintext); } impl Encrypt for Duplexer diff --git a/manta-crypto/src/rand.rs b/manta-crypto/src/rand.rs index a2931c690..cd0a6899c 100644 --- a/manta-crypto/src/rand.rs +++ b/manta-crypto/src/rand.rs @@ -223,6 +223,27 @@ pub trait Sample: Sized { } } +impl Sample for PhantomData { + #[inline] + fn sample(distribution: D, rng: &mut R) -> Self + where + R: RngCore + ?Sized, + { + let _ = (distribution, rng); + Self + } +} + +impl Sample for () { + #[inline] + fn sample(distribution: D, rng: &mut R) -> Self + where + R: RngCore + ?Sized, + { + let _ = (distribution, rng); + } +} + impl Sample for bool { #[inline] fn sample(_: (), rng: &mut R) -> Self diff --git a/manta-crypto/src/signature/convert.rs b/manta-crypto/src/signature/convert.rs new file mode 100644 index 000000000..96f9b3595 --- /dev/null +++ b/manta-crypto/src/signature/convert.rs @@ -0,0 +1,232 @@ +// Copyright 2019-2022 Manta Network. +// This file is part of manta-rs. +// +// manta-rs is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// manta-rs is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with manta-rs. If not, see . + +//! Signature Scheme Message Conversion Primitives and Adapters + +use crate::{ + eclair::alloc::Constant, + rand::{Rand, RngCore, Sample}, + signature::{ + Derive, MessageType, RandomnessType, Sign, SignatureType, SigningKeyType, Verify, + VerifyingKeyType, + }, +}; +use core::marker::PhantomData; +use manta_util::codec::{Decode, DecodeError, Encode, Read, Write}; + +#[cfg(feature = "serde")] +use manta_util::serde::{Deserialize, Serialize}; + +/// Forward Conversion +/// +/// When signing a message over [`TargetMessage`] we can apply the [`as_target`] conversion function +/// to objects of type [`Message`] to make them compatible with signing. +/// +/// [`TargetMessage`]: Self::TargetMessage +/// [`as_target`]: Self::as_target +/// [`Message`]: MessageType::Message +pub trait Forward: MessageType { + /// Target Message Type + type TargetMessage; + + /// Converts `source` into the [`TargetMessage`](Self::TargetMessage) type. + fn as_target(source: &Self::Message, compiler: &mut COM) -> Self::TargetMessage; +} + +/// Message-Converting Signature Scheme Adapter +/// +/// In many applications we may have some structured message data that feeds into a generic +/// signature scheme over some unstructured type (like signing a bit-string message). This converter +/// can be used to convert between the message types for conversion before signing. This `struct` +/// utilizes the [`Forward`] `trait` to give the definition of the conversion. The `C` type on this +/// `struct` is the converter that implements [`Forward`]. +#[cfg_attr( + feature = "serde", + derive(Deserialize, Serialize), + serde(crate = "manta_util::serde", deny_unknown_fields) +)] +#[derive(derivative::Derivative)] +#[derivative(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Converter { + /// Base Signature Scheme + pub base: S, + + /// Type Parameter Marker + __: PhantomData, +} + +impl Converter { + /// Builds a new [`Converter`] over `base`. + #[inline] + pub fn new(base: S) -> Self { + Self { + base, + __: PhantomData, + } + } + + /// Returns the inner signature scheme from `self`. + #[inline] + pub fn into_inner(self) -> S { + self.base + } +} + +impl SigningKeyType for Converter +where + S: SigningKeyType, +{ + type SigningKey = S::SigningKey; +} + +impl VerifyingKeyType for Converter +where + S: VerifyingKeyType, +{ + type VerifyingKey = S::VerifyingKey; +} + +impl MessageType for Converter +where + C: MessageType, +{ + type Message = C::Message; +} + +impl SignatureType for Converter +where + S: SignatureType, +{ + type Signature = S::Signature; +} + +impl RandomnessType for Converter +where + S: RandomnessType, +{ + type Randomness = S::Randomness; +} + +impl Derive for Converter +where + S: Derive, +{ + #[inline] + fn derive(&self, signing_key: &Self::SigningKey, compiler: &mut COM) -> Self::VerifyingKey { + self.base.derive(signing_key, compiler) + } +} + +impl Sign for Converter +where + S: Sign, + C: Forward, +{ + #[inline] + fn sign( + &self, + signing_key: &Self::SigningKey, + randomness: &Self::Randomness, + message: &Self::Message, + compiler: &mut COM, + ) -> Self::Signature { + self.base.sign( + signing_key, + randomness, + &C::as_target(message, compiler), + compiler, + ) + } +} + +impl Verify for Converter +where + S: Verify, + C: Forward, +{ + type Verification = S::Verification; + + #[inline] + fn verify( + &self, + verifying_key: &Self::VerifyingKey, + message: &Self::Message, + signature: &Self::Signature, + compiler: &mut COM, + ) -> Self::Verification { + self.base.verify( + verifying_key, + &C::as_target(message, compiler), + signature, + compiler, + ) + } +} + +impl Constant for Converter +where + S: Constant, + C: Constant, +{ + type Type = Converter; + + #[inline] + fn new_constant(this: &Self::Type, compiler: &mut COM) -> Self { + Self::new(Constant::new_constant(&this.base, compiler)) + } +} + +impl Decode for Converter +where + S: Decode, +{ + type Error = S::Error; + + #[inline] + fn decode(mut reader: R) -> Result> + where + R: Read, + { + Ok(Self::new(Decode::decode(&mut reader)?)) + } +} + +impl Encode for Converter +where + S: Encode, +{ + #[inline] + fn encode(&self, mut writer: W) -> Result<(), W::Error> + where + W: Write, + { + self.base.encode(&mut writer)?; + Ok(()) + } +} + +impl Sample for Converter +where + S: Sample, +{ + #[inline] + fn sample(distribution: D, rng: &mut R) -> Self + where + R: RngCore + ?Sized, + { + Self::new(rng.sample(distribution)) + } +} diff --git a/manta-crypto/src/signature.rs b/manta-crypto/src/signature/mod.rs similarity index 63% rename from manta-crypto/src/signature.rs rename to manta-crypto/src/signature/mod.rs index 07280e421..c84e31810 100644 --- a/manta-crypto/src/signature.rs +++ b/manta-crypto/src/signature/mod.rs @@ -34,6 +34,8 @@ //! //! See the [`correctness`](test::correctness) test for more. +pub mod convert; + /// Signing Key pub trait SigningKeyType { /// Signing Key Type @@ -47,6 +49,9 @@ where type SigningKey = T::SigningKey; } +/// Signing Key Type +pub type SigningKey = ::SigningKey; + /// Verifying Key pub trait VerifyingKeyType { /// Verifying Key Type @@ -60,6 +65,9 @@ where type VerifyingKey = T::VerifyingKey; } +/// Verifying Key Type +pub type VerifyingKey = ::VerifyingKey; + /// Message pub trait MessageType { /// Message Type @@ -73,6 +81,9 @@ where type Message = T::Message; } +/// Message Type +pub type Message = ::Message; + /// Signature pub trait SignatureType { /// Signature Type @@ -86,6 +97,9 @@ where type Signature = T::Signature; } +/// Signature Type +pub type Signature = ::Signature; + /// Randomness pub trait RandomnessType { /// Randomness Type @@ -99,6 +113,9 @@ where type Randomness = T::Randomness; } +/// Randomness Type +pub type Randomness = ::Randomness; + /// Signature Verifying Key Derivation Function pub trait Derive: SigningKeyType + VerifyingKeyType { /// Derives the verifying key from `signing_key`. @@ -176,6 +193,7 @@ where { type Verification = V::Verification; + #[inline] fn verify( &self, verifying_key: &Self::VerifyingKey, @@ -191,50 +209,69 @@ where pub mod schnorr { use super::*; use crate::{ - algebra::{security::DiscreteLogarithmHardness, Group, Scalar}, - eclair::{bool::Bool, cmp::PartialEq, Has}, + algebra::{ + security::DiscreteLogarithmHardness, Group as _, HasGenerator, Ring, ScalarMul, + ScalarMulGroup, + }, + eclair::{ + alloc::{Const, Constant}, + bool::Bool, + cmp::PartialEq, + Has, + }, hash::security::PreimageResistance, + rand::{Rand, RngCore, Sample}, }; use core::{cmp, fmt::Debug, hash::Hash, marker::PhantomData}; /// Schnorr Signature Hash Function - pub trait HashFunction: PreimageResistance - where - G: DiscreteLogarithmHardness + Group, - { + pub trait HashFunction: PreimageResistance { + /// Scalar Type + type Scalar: Ring; + + /// Group Type + type Group: ScalarMulGroup + + DiscreteLogarithmHardness; + /// Message Type type Message; - /// Hashes `message` along with `verifying_key` and `nonce_point` into a - /// [`Scalar`](Group::Scalar). + /// Hashes `message` along with `verifying_key` and `nonce_point` into a scalar of type + /// [`Scalar`](Self::Scalar). fn hash( &self, - verifying_key: &G, - nonce_point: &G, + verifying_key: &Self::Group, + nonce_point: &Self::Group, message: &Self::Message, compiler: &mut COM, - ) -> G::Scalar; + ) -> Self::Scalar; } + /// Scalar Type + pub type Scalar = >::Scalar; + + /// Group Type + pub type Group = >::Group; + + /// Message Type + pub type Message = >::Message; + /// Schnorr Signature #[derive(derivative::Derivative)] #[derivative( - Clone(bound = "G::Scalar: Clone, G: Clone"), - Copy(bound = "G::Scalar: Copy, G: Copy"), - Debug(bound = "G::Scalar: Debug, G: Debug"), - Eq(bound = "G::Scalar: Eq, G: Eq"), - Hash(bound = "G::Scalar: Hash, G: Hash"), - PartialEq(bound = "G::Scalar: cmp::PartialEq, G: cmp::PartialEq") + Clone(bound = "S: Clone, G: Clone"), + Copy(bound = "S: Copy, G: Copy"), + Debug(bound = "S: Debug, G: Debug"), + Eq(bound = "S: Eq, G: Eq"), + Hash(bound = "S: Hash, G: Hash"), + PartialEq(bound = "S: cmp::PartialEq, G: cmp::PartialEq") )] - pub struct Signature - where - G: DiscreteLogarithmHardness + Group, - { + pub struct Signature { /// Scalar /// /// This scalar is the hash output multiplied by the secret key, blinded by the nonce /// factor. - pub scalar: G::Scalar, + pub scalar: S, /// Nonce Point /// @@ -245,83 +282,116 @@ pub mod schnorr { /// Schnorr Signature Scheme #[derive(derivative::Derivative)] #[derivative( - Clone(bound = "G: Clone, H: Clone"), - Copy(bound = "G: Copy, H: Copy"), - Debug(bound = "G: Debug, H: Debug"), - Eq(bound = "G: Eq, H: Eq"), - Hash(bound = "G: Hash, H: Hash"), - PartialEq(bound = "G: cmp::PartialEq, H: cmp::PartialEq") + Clone(bound = "H:Clone, H::Group: Clone"), + Copy(bound = "H: Copy, H::Group: Copy"), + Debug(bound = "H: Debug, H::Group: Debug"), + Eq(bound = "H: Eq, H::Group: Eq"), + Hash(bound = "H: Hash, H::Group: Hash"), + PartialEq(bound = "H: cmp::PartialEq, H::Group: cmp::PartialEq") )] - pub struct Schnorr + pub struct Schnorr where - G: DiscreteLogarithmHardness + Group, - H: HashFunction, + H: HashFunction, { - /// Schnorr Group Generator - pub generator: G, - /// Schnorr Hash Function pub hash_function: H, + /// Schnorr Group Generator + pub generator: H::Group, + /// Type Parameter Marker __: PhantomData, } - impl SigningKeyType for Schnorr + impl Schnorr where - G: DiscreteLogarithmHardness + Group, - H: HashFunction, + H: HashFunction, { - type SigningKey = G::Scalar; + /// Builds a new [`Schnorr`] signature scheme over `hash_function` and `generator`. + #[inline] + pub fn new(hash_function: H, generator: H::Group) -> Self { + Self { + hash_function, + generator, + __: PhantomData, + } + } } - impl VerifyingKeyType for Schnorr + impl HasGenerator for Schnorr where - G: DiscreteLogarithmHardness + Group, - H: HashFunction, + H: HashFunction, { - type VerifyingKey = G; + type Generator = H::Group; + + #[inline] + fn generator(&self) -> &Self::Generator { + &self.generator + } + } + + impl Sample<(DH, DG)> for Schnorr + where + H: HashFunction + Sample, + H::Group: Sample, + { + #[inline] + fn sample(distribution: (DH, DG), rng: &mut R) -> Self + where + R: RngCore + ?Sized, + { + Self::new(rng.sample(distribution.0), rng.sample(distribution.1)) + } + } + + impl SigningKeyType for Schnorr + where + H: HashFunction, + { + type SigningKey = H::Scalar; } - impl MessageType for Schnorr + impl VerifyingKeyType for Schnorr where - G: DiscreteLogarithmHardness + Group, - H: HashFunction, + H: HashFunction, + { + type VerifyingKey = H::Group; + } + + impl MessageType for Schnorr + where + H: HashFunction, { type Message = H::Message; } - impl SignatureType for Schnorr + impl SignatureType for Schnorr where - G: DiscreteLogarithmHardness + Group, - H: HashFunction, + H: HashFunction, { - type Signature = Signature; + type Signature = Signature; } - impl RandomnessType for Schnorr + impl RandomnessType for Schnorr where - G: DiscreteLogarithmHardness + Group, - H: HashFunction, + H: HashFunction, { - type Randomness = G::Scalar; + type Randomness = H::Scalar; } - impl Derive for Schnorr + impl Derive for Schnorr where - G: DiscreteLogarithmHardness + Group, - H: HashFunction, + H: HashFunction, { #[inline] fn derive(&self, signing_key: &Self::SigningKey, compiler: &mut COM) -> Self::VerifyingKey { - self.generator.mul(signing_key, compiler) + self.generator.scalar_mul(signing_key, compiler) } } - impl Sign for Schnorr + impl Sign for Schnorr where - G: DiscreteLogarithmHardness + Group, - H: HashFunction, + H: HashFunction, { #[inline] fn sign( @@ -331,12 +401,12 @@ pub mod schnorr { message: &Self::Message, compiler: &mut COM, ) -> Self::Signature { - let nonce_point = self.generator.mul(randomness, compiler); + let nonce_point = self.generator.scalar_mul(randomness, compiler); Signature { scalar: randomness.add( &signing_key.mul( &self.hash_function.hash( - &self.generator.mul(signing_key, compiler), + &self.generator.scalar_mul(signing_key, compiler), &nonce_point, message, compiler, @@ -350,11 +420,11 @@ pub mod schnorr { } } - impl Verify for Schnorr + impl Verify for Schnorr where - G: DiscreteLogarithmHardness + Group + PartialEq, - H: HashFunction, COM: Has, + H: HashFunction, + H::Group: PartialEq, { type Verification = Bool; @@ -370,9 +440,9 @@ pub mod schnorr { scalar, nonce_point, } = signature; - self.generator.mul(scalar, compiler).eq( + self.generator.scalar_mul(scalar, compiler).eq( &nonce_point.add( - &verifying_key.mul( + &verifying_key.scalar_mul( &self .hash_function .hash(verifying_key, nonce_point, message, compiler), @@ -384,6 +454,24 @@ pub mod schnorr { ) } } + + impl Constant for Schnorr + where + H: Constant + HashFunction, + H::Type: HashFunction>, + H::Group: Constant, + Const: ScalarMulGroup + DiscreteLogarithmHardness, + { + type Type = Schnorr; + + #[inline] + fn new_constant(this: &Self::Type, compiler: &mut COM) -> Self { + Self::new( + H::new_constant(&this.hash_function, compiler), + H::Group::new_constant(&this.generator, compiler), + ) + } + } } /// Testing Framework diff --git a/manta-parameters/Cargo.toml b/manta-parameters/Cargo.toml index 7d4ff6290..41481faea 100644 --- a/manta-parameters/Cargo.toml +++ b/manta-parameters/Cargo.toml @@ -32,7 +32,7 @@ download = ["anyhow", "attohttpc", "std"] std = ["anyhow?/std"] [dependencies] -anyhow = { version = "1.0.57", optional = true, default-features = false } +anyhow = { version = "1.0.62", optional = true, default-features = false } attohttpc = { version = "0.19.1", optional = true } blake3 = { version = "1.3.1", default-features = false } workspace-hack = { version = "0.1.0", path = "../workspace-hack" } @@ -45,7 +45,7 @@ tempfile = { version = "3.3.0", default-features = false } walkdir = { version = "2.3.2", default-features = false } [build-dependencies] -anyhow = { version = "1.0.57", default-features = false, features = ["std"] } +anyhow = { version = "1.0.62", default-features = false, features = ["std"] } blake3 = { version = "1.3.1", default-features = false, features = ["std"] } hex = { version = "0.4.3", default-features = false, features = ["std"] } walkdir = { version = "2.3.2", default-features = false } diff --git a/manta-pay/Cargo.toml b/manta-pay/Cargo.toml index a2f69e358..d927f5b0e 100644 --- a/manta-pay/Cargo.toml +++ b/manta-pay/Cargo.toml @@ -105,10 +105,10 @@ ark-ed-on-bls12-381 = { version = "0.3.0", optional = true, default-features = f ark-groth16 = { version = "0.3.0", optional = true, default-features = false } ark-snark = { version = "0.3.0", optional = true, default-features = false } ark-std = { version = "0.3.0", optional = true, default-features = false } -bip32 = { version = "0.4.0", optional = true, default-features = false, features = ["bip39", "secp256k1"] } +bip32 = { version = "0.3.0", optional = true, default-features = false, features = ["bip39", "secp256k1"] } blake2 = { version = "0.10.4", default-features = false } bs58 = { version = "0.4.0", optional = true, default-features = false, features = ["alloc"] } -clap = { version = "3.2.15", optional = true, default-features = false, features = ["color", "derive", "std", "suggestions", "unicode", "wrap_help"] } +clap = { version = "3.2.17", optional = true, default-features = false, features = ["color", "derive", "std", "suggestions", "unicode", "wrap_help"] } derivative = { version = "2.2.0", default-features = false, features = ["use_core"] } futures = { version = "0.3.21", optional = true, default-features = false } indexmap = { version = "1.8.2", optional = true, default-features = false } @@ -121,7 +121,7 @@ rand_chacha = { version = "0.3.1", default-features = false } rayon = { version = "1.5.1", optional = true, default-features = false } scale-codec = { package = "parity-scale-codec", version = "3.1.2", optional = true, default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.1.2", optional = true, default-features = false, features = ["derive"] } -serde_json = { version = "1.0.82", optional = true, default-features = false, features = ["alloc"] } +serde_json = { version = "1.0.85", optional = true, default-features = false, features = ["alloc"] } tempfile = { version = "3.3.0", optional = true, default-features = false } tide = { version = "0.16.0", optional = true, default-features = false, features = ["h1-server"] } tokio = { version = "1.20.1", optional = true, default-features = false } diff --git a/manta-pay/src/config.rs b/manta-pay/src/config.rs index fb9b9ab94..633314283 100644 --- a/manta-pay/src/config.rs +++ b/manta-pay/src/config.rs @@ -41,7 +41,7 @@ use manta_crypto::{ ff::ToConstraintField, serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}, }, - constraint::ProofSystemInput, + constraint::Input, eclair::{ self, alloc::{ @@ -52,15 +52,12 @@ use manta_crypto::{ }, encryption, hash::ArrayHashFunction, - key::{ - self, - kdf::{AsBytes, KeyDerivationFunction}, - }, + key::{self, kdf::KeyDerivationFunction}, merkle_tree, }; use manta_util::{ codec::{Decode, DecodeError, Encode, Read, Write}, - into_array_unchecked, Array, SizeLimit, + into_array_unchecked, Array, AsBytes, SizeLimit, }; #[cfg(feature = "bs58")] @@ -153,7 +150,7 @@ impl poseidon::arkworks::Specification for PoseidonSpec<4> { } /// Key Agreement Scheme Type -pub type KeyAgreementScheme = DiffieHellman; +pub type KeyAgreementScheme = DiffieHellman; /// Secret Key Type pub type SecretKey = ::SecretKey; @@ -165,7 +162,7 @@ pub type PublicKey = ::PublicKey; pub type SharedSecret = ::SharedSecret; /// Key Agreement Scheme Variable Type -pub type KeyAgreementSchemeVar = DiffieHellman; +pub type KeyAgreementSchemeVar = DiffieHellman; /// Secret Key Variable Type pub type SecretKeyVar = ::SecretKey; @@ -633,31 +630,24 @@ impl Constant for MerkleTreeConfigurationVar { } } -impl ProofSystemInput for ProofSystem { - #[inline] - fn extend(input: &mut Self::Input, next: &AssetId) { - input.push(next.0.into()); - } -} - -impl ProofSystemInput for ProofSystem { +impl Input for AssetId { #[inline] - fn extend(input: &mut Self::Input, next: &AssetValue) { - input.push(next.0.into()); + fn extend(&self, input: &mut Vec) { + input.push(self.0.into()); } } -impl ProofSystemInput> for ProofSystem { +impl Input for AssetValue { #[inline] - fn extend(input: &mut Self::Input, next: &Fp) { - input.push(next.0); + fn extend(&self, input: &mut Vec) { + input.push(self.0.into()); } } -impl ProofSystemInput for ProofSystem { +impl Input for Group { #[inline] - fn extend(input: &mut Self::Input, next: &Group) { - input.append(&mut next.0.to_field_elements().unwrap()); + fn extend(&self, input: &mut Vec) { + input.append(&mut self.0.to_field_elements().unwrap()); } } diff --git a/manta-pay/src/crypto/constraint/arkworks/groth16.rs b/manta-pay/src/crypto/constraint/arkworks/groth16.rs index ce15573df..ae6473911 100644 --- a/manta-pay/src/crypto/constraint/arkworks/groth16.rs +++ b/manta-pay/src/crypto/constraint/arkworks/groth16.rs @@ -30,7 +30,7 @@ use manta_crypto::{ ec::PairingEngine, serialize::{CanonicalDeserialize, CanonicalSerialize, Read, Write}, }, - constraint::ProofSystem, + constraint::{Input, ProofSystem}, rand::{CryptoRng, RngCore, SizedRng}, }; use manta_util::codec::{self, DecodeError}; @@ -138,6 +138,19 @@ where } } +impl codec::Encode for Proof +where + E: PairingEngine, +{ + #[inline] + fn encode(&self, writer: W) -> Result<(), W::Error> + where + W: codec::Write, + { + proof_as_bytes(&self.0).encode(writer) + } +} + impl TryFrom> for Proof where E: PairingEngine, @@ -510,3 +523,23 @@ where ArkGroth16::verify_with_processed_vk(&context.0, input, &proof.0).map_err(|_| Error) } } + +impl Input> for bool +where + E: PairingEngine, +{ + #[inline] + fn extend(&self, input: &mut Vec) { + input.push((*self).into()); + } +} + +impl Input> for u128 +where + E: PairingEngine, +{ + #[inline] + fn extend(&self, input: &mut Vec) { + input.push((*self).into()); + } +} diff --git a/manta-pay/src/crypto/constraint/arkworks/mod.rs b/manta-pay/src/crypto/constraint/arkworks/mod.rs index 610bf29d0..1be20c847 100644 --- a/manta-pay/src/crypto/constraint/arkworks/mod.rs +++ b/manta-pay/src/crypto/constraint/arkworks/mod.rs @@ -17,10 +17,11 @@ //! Arkworks Constraint System and Proof System Implementations use alloc::vec::Vec; +use core::iter::{self, Extend}; use manta_crypto::{ algebra, arkworks::{ - ff::{Field, FpParameters, PrimeField}, + ff::{Field, FpParameters, PrimeField, ToConstraintField}, r1cs_std::{alloc::AllocVar, eq::EqGadget, select::CondSelectGadget, ToBitsGadget}, relations::{ ns, @@ -30,17 +31,19 @@ use manta_crypto::{ }, }, }, - constraint::measure::{Count, Measure}, + constraint::{ + measure::{Count, Measure}, + Input, ProofSystem, + }, eclair::{ self, alloc::{ - mode, - mode::{Public, Secret}, + mode::{self, Public, Secret}, Constant, Variable, }, - bool::{Assert, ConditionalSwap}, - num::AssertWithinBitRange, - ops::{Add, BitAnd}, + bool::{Assert, Bool, ConditionalSelect, ConditionalSwap}, + num::{AssertWithinBitRange, Zero}, + ops::{Add, BitAnd, BitOr}, Has, NonNative, }, rand::{RngCore, Sample}, @@ -89,6 +92,38 @@ pub struct Fp( where F: Field; +impl From for Fp +where + F: Field, +{ + #[inline] + fn from(value: u128) -> Self { + Self(value.into()) + } +} + +impl ToConstraintField for Fp +where + F: PrimeField, +{ + #[inline] + fn to_field_elements(&self) -> Option> { + self.0.to_field_elements() + } +} + +impl Input

for Fp +where + F: Field, + P: ProofSystem + ?Sized, + P::Input: Extend, +{ + #[inline] + fn extend(&self, input: &mut P::Input) { + input.extend(iter::once(self.0)) + } +} + impl Decode for Fp where F: Field, @@ -191,6 +226,64 @@ where } } +impl eclair::cmp::PartialEq for Fp +where + F: Field, +{ + #[inline] + fn eq(&self, rhs: &Self, _: &mut ()) -> bool { + PartialEq::eq(self, rhs) + } +} + +impl eclair::num::Zero for Fp +where + F: Field, +{ + type Verification = bool; + + #[inline] + fn zero(_: &mut ()) -> Self { + Self(F::zero()) + } + + #[inline] + fn is_zero(&self, _: &mut ()) -> Self::Verification { + self.0.is_zero() + } +} + +impl eclair::num::One for Fp +where + F: Field, +{ + type Verification = bool; + + #[inline] + fn one(_: &mut ()) -> Self { + Self(F::one()) + } + + #[inline] + fn is_one(&self, _: &mut ()) -> Self::Verification { + self.0.is_one() + } +} + +impl ConditionalSelect for Fp +where + F: Field, +{ + #[inline] + fn select(bit: &Bool, true_value: &Self, false_value: &Self, _: &mut ()) -> Self { + if *bit { + *true_value + } else { + *false_value + } + } +} + impl Sample for Fp where F: Field, @@ -204,7 +297,7 @@ where } } -impl algebra::Scalar for Fp +impl algebra::Group for Fp where F: Field, { @@ -212,7 +305,12 @@ where fn add(&self, rhs: &Self, _: &mut ()) -> Self { Self(self.0 + rhs.0) } +} +impl algebra::Ring for Fp +where + F: Field, +{ #[inline] fn mul(&self, rhs: &Self, _: &mut ()) -> Self { Self(self.0 * rhs.0) @@ -492,6 +590,19 @@ where } } +impl BitOr> for Boolean +where + F: PrimeField, +{ + type Output = Self; + + #[inline] + fn bitor(self, rhs: Self, compiler: &mut R1CS) -> Self::Output { + let _ = compiler; + self.or(&rhs).expect("Bitwise OR is not allowed to fail.") + } +} + impl Constant> for FpVar where F: PrimeField, @@ -578,6 +689,22 @@ where .expect("Conditionally selecting from two values is not allowed to fail.") } +impl ConditionalSelect> for FpVar +where + F: PrimeField, +{ + #[inline] + fn select( + bit: &Boolean, + true_value: &Self, + false_value: &Self, + compiler: &mut R1CS, + ) -> Self { + let _ = compiler; + conditionally_select(bit, true_value, false_value) + } +} + impl ConditionalSwap> for FpVar where F: PrimeField, @@ -605,6 +732,26 @@ where } } +impl Zero> for FpVar +where + F: PrimeField, +{ + type Verification = Boolean; + + #[inline] + fn zero(compiler: &mut R1CS) -> Self { + let _ = compiler; + FpVar::Constant(F::zero()) + } + + #[inline] + fn is_zero(&self, compiler: &mut R1CS) -> Self::Verification { + let _ = compiler; + self.is_eq(&FpVar::Constant(F::zero())) + .expect("Comparison with zero is not allowed to fail.") + } +} + /// Testing Suite #[cfg(test)] mod tests { diff --git a/manta-pay/src/crypto/ecc/arkworks.rs b/manta-pay/src/crypto/ecc/arkworks.rs index 835d38e1f..d2c967127 100644 --- a/manta-pay/src/crypto/ecc/arkworks.rs +++ b/manta-pay/src/crypto/ecc/arkworks.rs @@ -36,10 +36,9 @@ use manta_crypto::{ Allocate, Allocator, Constant, Variable, }, }, - key::kdf, rand::{RngCore, Sample}, }; -use manta_util::codec; +use manta_util::{codec, AsBytes}; #[cfg(feature = "serde")] use { @@ -203,7 +202,7 @@ where } } -impl kdf::AsBytes for Group +impl AsBytes for Group where C: ProjectiveCurve, { @@ -217,15 +216,20 @@ impl algebra::Group for Group where C: ProjectiveCurve, { - type Scalar = Scalar; - #[inline] fn add(&self, rhs: &Self, _: &mut ()) -> Self { Self(self.0 + rhs.0) } +} + +impl algebra::ScalarMul> for Group +where + C: ProjectiveCurve, +{ + type Output = Self; #[inline] - fn mul(&self, scalar: &Self::Scalar, _: &mut ()) -> Self { + fn scalar_mul(&self, scalar: &Scalar, _: &mut ()) -> Self::Output { Self(self.0.mul(scalar.0.into_repr()).into()) } } @@ -288,7 +292,7 @@ where } } -impl algebra::Scalar> for ScalarVar +impl algebra::Group> for ScalarVar where C: ProjectiveCurve, CV: CurveVar>, @@ -298,7 +302,13 @@ where let _ = compiler; Self::new(&self.0 + &rhs.0) } +} +impl algebra::Ring> for ScalarVar +where + C: ProjectiveCurve, + CV: CurveVar>, +{ #[inline] fn mul(&self, rhs: &Self, compiler: &mut Compiler) -> Self { let _ = compiler; @@ -380,8 +390,6 @@ where C: ProjectiveCurve, CV: CurveVar>, { - type Scalar = ScalarVar; - #[inline] fn add(&self, rhs: &Self, compiler: &mut Compiler) -> Self { let _ = compiler; @@ -389,9 +397,17 @@ where result += &rhs.0; Self::new(result) } +} + +impl algebra::ScalarMul, Compiler> for GroupVar +where + C: ProjectiveCurve, + CV: CurveVar>, +{ + type Output = Self; #[inline] - fn mul(&self, scalar: &Self::Scalar, compiler: &mut Compiler) -> Self { + fn scalar_mul(&self, scalar: &ScalarVar, compiler: &mut Compiler) -> Self::Output { let _ = compiler; Self::new( self.0 diff --git a/manta-pay/src/crypto/poseidon/encryption.rs b/manta-pay/src/crypto/poseidon/encryption.rs index c8f5faf09..887424a70 100644 --- a/manta-pay/src/crypto/poseidon/encryption.rs +++ b/manta-pay/src/crypto/poseidon/encryption.rs @@ -18,18 +18,38 @@ use crate::crypto::poseidon::{Permutation, Specification, State}; use alloc::{boxed::Box, vec::Vec}; -use core::{fmt::Debug, hash::Hash}; -use manta_crypto::permutation::{ - duplex::{self, Setup, Types, Verify}, - sponge::{Read, Write}, +use core::{fmt::Debug, hash::Hash, iter, ops::Deref, slice}; +use manta_crypto::{ + constraint::{HasInput, Input}, + eclair::{ + self, + alloc::{ + mode::{Public, Secret}, + Allocate, Allocator, Constant, Var, Variable, + }, + bool::{Assert, Bool}, + num::Zero, + ops::BitAnd, + Has, + }, + permutation::{ + duplex::{self, Setup, Types, Verify}, + sponge::{Read, Write}, + }, + rand::{Rand, RngCore, Sample}, +}; +use manta_util::{ + codec::{self, Encode}, + vec::padded_chunks_with, + BoxArray, }; -use manta_util::vec::padded_chunks; #[cfg(feature = "serde")] use manta_util::serde::{Deserialize, Serialize}; -/// Encryption Duplexer -pub type Duplexer = duplex::Duplexer, Encryption, COM>; +/// Fixed Encryption Duplexer +pub type FixedDuplexer = + duplex::Duplexer, FixedEncryption, COM>; /// Block Element pub trait BlockElement { @@ -80,19 +100,38 @@ where } } +impl eclair::cmp::PartialEq for SetupBlock +where + COM: Has, + Bool: Constant + BitAnd, COM, Output = Bool>, + S: Specification, + S::Field: eclair::cmp::PartialEq, +{ + #[inline] + fn eq(&self, rhs: &Self, compiler: &mut COM) -> Bool { + self.0.eq(&rhs.0, compiler) + } + + #[inline] + fn assert_equal(&self, rhs: &Self, compiler: &mut COM) + where + COM: Assert, + { + self.0.assert_equal(&rhs.0, compiler) + } +} + /// Plaintext Block +/* TODO: #[cfg_attr( feature = "serde", derive(Deserialize, Serialize), - serde( - bound( - deserialize = "S::Field: Deserialize<'de>", - serialize = "S::Field: Serialize" - ), - crate = "manta_util::serde", - deny_unknown_fields - ) + serde(bound( + deserialize = "S::Field: Deserialize<'de>", + serialize = "S::Field: Serialize" + ),) )] +*/ #[derive(derivative::Derivative)] #[derivative( Clone(bound = "S::Field: Clone"), @@ -101,7 +140,7 @@ where Hash(bound = "S::Field: Hash"), PartialEq(bound = "S::Field: PartialEq") )] -pub struct PlaintextBlock(Box<[S::Field]>) +pub struct PlaintextBlock(pub Box<[S::Field]>) where S: Specification; @@ -121,7 +160,79 @@ where } } +impl eclair::cmp::PartialEq for PlaintextBlock +where + COM: Has, + Bool: Constant + BitAnd, COM, Output = Bool>, + S: Specification, + S::Field: eclair::cmp::PartialEq, +{ + #[inline] + fn eq(&self, rhs: &Self, compiler: &mut COM) -> Bool { + self.0.eq(&rhs.0, compiler) + } + + #[inline] + fn assert_equal(&self, rhs: &Self, compiler: &mut COM) + where + COM: Assert, + { + self.0.assert_equal(&rhs.0, compiler) + } +} + +impl Variable for PlaintextBlock +where + S: Specification + Constant, + S::Field: Variable, + S::Type: Specification>, +{ + type Type = PlaintextBlock; + + #[inline] + fn new_unknown(compiler: &mut COM) -> Self { + Self( + iter::repeat_with(|| compiler.allocate_unknown()) + .take(S::WIDTH - 1) + .collect(), + ) + } + + #[inline] + fn new_known(this: &Self::Type, compiler: &mut COM) -> Self { + Self(this.0.iter().map(|this| this.as_known(compiler)).collect()) + } +} + +impl Encode for PlaintextBlock +where + S: Specification, + S::Field: Encode, +{ + #[inline] + fn encode(&self, writer: W) -> Result<(), W::Error> + where + W: codec::Write, + { + self.0.encode(writer) + } +} + +impl Input

for PlaintextBlock +where + S: Specification, + P: HasInput + ?Sized, +{ + #[inline] + fn extend(&self, input: &mut P::Input) { + for element in self.0.iter() { + P::extend(input, element); + } + } +} + /// Ciphertext Block +/* TODO: #[cfg_attr( feature = "serde", derive(Deserialize, Serialize), @@ -134,6 +245,7 @@ where deny_unknown_fields ) )] +*/ #[derive(derivative::Derivative)] #[derivative( Clone(bound = "S::Field: Clone"), @@ -142,7 +254,7 @@ where Hash(bound = "S::Field: Hash"), PartialEq(bound = "S::Field: PartialEq") )] -pub struct CiphertextBlock(Box<[S::Field]>) +pub struct CiphertextBlock(pub Box<[S::Field]>) where S: Specification; @@ -162,7 +274,187 @@ where } } +impl eclair::cmp::PartialEq for CiphertextBlock +where + COM: Has, + Bool: Constant + BitAnd, COM, Output = Bool>, + S: Specification, + S::Field: eclair::cmp::PartialEq, +{ + #[inline] + fn eq(&self, rhs: &Self, compiler: &mut COM) -> Bool { + self.0.eq(&rhs.0, compiler) + } + + #[inline] + fn assert_equal(&self, rhs: &Self, compiler: &mut COM) + where + COM: Assert, + { + self.0.assert_equal(&rhs.0, compiler) + } +} + +impl Variable for CiphertextBlock +where + S: Specification + Constant, + S::Field: Variable, + S::Type: Specification>, +{ + type Type = CiphertextBlock; + + #[inline] + fn new_unknown(compiler: &mut COM) -> Self { + Self( + iter::repeat_with(|| compiler.allocate_unknown()) + .take(S::WIDTH - 1) + .collect(), + ) + } + + #[inline] + fn new_known(this: &Self::Type, compiler: &mut COM) -> Self { + Self(this.0.iter().map(|this| this.as_known(compiler)).collect()) + } +} + +impl Encode for CiphertextBlock +where + S: Specification, + S::Field: Encode, +{ + #[inline] + fn encode(&self, writer: W) -> Result<(), W::Error> + where + W: codec::Write, + { + self.0.encode(writer) + } +} + +impl Input

for CiphertextBlock +where + S: Specification, + P: HasInput + ?Sized, +{ + #[inline] + fn extend(&self, input: &mut P::Input) { + for element in self.0.iter() { + P::extend(input, element); + } + } +} + +/// Block Array +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = "B: Clone"), + Debug(bound = "B: Debug"), + Eq(bound = "B: Eq"), + Hash(bound = "B: Hash"), + PartialEq(bound = "B: PartialEq") +)] +pub struct BlockArray(pub BoxArray); + +impl Deref for BlockArray { + type Target = BoxArray; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl FromIterator for BlockArray { + #[inline] + fn from_iter(iter: I) -> Self + where + I: IntoIterator, + { + Self(iter.into_iter().collect()) + } +} + +impl<'b, B, const N: usize> IntoIterator for &'b BlockArray { + type Item = &'b B; + type IntoIter = slice::Iter<'b, B>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl Encode for BlockArray +where + B: Encode, +{ + #[inline] + fn encode(&self, writer: W) -> Result<(), W::Error> + where + W: codec::Write, + { + self.0.encode(writer) + } +} + +impl Input

for BlockArray +where + P: HasInput + ?Sized, +{ + #[inline] + fn extend(&self, input: &mut P::Input) { + for block in &self.0 { + P::extend(input, block); + } + } +} + +impl eclair::cmp::PartialEq for BlockArray +where + COM: Has, + Bool: Constant + BitAnd, COM, Output = Bool>, + B: eclair::cmp::PartialEq, +{ + #[inline] + fn eq(&self, rhs: &Self, compiler: &mut COM) -> Bool { + self.0.eq(&rhs.0, compiler) + } + + #[inline] + fn assert_equal(&self, rhs: &Self, compiler: &mut COM) + where + COM: Assert, + { + self.0.assert_equal(&rhs.0, compiler) + } +} + +impl Variable for BlockArray +where + B: Variable, +{ + type Type = BlockArray; + + #[inline] + fn new_unknown(compiler: &mut COM) -> Self { + Self(compiler.allocate_unknown()) + } + + #[inline] + fn new_known(this: &Self::Type, compiler: &mut COM) -> Self { + Self(this.0.as_known(compiler)) + } +} + +/// Fixed Plaintext Type +pub type FixedPlaintext = BlockArray, N>; + +/// Fixed Ciphertext Type +pub type FixedCiphertext = BlockArray, N>; + /// Authentication Tag +/* TODO: #[cfg_attr( feature = "serde", derive(Deserialize, Serialize), @@ -175,6 +467,7 @@ where deny_unknown_fields ) )] +*/ #[derive(derivative::Derivative)] #[derivative( Clone(bound = "S::Field: Clone"), @@ -183,7 +476,7 @@ where Hash(bound = "S::Field: Hash"), PartialEq(bound = "S::Field: PartialEq") )] -pub struct Tag(S::Field) +pub struct Tag(pub S::Field) where S: Specification; @@ -199,7 +492,64 @@ where } } -/// Encryption Configuration +impl eclair::cmp::PartialEq for Tag +where + COM: Has, + S: Specification, + S::Field: eclair::cmp::PartialEq, +{ + #[inline] + fn eq(&self, rhs: &Self, compiler: &mut COM) -> Bool { + self.0.eq(&rhs.0, compiler) + } +} + +impl Variable for Tag +where + S: Specification + Constant, + S::Field: Variable, + S::Type: Specification>, +{ + type Type = Tag; + + #[inline] + fn new_unknown(compiler: &mut COM) -> Self { + Self(compiler.allocate_unknown()) + } + + #[inline] + fn new_known(this: &Self::Type, compiler: &mut COM) -> Self { + Self(this.0.as_known(compiler)) + } +} + +impl Encode for Tag +where + S: Specification, + S::Field: Encode, +{ + #[inline] + fn encode(&self, writer: W) -> Result<(), W::Error> + where + W: codec::Write, + { + self.0.encode(writer) + } +} + +impl Input

for Tag +where + S: Specification, + P: HasInput + ?Sized, +{ + #[inline] + fn extend(&self, input: &mut P::Input) { + P::extend(input, &self.0) + } +} + +/// Fixed Encryption Configuration +/* TODO: #[cfg_attr( feature = "serde", derive(Deserialize, Serialize), @@ -212,6 +562,7 @@ where deny_unknown_fields ) )] +*/ #[derive(derivative::Derivative)] #[derivative( Clone(bound = "S::Field: Clone"), @@ -220,7 +571,7 @@ where Hash(bound = "S::Field: Hash"), PartialEq(bound = "S::Field: PartialEq") )] -pub struct Encryption +pub struct FixedEncryption where S: Specification, { @@ -228,7 +579,39 @@ where pub initial_state: State, } -impl Types, COM> for Encryption +impl Constant for FixedEncryption +where + S: Specification + Constant, + S::Type: Specification, + State: Constant>, +{ + type Type = FixedEncryption; + + #[inline] + fn new_constant(this: &Self::Type, compiler: &mut COM) -> Self { + Self { + initial_state: this.initial_state.as_constant(compiler), + } + } +} + +impl Sample for FixedEncryption +where + S: Specification, + State: Sample, +{ + #[inline] + fn sample(distribution: D, rng: &mut R) -> Self + where + R: RngCore + ?Sized, + { + Self { + initial_state: rng.sample(distribution), + } + } +} + +impl Types, COM> for FixedEncryption where S: Specification, S::Field: Clone + BlockElement, @@ -237,14 +620,16 @@ where type Header = Vec; type SetupBlock = SetupBlock; type PlaintextBlock = PlaintextBlock; + type Plaintext = FixedPlaintext; type CiphertextBlock = CiphertextBlock; + type Ciphertext = FixedCiphertext; type Tag = Tag; } -impl Setup, COM> for Encryption +impl Setup, COM> for FixedEncryption where S: Specification, - S::Field: Clone + Default + BlockElement, + S::Field: Clone + BlockElement + Zero, { #[inline] fn initialize(&self, compiler: &mut COM) -> State { @@ -259,9 +644,10 @@ where header: &Self::Header, compiler: &mut COM, ) -> Vec { - let _ = compiler; - let mut blocks = padded_chunks(key.as_slice(), S::WIDTH - 1); - blocks.extend(padded_chunks(header.as_slice(), S::WIDTH - 1)); + let mut blocks = padded_chunks_with(key.as_slice(), S::WIDTH - 1, || Zero::zero(compiler)); + blocks.extend(padded_chunks_with(header.as_slice(), S::WIDTH - 1, || { + Zero::zero(compiler) + })); blocks .into_iter() .map(|b| SetupBlock(b.into_boxed_slice())) @@ -269,7 +655,7 @@ where } } -impl Verify> for Encryption +impl Verify> for FixedEncryption where S: Specification, S::Field: Clone + PartialEq + BlockElement, diff --git a/manta-util/Cargo.toml b/manta-util/Cargo.toml index 2e79d5c52..f60895db1 100644 --- a/manta-util/Cargo.toml +++ b/manta-util/Cargo.toml @@ -41,7 +41,7 @@ std = ["alloc"] crossbeam-channel = { version = "0.5.6", optional = true, default-features = false } rayon = { version = "1.5.3", optional = true, default-features = false } reqwest = { version = "0.11.11", optional = true, default-features = false, features = ["json"] } -serde = { version = "1.0.140", optional = true, default-features = false, features = ["derive"] } +serde = { version = "1.0.144", optional = true, default-features = false, features = ["derive"] } serde_with = { version = "1.14.0", optional = true, default-features = false, features = ["macros"] } tide = { version = "0.16.0", optional = true, default-features = false } workspace-hack = { version = "0.1.0", path = "../workspace-hack" } diff --git a/manta-util/src/bytes.rs b/manta-util/src/bytes.rs index d748f465a..592bc0c98 100644 --- a/manta-util/src/bytes.rs +++ b/manta-util/src/bytes.rs @@ -16,6 +16,15 @@ //! Utilities for Manipulating Bytes +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +/// Counts the number of bytes required to encode a number with the given number of `bits`. +#[inline] +pub const fn byte_count(bits: u32) -> u32 { + (bits / 8) + (((bits % 8) != 0) as u32) +} + /// Size Limit pub trait SizeLimit { /// Maximum Number of Bytes Required to Represent [`Self`] @@ -90,8 +99,10 @@ impl IntoBytes for [u8; N] { } } -/// Counts the number of bytes required to encode a number with the given number of `bits`. -#[inline] -pub const fn byte_count(bits: u32) -> u32 { - (bits / 8) + (((bits % 8) != 0) as u32) +/// Byte Vector Conversion +#[cfg(feature = "alloc")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] +pub trait AsBytes { + /// Returns an owned byte representation of `self`. + fn as_bytes(&self) -> Vec; } diff --git a/manta-util/src/cmp.rs b/manta-util/src/cmp.rs new file mode 100644 index 000000000..ebedf20d4 --- /dev/null +++ b/manta-util/src/cmp.rs @@ -0,0 +1,76 @@ +// Copyright 2019-2022 Manta Network. +// This file is part of manta-rs. +// +// manta-rs is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// manta-rs is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with manta-rs. If not, see . + +//! Comparison Utilities + +/// Independence Context +pub trait IndependenceContext { + /// Default Independence Value + const DEFAULT: bool; +} + +/// Default True +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct DefaultTrue; + +impl IndependenceContext for DefaultTrue { + const DEFAULT: bool = true; +} + +/// Default False +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct DefaultFalse; + +impl IndependenceContext for DefaultFalse { + const DEFAULT: bool = false; +} + +/// Independence Relation +pub trait Independence +where + C: IndependenceContext + ?Sized, +{ + /// Determines if `fst` and `snd` are independent. + /// + /// # Implementation Note + /// + /// By default two values are given the independence value [`C::DEFAULT`] as specified on the + /// `trait` parameter. + /// + /// [`C::DEFAULT`]: IndependenceContext::DEFAULT + #[inline] + fn is_independent(&self, rhs: &Self) -> bool { + let _ = rhs; + C::DEFAULT + } + + /// Returns the negation of the [`is_independent`](Self::is_independent) method. + #[inline] + fn is_related(&self, rhs: &Self) -> bool { + !self.is_independent(rhs) + } +} + +impl Independence for &T +where + C: IndependenceContext + ?Sized, + T: Independence + ?Sized, +{ + #[inline] + fn is_independent(&self, rhs: &Self) -> bool { + (*self).is_independent(rhs) + } +} diff --git a/manta-util/src/codec.rs b/manta-util/src/codec.rs index df0122322..75052de8d 100644 --- a/manta-util/src/codec.rs +++ b/manta-util/src/codec.rs @@ -21,7 +21,7 @@ use core::{convert::Infallible, fmt::Debug, hash::Hash, marker::PhantomData}; #[cfg(feature = "alloc")] -use {crate::into_array_unchecked, alloc::vec::Vec}; +use crate::{into_array_unchecked, vec::Vec}; /// Implements [`Decode`] and [`Encode`] for a type with no data that implements [`Default`]. #[macro_export] @@ -587,51 +587,54 @@ impl Encode for PhantomData { } } -impl Encode for u8 { +impl Encode for bool { #[inline] - fn encode(&self, mut writer: W) -> Result<(), W::Error> + fn encode(&self, writer: W) -> Result<(), W::Error> where W: Write, { - writer.write_ref(&[*self])?; - Ok(()) + (*self as u8).encode(writer) } } -impl Encode for u16 { - #[inline] - fn encode(&self, mut writer: W) -> Result<(), W::Error> - where - W: Write, - { - writer.write_ref(&self.to_le_bytes())?; - Ok(()) +/// Defines an [`Encode`] implemention for the given integer type `$type`. +macro_rules! encode_int { + ($($type:tt),* $(,)?) => { + $( + impl Encode for $type { + #[inline] + fn encode(&self, mut writer: W) -> Result<(), W::Error> + where + W: Write, + { + writer.write_ref(&self.to_le_bytes())?; + Ok(()) + } + } + )* } } -impl Encode for u32 { - #[inline] - fn encode(&self, mut writer: W) -> Result<(), W::Error> - where - W: Write, - { - writer.write_ref(&self.to_le_bytes())?; - Ok(()) - } -} +encode_int!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); -impl Encode for u64 { +impl Encode for [T] +where + T: Encode, +{ #[inline] fn encode(&self, mut writer: W) -> Result<(), W::Error> where W: Write, { - writer.write_ref(&self.to_le_bytes())?; + (self.len() as u64).encode(&mut writer)?; + for item in self { + item.encode(&mut writer)?; + } Ok(()) } } -impl Encode for [T] +impl Encode for [T; N] where T: Encode, { @@ -640,7 +643,6 @@ where where W: Write, { - (self.len() as u64).encode(&mut writer)?; for item in self { item.encode(&mut writer)?; } @@ -648,7 +650,9 @@ where } } -impl Encode for [T; N] +#[cfg(feature = "alloc")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] +impl Encode for Vec where T: Encode, { @@ -657,6 +661,7 @@ where where W: Write, { + (self.len() as u64).encode(&mut writer)?; for item in self { item.encode(&mut writer)?; } diff --git a/manta-util/src/convert.rs b/manta-util/src/convert.rs index 9bf1e7559..701163b4a 100644 --- a/manta-util/src/convert.rs +++ b/manta-util/src/convert.rs @@ -38,3 +38,21 @@ pub fn never_err(result: Result) -> T { Err(err) => never(err), } } + +/// Structure Field +pub trait Field { + /// Returns a shared reference to the field value. + fn get(&self) -> &T; + + /// Returns a mutable reference to the field value. + fn get_mut(&mut self) -> &mut T; + + /// Converts `self` into the field value, dropping the rest of the structure. + fn into(self) -> T; +} + +/// Enumeration Variant +pub trait Variant { + /// Constructs the value of the enumeration of the given `variant`. + fn from(variant: T) -> Self; +} diff --git a/manta-util/src/iter/mod.rs b/manta-util/src/iter/mod.rs index 6222ae374..4c8ffc6eb 100644 --- a/manta-util/src/iter/mod.rs +++ b/manta-util/src/iter/mod.rs @@ -16,7 +16,7 @@ //! Iteration Utilities -use crate::IsType; +use core::iter::Map; #[cfg(feature = "serde")] use crate::serde::{Deserialize, Serialize}; @@ -113,18 +113,124 @@ impl IteratorExt for I where I: Iterator {} /// Borrowing Iterator Trait pub trait IterRef<'i, I = &'i Self> { + /// Borrowed Item Type + type Item; + + /// Iterator Type + type IntoIter: Iterator; + /// Borrowing Iterator Type - type Iterator: IntoIterator + IsType; + type Iter: IntoIterator; + + /// Converts `this` into the iterator type. + fn iter(this: I) -> Self::Iter; +} + +impl<'i, I> IterRef<'i> for I +where + I: ?Sized, + for<'t> &'t Self: IntoIterator, +{ + type Item = <&'i Self as IntoIterator>::Item; + type IntoIter = <&'i Self as IntoIterator>::IntoIter; + type Iter = &'i Self; + + #[inline] + fn iter(this: &'i Self) -> Self::Iter { + this + } +} + +/// Item Type for [`IterRef`] +pub type RefItem<'t, T> = >::Item; + +/// Borrowing Iterator Type for [`IterRef`] +pub type RefIter<'t, T> = >::Iter; + +/// Exact Size Iteration Type +pub trait ExactSizeIterRef<'i, I = &'i Self> { + /// Item Type + type Item; + + /// Iterator Type + type IntoIter: ExactSizeIterator; +} + +impl<'i, I> ExactSizeIterRef<'i> for I +where + for<'t> &'t Self: IntoIterator, + <&'i Self as IntoIterator>::IntoIter: ExactSizeIterator, +{ + type Item = <&'i Self as IntoIterator>::Item; + type IntoIter = <&'i Self as IntoIterator>::IntoIter; } /// Iterable Type /// /// This `trait` is implemented for any type that has a borrowing [`IntoIterator`] implementation /// for any reference of that type. -pub trait Iterable: for<'i> IterRef<'i> {} +pub trait Iterable: for<'i> IterRef<'i> { + /// Returns the iterator for `self`. + #[inline] + fn iter(&self) -> as IntoIterator>::IntoIter { + >::iter(self).into_iter() + } + + /// Returns the converting iterator for `self`. + #[inline] + fn convert_iter<'t, T>(&'t self) -> ConvertItemRefMap<'t, T, Self> + where + Self: ConvertItemRef<'t, T, Item = RefItem<'t, Self>>, + { + self.iter().map(|item| Self::convert_item(item)) + } +} impl Iterable for T where T: for<'i> IterRef<'i> + ?Sized {} +/// Exact Size Iterable +pub trait ExactSizeIterable: + for<'i> IterRef<'i, IntoIter = >::IntoIter> + + for<'i> ExactSizeIterRef<'i, Item = RefItem<'i, Self>> +{ +} + +impl ExactSizeIterable for I where + I: for<'i> IterRef<'i, IntoIter = >::IntoIter> + + for<'i> ExactSizeIterRef<'i, Item = RefItem<'i, Self>> +{ +} + +/// [`ConvertItemRef`] Map Type +pub type ConvertItemRefMap<'t, T, I> = + Map< as IntoIterator>::IntoIter, fn(RefItem<'t, I>) -> T>; + +/// Item Type Converter +pub trait ConvertItemRef<'i, T, I = &'i Self> { + /// Item Type + type Item: Into; + + /// Converts `item` into an element of type `T`. + #[inline] + fn convert_item(item: Self::Item) -> T { + item.into() + } +} + +impl<'i, T, I> ConvertItemRef<'i, T> for I +where + I: ?Sized, + for<'t> &'t Self: IntoIterator, + <&'i Self as IntoIterator>::Item: Into, +{ + type Item = <&'i Self as IntoIterator>::Item; +} + +/// Borrow Iterator +pub trait BorrowIterator: for<'i> IterRef<'i, Item = &'i T> {} + +impl BorrowIterator for I where I: for<'i> IterRef<'i, Item = &'i T> {} + /// For-Each Collector /// /// In the same way that `() : FromIterator<()>` which just calls [`Iterator::for_each`] internally, diff --git a/manta-util/src/lib.rs b/manta-util/src/lib.rs index 4ddef5d11..b9a4e09b3 100644 --- a/manta-util/src/lib.rs +++ b/manta-util/src/lib.rs @@ -29,6 +29,7 @@ mod bytes; mod macros; mod sealed; +pub mod cmp; pub mod codec; pub mod convert; pub mod future; diff --git a/workspace-hack/Cargo.toml b/workspace-hack/Cargo.toml index e6fdfced8..3c92e6620 100644 --- a/workspace-hack/Cargo.toml +++ b/workspace-hack/Cargo.toml @@ -15,10 +15,11 @@ publish = false ### BEGIN HAKARI SECTION [dependencies] aes-gcm = { version = "0.9.4", features = ["aes", "alloc"] } -anyhow = { version = "1.0.61", features = ["std"] } +anyhow = { version = "1.0.62", features = ["std"] } ark-serialize = { version = "0.3.0", default-features = false, features = ["ark-serialize-derive", "derive"] } bitflags = { version = "1.3.2" } blake3 = { version = "1.3.1", default-features = false, features = ["digest", "std"] } +block-buffer = { version = "0.9.0", default-features = false, features = ["block-padding"] } byteorder = { version = "1.4.3", features = ["std"] } crypto-common = { version = "0.1.6", default-features = false, features = ["std"] } digest-93f6ce9d446188ac = { package = "digest", version = "0.10.3", features = ["alloc", "block-buffer", "core-api", "mac", "std", "subtle"] } @@ -36,12 +37,13 @@ indexmap = { version = "1.9.1", default-features = false, features = ["std"] } log = { version = "0.4.17", default-features = false, features = ["kv_unstable", "kv_unstable_std", "std", "value-bag"] } memchr = { version = "2.5.0", features = ["std"] } num-traits = { version = "0.2.15", features = ["i128", "libm", "std"] } +pbkdf2 = { version = "0.9.0", default-features = false, features = ["hmac", "sha2"] } ppv-lite86 = { version = "0.2.16", default-features = false, features = ["simd", "std"] } rand = { version = "0.8.5", features = ["alloc", "getrandom", "libc", "rand_chacha", "std", "std_rng"] } rand_chacha = { version = "0.3.1", default-features = false, features = ["std"] } rand_core = { version = "0.6.3", default-features = false, features = ["alloc", "getrandom", "std"] } -serde = { version = "1.0.143", features = ["alloc", "derive", "serde_derive", "std"] } -serde_json = { version = "1.0.83", features = ["alloc", "std"] } +serde = { version = "1.0.144", features = ["alloc", "derive", "serde_derive", "std"] } +serde_json = { version = "1.0.85", features = ["alloc", "std"] } sha2 = { version = "0.9.9", features = ["std"] } standback = { version = "0.2.17", default-features = false, features = ["std"] } subtle = { version = "2.4.1", default-features = false, features = ["i128"] } @@ -51,7 +53,7 @@ web-sys = { version = "0.3.59", default-features = false, features = ["BinaryTyp zeroize = { version = "1.5.7", default-features = false, features = ["alloc", "zeroize_derive"] } [build-dependencies] -anyhow = { version = "1.0.61", features = ["std"] } +anyhow = { version = "1.0.62", features = ["std"] } blake3 = { version = "1.3.1", default-features = false, features = ["digest", "std"] } cc = { version = "1.0.73", default-features = false, features = ["jobserver", "parallel"] } crypto-common = { version = "0.1.6", default-features = false, features = ["std"] } @@ -59,7 +61,7 @@ digest-93f6ce9d446188ac = { package = "digest", version = "0.10.3", features = [ generic-array = { version = "0.14.6", default-features = false, features = ["more_lengths"] } log = { version = "0.4.17", default-features = false, features = ["kv_unstable", "kv_unstable_std", "std", "value-bag"] } num-traits = { version = "0.2.15", features = ["i128", "libm", "std"] } -serde = { version = "1.0.143", features = ["alloc", "derive", "serde_derive", "std"] } +serde = { version = "1.0.144", features = ["alloc", "derive", "serde_derive", "std"] } standback = { version = "0.2.17", default-features = false, features = ["std"] } subtle = { version = "2.4.1", default-features = false, features = ["i128"] } syn = { version = "1.0.99", features = ["clone-impls", "derive", "extra-traits", "fold", "full", "parsing", "printing", "proc-macro", "quote", "visit", "visit-mut"] }