[−][src]Function ed25519_dalek::verify_batch
pub fn verify_batch(
messages: &[&[u8]],
signatures: &[Signature],
public_keys: &[PublicKey]
) -> Result<(), SignatureError>
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 ofSignature
s.public_keys
is a slice ofPublicKey
s.
Returns
- A
Result
whoseOk
value is an emtpy tuple and whoseErr
value is aSignatureError
containing a description of the internal error which occured.
Notes on Nonce Generation & Malleability
On Synthetic Nonces
This library defaults to using what is called "synthetic" nonces, which means that a mixture of deterministic (per any unique set of inputs to this function) data and system randomness is used to seed the CSPRNG for nonce generation. For more of the background theory on why many cryptographers currently believe this to be superior to either purely deterministic generation or purely relying on the system's randomness, see this section of the Merlin design by Henry de Valence, isis lovecruft, and Oleg Andreev, as well as Trevor Perrin's designs for generalised EdDSA.
On Deterministic Nonces
In order to be ammenable to protocols which require stricter third-party
auditability trails, such as in some financial cryptographic settings, this
library also supports a --features=batch_deterministic
setting, where the
nonces for batch signature verification are derived purely from the inputs
to this function themselves.
This is not recommended for use unless you have several cryptographers on staff who can advise you in its usage and all the horrible, terrible, awful ways it can go horribly, terribly, awfully wrong.
In any sigma protocol it is wise to include as much context pertaining to the public state in the protocol as possible, to avoid malleability attacks where an adversary alters publics in an algebraic manner that manages to satisfy the equations for the protocol in question.
For ed25519 batch verification (both with synthetic and deterministic nonce generation), we include the following as scalars in the protocol transcript:
- All of the computed
H(R||A||M)
s to the protocol transcript, and - All of the
s
components of each signature.
Each is also prefixed with their index in the vector.
The former, while not quite as elegant as adding the R
s, A
s, and
M
s separately, saves us a bit of context hashing since the
H(R||A||M)
s need to be computed for the verification equation anyway.
The latter prevents a malleability attack only found in deterministic batch
signature verification (i.e. only when compiling ed25519-dalek
with
--features batch_deterministic
) wherein an adversary, without access
to the signing key(s), can take any valid signature, (s,R)
, and swap
s
with s' = -z1
. This doesn't contitute a signature forgery, merely
a vulnerability, as the resulting signature will not pass single
signature verification. (Thanks to Github users @real_or_random and
@jonasnick for pointing out this malleability issue.)
For an additional way in which signatures can be made to probablistically
falsely "pass" the synthethic batch verification equation for the same
inputs, but only some crafted inputs will pass the deterministic batch
single, and neither of these will ever pass single signature verification,
see the documentation for [PublicKey.validate()
].
Examples
extern crate ed25519_dalek; extern crate rand; use ed25519_dalek::verify_batch; use ed25519_dalek::Keypair; use ed25519_dalek::PublicKey; use ed25519_dalek::Signer; use ed25519_dalek::Signature; use rand::rngs::OsRng; let mut csprng = OsRng{}; let keypairs: Vec<Keypair> = (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<Signature> = keypairs.iter().map(|key| key.sign(&msg)).collect(); let public_keys: Vec<PublicKey> = keypairs.iter().map(|key| key.public).collect(); let result = verify_batch(&messages[..], &signatures[..], &public_keys[..]); assert!(result.is_ok());