diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..74550de --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,38 @@ +name: Rust + +on: + push: + branches: [ '**' ] + pull_request: + branches: [ '**' ] + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: '-D warnings' + +jobs: + test: + name: Run tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo test + + clippy: + name: Check that clippy is happy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + - run: cargo clippy --target x86_64-unknown-linux-gnu + + bench: + name: Check that benchmarks compile + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo build --benches diff --git a/Cargo.toml b/Cargo.toml index 85d096a..c730127 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "schnorrkel" -version = "0.10.2" +version = "0.11.0" authors = ["Jeff Burdges "] readme = "README.md" license = "BSD-3-Clause" @@ -10,98 +10,31 @@ keywords = ["cryptography", "ed25519", "curve25519", "signature", "ECC"] categories = ["cryptography", "no-std"] description = "Schnorr VRF, signatures, etc. using the Ristretto group" exclude = [ ".gitignore", "res/*" ] -edition = "2018" +edition = "2021" -# [badges] -# travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} - -[dependencies.aead] -version = "0.4.3" -default-features = false -optional = true - -[dependencies.arrayref] -version = "0.3.6" -default-features = false - -[dependencies.arrayvec] +[dependencies] +aead = { version = "0.5.2", default-features = false, optional = true } +arrayref = { version = "0.3.6", default-features = false } # needs to match parity-scale-code which is "=0.7.0" -version = "0.7.0" -default-features = false - -[dependencies.curve25519-dalek] -package = "curve25519-dalek-ng" -# git = "https://github.com/dalek-cryptography/curve25519-dalek" -version = "4.1.1" -default-features = false - -# [dependencies.ed25519-dalek] -# version = "1.0.0" -# default-features = false -# optional = true - -[dependencies.subtle] -package = "subtle-ng" -version = "2.5.0" -default-features = false - -[dependencies.merlin] -version = "3.0.0" -# features = ["debug-transcript"] -default-features = false - -# [dependencies.rand] -# version = "0.8.3" -# default-features = false -# optional = true - -[dependencies.rand_core] -version = "0.6.2" -default-features = false - -[dependencies.rand_chacha] -version = "0.3.1" -default-features = false -optional = true - -[dependencies.serde_crate] -version = "1.0.130" -package = "serde" -default-features = false -optional = true - -[dependencies.serde_bytes] -version = "0.11.5" -default-features = false -optional = true - -[dependencies.cfg-if] -version = "1.0.0" -optional = true - -[dependencies.sha2] -version = "0.9.8" -default-features = false - -[dependencies.failure] -version = "0.1.8" -default-features = false -optional = true - -[dependencies.zeroize] -version = "1.4.2" -default-features = false -features = ["zeroize_derive"] +arrayvec = { version = "0.7.0", default-features = false } +curve25519-dalek = { version = "4.0.0-rc.2", default-features = false, features = ["digest", "zeroize"] } +subtle = { version = "2.5.0", default-features = false } +merlin = { version = "3.0.0", default-features = false } +rand_core = { version = "0.6.2", default-features = false } +serde_crate = { version = "1.0.130", package = "serde", default-features = false, optional = true } +serde_bytes = { version = "0.11.5", default-features = false, optional = true } +cfg-if = { version = "1.0.0", optional = true } +sha2 = { version = "0.10.6", default-features = false } +failure = { version = "0.1.8", default-features = false, optional = true } +zeroize = { version = "1.4.2", default-features = false, features = ["zeroize_derive"] } [dev-dependencies] rand = "0.8.4" -rand_chacha = "0.3.1" -# hex = "0.3.2" -hex-literal = "0.3.3" -sha2 = "0.9.8" -sha3 = "0.9.1" +rand_chacha = { version = "0.3.1", default-features = false } +hex-literal = "0.4.1" +sha3 = "0.10.7" bincode = "1.3.3" -criterion = "0.3.5" +criterion = "0.4.0" serde_json = "1.0.68" [[bench]] @@ -109,15 +42,13 @@ name = "schnorr_benchmarks" harness = false [features] -default = ["std", "u64_backend", "getrandom"] # "rand" +default = ["std", "getrandom", "precomputed-tables"] preaudit_deprecated = [] -nightly = ["curve25519-dalek/nightly"] # "zeroize/nightly" +nightly = [] alloc = ["curve25519-dalek/alloc", "rand_core/alloc", "serde_bytes/alloc"] -std = ["getrandom", "curve25519-dalek/std", "serde_bytes/std"] # "failure/std" +std = ["alloc", "getrandom", "serde_bytes/std"] asm = ["sha2/asm"] -u64_backend = ["curve25519-dalek/u64_backend"] -u32_backend = ["curve25519-dalek/u32_backend"] -avx2_backend = ["curve25519-dalek/avx2_backend"] +precomputed-tables = ["curve25519-dalek/precomputed-tables"] serde = ["serde_crate", "serde_bytes", "cfg-if"] # We cannot make getrandom a direct dependency because rand_core makes # getrandom a feature name, which requires forwarding. diff --git a/iffy/migration_from_ed25519/src/derive.rs.diff b/iffy/migration_from_ed25519/src/derive.rs.diff deleted file mode 100644 index 194ac09..0000000 --- a/iffy/migration_from_ed25519/src/derive.rs.diff +++ /dev/null @@ -1,60 +0,0 @@ -diff --git a/src/derive.rs b/src/derive.rs -index 55f188b..eb03738 100644 ---- a/src/derive.rs -+++ b/src/derive.rs -@@ -190,7 +190,6 @@ mod tests { - use rand::prelude::*; // thread_rng - - use sha3::digest::{Input}; // ExtendableOutput,XofReader -- use sha3::{Shake128,Sha3_512}; // Shake256 - - use super::*; - -@@ -200,7 +199,6 @@ mod tests { - let chaincode = ChainCode([0u8; CHAIN_CODE_LENGTH]); - let msg : &'static [u8] = b"Just some test message!"; - let mut h = Shake128::default().chain(msg); -- let mut h_ed25519 = Sha3_512::default().chain(msg); - - let key = Keypair::generate(&mut rng); - let mut extended_public_key = ExtendedKey { -@@ -226,7 +224,6 @@ mod tests { - extended_public_key = extended_public_key1; - - h.input(b"Another"); -- h_ed25519.input(b"Another"); - - if i % 5 == 0 { - let good_sig = extended_keypair.key.sign(ctx.xof(h.clone())); -@@ -246,31 +243,6 @@ mod tests { - "Verification of a signature on a different message passed!" - ); - } -- -- if i % 7 == 0 { -- let context = Some(b"testing testing 1 2 3" as &[u8]); -- let good_sig = extended_keypair.key -- .sign_ed25519_prehashed::(h_ed25519.clone(), context); -- let h_bad = h_ed25519.clone().chain(b"oops"); -- let bad_sig = extended_keypair.key -- .sign_ed25519_prehashed::(h_bad.clone(), context); -- -- assert!( -- extended_public_key.key -- .verify_ed25519_prehashed(h_ed25519.clone(), context, &good_sig), -- "Verification of a valid signature failed!" -- ); -- assert!( -- ! extended_public_key.key -- .verify_ed25519_prehashed::(h_ed25519.clone(), context, &bad_sig), -- "Verification of a signature on a different message passed!" -- ); -- assert!( -- ! extended_public_key.key -- .verify_ed25519_prehashed::(h_bad, context, &good_sig), -- "Verification of a signature on a different message passed!" -- ); -- } - } - } - } diff --git a/iffy/migration_from_ed25519/src/ed25519.rs b/iffy/migration_from_ed25519/src/ed25519.rs deleted file mode 100644 index c978c97..0000000 --- a/iffy/migration_from_ed25519/src/ed25519.rs +++ /dev/null @@ -1,327 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 Isis Lovecruft and Web 3 Foundation -// See LICENSE for licensing information. -// -// Authors: -// - Isis Agora Lovecruft -// - Jeff Burdges - -//! Export, import, and use Ed25519 public keys. -//! -//! Avoid using this module, except as a short-term transitional convenience. -//! -//! We warn that each Ristretto public key corresponds to two Ed25519 -//! public keys because ristretto involves a square root. As such, -//! all methods provided here must be considered non-cannonical, -//! meaning if another ristretto impleentation chooses another brnach -//! of the square root then the results will be incompatable. -//! -//! We do not expect vuonerabilities from this when merely using or -//! exporting Ristretto public keys as Ed25519 public keys, but -//! Ed25519 signatures created here may fail verification when used -//! with another Ristretto implementation. -//! -//! We foresee worse when using `PublicKey::from_ed25519_public_key_bytes` -//! provided here because protocols might expose vulnerablities if they -//! import the same Ristretto key expecting two different keys. -//! As a minor example, two tightly related Ed25519 public keys used -//! with out our HDKD methods could yield the same derived keys. -//! -//! In the near future, we shall hide this module behind a "transitional" -//! feature flag due to these concerns. - -use curve25519_dalek::digest; -use curve25519_dalek::digest::generic_array::typenum::U64; - -use curve25519_dalek::edwards::{CompressedEdwardsY,EdwardsPoint}; -use curve25519_dalek::ristretto::{RistrettoPoint}; -use curve25519_dalek::scalar::Scalar; - -use super::*; - - -type Ed25519Signature = [u8; ::ed25519_dalek::SIGNATURE_LENGTH]; - - -/// Requires `RistrettoPoint` be defined as `RistrettoPoint(EdwardsPoint)`. -/// Any usage risks signature ed25519 verification failure when verifiers -/// use another Ristretto implementation. -pub fn ristretto_to_edwards(p: RistrettoPoint) -> EdwardsPoint { - unsafe { ::std::mem::transmute::(p) } -} - -/// Requires `RistrettoPoint` be defined as `RistrettoPoint(EdwardsPoint)` -/// -/// Avoid using this function. It is necessarily painfully slow. -pub fn edwards_to_ristretto(p: EdwardsPoint) -> Result { - if ! p.is_torsion_free() { - return Err(SignatureError::PointDecompressionError); - } - Ok(unsafe { ::std::mem::transmute::(p) }) -} - - -impl SecretKey { - /// Sign a message with this `SecretKey` using the old Ed25519 - /// algorithm. - /// - /// Incurs a public key comression cost which Ed25519 normally avoids, - /// making the `ed25519-dalek` crate faster. - #[allow(non_snake_case)] - pub fn sign_ed25519(&self, message: &[u8], public_key: &PublicKey) -> Ed25519Signature { - let public_key = public_key.to_ed25519_public_key(); - self.to_ed25519_expanded_secret_key() - .sign(message,&public_key).to_bytes() - } - - /// Sign a `prehashed_message` with this `SecretKey` using the - /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. - /// - /// Incurs a public key comression cost which Ed25519ph normally avoids, - /// making the `ed25519-dalek` crate faster. - /// - /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 - #[allow(non_snake_case)] - pub fn sign_ed25519_prehashed( - &self, - prehashed_message: D, - public_key: &PublicKey, - context: Option<&'static [u8]>, - ) -> Ed25519Signature - where D: digest::Digest + Default + Clone, - { - let public_key = public_key.to_ed25519_public_key(); - self.to_ed25519_expanded_secret_key() - .sign_prehashed::(prehashed_message,&public_key,context).to_bytes() - } -} - -impl PublicKey { - /// A serialized Ed25519 public key compatable with our serialization - /// of the corresponding `SecretKey`. - /// - /// We multiply by the cofactor 8 here because we multiply our - /// scalars by the cofactor 8 in serialization as well. In this way, - /// our serializations remain somewhat ed25519 compatable, except for - /// clamping, but internally we only operate on honest scalars - /// represented mod l, and thus avoid spooky cofactor bugs. - pub fn to_ed25519_public_key_bytes(&self) -> [u8; 32] { - ristretto_to_edwards(self.as_point().clone()).mul_by_cofactor().compress().to_bytes() - } - - /// An Ed25519 public key compatable with our serialization of - /// the corresponding `SecretKey`. - pub fn to_ed25519_public_key(&self) -> ::ed25519_dalek::PublicKey { - let pkb = self.to_ed25519_public_key_bytes(); - ::ed25519_dalek::PublicKey::from_bytes(&pkb[..]) - .expect("Improper serialisation of Ed25519 public key!") - } - - /// Deserialized an Ed25519 public key compatable with our - /// serialization of the corresponding `SecretKey`. - /// - /// Avoid using this function. It is necessarily painfully slow, - /// perahps the slowest in this crate, and will make you look bad. - /// It's also extremely dangerous because two different ed25519 - /// public keys import as the same Ristretto public key, which - /// could concievably create vulnerabilities for more complex - /// protocols built around Ristretto. - /// Instead, communitate and use only Ristretto public keys, and - /// convert to ed25519 keys as required. - pub fn from_ed25519_public_key_bytes(bytes: &[u8]) -> Result { - if bytes.len() != PUBLIC_KEY_LENGTH { - return Err(SignatureError::BytesLengthError { - name: "PublicKey", - discription: "An ed25519 public key as a 32-byte compressed point, as specified in RFC8032", - length: PUBLIC_KEY_LENGTH - }); - } - let mut bits: [u8; 32] = [0u8; 32]; - bits.copy_from_slice(&bytes[..32]); - - let mut point = edwards_to_ristretto( - CompressedEdwardsY(bits).decompress() - .ok_or(SignatureError::PointDecompressionError) ? - ) ?; // PointDecompressionError unless 2-torsion free - let eighth = Scalar::from(8u8).invert(); - debug_assert_eq!(Scalar::one(), eighth * Scalar::from(8u8)); - point *= &eighth; - Ok(PublicKey::from_point(point)) - // debug_assert_eq!(bytes,p.to_ed25519_public_key_bytes()); - } - - /// Verify a signature on a message with this public key. - /// - /// Incurs a public key comression cost which Ed25519 normally avoids, - /// making the `ed25519-dalek` crate faster. - #[allow(non_snake_case)] - pub fn verify_ed25519(&self, message: &[u8], signature: &Ed25519Signature) -> bool { - ::ed25519_dalek::Signature::from_bytes(&signature[..]) - .and_then(|s| self.to_ed25519_public_key().verify(message,&s)).is_ok() - } - - /// Verify a `signature` on a `prehashed_message` using the - /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. - /// - /// Incurs a public key comression cost which Ed25519ph normally avoids, - /// making the `ed25519-dalek` crate faster. - /// - /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 - #[allow(non_snake_case)] - pub fn verify_ed25519_prehashed( - &self, - prehashed_message: D, - context: Option<&[u8]>, - signature: &Ed25519Signature - ) -> bool - where D: digest::Digest + Default - { - ::ed25519_dalek::Signature::from_bytes(&signature[..]) - .and_then(|s| self.to_ed25519_public_key().verify_prehashed::(prehashed_message,context,&s)).is_ok() - } -} - -impl Keypair { - /// Sign a message with this `SecretKey` using ed25519. - #[allow(non_snake_case)] - pub fn sign_ed25519(&self, message: &[u8]) -> Ed25519Signature { - self.secret.sign_ed25519(message, &self.public) - } - - /// Sign a `prehashed_message` with this `SecretKey` using the - /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. - #[allow(non_snake_case)] - pub fn sign_ed25519_prehashed( - &self, - prehashed_message: D, - context: Option<&'static [u8]>, - ) -> Ed25519Signature - where D: digest::Digest + Default + Clone, - { - self.secret.sign_ed25519_prehashed::(prehashed_message, &self.public, context) - } - - /// Verify a signature on a message with this public key. - /// - /// Incurs a public key comression cost which Ed25519 normally avoids, - /// making the `ed25519-dalek` crate faster. - #[allow(non_snake_case)] - pub fn verify_ed25519(&self, message: &[u8], signature: &Ed25519Signature) -> bool { - self.public.verify_ed25519(message,signature) - } - - /// Verify a `signature` on a `prehashed_message` using the - /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. - /// - /// Incurs a public key comression cost which Ed25519ph normally avoids, - /// making the `ed25519-dalek` crate faster. - /// - /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 - #[allow(non_snake_case)] - #[allow(non_snake_case)] - pub fn verify_ed25519_prehashed( - &self, - prehashed_message: D, - context: Option<&[u8]>, - signature: &Ed25519Signature - ) -> bool - where D: digest::Digest + Default - { - self.public.verify_ed25519_prehashed::(prehashed_message,context,signature) - } -} - - -#[cfg(test)] -mod test { - use std::vec::Vec; - use hex::FromHex; - // use rand::prelude::*; // ThreadRng,thread_rng - use sha2::{Sha512,Digest}; - use super::*; - - /* *** We have no test vectors obviously *** - - use std::io::BufReader; - use std::io::BufRead; - use std::fs::File; - use std::string::String; - - // TESTVECTORS is taken from sign.input.gz in agl's ed25519 Golang - // package. It is a selection of test cases from - // http://ed25519.cr.yp.to/python/sign.input - #[cfg(test)] - #[cfg(not(release))] - #[test] - fn golden() { // TestGolden - let mut line: String; - let mut lineno: usize = 0; - - let f = File::open("TESTVECTORS"); - if f.is_err() { - println!("This test is only available when the code has been cloned \ - from the git repository, since the TESTVECTORS file is large \ - and is therefore not included within the distributed crate."); - panic!(); - } - let file = BufReader::new(f.unwrap()); - - for l in file.lines() { - lineno += 1; - line = l.unwrap(); - - let parts: Vec<&str> = line.split(':').collect(); - assert_eq!(parts.len(), 5, "wrong number of fields in line {}", lineno); - - let sec_bytes: Vec = FromHex::from_hex(&parts[0]).unwrap(); - let pub_bytes: Vec = FromHex::from_hex(&parts[1]).unwrap(); - let msg_bytes: Vec = FromHex::from_hex(&parts[2]).unwrap(); - let sig_bytes: Vec = FromHex::from_hex(&parts[3]).unwrap(); - - let secret: MiniSecretKey = MiniSecretKey::from_bytes(&sec_bytes[..MINI_SECRET_KEY_LENGTH]).unwrap(); - let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); - let keypair: Keypair = Keypair{ secret: secret, public: public }; - - // The signatures in the test vectors also include the message - // at the end, but we just want R and S. - let sig1: Signature = Signature::from_bytes(&sig_bytes[..64]).unwrap(); - let sig2: Signature = keypair.sign::(&msg_bytes); - - assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); - assert!(keypair.verify::(&msg_bytes, &sig2), - "Signature verification failed on line {}", lineno); - } - } - *** We have no test vectors obviously *** */ - - // From https://tools.ietf.org/html/rfc8032#section-7.3 - #[test] - fn ed25519ph_rf8032_test_vector() { - let secret_key: &[u8] = b"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"; - let public_key: &[u8] = b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"; - let message: &[u8] = b"616263"; - let sig1: &[u8] = b"98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406"; - - let sec_bytes: Vec = FromHex::from_hex(secret_key).unwrap(); - let pub_bytes: Vec = FromHex::from_hex(public_key).unwrap(); - let msg_bytes: Vec = FromHex::from_hex(message).unwrap(); - let sig1: Vec = FromHex::from_hex(sig1).unwrap(); - - let secret: MiniSecretKey = MiniSecretKey::from_bytes(&sec_bytes[..MINI_SECRET_KEY_LENGTH]).unwrap(); - let public: PublicKey = PublicKey::from_ed25519_public_key_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); - let keypair: Keypair = Keypair{ secret: secret.expand::(), public: public }; - - let prehash_for_signing: Sha512 = Sha512::default().chain(&msg_bytes[..]); - let prehash_for_verifying: Sha512 = Sha512::default().chain(&msg_bytes[..]); - - let sig2 = keypair.sign_ed25519_prehashed(prehash_for_signing, None); - - assert!(&sig1[..] == &sig2[..], - "Original signature from test vectors doesn't equal signature produced:\ - \noriginal:\n{:?}\nproduced:\n{:?}", &sig1[..], &sig2[..]); - assert!(keypair.verify_ed25519_prehashed(prehash_for_verifying, None, &sig2), - "Could not verify ed25519ph signature!"); - } -} diff --git a/iffy/src/malleable.rs b/iffy/src/malleable.rs deleted file mode 100644 index a6dbca8..0000000 --- a/iffy/src/malleable.rs +++ /dev/null @@ -1,128 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of schnorr-dalek. -// Copyright (c) 2017-2018 Web 3 Foundation -// See LICENSE for licensing information. -// -// Authors: -// - jeffrey Burdges - -//! Dangerously malleable Schnorr signatures -//! -//! We provide this module only to acknoledge scope, but recommend -//! strongly against its use, and do not provide tests or use the -//! module, even behind a feature gate. - -use curve25519_dalek::digest::{Input}; // ExtendableOutput,XofReader -use curve25519_dalek::digest::generic_array::typenum::U64; - -use super::*; - - -https://crypto.stackexchange.com/questions/60825/schnorr-pubkey-recovery -https://www.deadalnix.me/2017/02/17/schnorr-signatures-for-not-so-dummies/ - -impl Signature { - /// Extract the public signing key from a dangerously malleable Schnorr signatures - /// - /// There is deprecated style of Schnorr signatures in which the - /// public key does not make an apperance in the signature's onw - /// derivation of `k`, but may optionally influence k by appearing - /// in the message body. We cnanot use these more malleable - /// signatures for standard blockchain applications, like accounts, - /// becuase they break many advanced features, like ["hierarchical - /// deterministic" key derivation.](https://www.deadalnix.me/2017/02/17/schnorr-signatures-for-not-so-dummies/) - /// - /// There are however applications that never require such features - /// but benefint form smaller signatures, in which case this - /// function can extract the public signing key from a signature - /// We recommend strongly against doing this. - // https://crypto.stackexchange.com/questions/60825/schnorr-pubkey-recovery - pub signer_from_dangerously_malleable(&self) -> Result { - let k_inv = scalars::scalar_from_xof( - context.context_digest() - .chain(signature.R.as_bytes()) - // .chain(public_key.compressed.as_bytes()) // DANGER !!! - .chain(&message) - ).invert(); - let mut point = &self.s * &constants::RISTRETTO_BASEPOINT_TABLE; - point -= signature.R.decompress() ?; - point *= &k_inv; - PublicKey { - compressed: point.compress(), - point - } - } -} - -impl SecretKey { - /// Dangerously malleably sign a message with this `SecretKey`. - /// - /// There is deprecated style of Schnorr signatures in which the - /// public key does not make an apperance in the signature's onw - /// derivation of `k`, but may optionally influence k by appearing - /// in the message body. We cnanot use these more malleable - /// signatures for standard blockchain applications, like accounts, - /// becuase they break many advanced features, like ["hierarchical - /// deterministic" key derivation.](https://www.deadalnix.me/2017/02/17/schnorr-signatures-for-not-so-dummies/) - /// - /// There are however applications that never require such features - /// but benefint form smaller signatures, in which case this - /// function can extract the public signing key from a signature - /// We recommend strongly against doing this. - #[allow(non_snake_case)] - pub fn sign_dangerously_malleable(&self, context: &C, message: &[u8]) -> Signature - where C: SigningContext, - C::Digest: ExtendableOutput - { - let R: CompressedRistretto; - let r: Scalar; - let s: Scalar; - let k: Scalar; - - r = scalars::scalar_from_xof( - context.nonce_randomness() - .chain(&self.nonce) - .chain(&message) - ); - R = (&r * &constants::RISTRETTO_BASEPOINT_TABLE).compress(); - - k = scalars::scalar_from_xof( - context.context_digest() - .chain(R.as_bytes()) - // .chain(public_key.compressed.as_bytes()) // DANGER !!! - .chain(&message) - ); - s = &(&k * &self.key) + &r; - - Signature{ R, s } - } -} - -impl PublicKey { - /// Verify a dangerously malleable signature on a message with this public key. - /// - /// These dangerously malleable signatures always verify when checked with - /// the signature produced by `signer_from_dangerously_malleable` so - /// perhaps only that funcituon should exist. - #[allow(non_snake_case)] - pub fn verify_dangerously_malleable(&self, context: &C, message: &[u8], signature: &Signature) -> bool - where C: SigningContext, - C::Digest: ExtendableOutput - { - let A: RistrettoPoint = self.point; - let R: RistrettoPoint; - let k: Scalar; - - k = scalars::scalar_from_xof( - context.context_digest() - .chain(signature.R.as_bytes()) - // .chain(public_key.compressed.as_bytes()) // DANGER !!! - .chain(&message) - ); - R = RistrettoPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s); - - R.compress() == signature.R - } -} - diff --git a/old/README.md b/old/README.md deleted file mode 100644 index 8ebe578..0000000 --- a/old/README.md +++ /dev/null @@ -1,165 +0,0 @@ -# ed25519-dalek [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) [![](https://travis-ci.org/dalek-cryptography/ed25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/ed25519-dalek?branch=master) - -Fast and efficient Rust implementation of ed25519 key generation, signing, and -verification in Rust. - -# Documentation - -Documentation is available [here](https://docs.rs/ed25519-dalek). - -# Benchmarks - -On an Intel Skylake i9-7900X running at 3.30 GHz, without TurboBoost, this code achieves -the following performance benchmarks: - - ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench - Compiling ed25519-dalek v0.7.0 (file:///home/isis/code/rust/ed25519-dalek) - Finished release [optimized] target(s) in 3.11s - Running target/release/deps/ed25519_benchmarks-721332beed423bce - - Ed25519 signing time: [15.617 us 15.630 us 15.647 us] - Ed25519 signature verification time: [45.930 us 45.968 us 46.011 us] - Ed25519 keypair generation time: [15.440 us 15.465 us 15.492 us] - -By enabling the avx2 backend (on machines with compatible microarchitectures), -the performance for signature verification is greatly improved: - - ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ export RUSTFLAGS=-Ctarget_cpu=native - ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench --features=avx2_backend - Compiling ed25519-dalek v0.7.0 (file:///home/isis/code/rust/ed25519-dalek) - Finished release [optimized] target(s) in 4.28s - Running target/release/deps/ed25519_benchmarks-e4866664de39c84d - Ed25519 signing time: [15.923 us 15.945 us 15.967 us] - Ed25519 signature verification time: [33.382 us 33.411 us 33.445 us] - Ed25519 keypair generation time: [15.246 us 15.260 us 15.275 us] - -In comparison, the equivalent package in Golang performs as follows: - - ∃!isisⒶmistakenot:(master *=)~/code/go/src/github.com/agl/ed25519 ∴ go test -bench . - BenchmarkKeyGeneration 30000 47007 ns/op - BenchmarkSigning 30000 48820 ns/op - BenchmarkVerification 10000 119701 ns/op - ok github.com/agl/ed25519 5.775s - -Making key generation and signing a rough average of 2x faster, and -verification 2.5-3x faster depending on the availability of avx2. Of course, this -is just my machine, and these results—nowhere near rigorous—should be taken -with a handful of salt. - -Translating to a rough cycle count: we multiply by a factor of 3.3 to convert -nanoseconds to cycles per second on a 3300 Mhz CPU, that's 110256 cycles for -verification and 52618 for signing, which is competitive with hand-optimised -assembly implementations. - -Additionally, if you're using a CSPRNG from the `rand` crate, the `nightly` -feature will enable `u128`/`i128` features there, resulting in potentially -faster performance. - -If your protocol or application is able to batch signatures for verification, -the `verify_batch()` function has greatly improved performance. On the -aforementioned Intel Skylake i9-7900X, verifying a batch of 96 signatures takes -1.7673ms. That's 18.4094us, or roughly 60750 cycles, per signature verification, -more than double the speed of batch verification given in the original paper -(this is likely not a fair comparison as that was a Nehalem machine). -The numbers after the `/` in the test name refer to the size of the batch: - - ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ export RUSTFLAGS=-Ctarget_cpu=native - ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench --features=avx2_backend batch - Compiling ed25519-dalek v0.8.0 (file:///home/isis/code/rust/ed25519-dalek) - Finished release [optimized] target(s) in 34.16s - Running target/release/deps/ed25519_benchmarks-cf0daf7d68fc71b6 - Ed25519 batch signature verification/4 time: [105.20 us 106.04 us 106.99 us] - Ed25519 batch signature verification/8 time: [178.66 us 179.01 us 179.39 us] - Ed25519 batch signature verification/16 time: [325.65 us 326.67 us 327.90 us] - Ed25519 batch signature verification/32 time: [617.96 us 620.74 us 624.12 us] - Ed25519 batch signature verification/64 time: [1.1862 ms 1.1900 ms 1.1943 ms] - Ed25519 batch signature verification/96 time: [1.7611 ms 1.7673 ms 1.7742 ms] - Ed25519 batch signature verification/128 time: [2.3320 ms 2.3376 ms 2.3446 ms] - Ed25519 batch signature verification/256 time: [5.0124 ms 5.0290 ms 5.0491 ms] - -As you can see, there's an optimal batch size for each machine, so you'll likely -want to your the benchmarks on your target CPU to discover the best size. For -this machine, around 100 signatures per batch is the optimum: - -![](https://github.com/dalek-cryptography/ed25519-dalek/blob/master/res/batch-violin-benchmark.svg) - -Additionally, thanks to Rust, this implementation has both type and memory -safety. It's also easily readable by a much larger set of people than those who -can read qhasm, making it more readily and more easily auditable. We're of -the opinion that, ultimately, these features—combined with speed—are more -valuable than simply cycle counts alone. - -### A Note on Signature Malleability - -The signatures produced by this library are malleable, as discussed in -[the original paper](https://ed25519.cr.yp.to/ed25519-20110926.pdf): - -![](https://github.com/dalek-cryptography/ed25519-dalek/blob/master/res/ed25519-malleability.png) - -We could eliminate the malleability property by multiplying by the curve -cofactor, however, this would cause our implementation to *not* match the -behaviour of every other implementation in existence. As of this writing, -[RFC 8032](https://tools.ietf.org/html/rfc8032), "Edwards-Curve Digital -Signature Algorithm (EdDSA)," advises that the stronger check should be done. -While we agree that the stronger check should be done, it is our opinion that -one shouldn't get to change the definition of "ed25519 verification" a decade -after the fact, breaking compatibility with every other implementation. - -In short, if malleable signatures are bad for your protocol, don't use them. -Consider using a curve25519-based Verifiable Random Function (VRF), such as -[Trevor Perrin's VXEdDSA](https://www.whispersystems.org/docs/specifications/xeddsa/), -instead. We -[plan](https://github.com/dalek-cryptography/curve25519-dalek/issues/9) to -eventually support VXEdDSA in curve25519-dalek. - -# Installation - -To install, add the following to your project's `Cargo.toml`: - -```toml -[dependencies.ed25519-dalek] -version = "1" -``` - -Then, in your library or executable source, add: - -```rust -extern crate ed25519_dalek; -``` - -# Features - -To cause your application to build `ed25519-dalek` with the nightly feature -enabled by default, instead do: - -```toml -[dependencies.ed25519-dalek] -version = "1" -features = ["nightly"] -``` - -To cause your application to instead build with the nightly feature enabled -when someone builds with `cargo build --features="nightly"` add the following -to the `Cargo.toml`: - -```toml -[features] -nightly = ["ed25519-dalek/nightly"] -``` - -To enable [serde](https://serde.rs) support, build `ed25519-dalek` with: - -```toml -[dependencies.ed25519-dalek] -version = "1" -features = ["serde"] -``` - -By default, `ed25519-dalek` builds against `curve25519-dalek`'s `u64_backend` -feature, which uses Rust's `i128` feature to achieve roughly double the speed as -the `u32_backend` feature. When targetting 32-bit systems, however, you'll -likely want to compile with - `cargo build --no-default-features --features="u32_backend"`. -If you're building for a machine with avx2 instructions, there's also the -experimental `avx2_backend`. To use it, compile with -`RUSTFLAGS="-C target_cpu=native" cargo build --no-default-features --features="avx2_backend"` diff --git a/src/aead.rs b/src/aead.rs index 7dd84ee..75c4083 100644 --- a/src/aead.rs +++ b/src/aead.rs @@ -31,7 +31,6 @@ use curve25519_dalek::digest::generic_array::typenum::{U32}; use curve25519_dalek::{ ristretto::{CompressedRistretto}, // RistrettoPoint - // scalar::Scalar, }; use super::{SecretKey,PublicKey,Keypair,SignatureResult}; @@ -177,10 +176,3 @@ impl Keypair { (cert, aead) } } - -/* -#[cfg(test)] -mod test { - use super::super::*; -} -*/ diff --git a/src/batch.rs b/src/batch.rs index 13a3a07..b690e5b 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -20,11 +20,8 @@ use crate::context::{SigningTranscript}; #[cfg(feature = "alloc")] use alloc::vec::Vec; -#[cfg(feature = "std")] -use std::vec::Vec; - -const ASSERT_MESSAGE: &'static str = "The number of messages/transcripts, signatures, and public keys must be equal."; +const ASSERT_MESSAGE: &str = "The number of messages/transcripts, signatures, and public keys must be equal."; /// Verify a batch of `signatures` on `messages` with their respective `public_keys`. @@ -246,7 +243,7 @@ fn verify_batch_equation( let As = if ! deduplicate_public_keys { // Multiply each H(R || A || M) by the random value for (hram, z) in hrams.iter_mut().zip(zs.iter()) { - *hram = &*hram * z; + *hram *= z; } public_keys } else { @@ -254,18 +251,18 @@ fn verify_batch_equation( ppks.reserve( public_keys.len() ); // Multiply each H(R || A || M) by the random value for i in 0..public_keys.len() { - let zhram = &hrams[i] * zs[i]; + let zhram = hrams[i] * zs[i]; let j = ppks.len().checked_sub(1); if j.is_none() || ppks[j.unwrap()] != public_keys[i] { ppks.push(public_keys[i]); hrams[ppks.len()-1] = zhram; } else { - hrams[ppks.len()-1] = &hrams[ppks.len()-1] + zhram; + hrams[ppks.len()-1] = hrams[ppks.len()-1] + zhram; } } hrams.truncate(ppks.len()); ppks.as_slice() - }.iter().map(|pk| Some(pk.as_point().clone())); + }.iter().map(|pk| Some(*pk.as_point())); // Compute (-∑ z[i]s[i] (mod l)) B + ∑ z[i]R[i] + ∑ (z[i]H(R||A||M)[i] (mod l)) A[i] = 0 let b = RistrettoPoint::optional_multiscalar_mul( @@ -359,7 +356,7 @@ impl PreparedBatch{ let mut read = || { let (head,tail) = bytes.split_at(32); bytes = tail; - array_ref![head,0,32].clone() + *array_ref![head,0,32] }; let mut bs = read(); bs[31] &= 127; @@ -393,7 +390,7 @@ impl PreparedBatch{ pub fn reserve_mut<'heap, T>(heap: &mut &'heap mut [T], len: usize) -> &'heap mut [T] { - let tmp: &'heap mut [T] = ::std::mem::replace(&mut *heap, &mut []); + let tmp: &'heap mut [T] = std::mem::take(&mut *heap); let (reserved, tmp) = tmp.split_at_mut(len); *heap = tmp; reserved @@ -404,14 +401,12 @@ pub fn reserve_mut<'heap, T>(heap: &mut &'heap mut [T], len: usize) -> &'heap mu mod test { #[cfg(feature = "alloc")] use alloc::vec::Vec; - #[cfg(feature = "std")] - use std::vec::Vec; use rand::prelude::*; // ThreadRng,thread_rng use super::super::*; - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] #[test] fn verify_batch_seven_signatures() { let ctx = signing_context(b"my batch context"); diff --git a/src/cert.rs b/src/cert.rs index e339969..36ed847 100644 --- a/src/cert.rs +++ b/src/cert.rs @@ -66,14 +66,6 @@ use crate::context::SigningTranscript; pub struct AdaptorCertSecret(pub [u8; 64]); /// TODO: Serde serialization/deserialization -/* -impl<'a> From<&'a AdaptorCertSecret> for &'a AdaptorCertPublic { - from(secret: &AdaptorCertSecret) -> &AdaptorCertPublic { - unsafe { core::mem::transmute(secret) } - } -} -*/ - impl From for AdaptorCertPublic { fn from(secret: AdaptorCertSecret) -> AdaptorCertPublic { let mut public = AdaptorCertPublic([0u8; 32]); @@ -120,7 +112,7 @@ impl Keypair { let k = t.witness_scalar(b"issuing",&[ &self.secret.nonce, seed_public_key.as_compressed().as_bytes() ]); // Compute the public key reconstruction data - let gamma = seed_public_key.as_point() + &k * &constants::RISTRETTO_BASEPOINT_TABLE; + let gamma = seed_public_key.as_point() + &k * constants::RISTRETTO_BASEPOINT_TABLE; let gamma = gamma.compress(); t.commit_point(b"gamma",&gamma); let cert_public = AdaptorCertPublic(gamma.0); @@ -172,9 +164,9 @@ impl PublicKey { let mut s = [0u8; 32]; s.copy_from_slice(&cert_secret.0[32..64]); - let s = Scalar::from_canonical_bytes(s).ok_or(SignatureError::ScalarFormatError) ?; + let s = crate::scalar_from_canonical_bytes(s).ok_or(SignatureError::ScalarFormatError) ?; let cert_public : AdaptorCertPublic = cert_secret.into(); - let gamma = CompressedRistretto(cert_public.0.clone()); + let gamma = CompressedRistretto(cert_public.0); t.commit_point(b"gamma",&gamma); let key = s + seed_secret_key.key; @@ -229,7 +221,7 @@ impl PublicKey { t.proto_name(b"Adaptor"); t.commit_point(b"issuer-pk",self.as_compressed()); - let gamma = CompressedRistretto(cert_public.0.clone()); + let gamma = CompressedRistretto(cert_public.0); t.commit_point(b"gamma",&gamma); let gamma = gamma.decompress().ok_or(SignatureError::PointDecompressionError) ?; @@ -246,7 +238,6 @@ mod tests { fn adaptor_cert_public_vs_private_paths() { let t = signing_context(b"").bytes(b"MrMeow!"); - // #[cfg(feature = "getrandom")] let mut csprng = rand_core::OsRng; let issuer = Keypair::generate_with(&mut csprng); diff --git a/src/context.rs b/src/context.rs index 2662bb5..8775b89 100644 --- a/src/context.rs +++ b/src/context.rs @@ -57,22 +57,6 @@ pub trait SigningTranscript { self.commit_bytes(label, compressed.as_bytes()); } - /* - fn commit_sorted_points(&mut self, label: &'static [u8], set: &mut [P]) - where P: Borrow, - // S: BorrowMut<[P]>, - { - // let set = set.borrow_mut(); - set.sort_unstable_by( - |a,b| a.borrow().as_bytes() - .cmp(b.borrow().as_bytes()) - ); - for p in set.iter() { - self.commit_point(label,p.borrow()); - } - } - */ - /// Produce some challenge bytes, shadowed by `merlin::Transcript`. fn challenge_bytes(&mut self, label: &'static [u8], dest: &mut [u8]); @@ -277,7 +261,7 @@ where H: Update + ExtendableOutput + Clone; fn input_bytes(h: &mut H, bytes: &[u8]) { let l = bytes.len() as u64; - h.update(l.to_le_bytes()); + h.update(&l.to_le_bytes()); h.update(bytes); } @@ -313,7 +297,7 @@ where H: Update + ExtendableOutput + Clone self.0.update(b"ch"); input_bytes(&mut self.0, label); let l = dest.len() as u64; - self.0.update(l.to_le_bytes()); + self.0.update(&l.to_le_bytes()); self.0.clone().chain(b"xof").finalize_xof().read(dest); } @@ -326,7 +310,7 @@ where H: Update + ExtendableOutput + Clone input_bytes(&mut h, ns); } let l = dest.len() as u64; - h.update(l.to_le_bytes()); + h.update(&l.to_le_bytes()); let mut r = [0u8; 32]; rng.fill_bytes(&mut r); @@ -401,14 +385,3 @@ where T: SigningTranscript use rand_core::SeedableRng; attach_rng(t,ChaChaRng::from_seed(seed)) } - - - -/* -#[cfg(test)] -mod test { - use sha3::Shake128; - use curve25519_dalek::digest::{Update}; - -} -*/ diff --git a/src/derive.rs b/src/derive.rs index 4e6d333..2ce7054 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -222,7 +222,7 @@ impl Derivation for PublicKey { where T: SigningTranscript { let (scalar, chaincode) = self.derive_scalar_and_chaincode(&mut t, cc); - let point = self.as_point() + (&scalar * &constants::RISTRETTO_BASEPOINT_TABLE); + let point = self.as_point() + (&scalar * constants::RISTRETTO_BASEPOINT_TABLE); (PublicKey::from_point(point), chaincode) } } @@ -248,7 +248,7 @@ impl ExtendedKey { pub fn derived_key(&self, t: T) -> ExtendedKey where T: SigningTranscript { - let (key, chaincode) = self.key.derived_key(t, self.chaincode.clone()); + let (key, chaincode) = self.key.derived_key(t, self.chaincode); ExtendedKey { key, chaincode } } @@ -256,7 +256,7 @@ impl ExtendedKey { /// a chain code in the extended key. pub fn derived_key_simple>(&self, i: B) -> ExtendedKey { - let (key, chaincode) = self.key.derived_key_simple(self.chaincode.clone(), i); + let (key, chaincode) = self.key.derived_key_simple(self.chaincode, i); ExtendedKey { key, chaincode } } } @@ -297,7 +297,6 @@ mod tests { let msg : &'static [u8] = b"Just some test message!"; let mut h = Shake128::default().chain(msg); - // #[cfg(feature = "getrandom")] let mut csprng = rand_core::OsRng; let key = Keypair::generate_with(&mut csprng); diff --git a/src/errors.rs b/src/errors.rs index 15213df..cdb37db 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -108,22 +108,7 @@ pub enum SignatureError { /// duplicate disagrees. duplicate: bool, }, - - // /// Reveal did not match commitment - // InvalidReveal, -// other multisig errors -// AbsentCommitment -// InvalidCommitment -} - -/* -impl SignatureError { - #[inline(always)] - fn equation(b: bool) -> SignatureResult<()> { - if b { Ok(()) } else { Err(SignatureError::EquationFalse) } - } } -*/ impl Display for SignatureError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -136,16 +121,16 @@ impl Display for SignatureError { ScalarFormatError => write!(f, "Cannot use scalar with high-bit set"), BytesLengthError { name, length, .. } => - write!(f, "{} must be {} bytes in length", name, length), + write!(f, "{name} must be {length} bytes in length"), NotMarkedSchnorrkel => write!(f, "Signature bytes not marked as a schnorrkel signature"), MuSigAbsent { musig_stage, } => - write!(f, "Absent {} violated multi-signature protocol", musig_stage), + write!(f, "Absent {musig_stage} violated multi-signature protocol"), MuSigInconsistent { musig_stage, duplicate, } => if duplicate { - write!(f, "Inconsistent duplicate {} in multi-signature", musig_stage) + write!(f, "Inconsistent duplicate {musig_stage} in multi-signature") } else { - write!(f, "Inconsistent {} violated multi-signature protocol", musig_stage) + write!(f, "Inconsistent {musig_stage} violated multi-signature protocol") }, } } diff --git a/src/keys.rs b/src/keys.rs index 08a4c59..ddfd6c6 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -457,7 +457,7 @@ impl SecretKey { let mut key: [u8; 32] = [0u8; 32]; key.copy_from_slice(&bytes[00..32]); - let key = Scalar::from_canonical_bytes(key).ok_or(SignatureError::ScalarFormatError) ?; + let key = crate::scalar_from_canonical_bytes(key).ok_or(SignatureError::ScalarFormatError) ?; let mut nonce: [u8; 32] = [0u8; 32]; nonce.copy_from_slice(&bytes[32..64]); @@ -555,7 +555,7 @@ impl SecretKey { /// Derive the `PublicKey` corresponding to this `SecretKey`. pub fn to_public(&self) -> PublicKey { // No clamping necessary in the ristretto255 group - PublicKey::from_point(&self.key * &constants::RISTRETTO_BASEPOINT_TABLE) + PublicKey::from_point(&self.key * constants::RISTRETTO_BASEPOINT_TABLE) } /// Derive the `PublicKey` corresponding to this `SecretKey`. @@ -610,13 +610,13 @@ impl PublicKey { const DESCRIPTION : &'static str = "A Ristretto Schnorr public key represented as a 32-byte Ristretto compressed point"; /// Access the compressed Ristretto form - pub fn as_compressed(&self) -> &CompressedRistretto { &self.0.as_compressed() } + pub fn as_compressed(&self) -> &CompressedRistretto { self.0.as_compressed() } /// Extract the compressed Ristretto form pub fn into_compressed(self) -> CompressedRistretto { self.0.into_compressed() } /// Access the point form - pub fn as_point(&self) -> &RistrettoPoint { &self.0.as_point() } + pub fn as_point(&self) -> &RistrettoPoint { self.0.as_point() } /// Extract the point form pub fn into_point(self) -> RistrettoPoint { self.0.into_point() } @@ -786,7 +786,7 @@ impl Keypair { let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH]) ?; let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..]) ?; - Ok(Keypair{ secret: secret, public: public }) + Ok(Keypair{ secret, public }) } /// Serialize `Keypair` to bytes with Ed25519 secret key format. @@ -839,7 +839,7 @@ impl Keypair { let secret = SecretKey::from_ed25519_bytes(&bytes[..SECRET_KEY_LENGTH]) ?; let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..]) ?; - Ok(Keypair{ secret: secret, public: public }) + Ok(Keypair{ secret, public }) } /// Generate a Ristretto Schnorr `Keypair` directly, @@ -942,7 +942,6 @@ mod test { #[test] fn keypair_zeroize() { - // #[cfg(feature = "getrandom")] let mut csprng = rand_core::OsRng; let mut keypair = Keypair::generate_with(&mut csprng); @@ -963,7 +962,6 @@ mod test { #[test] fn pubkey_from_mini_secret_and_expanded_secret() { - // #[cfg(feature = "getrandom")] let mut csprng = rand_core::OsRng; let mini_secret: MiniSecretKey = MiniSecretKey::generate_with(&mut csprng); diff --git a/src/lib.rs b/src/lib.rs index 2a5119a..e4938bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -212,6 +212,7 @@ #![warn(rust_2018_compatibility)] #![warn(rust_2018_idioms)] #![deny(missing_docs)] // refuse to compile if documentation is missing +#![allow(clippy::needless_lifetimes)] #[cfg(any(feature = "std"))] #[macro_use] @@ -221,18 +222,8 @@ extern crate std; extern crate alloc; use rand_core::{RngCore,CryptoRng}; +use curve25519_dalek::scalar::Scalar; -// Removed rand dependency because naming the same feature std_rng on rand -// and getrandom on rand_code is too confusing to propogate correctly. -// Use transcript.attach_rng(::rand::thread_rng()) when signing if you -// application suffers from this performance regression. - -// #[cfg(all(feature = "getrandom", feature = "rand"))] -// fn rand_hack() -> impl RngCore+CryptoRng { -// rand::thread_rng() -// } - -// #[cfg(all(feature = "getrandom", not(feature = "rand")))] #[cfg(feature = "getrandom")] fn rand_hack() -> impl RngCore+CryptoRng { rand_core::OsRng @@ -271,10 +262,12 @@ pub mod errors; #[cfg(feature = "aead")] pub mod aead; -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] mod batch; -// Not safe because need randomness #[cfg(any(feature = "alloc", feature = "std"))] +// Not safe because need randomness + +#[cfg_attr(not(test), deprecated(since = "0.11.0", note = "This module will be replaced in the future"))] #[cfg(feature = "std")] pub mod musig; @@ -283,5 +276,16 @@ pub use crate::context::{signing_context}; // SigningContext,SigningTranscript pub use crate::sign::{Signature,SIGNATURE_LENGTH}; pub use crate::errors::{SignatureError,SignatureResult}; -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] pub use crate::batch::{verify_batch,verify_batch_rng,verify_batch_deterministic,PreparedBatch}; + +pub(crate) fn scalar_from_canonical_bytes(bytes: [u8; 32]) -> Option { + let key = Scalar::from_canonical_bytes(bytes); + + // Note: this is a `CtOption` so we have to do this to extract the value. + if bool::from(key.is_none()) { + return None; + } + + Some(key.unwrap()) +} diff --git a/src/musig.rs b/src/musig.rs index b2ee826..8d89127 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -35,8 +35,6 @@ use core::borrow::{Borrow}; // BorrowMut #[cfg(feature = "alloc")] use alloc::{collections::btree_map::{BTreeMap, Entry}}; -#[cfg(feature = "std")] -use std::{collections::btree_map::{BTreeMap, Entry}}; use arrayref::array_ref; use arrayvec::ArrayVec; @@ -107,7 +105,9 @@ impl AggregatePublicKey for BTreeMap where K: Borrow+Ord { fn weighting(&self, choice: &PublicKey) -> Option { - if ! self.contains_key(choice) { return None; } + if !self.contains_key(choice) { + return None; + } let t0 = commit_public_keys( self.keys().map(|pk| pk.borrow()) ); Some(compute_weighting(t0, choice)) } @@ -160,7 +160,9 @@ impl<'a,K> AggregatePublicKey for AggregatePublicKeySlice<'a,K> where K: Borrow+PartialEq { fn weighting(&self, choice: &PublicKey) -> Option { - if self.0.iter().any(|pk| pk.borrow() == choice) { return None; } + if self.0.iter().any(|pk| pk.borrow() == choice) { + return None; + } let t0 = commit_public_keys( self.0.iter().map(|pk| pk.borrow()) ); Some(compute_weighting(t0, choice)) } @@ -230,17 +232,13 @@ pub struct Reveal(pub [u8; 32*REWINDS]); // TODO: serde_boilerplate!(Reveal); impl Clone for Reveal { - fn clone(&self) -> Reveal { Reveal(self.0.clone()) } + fn clone(&self) -> Reveal { Reveal(self.0) } } impl PartialEq for Reveal { #[inline] fn eq(&self, other: &Reveal) -> bool { self.0[..] == other.0[..] } - #[inline] - fn ne(&self, other: &Reveal) -> bool { - self.0[..] != other.0[..] - } } impl Eq for Reveal { } @@ -251,7 +249,7 @@ impl Reveal { #[allow(non_snake_case)] fn iter_points<'a>(&'a self) -> impl Iterator + 'a { - (&self.0).chunks(32).map( |R| CompressedRistretto( array_ref![R,0,32].clone() ) ) + self.0.chunks(32).map( |R| CompressedRistretto( *array_ref![R,0,32] ) ) } fn to_commitment(&self) -> SignatureResult { @@ -259,6 +257,7 @@ impl Reveal { Ok(Commitment::for_R( self.iter_points() )) } + #[allow(clippy::wrong_self_convention)] fn into_points(&self) -> SignatureResult { self.check_length() ?; let a = self.iter_points().map( @@ -493,7 +492,7 @@ where K: Borrow, T: SigningTranscript+Clone let r_me = r_me.into_inner().unwrap(); // context, message, nonce, but not &self.public.compressed - let B = &constants::RISTRETTO_BASEPOINT_TABLE; + let B = constants::RISTRETTO_BASEPOINT_TABLE; let R_me_points: ArrayVec = r_me.iter() .map(|r_me_i| r_me_i * B).collect(); let R_me_points = RevealedPoints(R_me_points.into_inner().unwrap()); @@ -517,7 +516,7 @@ where K: Borrow, T: SigningTranscript+Clone { let theirs = CoR::Commit(theirs); match self.Rs.entry(them) { - Entry::Vacant(v) => { v.insert(theirs); () }, + Entry::Vacant(v) => { v.insert(theirs); }, Entry::Occupied(o) => if o.get() != &theirs { let musig_stage = MultiSignatureStage::Commitment; @@ -595,7 +594,7 @@ where K: Borrow, T: SigningTranscript+Clone let reveal = theirs.into_points() ?; let theirs = CoR::Reveal(reveal); match self.Rs.entry(them) { - Entry::Vacant(v) => { v.insert(theirs); () }, + Entry::Vacant(v) => { v.insert(theirs); }, Entry::Occupied(o) => if o.get() != &theirs { let musig_stage = MultiSignatureStage::Reveal; @@ -610,7 +609,7 @@ where K: Borrow, T: SigningTranscript+Clone pub fn cosign_stage(mut self) -> MuSig { self.t.proto_name(b"Schnorr-sig"); - let pk = self.public_key().as_compressed().clone(); + let pk = *self.public_key().as_compressed(); self.t.commit_point(b"sign:pk",&pk); let rewinder = self.rewinder(); @@ -623,12 +622,12 @@ where K: Borrow, T: SigningTranscript+Clone let c = self.t.challenge_scalar(b"sign:c"); // context, message, A/public_key, R=rG let mut s_me: Scalar = self.stage.r_me.iter().zip(&rewinds).map(|(y,x)| x*y).sum(); - s_me += &(&c * &a_me * &self.stage.keypair.borrow().secret.key); + s_me += c * a_me * self.stage.keypair.borrow().secret.key; zeroize::Zeroize::zeroize(&mut self.stage.r_me); let MuSig { t, mut Rs, stage: RevealStage { .. }, } = self; - *(Rs.get_mut(&self.stage.keypair.borrow().public).expect("Rs known to contain this public; qed")) = CoR::Cosigned { s: s_me.clone() }; + *(Rs.get_mut(&self.stage.keypair.borrow().public).expect("Rs known to contain this public; qed")) = CoR::Cosigned { s: s_me }; MuSig { t, Rs, stage: CosignStage { R, s_me }, } } } @@ -656,7 +655,7 @@ impl MuSig { pub fn add_their_cosignature(&mut self, them: PublicKey, theirs: Cosignature) -> SignatureResult<()> { - let theirs = Scalar::from_canonical_bytes(theirs.0) + let theirs = crate::scalar_from_canonical_bytes(theirs.0) .ok_or(SignatureError::ScalarFormatError) ?; match self.Rs.entry(them) { Entry::Vacant(_) => { @@ -723,12 +722,12 @@ impl MuSig { -> SignatureResult<()> { let reveal = their_reveal.into_points() ?; - let s = Scalar::from_canonical_bytes(their_cosignature.0) + let s = crate::scalar_from_canonical_bytes(their_cosignature.0) .ok_or(SignatureError::ScalarFormatError) ?; let cor = CoR::Collect { reveal, s }; match self.Rs.entry(them) { - Entry::Vacant(v) => { v.insert(cor); () }, + Entry::Vacant(v) => { v.insert(cor); }, Entry::Occupied(o) => if o.get() != &cor { let musig_stage = MultiSignatureStage::Reveal; @@ -741,16 +740,15 @@ impl MuSig { /// Actually computes the collected cosignature. #[allow(non_snake_case)] pub fn signature(mut self) -> Signature { - let pk = self.public_key().as_compressed().clone(); + let pk = *self.public_key().as_compressed(); self.t.commit_point(b"sign:pk",&pk); let R = self.compute_R(self.rewinder()); - let s: Scalar = self.Rs.iter() - .map( |(_pk,cor)| match cor { + let s: Scalar = self.Rs.values().map(|cor| match cor { CoR::Collect { s, .. } => s, _ => panic!("Reached CollectStage from another stage"), - } ).sum(); + }).sum(); Signature { s, R, } } } @@ -760,8 +758,6 @@ impl MuSig { mod tests { #[cfg(feature = "alloc")] use alloc::vec::Vec; - #[cfg(feature = "std")] - use std::vec::Vec; use super::*; diff --git a/src/points.rs b/src/points.rs index 1ff24fb..3f9954a 100644 --- a/src/points.rs +++ b/src/points.rs @@ -53,22 +53,6 @@ impl ConstantTimeEq for RistrettoBoth { } } -/* -#[inline(always)] -fn zeroize_hack(z: &mut Z) { - use core::{ptr, sync::atomic}; - unsafe { ptr::write_volatile(z, Z::default()); } - atomic::compiler_fence(atomic::Ordering::SeqCst); -} - -impl zeroize::Zeroize for RistrettoBoth { - fn zeroize(&mut self) { - zeroize_hack(&mut self.compressed); - zeroize_hack(&mut self.point); - } -} -*/ - impl RistrettoBoth { const DESCRIPTION : &'static str = "A ristretto point represented as a 32-byte compressed point"; @@ -168,44 +152,18 @@ impl PartialEq for RistrettoBoth { debug_assert_eq!(r, self.point.eq(&other.point)); r } - - // fn ne(&self, other: &Rhs) -> bool { - // self.compressed.0.ne(&other.compressed.0) - // } } -// impl Eq for RistrettoBoth {} - impl PartialOrd for RistrettoBoth { fn partial_cmp(&self, other: &RistrettoBoth) -> Option<::core::cmp::Ordering> { self.compressed.0.partial_cmp(&other.compressed.0) } - - // fn lt(&self, other: &Rhs) -> bool { - // self.compressed.0.lt(&other.compressed.0) - // } - // fn le(&self, other: &Rhs) -> bool { - // self.compressed.0.le(&other.compressed.0) - // } - // fn gt(&self, other: &Rhs) -> bool { - // self.compressed.0.gt(&other.compressed.0) - // } - // fn ge(&self, other: &Rhs) -> bool { - // self.compressed.0.ge(&other.compressed.0) - // } } impl Ord for RistrettoBoth { fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.compressed.0.cmp(&other.compressed.0) } - - // fn max(self, other: Self) -> Self { - // self.compressed.0.max(other.compressed.0) - // } - // fn min(self, other: Self) -> Self { - // self.compressed.0.min(other.compressed.0) - // } } impl core::hash::Hash for RistrettoBoth { diff --git a/src/scalars.rs b/src/scalars.rs index f2e2bd1..6b93fe5 100644 --- a/src/scalars.rs +++ b/src/scalars.rs @@ -12,9 +12,6 @@ //! Elliptic curve utilities not provided by curve25519-dalek, //! including some not so safe utilities for managing scalars and points. -// use curve25519_dalek::scalar::Scalar; - - pub(crate) fn divide_scalar_bytes_by_cofactor(scalar: &mut [u8; 32]) { let mut low = 0u8; for i in scalar.iter_mut().rev() { @@ -35,20 +32,6 @@ pub(crate) fn multiply_scalar_bytes_by_cofactor(scalar: &mut [u8; 32]) { } } -/* -pub fn divide_scalar_by_cofactor(scalar: Scalar) -> Scalar { - let mut x = scalar.to_bytes(); - divide_scalar_bytes_by_cofactor(&mut x); - Scalar::from_bits(x) -} - -pub fn multiply_scalar_by_cofactor(scalar: Scalar) -> Scalar { - let mut x = scalar.to_bytes(); - multiply_scalar_bytes_by_cofactor(&mut x); - Scalar::from_bits(x) -} -*/ - #[cfg(test)] mod tests { use super::*; diff --git a/src/serdey.rs b/src/serdey.rs index faff804..64c5e26 100644 --- a/src/serdey.rs +++ b/src/serdey.rs @@ -10,15 +10,6 @@ //! ### Various and tooling related to serde -// #[cfg(feature = "serde")] -// use serde::{Serialize, Deserialize}; -// #[cfg(feature = "serde")] -// use serde::{Serializer, Deserializer}; -// #[cfg(feature = "serde")] -// use serde::de::Error as SerdeError; -// #[cfg(feature = "serde")] -// use serde::de::Visitor; - #[cfg(feature = "serde")] macro_rules! serde_boilerplate { ($t:ty) => { impl serde_crate::Serialize for $t { diff --git a/src/sign.rs b/src/sign.rs index c8ef01d..03e7678 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -76,7 +76,7 @@ pub(crate) fn check_scalar(bytes: [u8; 32]) -> SignatureResult { return Ok(Scalar::from_bits(bytes)) } - Scalar::from_canonical_bytes(bytes).ok_or(SignatureError::ScalarFormatError) + crate::scalar_from_canonical_bytes(bytes).ok_or(SignatureError::ScalarFormatError) } impl Signature { @@ -177,12 +177,12 @@ impl SecretKey { t.commit_point(b"sign:pk",public_key.as_compressed()); let mut r = t.witness_scalar(b"signing",&[&self.nonce]); // context, message, A/public_key - let R = (&r * &constants::RISTRETTO_BASEPOINT_TABLE).compress(); + let R = (&r * constants::RISTRETTO_BASEPOINT_TABLE).compress(); t.commit_point(b"sign:R",&R); let k: Scalar = t.challenge_scalar(b"sign:c"); // context, message, A/public_key, R=rG - let s: Scalar = &(&k * &self.key) + &r; + let s: Scalar = k * self.key + r; zeroize::Zeroize::zeroize(&mut r); @@ -431,7 +431,6 @@ mod test { let good: &[u8] = "test message".as_bytes(); let bad: &[u8] = "wrong message".as_bytes(); - // #[cfg(feature = "getrandom")] let mut csprng = rand_core::OsRng; let keypair = Keypair::generate_with(&mut csprng); @@ -465,7 +464,6 @@ mod test { let prehashed_bad: Shake128 = Shake128::default().chain(bad); // You may verify that `Shake128: Copy` is possible, making these clones below correct. - // #[cfg(feature = "getrandom")] let mut csprng = rand_core::OsRng; let keypair = Keypair::generate_with(&mut csprng); diff --git a/src/vrf.rs b/src/vrf.rs index 1a42c2e..ff9578b 100644 --- a/src/vrf.rs +++ b/src/vrf.rs @@ -78,19 +78,17 @@ use core::borrow::Borrow; -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] use core::iter::once; #[cfg(feature = "alloc")] use alloc::{boxed::Box, vec::Vec}; -#[cfg(feature = "std")] -use std::{boxed::Box, vec::Vec}; use curve25519_dalek::constants; use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint}; use curve25519_dalek::scalar::Scalar; use curve25519_dalek::traits::{IsIdentity}; // Identity -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] use curve25519_dalek::traits::{MultiscalarMul,VartimeMultiscalarMul}; use merlin::Transcript; @@ -147,7 +145,6 @@ impl VRFSigningTranscript for T where T: SigningTranscript { #[inline(always)] fn transcript_with_malleability_addressed(mut self, publickey: &PublicKey) -> T { self.commit_point(b"vrf-nm-pk", publickey.as_compressed()); - // publickey.make_transcript_nonmalleable(&mut self); self } } @@ -282,7 +279,7 @@ impl SecretKey { /// Evaluate the VRF-like multiplication on an uncompressed point, /// probably not useful in this form. pub fn vrf_create_from_point(&self, input: RistrettoBoth) -> VRFInOut { - let output = RistrettoBoth::from_point(&self.key * input.as_point()); + let output = RistrettoBoth::from_point(self.key * input.as_point()); VRFInOut { input, output } } @@ -434,7 +431,7 @@ impl PublicKey { where B: Borrow, { - assert!( ps.len() > 0); + assert!(!ps.is_empty()); let mut t = merlin::Transcript::new(b"MergeVRFs"); t.commit_point(b"vrf:pk", self.as_compressed()); for p in ps.iter() { @@ -446,9 +443,9 @@ impl PublicKey { p.borrow().commit(&mut t0); challenge_scalar_128(t0) }); - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] let zs: Vec = zf().collect(); - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] let zf = || zs.iter(); // We need actual fns here because closures cannot easily take @@ -456,7 +453,7 @@ impl PublicKey { // closures but giving all closures unique types. fn get_input(p: &VRFInOut) -> &RistrettoPoint { p.input.as_point() } fn get_output(p: &VRFInOut) -> &RistrettoPoint { p.output.as_point() } - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] let go = |io: fn(p: &VRFInOut) -> &RistrettoPoint| { let ps = ps.iter().map( |p| io(p.borrow()) ); RistrettoBoth::from_point(if vartime { @@ -465,7 +462,7 @@ impl PublicKey { RistrettoPoint::multiscalar_mul(zf(), ps) }) }; - #[cfg(not(any(feature = "alloc", feature = "std")))] + #[cfg(not(feature = "alloc"))] let go = |io: fn(p: &VRFInOut) -> &RistrettoPoint| { let _ = vartime; // ignore unused variable use curve25519_dalek::traits::Identity; @@ -521,8 +518,8 @@ impl VRFProof { c.copy_from_slice(&bytes[..32]); s.copy_from_slice(&bytes[32..]); - let c = Scalar::from_canonical_bytes(c).ok_or(SignatureError::ScalarFormatError) ?; - let s = Scalar::from_canonical_bytes(s).ok_or(SignatureError::ScalarFormatError) ?; + let c = crate::scalar_from_canonical_bytes(c).ok_or(SignatureError::ScalarFormatError) ?; + let s = crate::scalar_from_canonical_bytes(s).ok_or(SignatureError::ScalarFormatError) ?; Ok(VRFProof { c, s }) } } @@ -576,7 +573,7 @@ impl VRFProofBatchable { Hr.copy_from_slice(&bytes[32..64]); s.copy_from_slice(&bytes[64..96]); - let s = Scalar::from_canonical_bytes(s).ok_or(SignatureError::ScalarFormatError) ?; + let s = crate::scalar_from_canonical_bytes(s).ok_or(SignatureError::ScalarFormatError) ?; Ok(VRFProofBatchable { R: CompressedRistretto(R), Hr: CompressedRistretto(Hr), s }) } @@ -637,11 +634,11 @@ impl Keypair { if !kusama { t.commit_point(b"vrf:pk", self.public.as_compressed()); } // We compute R after adding pk and all h. - let mut r = t.witness_scalar(b"proving\00",&[&self.secret.nonce]); - let R = (&r * &constants::RISTRETTO_BASEPOINT_TABLE).compress(); + let mut r = t.witness_scalar(b"proving\x000",&[&self.secret.nonce]); + let R = (&r * constants::RISTRETTO_BASEPOINT_TABLE).compress(); t.commit_point(b"vrf:R=g^r", &R); - let Hr = (&r * p.input.as_point()).compress(); + let Hr = (r * p.input.as_point()).compress(); t.commit_point(b"vrf:h^r", &Hr); if kusama { t.commit_point(b"vrf:pk", self.public.as_compressed()); } @@ -649,7 +646,7 @@ impl Keypair { t.commit_point(b"vrf:h^sk", p.output.as_compressed()); let c = t.challenge_scalar(b"prove"); // context, message, A/public_key, R=rG - let s = &r - &(&c * &self.secret.key); + let s = r - c * self.secret.key; zeroize::Zeroize::zeroize(&mut r); @@ -722,7 +719,7 @@ impl Keypair { /// We merge the VRF outputs using variable time arithmetic, so /// if even the hash of the message being signed is sensitive then /// you might reimplement some constant time variant. - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] pub fn vrfs_sign(&self, ts: I) -> (Box<[VRFInOut]>, VRFProof, VRFProofBatchable) where T: VRFSigningTranscript, @@ -737,7 +734,7 @@ impl Keypair { /// We merge the VRF outputs using variable time arithmetic, so /// if even the hash of the message being signed is sensitive then /// you might reimplement some constant time variant. - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] pub fn vrfs_sign_extra(&self, ts: I, extra: E) -> (Box<[VRFInOut]>, VRFProof, VRFProofBatchable) where T: VRFSigningTranscript, @@ -790,11 +787,11 @@ impl PublicKey { t.commit_point(b"vrf:R=g^r", &R); // We also recompute h^r aka u using the proof - #[cfg(not(any(feature = "alloc", feature = "std")))] + #[cfg(not(feature = "alloc"))] let Hr = (&proof.c * p.output.as_point()) + (&proof.s * p.input.as_point()); // TODO: Verify if this is actually faster using benchmarks - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] let Hr = RistrettoPoint::vartime_multiscalar_mul( &[proof.c, proof.s], &[*p.output.as_point(), *p.input.as_point()], @@ -843,7 +840,7 @@ impl PublicKey { } /// Verify a common VRF short proof for several input transcripts and corresponding outputs. - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] pub fn vrfs_verify( &self, transcripts: I, @@ -859,7 +856,7 @@ impl PublicKey { } /// Verify a common VRF short proof for several input transcripts and corresponding outputs. - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] pub fn vrfs_verify_extra( &self, transcripts: I, @@ -904,7 +901,7 @@ impl PublicKey { /// any combination doubles the scalar by scalar multiplications /// and hashing, so large enough batch verifications should favor two /// separate calls. -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] #[allow(non_snake_case)] pub fn dleq_verify_batch( ps: &[VRFInOut], @@ -912,7 +909,7 @@ pub fn dleq_verify_batch( public_keys: &[PublicKey], kusama: bool, ) -> SignatureResult<()> { - const ASSERT_MESSAGE: &'static str = "The number of messages/transcripts / input points, output points, proofs, and public keys must be equal."; + const ASSERT_MESSAGE: &str = "The number of messages/transcripts / input points, output points, proofs, and public keys must be equal."; assert!(ps.len() == proofs.len(), "{}", ASSERT_MESSAGE); assert!(proofs.len() == public_keys.len(), "{}", ASSERT_MESSAGE); @@ -975,7 +972,7 @@ pub fn dleq_verify_batch( /// Batch verify VRFs by different signers /// /// -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] pub fn vrf_verify_batch( transcripts: I, outs: &[VRFPreOut], @@ -1008,14 +1005,11 @@ where mod tests { #[cfg(feature = "alloc")] use alloc::vec::Vec; - #[cfg(feature = "std")] - use std::vec::Vec; use super::*; #[test] fn vrf_single() { - // #[cfg(feature = "getrandom")] let mut csprng = rand_core::OsRng; let keypair1 = Keypair::generate_with(&mut csprng); @@ -1061,7 +1055,6 @@ mod tests { #[test] fn vrf_malleable() { - // #[cfg(feature = "getrandom")] let mut csprng = rand_core::OsRng; let keypair1 = Keypair::generate_with(&mut csprng); @@ -1131,7 +1124,7 @@ mod tests { .is_ok()); } - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] #[test] fn vrfs_merged_and_batched() { let mut csprng = rand_core::OsRng;