diff --git a/Cargo.toml b/Cargo.toml index 5a1b7743..a81e8e6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,17 +12,18 @@ keywords = ["cryptography", "crypto", "ristretto", "zero-knowledge", "bulletproo description = "A pure-Rust implementation of Bulletproofs using Ristretto" [dependencies] -curve25519-dalek = { version = "^1.2.3", features = ["serde"] } -subtle = "2" -sha3 = "0.8" -digest = "0.8" -rand = "0.6" -byteorder = "1" -serde = "1" -serde_derive = "1" -failure = "0.1" -merlin = "1.1" -clear_on_drop = "0.2" +curve25519-dalek = { version = "^1.2.3", default-features = false, features = ["u64_backend", "nightly", "serde", "alloc"] } +subtle = { version = "2", default-features = false } +sha3 = { version = "0.8", default-features = false } +digest = { version = "0.8", default-features = false } +rand_core = { version = "0.4", default-features = false, features = ["alloc"] } +rand = { version = "0.6", default-features = false, optional = true } +byteorder = { version = "1", default-features = false } +serde = { version = "1", default-features = false, features = ["alloc"] } +serde_derive = { version = "1", default-features = false } +failure = { version = "0.1", default-features = false, features = ["derive"] } +merlin = { version = "1.2", default-features = false } +clear_on_drop = { version = "0.2", default-features = false, features = ["nightly"] } [dev-dependencies] hex = "0.3" @@ -31,8 +32,10 @@ bincode = "1" rand_chacha = "0.1" [features] +default = ["std", "avx2_backend"] avx2_backend = ["curve25519-dalek/avx2_backend"] yoloproofs = [] +std = ["rand", "rand/std"] [[test]] name = "range_proof" diff --git a/src/errors.rs b/src/errors.rs index ca70e31e..b20fbb61 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,5 +1,8 @@ //! Errors related to proving and verifying proofs. +extern crate alloc; +use alloc::vec::Vec; + /// Represents an error in proof creation, verification, or parsing. #[derive(Fail, Clone, Debug, Eq, PartialEq)] pub enum ProofError { diff --git a/src/generators.rs b/src/generators.rs index 20d4e249..1837b90f 100644 --- a/src/generators.rs +++ b/src/generators.rs @@ -4,12 +4,14 @@ #![allow(non_snake_case)] #![deny(missing_docs)] +extern crate alloc; + +use alloc::vec::Vec; use curve25519_dalek::constants::RISTRETTO_BASEPOINT_COMPRESSED; use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; use curve25519_dalek::ristretto::RistrettoPoint; use curve25519_dalek::scalar::Scalar; use curve25519_dalek::traits::MultiscalarMul; - use digest::{ExtendableOutput, Input, XofReader}; use sha3::{Sha3XofReader, Sha3_512, Shake256}; diff --git a/src/inner_product_proof.rs b/src/inner_product_proof.rs index e42ee6ce..52285650 100644 --- a/src/inner_product_proof.rs +++ b/src/inner_product_proof.rs @@ -1,9 +1,12 @@ #![allow(non_snake_case)] #![doc(include = "../docs/inner-product-protocol.md")] -use std::borrow::Borrow; -use std::iter; +extern crate alloc; +use alloc::borrow::Borrow; +use alloc::vec::Vec; + +use core::iter; use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint}; use curve25519_dalek::scalar::Scalar; use curve25519_dalek::traits::VartimeMultiscalarMul; diff --git a/src/lib.rs b/src/lib.rs index 82d760d6..2d18d359 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +#![cfg_attr(not(feature = "std"), no_std)] #![feature(nll)] #![feature(external_doc)] #![feature(try_trait)] @@ -6,9 +7,17 @@ #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] extern crate byteorder; + +extern crate alloc; + +#[cfg(feature = "std")] extern crate core; -extern crate digest; + +#[cfg(feature = "std")] extern crate rand; + +extern crate digest; +extern crate rand_core; extern crate sha3; extern crate clear_on_drop; @@ -56,4 +65,5 @@ pub mod range_proof_mpc { } #[cfg(feature = "yoloproofs")] +#[cfg(feature = "std")] pub mod r1cs; diff --git a/src/range_proof/dealer.rs b/src/range_proof/dealer.rs index 80d6bf63..83714e77 100644 --- a/src/range_proof/dealer.rs +++ b/src/range_proof/dealer.rs @@ -5,6 +5,11 @@ //! [the API for the aggregated multiparty computation protocol](../aggregation/index.html#api-for-the-aggregated-multiparty-computation-protocol). use core::iter; + +extern crate alloc; + +use alloc::vec::Vec; + use curve25519_dalek::ristretto::RistrettoPoint; use curve25519_dalek::scalar::Scalar; use merlin::Transcript; @@ -15,8 +20,13 @@ use inner_product_proof; use range_proof::RangeProof; use transcript::TranscriptProtocol; +use rand_core::{CryptoRng, RngCore}; + use util; +#[cfg(feature = "std")] +use rand::thread_rng; + use super::messages::*; /// Used to construct a dealer for the aggregated rangeproof MPC protocol. @@ -282,6 +292,17 @@ impl<'a, 'b> DealerAwaitingProofShares<'a, 'b> { }) } + /// Assemble the final aggregated [`RangeProof`] from the given + /// `proof_shares`, then validate the proof to ensure that all + /// `ProofShare`s were well-formed. + /// + /// This is a convenience wrapper around receive_shares_with_rng + /// + #[cfg(feature = "std")] + pub fn receive_shares(self, proof_shares: &[ProofShare]) -> Result { + self.receive_shares_with_rng(proof_shares, &mut thread_rng()) + } + /// Assemble the final aggregated [`RangeProof`] from the given /// `proof_shares`, then validate the proof to ensure that all /// `ProofShare`s were well-formed. @@ -295,7 +316,11 @@ impl<'a, 'b> DealerAwaitingProofShares<'a, 'b> { /// performing local aggregation, /// [`receive_trusted_shares`](DealerAwaitingProofShares::receive_trusted_shares) /// saves time by skipping verification of the aggregated proof. - pub fn receive_shares(mut self, proof_shares: &[ProofShare]) -> Result { + pub fn receive_shares_with_rng( + mut self, + proof_shares: &[ProofShare], + rng: &mut T, + ) -> Result { let proof = self.assemble_shares(proof_shares)?; let Vs: Vec<_> = self.bit_commitments.iter().map(|vc| vc.V_j).collect(); @@ -303,7 +328,7 @@ impl<'a, 'b> DealerAwaitingProofShares<'a, 'b> { // See comment in `Dealer::new` for why we use `initial_transcript` let transcript = &mut self.initial_transcript; if proof - .verify_multiple(self.bp_gens, self.pc_gens, transcript, &Vs, self.n) + .verify_multiple_with_rng(self.bp_gens, self.pc_gens, transcript, &Vs, self.n, rng) .is_ok() { Ok(proof) diff --git a/src/range_proof/messages.rs b/src/range_proof/messages.rs index db59f15a..504216c2 100644 --- a/src/range_proof/messages.rs +++ b/src/range_proof/messages.rs @@ -4,9 +4,12 @@ //! For more explanation of how the `dealer`, `party`, and `messages` modules orchestrate the protocol execution, see //! [the API for the aggregated multiparty computation protocol](../aggregation/index.html#api-for-the-aggregated-multiparty-computation-protocol). +extern crate alloc; + +use alloc::vec::Vec; +use core::iter; use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint}; use curve25519_dalek::scalar::Scalar; - use generators::{BulletproofGens, PedersenGens}; /// A commitment to the bits of a party's value. @@ -87,8 +90,6 @@ impl ProofShare { poly_commitment: &PolyCommitment, poly_challenge: &PolyChallenge, ) -> Result<(), ()> { - use std::iter; - use curve25519_dalek::traits::{IsIdentity, VartimeMultiscalarMul}; use inner_product_proof::inner_product; diff --git a/src/range_proof/mod.rs b/src/range_proof/mod.rs index c680ae78..592d81d4 100644 --- a/src/range_proof/mod.rs +++ b/src/range_proof/mod.rs @@ -1,9 +1,15 @@ #![allow(non_snake_case)] #![doc(include = "../../docs/range-proof-protocol.md")] -use rand; +extern crate alloc; +#[cfg(feature = "std")] +extern crate rand; -use std::iter; +#[cfg(feature = "std")] +use self::rand::thread_rng; +use alloc::vec::Vec; + +use core::iter; use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint}; use curve25519_dalek::scalar::Scalar; @@ -16,6 +22,7 @@ use inner_product_proof::InnerProductProof; use transcript::TranscriptProtocol; use util; +use rand_core::{CryptoRng, RngCore}; use serde::de::Visitor; use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; @@ -125,19 +132,51 @@ impl RangeProof { /// ); /// # } /// ``` - pub fn prove_single( + pub fn prove_single_with_rng( bp_gens: &BulletproofGens, pc_gens: &PedersenGens, transcript: &mut Transcript, v: u64, v_blinding: &Scalar, n: usize, + rng: &mut T, ) -> Result<(RangeProof, CompressedRistretto), ProofError> { - let (p, Vs) = - RangeProof::prove_multiple(bp_gens, pc_gens, transcript, &[v], &[*v_blinding], n)?; + let (p, Vs) = RangeProof::prove_multiple_with_rng( + bp_gens, + pc_gens, + transcript, + &[v], + &[*v_blinding], + n, + rng, + )?; Ok((p, Vs[0])) } + /// Create a rangeproof for a given pair of value `v` and + /// blinding scalar `v_blinding`. + /// This is a convenience wrapper around [`RangeProof::prove_single_with_rng`], + /// passing in a threadsafe RNG. + #[cfg(feature = "std")] + pub fn prove_single( + bp_gens: &BulletproofGens, + pc_gens: &PedersenGens, + transcript: &mut Transcript, + v: u64, + v_blinding: &Scalar, + n: usize, + ) -> Result<(RangeProof, CompressedRistretto), ProofError> { + RangeProof::prove_single_with_rng( + bp_gens, + pc_gens, + transcript, + v, + v_blinding, + n, + &mut thread_rng(), + ) + } + /// Create a rangeproof for a set of values. /// /// # Example @@ -192,13 +231,14 @@ impl RangeProof { /// ); /// # } /// ``` - pub fn prove_multiple( + pub fn prove_multiple_with_rng( bp_gens: &BulletproofGens, pc_gens: &PedersenGens, transcript: &mut Transcript, values: &[u64], blindings: &[Scalar], n: usize, + rng: &mut T, ) -> Result<(RangeProof, Vec), ProofError> { use self::dealer::*; use self::party::*; @@ -220,7 +260,7 @@ impl RangeProof { .into_iter() .enumerate() .map(|(j, p)| { - p.assign_position(j) + p.assign_position_with_rng(j, rng) .expect("We already checked the parameters, so this should never happen") }) .unzip(); @@ -231,7 +271,7 @@ impl RangeProof { let (parties, poly_commitments): (Vec<_>, Vec<_>) = parties .into_iter() - .map(|p| p.apply_challenge(&bit_challenge)) + .map(|p| p.apply_challenge_with_rng(&bit_challenge, rng)) .unzip(); let (dealer, poly_challenge) = dealer.receive_poly_commitments(poly_commitments)?; @@ -247,9 +287,49 @@ impl RangeProof { Ok((proof, value_commitments)) } + /// Create a rangeproof for a set of values. + /// This is a convenience wrapper around [`RangeProof::prove_multiple_with_rng`], + /// passing in a threadsafe RNG. + #[cfg(feature = "std")] + pub fn prove_multiple( + bp_gens: &BulletproofGens, + pc_gens: &PedersenGens, + transcript: &mut Transcript, + values: &[u64], + blindings: &[Scalar], + n: usize, + ) -> Result<(RangeProof, Vec), ProofError> { + RangeProof::prove_multiple_with_rng( + bp_gens, + pc_gens, + transcript, + values, + blindings, + n, + &mut thread_rng(), + ) + } + /// Verifies a rangeproof for a given value commitment \\(V\\). /// /// This is a convenience wrapper around `verify_multiple` for the `m=1` case. + pub fn verify_single_with_rng( + &self, + bp_gens: &BulletproofGens, + pc_gens: &PedersenGens, + transcript: &mut Transcript, + V: &CompressedRistretto, + n: usize, + rng: &mut T, + ) -> Result<(), ProofError> { + self.verify_multiple_with_rng(bp_gens, pc_gens, transcript, &[*V], n, rng) + } + + /// Verifies a rangeproof for a given value commitment \\(V\\). + /// + /// This is a convenience wrapper around [`RangeProof::verify_single_with_rng`], + /// passing in a threadsafe RNG. + #[cfg(feature = "std")] pub fn verify_single( &self, bp_gens: &BulletproofGens, @@ -258,17 +338,18 @@ impl RangeProof { V: &CompressedRistretto, n: usize, ) -> Result<(), ProofError> { - self.verify_multiple(bp_gens, pc_gens, transcript, &[*V], n) + self.verify_single_with_rng(bp_gens, pc_gens, transcript, V, n, &mut thread_rng()) } /// Verifies an aggregated rangeproof for the given value commitments. - pub fn verify_multiple( + pub fn verify_multiple_with_rng( &self, bp_gens: &BulletproofGens, pc_gens: &PedersenGens, transcript: &mut Transcript, value_commitments: &[CompressedRistretto], n: usize, + rng: &mut T, ) -> Result<(), ProofError> { let m = value_commitments.len(); @@ -311,10 +392,8 @@ impl RangeProof { let w = transcript.challenge_scalar(b"w"); - let mut rng = transcript.build_rng().finalize(&mut rand::thread_rng()); - // Challenge value for batching statements to be verified - let c = Scalar::random(&mut rng); + let c = Scalar::random(rng); let (x_sq, x_inv_sq, s) = self.ipp_proof.verification_scalars(n * m, transcript)?; let s_inv = s.iter().rev(); @@ -372,6 +451,28 @@ impl RangeProof { } } + /// Verifies an aggregated rangeproof for the given value commitments. + /// This is a convenience wrapper around [`RangeProof::verify_multiple_with_rng`], + /// passing in a threadsafe RNG. + #[cfg(feature = "std")] + pub fn verify_multiple( + &self, + bp_gens: &BulletproofGens, + pc_gens: &PedersenGens, + transcript: &mut Transcript, + value_commitments: &[CompressedRistretto], + n: usize, + ) -> Result<(), ProofError> { + self.verify_multiple_with_rng( + bp_gens, + pc_gens, + transcript, + value_commitments, + n, + &mut thread_rng(), + ) + } + /// Serializes the proof into a byte array of \\(2 \lg n + 9\\) /// 32-byte elements, where \\(n\\) is the number of secret bits. /// @@ -528,7 +629,7 @@ mod tests { // data is shared between the prover and the verifier. // Use bincode for serialization - use bincode; + //use bincode; // already present in lib.rs // Both prover and verifier have access to the generators and the proof let max_bitsize = 64; @@ -538,7 +639,7 @@ mod tests { // Prover's scope let (proof_bytes, value_commitments) = { - use rand::Rng; + use self::rand::Rng; let mut rng = rand::thread_rng(); // 0. Create witness data @@ -630,7 +731,7 @@ mod tests { let pc_gens = PedersenGens::default(); let bp_gens = BulletproofGens::new(n, m); - use rand::Rng; + use self::rand::Rng; let mut rng = rand::thread_rng(); let mut transcript = Transcript::new(b"AggregatedRangeProofTest"); @@ -703,7 +804,7 @@ mod tests { let pc_gens = PedersenGens::default(); let bp_gens = BulletproofGens::new(n, m); - use rand::Rng; + use self::rand::Rng; let mut rng = rand::thread_rng(); let mut transcript = Transcript::new(b"AggregatedRangeProofTest"); diff --git a/src/range_proof/party.rs b/src/range_proof/party.rs index 8bbf8621..aaf2c8fe 100644 --- a/src/range_proof/party.rs +++ b/src/range_proof/party.rs @@ -10,17 +10,22 @@ //! modules orchestrate the protocol execution, see the documentation //! in the [`aggregation`](::range_proof_mpc) module. +extern crate alloc; + +use alloc::vec::Vec; +use clear_on_drop::clear::Clear; +use core::iter; use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint}; use curve25519_dalek::scalar::Scalar; use curve25519_dalek::traits::MultiscalarMul; - -use clear_on_drop::clear::Clear; use errors::MPCError; use generators::{BulletproofGens, PedersenGens}; -use rand; -use std::iter; +use rand_core::{CryptoRng, RngCore}; use util; +#[cfg(feature = "std")] +use rand::thread_rng; + use super::messages::*; /// Used to construct a party for the aggregated rangeproof MPC protocol. @@ -68,20 +73,28 @@ pub struct PartyAwaitingPosition<'a> { impl<'a> PartyAwaitingPosition<'a> { /// Assigns a position in the aggregated proof to this party, /// allowing the party to commit to the bits of their value. + #[cfg(feature = "std")] pub fn assign_position( self, j: usize, ) -> Result<(PartyAwaitingBitChallenge<'a>, BitCommitment), MPCError> { - // XXX use transcript RNG - let mut rng = rand::thread_rng(); + self.assign_position_with_rng(j, &mut thread_rng()) + } + /// Assigns a position in the aggregated proof to this party, + /// allowing the party to commit to the bits of their value. + pub fn assign_position_with_rng( + self, + j: usize, + rng: &mut T, + ) -> Result<(PartyAwaitingBitChallenge<'a>, BitCommitment), MPCError> { if self.bp_gens.party_capacity <= j { return Err(MPCError::InvalidGeneratorsLength); } let bp_share = self.bp_gens.share(j); - let a_blinding = Scalar::random(&mut rng); + let a_blinding = Scalar::random(rng); // Compute A = + + a_blinding * B_blinding let mut A = self.pc_gens.B_blinding * a_blinding; @@ -97,9 +110,9 @@ impl<'a> PartyAwaitingPosition<'a> { i += 1; } - let s_blinding = Scalar::random(&mut rng); - let s_L: Vec = (0..self.n).map(|_| Scalar::random(&mut rng)).collect(); - let s_R: Vec = (0..self.n).map(|_| Scalar::random(&mut rng)).collect(); + let s_blinding = Scalar::random(rng); + let s_L: Vec = (0..self.n).map(|_| Scalar::random(rng)).collect(); + let s_R: Vec = (0..self.n).map(|_| Scalar::random(rng)).collect(); // Compute S = + + s_blinding * B_blinding let S = RistrettoPoint::multiscalar_mul( @@ -155,12 +168,21 @@ pub struct PartyAwaitingBitChallenge<'a> { impl<'a> PartyAwaitingBitChallenge<'a> { /// Receive a [`BitChallenge`] from the dealer and use it to /// compute commitments to the party's polynomial coefficients. + #[cfg(feature = "std")] pub fn apply_challenge( self, vc: &BitChallenge, ) -> (PartyAwaitingPolyChallenge, PolyCommitment) { - let mut rng = rand::thread_rng(); + self.apply_challenge_with_rng(vc, &mut thread_rng()) + } + /// Receive a [`BitChallenge`] from the dealer and use it to + /// compute commitments to the party's polynomial coefficients. + pub fn apply_challenge_with_rng( + self, + vc: &BitChallenge, + rng: &mut T, + ) -> (PartyAwaitingPolyChallenge, PolyCommitment) { let n = self.n; let offset_y = util::scalar_exp_vartime(&vc.y, (self.j * n) as u64); let offset_z = util::scalar_exp_vartime(&vc.z, self.j as u64); @@ -188,8 +210,8 @@ impl<'a> PartyAwaitingBitChallenge<'a> { let t_poly = l_poly.inner_product(&r_poly); // Generate x by committing to T_1, T_2 (line 49-54) - let t_1_blinding = Scalar::random(&mut rng); - let t_2_blinding = Scalar::random(&mut rng); + let t_1_blinding = Scalar::random(rng); + let t_2_blinding = Scalar::random(rng); let T_1 = self.pc_gens.commit(t_poly.1, t_1_blinding); let T_2 = self.pc_gens.commit(t_poly.2, t_2_blinding); diff --git a/src/util.rs b/src/util.rs index 7c65735b..ac5330ac 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,6 +1,10 @@ #![deny(missing_docs)] #![allow(non_snake_case)] +extern crate alloc; + +use alloc::vec; +use alloc::vec::Vec; use clear_on_drop::clear::Clear; use curve25519_dalek::scalar::Scalar; use inner_product_proof::inner_product; @@ -64,7 +68,7 @@ pub fn exp_iter(x: Scalar) -> ScalarExp { pub fn add_vec(a: &[Scalar], b: &[Scalar]) -> Vec { if a.len() != b.len() { // throw some error - println!("lengths of vectors don't match for vector addition"); + //println!("lengths of vectors don't match for vector addition"); } let mut out = vec![Scalar::zero(); b.len()]; for i in 0..a.len() {