diff --git a/src/ed25519.rs b/src/ed25519.rs index 7cfca3f..7c55a65 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -7,9 +7,8 @@ // Authors: // - isis agora lovecruft -//! ed25519 keypairs and batch verification. +//! ed25519 keypairs. -#[allow(unused_imports)] use core::default::Default; use rand::{CryptoRng, RngCore}; @@ -19,139 +18,21 @@ use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; #[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; -#[cfg(feature = "serde")] -use serde::{Deserializer, Serializer}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub use sha2::Sha512; use curve25519_dalek::digest::generic_array::typenum::U64; pub use curve25519_dalek::digest::Digest; -#[cfg(all(feature = "batch", any(feature = "alloc", feature = "std")))] -use curve25519_dalek::constants; -#[cfg(all(feature = "batch", any(feature = "alloc", feature = "std")))] -use curve25519_dalek::edwards::EdwardsPoint; -#[cfg(all(feature = "batch", any(feature = "alloc", feature = "std")))] -use curve25519_dalek::scalar::Scalar; - +#[cfg(all(feature = "batch", any(feature = "std", feature = "alloc")))] +pub use crate::batch::*; pub use crate::constants::*; pub use crate::errors::*; pub use crate::public::*; pub use crate::secret::*; pub use crate::signature::*; -/// Verify a batch of `signatures` on `messages` with their respective `public_keys`. -/// -/// # Inputs -/// -/// * `messages` is a slice of byte slices, one per signed message. -/// * `signatures` is a slice of `Signature`s. -/// * `public_keys` is a slice of `PublicKey`s. -/// * `csprng` is an implementation of `Rng + CryptoRng`. -/// -/// # Returns -/// -/// * A `Result` whose `Ok` value is an emtpy tuple and whose `Err` value is a -/// `SignatureError` containing a description of the internal error which -/// occured. -/// -/// # Examples -/// -/// ``` -/// extern crate ed25519_dalek; -/// extern crate rand; -/// -/// use ed25519_dalek::verify_batch; -/// use ed25519_dalek::Keypair; -/// use ed25519_dalek::PublicKey; -/// use ed25519_dalek::Signature; -/// use rand::rngs::OsRng; -/// -/// # fn main() { -/// let mut csprng = OsRng{}; -/// let keypairs: Vec = (0..64).map(|_| Keypair::generate(&mut csprng)).collect(); -/// let msg: &[u8] = b"They're good dogs Brant"; -/// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect(); -/// let signatures: Vec = keypairs.iter().map(|key| key.sign(&msg)).collect(); -/// let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); -/// -/// let result = verify_batch(&messages[..], &signatures[..], &public_keys[..]); -/// assert!(result.is_ok()); -/// # } -/// ``` -#[cfg(all(feature = "batch", any(feature = "alloc", feature = "std")))] -#[allow(non_snake_case)] -pub fn verify_batch( - messages: &[&[u8]], - signatures: &[Signature], - public_keys: &[PublicKey], -) -> Result<(), SignatureError> -{ - if signatures.len() != messages.len() || - signatures.len() != public_keys.len() || - public_keys.len() != messages.len() { - return Err(SignatureError(InternalError::ArrayLengthError{ - name_a: "signatures", length_a: signatures.len(), - name_b: "messages", length_b: messages.len(), - name_c: "public_keys", length_c: public_keys.len(), - })); - } - - #[cfg(feature = "alloc")] - use alloc::vec::Vec; - #[cfg(feature = "std")] - use std::vec::Vec; - - use core::iter::once; - use rand::{Rng, thread_rng}; - - use curve25519_dalek::traits::IsIdentity; - use curve25519_dalek::traits::VartimeMultiscalarMul; - - // Select a random 128-bit scalar for each signature. - let zs: Vec = signatures - .iter() - .map(|_| Scalar::from(thread_rng().gen::())) - .collect(); - - // Compute the basepoint coefficient, ∑ s[i]z[i] (mod l) - let B_coefficient: Scalar = signatures - .iter() - .map(|sig| sig.s) - .zip(zs.iter()) - .map(|(s, z)| z * s) - .sum(); - - // Compute H(R || A || M) for each (signature, public_key, message) triplet - let hrams = (0..signatures.len()).map(|i| { - let mut h: Sha512 = Sha512::default(); - h.input(signatures[i].R.as_bytes()); - h.input(public_keys[i].as_bytes()); - h.input(&messages[i]); - Scalar::from_hash(h) - }); - - // Multiply each H(R || A || M) by the random value - let zhrams = hrams.zip(zs.iter()).map(|(hram, z)| hram * z); - - let Rs = signatures.iter().map(|sig| sig.R.decompress()); - let As = public_keys.iter().map(|pk| Some(pk.1)); - let B = once(Some(constants::ED25519_BASEPOINT_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 id = EdwardsPoint::optional_multiscalar_mul( - once(-B_coefficient).chain(zs.iter().cloned()).chain(zhrams), - B.chain(Rs).chain(As), - ).ok_or_else(|| SignatureError(InternalError::VerifyError))?; - - if id.is_identity() { - Ok(()) - } else { - Err(SignatureError(InternalError::VerifyError)) - } -} - /// An ed25519 keypair. #[derive(Debug, Default)] // we derive Default in order to use the clear() method in Drop pub struct Keypair { diff --git a/src/lib.rs b/src/lib.rs index 92f1d45..bce5edf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -247,6 +247,8 @@ extern crate rand; extern crate serde; extern crate sha2; +#[cfg(all(feature = "batch", any(feature = "std", feature = "alloc")))] +mod batch; mod constants; mod ed25519; mod errors;