Skip to content

Commit

Permalink
Improve no_std support by handling randomness better
Browse files Browse the repository at this point in the history
  • Loading branch information
burdges committed Aug 6, 2019
1 parent 9e776da commit 21a039e
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 38 deletions.
12 changes: 11 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,17 @@ default-features = false
[dependencies.rand]
version = "0.6"
default-features = false
optional = true
features = ["i128_support"]

[dependencies.rand_core]
version = "0.4"
default-features = false

[dependencies.rand_os]
version = "0.1.3"
default-features = false

[dependencies.rand_chacha]
version = "0.2"
default-features = false
Expand All @@ -63,6 +72,7 @@ default-features = false
# features = ["zeroize_derive"]

[dev-dependencies]
rand = "0.6"
rand_chacha = "0.1.0"
# hex = "0.3.2"
hex-literal = "0.2.0"
Expand All @@ -76,7 +86,7 @@ name = "schnorr_benchmarks"
harness = false

[features]
default = ["std", "u64_backend"] # "chacha"
default = ["std", "u64_backend", "rand"] # "chacha"
preaudit_deprecated = []
chacha = ["rand_chacha"]
std = ["curve25519-dalek/std", "rand/std"] # "failure/std"
Expand Down
5 changes: 4 additions & 1 deletion src/cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,10 @@ impl Keypair {
pub fn issue_self_ecqv_cert<T>(&self, t: T) -> (ECQVCertPublic, SecretKey)
where T: SigningTranscript+Clone
{
let seed = Keypair::generate();
let key = t.witness_scalar(b"issue_self_ecqv_cert-secret_scalar",&[&self.secret.nonce]);
let mut nonce: [u8; 32] = [0u8; 32];
t.witness_bytes(b"issue_self_ecqv_cert-secret_nonce", &mut nonce, &[&self.secret.nonce]);
let seed = SecretKey { key, nonce }.to_keypair();
let cert_secret = self.issue_ecqv_cert(t.clone(), &seed.public);
self.public.accept_ecqv_cert(t, &seed.secret, cert_secret).expect("Cert issued above and known to produce signature errors; qed")
}
Expand Down
11 changes: 5 additions & 6 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

use core::{cell::RefCell};

use rand::prelude::*; // {RngCore,thread_rng};
use rand_core::{RngCore,CryptoRng};

use merlin::{Transcript};

Expand Down Expand Up @@ -94,7 +94,7 @@ pub trait SigningTranscript {
/// Produce secret witness bytes from the protocol transcript
/// and any "nonce seeds" kept with the secret keys.
fn witness_bytes(&self, label: &'static [u8], dest: &mut [u8], nonce_seeds: &[&[u8]]) {
self.witness_bytes_rng(label, dest, nonce_seeds, thread_rng())
self.witness_bytes_rng(label, dest, nonce_seeds, super::rand_hack())
}

/// Produce secret witness bytes from the protocol transcript
Expand Down Expand Up @@ -408,7 +408,7 @@ where T: SigningTranscript
fn fill_bytes(&mut self, dest: &mut [u8]) {
for i in dest.iter_mut() { *i = 0; }
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), ::rand_core::Error> {
self.fill_bytes(dest);
Ok(())
}
Expand All @@ -419,11 +419,11 @@ where T: SigningTranscript


/*
#[cfg(debug_assertions)]
#[cfg(feature = "rand_chacha")]
use rand_chacha::ChaChaRng;
/// Attach a `ChaChaRng` to a `Transcript` to repalce the default `ThreadRng`
#[cfg(debug_assertions)]
#[cfg(feature = "rand_chacha")]
pub fn attach_chacharng(t: Transcript, seed: [u8; 32]) -> SigningTranscriptWithRng<ChaChaRng> {
attach_rng(t,ChaChaRng::from_seed(seed))
}
Expand All @@ -433,7 +433,6 @@ pub fn attach_chacharng(t: Transcript, seed: [u8; 32]) -> SigningTranscriptWithR
/*
#[cfg(test)]
mod test {
use rand::prelude::*; // ThreadRng,thread_rng
use sha3::Shake128;
use curve25519_dalek::digest::{Input};
Expand Down
4 changes: 1 addition & 3 deletions src/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,16 +173,14 @@ impl Keypair {
pub fn derive_secret_key<T>(&self, mut t: T, cc: ChainCode) -> (SecretKey, ChainCode)
where T: SigningTranscript+Clone
{
use ::rand::prelude::*;

let (scalar, chaincode) = self.public.derive_scalar_and_chaincode(&mut t, cc);

// We can define the nonce however we like here since it only protects
// the signature from bad random number generators. It need not be
// specified by any spcification or standard. It must however be
// independent from the mutating scalar and new chain code.
let mut nonce = [0u8; 32];
thread_rng().fill_bytes(&mut nonce);
rand_hack().fill_bytes(&mut nonce);
// Ideally we'd use the witness mechanism from `merlin::transcript` here,
// instead of the commit and challenge machinery. Yet, we lack access so
// long as we work behind the `SigningTranscript` trait, so we fork the
Expand Down
17 changes: 10 additions & 7 deletions src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
use core::convert::AsRef;
use core::fmt::{Debug};

use rand::prelude::*; // {RngCore,thread_rng};
use rand_core::{RngCore,CryptoRng};

use curve25519_dalek::constants;
use curve25519_dalek::ristretto::{CompressedRistretto,RistrettoPoint};
Expand Down Expand Up @@ -315,7 +315,7 @@ impl MiniSecretKey {
///
/// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng`
pub fn generate_with<R>(mut csprng: R) -> MiniSecretKey
where R: CryptoRng + Rng,
where R: CryptoRng + RngCore,
{
let mut sk: MiniSecretKey = MiniSecretKey([0u8; 32]);
csprng.fill_bytes(&mut sk.0);
Expand Down Expand Up @@ -344,8 +344,9 @@ impl MiniSecretKey {
///
/// let public_key: PublicKey = secret_key.expand_to_public(ExpansionMode::Ed25519);
/// ```
#[cfg(feature = "std")]
pub fn generate() -> MiniSecretKey {
Self::generate_with(thread_rng())
Self::generate_with(super::rand_hack())
}
}

Expand Down Expand Up @@ -563,7 +564,7 @@ impl SecretKey {
/// suplied `csprng` uniformly, bypassing the `MiniSecretKey`
/// layer.
pub fn generate_with<R>(mut csprng: R) -> SecretKey
where R: CryptoRng + Rng,
where R: CryptoRng + RngCore,
{
let mut key: [u8; 64] = [0u8; 64];
csprng.fill_bytes(&mut key);
Expand All @@ -574,8 +575,9 @@ impl SecretKey {

/// Generate an "unbiased" `SecretKey` directly,
/// bypassing the `MiniSecretKey` layer.
#[cfg(feature = "std")]
pub fn generate() -> SecretKey {
Self::generate_with(thread_rng())
Self::generate_with(super::rand_hack())
}

/// Derive the `PublicKey` corresponding to this `SecretKey`.
Expand Down Expand Up @@ -886,7 +888,7 @@ impl Keypair {
/// so our secret keys do not satisfy the high bit "clamping"
/// impoised on Ed25519 keys.
pub fn generate_with<R>(csprng: R) -> Keypair
where R: CryptoRng + Rng,
where R: CryptoRng + RngCore,
{
let secret: SecretKey = SecretKey::generate_with(csprng);
let public: PublicKey = secret.to_public();
Expand All @@ -896,8 +898,9 @@ impl Keypair {

/// Generate a Ristretto Schnorr `Keypair` directly, from a user
/// suplied `csprng`, bypassing the `MiniSecretKey` layer.
#[cfg(feature = "std")]
pub fn generate() -> Keypair {
Self::generate_with(thread_rng())
Self::generate_with(super::rand_hack())
}
}

Expand Down
30 changes: 29 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,33 @@ fn zeroize_hack<Z: Default>(z: &mut Z) {
atomic::compiler_fence(atomic::Ordering::SeqCst);
}

use rand_core::{RngCore,CryptoRng};

#[cfg(feature = "std")]
fn rand_hack() -> impl RngCore+CryptoRng {
#[cfg(feature = "rand")]
{ ::rand::thread_rng() }

#[cfg(not(feature = "rand"))]
{ ::rand_os::OsRng::new() }
}

#[cfg(not(feature = "std"))]
fn rand_hack() -> impl RngCore+CryptoRng {
const PRM : &'static str = "Attempted to use functionality that requires system randomness!!";

struct PanicRng;
impl ::rand_core::RngCore for PanicRng {
fn next_u32(&mut self) -> u32 { panic!(&PRM) }
fn next_u64(&mut self) -> u64 { panic!(&PRM) }
fn fill_bytes(&mut self, _dest: &mut [u8]) { panic!(&PRM) }
fn try_fill_bytes(&mut self, _dest: &mut [u8]) -> Result<(), ::rand_core::Error> { panic!(&PRM) }
}
impl ::rand_core::CryptoRng for PanicRng {}

PanicRng
}

#[macro_use]
mod serdey;

Expand All @@ -243,7 +270,8 @@ pub mod derive;
pub mod cert;
pub mod errors;

#[cfg(any(feature = "alloc", feature = "std"))]
// Not safe because need randomness #[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(feature = "std")]
pub mod musig;

pub use crate::keys::*; // {MiniSecretKey,SecretKey,PublicKey,Keypair,ExpansionMode}; + *_LENGTH
Expand Down
15 changes: 8 additions & 7 deletions src/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@

use core::fmt::{Debug};

use rand::prelude::*; // {RngCore,thread_rng};

use curve25519_dalek::constants;
use curve25519_dalek::ristretto::{CompressedRistretto,RistrettoPoint};
use curve25519_dalek::scalar::Scalar;
Expand Down Expand Up @@ -310,20 +308,23 @@ where

// Use a random number generator keyed by both the publidc keys,
// and the system randomn number gnerator
let mut rng = {
let mut csprng = {
let mut t = merlin::Transcript::new(b"V-RNG");
for pk in public_keys {
t.commit_point(b"",pk.as_compressed());
}
t.build_rng().finalize(&mut rand::prelude::thread_rng())
t.build_rng().finalize(&mut rand_hack())
};

// Select a random 128-bit scalar for each signature.
// We may represent these as scalars because we use
// variable time 256 bit multiplication below.
let zs: Vec<Scalar> = signatures.iter()
.map(|_| Scalar::from(rng.gen::<u128>()))
.collect();
let rnd_128bit_scalar = |_| {
let mut r = [0u8; 16];
csprng.fill_bytes(&mut r);
Scalar::from(u128::from_le_bytes(r))
};
let zs: Vec<Scalar> = signatures.iter().map(rnd_128bit_scalar).collect();

// Compute the basepoint coefficient, ∑ s[i]z[i] (mod l)
let B_coefficient: Scalar = signatures.iter()
Expand Down
25 changes: 13 additions & 12 deletions src/vrf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,6 @@ use alloc::{boxed::Box, vec::Vec};
#[cfg(feature = "std")]
use std::{boxed::Box, vec::Vec};

use rand::prelude::*; // ThreadRng,thread_rng

use curve25519_dalek::constants;
use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
use curve25519_dalek::scalar::Scalar;
Expand Down Expand Up @@ -324,7 +322,7 @@ impl VRFInOut {
/// If you are not the signer then you must verify the VRF before calling this method.
///
/// We expect most users would prefer the less generic `VRFInOut::make_chacharng` method.
pub fn make_rng<R: SeedableRng>(&self, context: &[u8]) -> R {
pub fn make_rng<R: ::rand_core::SeedableRng>(&self, context: &[u8]) -> R {
R::from_seed(self.make_bytes::<R::Seed>(context))
}

Expand Down Expand Up @@ -356,18 +354,18 @@ impl VRFInOut {
pub fn make_merlin_rng(&self, context: &[u8]) -> merlin::TranscriptRng {
// Very insecure hack except for our commit_witness_bytes below
struct ZeroFakeRng;
impl ::rand::RngCore for ZeroFakeRng {
impl ::rand_core::RngCore for ZeroFakeRng {
fn next_u32(&mut self) -> u32 { panic!() }
fn next_u64(&mut self) -> u64 { panic!() }
fn fill_bytes(&mut self, dest: &mut [u8]) {
for i in dest.iter_mut() { *i = 0; }
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), ::rand_core::Error> {
self.fill_bytes(dest);
Ok(())
}
}
impl ::rand::CryptoRng for ZeroFakeRng {}
impl ::rand_core::CryptoRng for ZeroFakeRng {}

let mut t = Transcript::new(b"VRFResult");
t.append_message(b"",context);
Expand Down Expand Up @@ -823,21 +821,24 @@ pub fn dleq_verify_batch(

// Use a random number generator keyed by the publidc keys, the
// inout and putput points, and the system randomn number gnerator.
let mut rng = {
let mut csprng = {
let mut t = Transcript::new(b"VB-RNG");
for (pk,p) in public_keys.iter().zip(ps) {
t.commit_point(b"",pk.as_compressed());
p.commit(&mut t);
}
t.build_rng().finalize(&mut rand::prelude::thread_rng())
t.build_rng().finalize(&mut rand_hack())
};

// Select a random 128-bit scalar for each signature.
// We may represent these as scalars because we use
// variable time 256 bit multiplication below.
let zz: Vec<Scalar> = proofs.iter()
.map(|_| Scalar::from(rng.gen::<u128>()))
.collect();
let rnd_128bit_scalar = |_| {
let mut r = [0u8; 16];
csprng.fill_bytes(&mut r);
Scalar::from(u128::from_le_bytes(r))
};
let zz: Vec<Scalar> = proofs.iter().map(rnd_128bit_scalar).collect();

let z_s: Vec<Scalar> = zz.iter().zip(proofs)
.map(|(z, proof)| z * proof.s)
Expand Down Expand Up @@ -1030,7 +1031,7 @@ mod tests {
#[cfg(any(feature = "alloc", feature = "std"))]
#[test]
fn vrfs_merged_and_batched() {
let mut csprng = thread_rng();
let mut csprng = ::rand::thread_rng();
let keypairs: Vec<Keypair> = (0..4)
.map(|_| Keypair::generate_with(&mut csprng))
.collect();
Expand Down

0 comments on commit 21a039e

Please sign in to comment.