mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-08 21:00:40 +00:00
Merge branch 'release/1.0.1'
This commit is contained in:
commit
925eb9ea56
8 changed files with 216 additions and 172 deletions
12
Cargo.toml
12
Cargo.toml
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "ed25519-dalek"
|
name = "ed25519-dalek"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = ["isis lovecruft <isis@patternsinthevoid.net>"]
|
authors = ["isis lovecruft <isis@patternsinthevoid.net>"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
@ -28,12 +28,14 @@ merlin = { version = "2", default-features = false, optional = true }
|
||||||
rand = { version = "0.7", default-features = false, optional = true }
|
rand = { version = "0.7", default-features = false, optional = true }
|
||||||
rand_core = { version = "0.5", default-features = false, optional = true }
|
rand_core = { version = "0.5", default-features = false, optional = true }
|
||||||
serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true }
|
serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true }
|
||||||
|
serde_bytes = { version = "0.11", optional = true }
|
||||||
sha2 = { version = "0.9", default-features = false }
|
sha2 = { version = "0.9", default-features = false }
|
||||||
zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] }
|
zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex = "^0.4"
|
hex = "^0.4"
|
||||||
bincode = "^0.9"
|
bincode = "1.0"
|
||||||
|
serde_json = "1.0"
|
||||||
criterion = "0.3"
|
criterion = "0.3"
|
||||||
rand = "0.7"
|
rand = "0.7"
|
||||||
serde_crate = { package = "serde", version = "1.0", features = ["derive"] }
|
serde_crate = { package = "serde", version = "1.0", features = ["derive"] }
|
||||||
|
|
@ -47,11 +49,11 @@ harness = false
|
||||||
# required-features = ["batch"]
|
# required-features = ["batch"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std", "u64_backend"]
|
default = ["std", "rand", "u64_backend"]
|
||||||
std = ["curve25519-dalek/std", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"]
|
std = ["curve25519-dalek/std", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"]
|
||||||
alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"]
|
alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"]
|
||||||
nightly = ["curve25519-dalek/nightly", "rand/nightly"]
|
nightly = ["curve25519-dalek/nightly"]
|
||||||
serde = ["serde_crate", "ed25519/serde"]
|
serde = ["serde_crate", "serde_bytes", "ed25519/serde"]
|
||||||
batch = ["merlin", "rand"]
|
batch = ["merlin", "rand"]
|
||||||
# This feature enables deterministic batch verification.
|
# This feature enables deterministic batch verification.
|
||||||
batch_deterministic = ["merlin", "rand", "rand_core"]
|
batch_deterministic = ["merlin", "rand", "rand_core"]
|
||||||
|
|
|
||||||
88
src/batch.rs
88
src/batch.rs
|
|
@ -43,22 +43,32 @@ use crate::public::PublicKey;
|
||||||
use crate::signature::InternalSignature;
|
use crate::signature::InternalSignature;
|
||||||
|
|
||||||
trait BatchTranscript {
|
trait BatchTranscript {
|
||||||
fn append_hrams(&mut self, hrams: &Vec<Scalar>);
|
fn append_scalars(&mut self, scalars: &Vec<Scalar>);
|
||||||
fn append_message_lengths(&mut self, message_lengths: &Vec<usize>);
|
fn append_message_lengths(&mut self, message_lengths: &Vec<usize>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BatchTranscript for Transcript {
|
impl BatchTranscript for Transcript {
|
||||||
/// Add all the computed `H(R||A||M)`s to the protocol transcript.
|
/// Append some `scalars` to this batch verification sigma protocol transcript.
|
||||||
|
///
|
||||||
|
/// For ed25519 batch verification, we include the following as scalars:
|
||||||
|
///
|
||||||
|
/// * 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.
|
/// Each is also prefixed with their index in the vector.
|
||||||
fn append_hrams(&mut self, hrams: &Vec<Scalar>) {
|
fn append_scalars(&mut self, scalars: &Vec<Scalar>) {
|
||||||
for (i, hram) in hrams.iter().enumerate() {
|
for (i, scalar) in scalars.iter().enumerate() {
|
||||||
// XXX add message length into transcript
|
|
||||||
self.append_u64(b"", i as u64);
|
self.append_u64(b"", i as u64);
|
||||||
self.append_message(b"hram", hram.as_bytes());
|
self.append_message(b"hram", scalar.as_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Append the lengths of the messages into the transcript.
|
||||||
|
///
|
||||||
|
/// This is done out of an (potential over-)abundance of caution, to guard
|
||||||
|
/// against the unlikely event of collisions. However, a nicer way to do
|
||||||
|
/// this would be to append the message length before the message, but this
|
||||||
|
/// is messy w.r.t. the calculations of the `H(R||A||M)`s above.
|
||||||
fn append_message_lengths(&mut self, message_lengths: &Vec<usize>) {
|
fn append_message_lengths(&mut self, message_lengths: &Vec<usize>) {
|
||||||
for (i, len) in message_lengths.iter().enumerate() {
|
for (i, len) in message_lengths.iter().enumerate() {
|
||||||
self.append_u64(b"", i as u64);
|
self.append_u64(b"", i as u64);
|
||||||
|
|
@ -121,6 +131,65 @@ fn zero_rng() -> ZeroRng {
|
||||||
/// `SignatureError` containing a description of the internal error which
|
/// `SignatureError` containing a description of the internal error which
|
||||||
/// occured.
|
/// 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](https://merlin.cool/transcript/rng.html) by Henry de
|
||||||
|
/// Valence, isis lovecruft, and Oleg Andreev, as well as Trevor Perrin's
|
||||||
|
/// [designs for generalised
|
||||||
|
/// EdDSA](https://moderncrypto.org/mail-archive/curves/2017/000925.html).
|
||||||
|
///
|
||||||
|
/// ## 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
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
|
@ -181,8 +250,10 @@ pub fn verify_batch(
|
||||||
Scalar::from_hash(h)
|
Scalar::from_hash(h)
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
// Collect the message lengths to add into the transcript.
|
// Collect the message lengths and the scalar portions of the signatures,
|
||||||
|
// and add them into the transcript.
|
||||||
let message_lengths: Vec<usize> = messages.iter().map(|i| i.len()).collect();
|
let message_lengths: Vec<usize> = messages.iter().map(|i| i.len()).collect();
|
||||||
|
let scalars: Vec<Scalar> = signatures.iter().map(|i| i.s).collect();
|
||||||
|
|
||||||
// Build a PRNG based on a transcript of the H(R || A || M)s seen thus far.
|
// Build a PRNG based on a transcript of the H(R || A || M)s seen thus far.
|
||||||
// This provides synthethic randomness in the default configuration, and
|
// This provides synthethic randomness in the default configuration, and
|
||||||
|
|
@ -190,8 +261,9 @@ pub fn verify_batch(
|
||||||
// "batch_deterministic" feature.
|
// "batch_deterministic" feature.
|
||||||
let mut transcript: Transcript = Transcript::new(b"ed25519 batch verification");
|
let mut transcript: Transcript = Transcript::new(b"ed25519 batch verification");
|
||||||
|
|
||||||
transcript.append_hrams(&hrams);
|
transcript.append_scalars(&hrams);
|
||||||
transcript.append_message_lengths(&message_lengths);
|
transcript.append_message_lengths(&message_lengths);
|
||||||
|
transcript.append_scalars(&scalars);
|
||||||
|
|
||||||
#[cfg(all(feature = "batch", not(feature = "batch_deterministic")))]
|
#[cfg(all(feature = "batch", not(feature = "batch_deterministic")))]
|
||||||
let mut prng = transcript.build_rng().finalize(&mut thread_rng());
|
let mut prng = transcript.build_rng().finalize(&mut thread_rng());
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,9 @@ use rand::{CryptoRng, RngCore};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::de::Error as SerdeError;
|
use serde::de::Error as SerdeError;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::de::Visitor;
|
|
||||||
#[cfg(feature = "serde")]
|
|
||||||
use serde::de::SeqAccess;
|
|
||||||
#[cfg(feature = "serde")]
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
use serde_bytes::{Bytes as SerdeBytes, ByteBuf as SerdeByteBuf};
|
||||||
|
|
||||||
pub use sha2::Sha512;
|
pub use sha2::Sha512;
|
||||||
|
|
||||||
|
|
@ -125,6 +123,7 @@ impl Keypair {
|
||||||
/// The standard hash function used for most ed25519 libraries is SHA-512,
|
/// The standard hash function used for most ed25519 libraries is SHA-512,
|
||||||
/// which is available with `use sha2::Sha512` as in the example above.
|
/// which is available with `use sha2::Sha512` as in the example above.
|
||||||
/// Other suitable hash functions include Keccak-512 and Blake2b-512.
|
/// Other suitable hash functions include Keccak-512 and Blake2b-512.
|
||||||
|
#[cfg(feature = "rand")]
|
||||||
pub fn generate<R>(csprng: &mut R) -> Keypair
|
pub fn generate<R>(csprng: &mut R) -> Keypair
|
||||||
where
|
where
|
||||||
R: CryptoRng + RngCore,
|
R: CryptoRng + RngCore,
|
||||||
|
|
@ -427,7 +426,8 @@ impl Serialize for Keypair {
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
serializer.serialize_bytes(&self.to_bytes()[..])
|
let bytes = &self.to_bytes()[..];
|
||||||
|
SerdeBytes::new(bytes).serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -437,63 +437,7 @@ impl<'d> Deserialize<'d> for Keypair {
|
||||||
where
|
where
|
||||||
D: Deserializer<'d>,
|
D: Deserializer<'d>,
|
||||||
{
|
{
|
||||||
struct KeypairVisitor;
|
let bytes = <SerdeByteBuf>::deserialize(deserializer)?;
|
||||||
|
Keypair::from_bytes(bytes.as_ref()).map_err(SerdeError::custom)
|
||||||
impl<'d> Visitor<'d> for KeypairVisitor {
|
|
||||||
type Value = Keypair;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
|
||||||
formatter.write_str("An ed25519 keypair, 64 bytes in total where the secret key is \
|
|
||||||
the first 32 bytes and is in unexpanded form, and the second \
|
|
||||||
32 bytes is a compressed point for a public key.")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_bytes<E>(self, bytes: &[u8]) -> Result<Keypair, E>
|
|
||||||
where
|
|
||||||
E: SerdeError,
|
|
||||||
{
|
|
||||||
if bytes.len() != KEYPAIR_LENGTH {
|
|
||||||
return Err(SerdeError::invalid_length(bytes.len(), &self));
|
|
||||||
}
|
|
||||||
|
|
||||||
let secret_key = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH]);
|
|
||||||
let public_key = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..]);
|
|
||||||
|
|
||||||
if let (Ok(secret), Ok(public)) = (secret_key, public_key) {
|
|
||||||
Ok(Keypair{ secret, public })
|
|
||||||
} else {
|
|
||||||
Err(SerdeError::invalid_length(bytes.len(), &self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_seq<A>(self, mut seq: A) -> Result<Keypair, A::Error>
|
|
||||||
where
|
|
||||||
A: SeqAccess<'d>
|
|
||||||
{
|
|
||||||
if let Some(len) = seq.size_hint() {
|
|
||||||
if len != KEYPAIR_LENGTH {
|
|
||||||
return Err(SerdeError::invalid_length(len, &self));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: We could do this with `MaybeUninit` to avoid unnecessary initialization costs
|
|
||||||
let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH];
|
|
||||||
|
|
||||||
for i in 0..KEYPAIR_LENGTH {
|
|
||||||
bytes[i] = seq.next_element()?.ok_or_else(|| SerdeError::invalid_length(i, &self))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let secret_key = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH]);
|
|
||||||
let public_key = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..]);
|
|
||||||
|
|
||||||
if let (Ok(secret), Ok(public)) = (secret_key, public_key) {
|
|
||||||
Ok(Keypair{ secret, public })
|
|
||||||
} else {
|
|
||||||
Err(SerdeError::invalid_length(bytes.len(), &self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
deserializer.deserialize_bytes(KeypairVisitor)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
15
src/lib.rs
15
src/lib.rs
|
|
@ -176,7 +176,7 @@
|
||||||
//! # fn main() {
|
//! # fn main() {
|
||||||
//! # use rand::rngs::OsRng;
|
//! # use rand::rngs::OsRng;
|
||||||
//! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey};
|
//! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey};
|
||||||
//! use bincode::{serialize, Infinite};
|
//! use bincode::serialize;
|
||||||
//! # let mut csprng = OsRng{};
|
//! # let mut csprng = OsRng{};
|
||||||
//! # let keypair: Keypair = Keypair::generate(&mut csprng);
|
//! # let keypair: Keypair = Keypair::generate(&mut csprng);
|
||||||
//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
|
//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
|
||||||
|
|
@ -184,8 +184,8 @@
|
||||||
//! # let public_key: PublicKey = keypair.public;
|
//! # let public_key: PublicKey = keypair.public;
|
||||||
//! # let verified: bool = public_key.verify(message, &signature).is_ok();
|
//! # let verified: bool = public_key.verify(message, &signature).is_ok();
|
||||||
//!
|
//!
|
||||||
//! let encoded_public_key: Vec<u8> = serialize(&public_key, Infinite).unwrap();
|
//! let encoded_public_key: Vec<u8> = serialize(&public_key).unwrap();
|
||||||
//! let encoded_signature: Vec<u8> = serialize(&signature, Infinite).unwrap();
|
//! let encoded_signature: Vec<u8> = serialize(&signature).unwrap();
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "serde"))]
|
//! # #[cfg(not(feature = "serde"))]
|
||||||
//! # fn main() {}
|
//! # fn main() {}
|
||||||
|
|
@ -206,7 +206,7 @@
|
||||||
//! # fn main() {
|
//! # fn main() {
|
||||||
//! # use rand::rngs::OsRng;
|
//! # use rand::rngs::OsRng;
|
||||||
//! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey};
|
//! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey};
|
||||||
//! # use bincode::{serialize, Infinite};
|
//! # use bincode::serialize;
|
||||||
//! use bincode::deserialize;
|
//! use bincode::deserialize;
|
||||||
//!
|
//!
|
||||||
//! # let mut csprng = OsRng{};
|
//! # let mut csprng = OsRng{};
|
||||||
|
|
@ -215,8 +215,8 @@
|
||||||
//! # let signature: Signature = keypair.sign(message);
|
//! # let signature: Signature = keypair.sign(message);
|
||||||
//! # let public_key: PublicKey = keypair.public;
|
//! # let public_key: PublicKey = keypair.public;
|
||||||
//! # let verified: bool = public_key.verify(message, &signature).is_ok();
|
//! # let verified: bool = public_key.verify(message, &signature).is_ok();
|
||||||
//! # let encoded_public_key: Vec<u8> = serialize(&public_key, Infinite).unwrap();
|
//! # let encoded_public_key: Vec<u8> = serialize(&public_key).unwrap();
|
||||||
//! # let encoded_signature: Vec<u8> = serialize(&signature, Infinite).unwrap();
|
//! # let encoded_signature: Vec<u8> = serialize(&signature).unwrap();
|
||||||
//! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap();
|
//! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap();
|
||||||
//! let decoded_signature: Signature = deserialize(&encoded_signature).unwrap();
|
//! let decoded_signature: Signature = deserialize(&encoded_signature).unwrap();
|
||||||
//!
|
//!
|
||||||
|
|
@ -235,6 +235,9 @@
|
||||||
#![warn(future_incompatible)]
|
#![warn(future_incompatible)]
|
||||||
#![deny(missing_docs)] // refuse to compile if documentation is missing
|
#![deny(missing_docs)] // refuse to compile if documentation is missing
|
||||||
|
|
||||||
|
#![cfg(not(test))]
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
#[cfg(any(feature = "std", test))]
|
#[cfg(any(feature = "std", test))]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate std;
|
extern crate std;
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,9 @@ pub use sha2::Sha512;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::de::Error as SerdeError;
|
use serde::de::Error as SerdeError;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::de::Visitor;
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde_bytes::{Bytes as SerdeBytes, ByteBuf as SerdeByteBuf};
|
||||||
#[cfg(feature = "serde")]
|
|
||||||
use serde::{Deserializer, Serializer};
|
|
||||||
|
|
||||||
use crate::constants::*;
|
use crate::constants::*;
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
|
|
@ -362,7 +360,7 @@ impl Serialize for PublicKey {
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
serializer.serialize_bytes(self.as_bytes())
|
SerdeBytes::new(self.as_bytes()).serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -372,24 +370,7 @@ impl<'d> Deserialize<'d> for PublicKey {
|
||||||
where
|
where
|
||||||
D: Deserializer<'d>,
|
D: Deserializer<'d>,
|
||||||
{
|
{
|
||||||
struct PublicKeyVisitor;
|
let bytes = <SerdeByteBuf>::deserialize(deserializer)?;
|
||||||
|
PublicKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom)
|
||||||
impl<'d> Visitor<'d> for PublicKeyVisitor {
|
|
||||||
type Value = PublicKey;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
|
||||||
formatter.write_str(
|
|
||||||
"An ed25519 public key as a 32-byte compressed point, as specified in RFC8032",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_bytes<E>(self, bytes: &[u8]) -> Result<PublicKey, E>
|
|
||||||
where
|
|
||||||
E: SerdeError,
|
|
||||||
{
|
|
||||||
PublicKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deserializer.deserialize_bytes(PublicKeyVisitor)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ use curve25519_dalek::digest::Digest;
|
||||||
use curve25519_dalek::edwards::CompressedEdwardsY;
|
use curve25519_dalek::edwards::CompressedEdwardsY;
|
||||||
use curve25519_dalek::scalar::Scalar;
|
use curve25519_dalek::scalar::Scalar;
|
||||||
|
|
||||||
|
#[cfg(feature = "rand")]
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
|
|
||||||
use sha2::Sha512;
|
use sha2::Sha512;
|
||||||
|
|
@ -24,11 +25,9 @@ use sha2::Sha512;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::de::Error as SerdeError;
|
use serde::de::Error as SerdeError;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::de::Visitor;
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde_bytes::{Bytes as SerdeBytes, ByteBuf as SerdeByteBuf};
|
||||||
#[cfg(feature = "serde")]
|
|
||||||
use serde::{Deserializer, Serializer};
|
|
||||||
|
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
|
|
@ -164,6 +163,7 @@ impl SecretKey {
|
||||||
/// # Input
|
/// # Input
|
||||||
///
|
///
|
||||||
/// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng`
|
/// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng`
|
||||||
|
#[cfg(feature = "rand")]
|
||||||
pub fn generate<T>(csprng: &mut T) -> SecretKey
|
pub fn generate<T>(csprng: &mut T) -> SecretKey
|
||||||
where
|
where
|
||||||
T: CryptoRng + RngCore,
|
T: CryptoRng + RngCore,
|
||||||
|
|
@ -182,7 +182,7 @@ impl Serialize for SecretKey {
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
serializer.serialize_bytes(self.as_bytes())
|
SerdeBytes::new(self.as_bytes()).serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,23 +192,8 @@ impl<'d> Deserialize<'d> for SecretKey {
|
||||||
where
|
where
|
||||||
D: Deserializer<'d>,
|
D: Deserializer<'d>,
|
||||||
{
|
{
|
||||||
struct SecretKeyVisitor;
|
let bytes = <SerdeByteBuf>::deserialize(deserializer)?;
|
||||||
|
SecretKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom)
|
||||||
impl<'d> Visitor<'d> for SecretKeyVisitor {
|
|
||||||
type Value = SecretKey;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
|
||||||
formatter.write_str("An ed25519 secret key as 32 bytes, as specified in RFC8032.")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_bytes<E>(self, bytes: &[u8]) -> Result<SecretKey, E>
|
|
||||||
where
|
|
||||||
E: SerdeError,
|
|
||||||
{
|
|
||||||
SecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deserializer.deserialize_bytes(SecretKeyVisitor)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -519,7 +504,8 @@ impl Serialize for ExpandedSecretKey {
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
serializer.serialize_bytes(&self.to_bytes()[..])
|
let bytes = &self.to_bytes()[..];
|
||||||
|
SerdeBytes::new(bytes).serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -529,26 +515,8 @@ impl<'d> Deserialize<'d> for ExpandedSecretKey {
|
||||||
where
|
where
|
||||||
D: Deserializer<'d>,
|
D: Deserializer<'d>,
|
||||||
{
|
{
|
||||||
struct ExpandedSecretKeyVisitor;
|
let bytes = <SerdeByteBuf>::deserialize(deserializer)?;
|
||||||
|
ExpandedSecretKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom)
|
||||||
impl<'d> Visitor<'d> for ExpandedSecretKeyVisitor {
|
|
||||||
type Value = ExpandedSecretKey;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
|
||||||
formatter.write_str(
|
|
||||||
"An ed25519 expanded secret key as 64 bytes, as specified in RFC8032.",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_bytes<E>(self, bytes: &[u8]) -> Result<ExpandedSecretKey, E>
|
|
||||||
where
|
|
||||||
E: SerdeError,
|
|
||||||
{
|
|
||||||
ExpandedSecretKey::from_bytes(bytes)
|
|
||||||
.or(Err(SerdeError::invalid_length(bytes.len(), &self)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deserializer.deserialize_bytes(ExpandedSecretKeyVisitor)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ fn check_scalar(bytes: [u8; 32]) -> Result<Scalar, SignatureError> {
|
||||||
// This is compatible with ed25519-donna and libsodium when
|
// This is compatible with ed25519-donna and libsodium when
|
||||||
// -DED25519_COMPAT is NOT specified.
|
// -DED25519_COMPAT is NOT specified.
|
||||||
if bytes[31] & 224 != 0 {
|
if bytes[31] & 224 != 0 {
|
||||||
return Err(SignatureError(InternalError::ScalarFormatError));
|
return Err(InternalError::ScalarFormatError.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Scalar::from_bits(bytes))
|
Ok(Scalar::from_bits(bytes))
|
||||||
|
|
|
||||||
118
tests/ed25519.rs
118
tests/ed25519.rs
|
|
@ -230,11 +230,11 @@ struct Demo {
|
||||||
mod serialisation {
|
mod serialisation {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use self::bincode::{serialize, serialized_size, deserialize, Infinite};
|
|
||||||
use self::toml;
|
|
||||||
|
|
||||||
use ed25519::signature::Signature as _;
|
use ed25519::signature::Signature as _;
|
||||||
|
|
||||||
|
// The size for bincode to serialize the length of a byte array.
|
||||||
|
static BINCODE_INT_LENGTH: usize = 8;
|
||||||
|
|
||||||
static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [
|
static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [
|
||||||
130, 039, 155, 015, 062, 076, 188, 063,
|
130, 039, 155, 015, 062, 076, 188, 063,
|
||||||
124, 122, 026, 251, 233, 253, 225, 220,
|
124, 122, 026, 251, 233, 253, 225, 220,
|
||||||
|
|
@ -269,42 +269,104 @@ mod serialisation {
|
||||||
035, 056, 000, 074, 130, 168, 225, 071, ];
|
035, 056, 000, 074, 130, 168, 225, 071, ];
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_deserialize_signature() {
|
fn serialize_deserialize_signature_bincode() {
|
||||||
let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap();
|
let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap();
|
||||||
let encoded_signature: Vec<u8> = serialize(&signature, Infinite).unwrap();
|
let encoded_signature: Vec<u8> = bincode::serialize(&signature).unwrap();
|
||||||
let decoded_signature: Signature = deserialize(&encoded_signature).unwrap();
|
let decoded_signature: Signature = bincode::deserialize(&encoded_signature).unwrap();
|
||||||
|
|
||||||
assert_eq!(signature, decoded_signature);
|
assert_eq!(signature, decoded_signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_deserialize_public_key() {
|
fn serialize_deserialize_signature_json() {
|
||||||
let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap();
|
let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap();
|
||||||
let encoded_public_key: Vec<u8> = serialize(&public_key, Infinite).unwrap();
|
let encoded_signature = serde_json::to_string(&signature).unwrap();
|
||||||
let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap();
|
let decoded_signature: Signature = serde_json::from_str(&encoded_signature).unwrap();
|
||||||
|
|
||||||
assert_eq!(&PUBLIC_KEY_BYTES[..], &encoded_public_key[encoded_public_key.len() - 32..]);
|
assert_eq!(signature, decoded_signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_deserialize_public_key_bincode() {
|
||||||
|
let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap();
|
||||||
|
let encoded_public_key: Vec<u8> = bincode::serialize(&public_key).unwrap();
|
||||||
|
let decoded_public_key: PublicKey = bincode::deserialize(&encoded_public_key).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(&PUBLIC_KEY_BYTES[..], &encoded_public_key[encoded_public_key.len() - PUBLIC_KEY_LENGTH..]);
|
||||||
assert_eq!(public_key, decoded_public_key);
|
assert_eq!(public_key, decoded_public_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_deserialize_secret_key() {
|
fn serialize_deserialize_public_key_json() {
|
||||||
let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap();
|
let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap();
|
||||||
let encoded_secret_key: Vec<u8> = serialize(&secret_key, Infinite).unwrap();
|
let encoded_public_key = serde_json::to_string(&public_key).unwrap();
|
||||||
let decoded_secret_key: SecretKey = deserialize(&encoded_secret_key).unwrap();
|
let decoded_public_key: PublicKey = serde_json::from_str(&encoded_public_key).unwrap();
|
||||||
|
|
||||||
for i in 0..32 {
|
assert_eq!(public_key, decoded_public_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_deserialize_secret_key_bincode() {
|
||||||
|
let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap();
|
||||||
|
let encoded_secret_key: Vec<u8> = bincode::serialize(&secret_key).unwrap();
|
||||||
|
let decoded_secret_key: SecretKey = bincode::deserialize(&encoded_secret_key).unwrap();
|
||||||
|
|
||||||
|
for i in 0..SECRET_KEY_LENGTH {
|
||||||
assert_eq!(SECRET_KEY_BYTES[i], decoded_secret_key.as_bytes()[i]);
|
assert_eq!(SECRET_KEY_BYTES[i], decoded_secret_key.as_bytes()[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_deserialize_secret_key_json() {
|
||||||
|
let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap();
|
||||||
|
let encoded_secret_key = serde_json::to_string(&secret_key).unwrap();
|
||||||
|
let decoded_secret_key: SecretKey = serde_json::from_str(&encoded_secret_key).unwrap();
|
||||||
|
|
||||||
|
for i in 0..SECRET_KEY_LENGTH {
|
||||||
|
assert_eq!(SECRET_KEY_BYTES[i], decoded_secret_key.as_bytes()[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_deserialize_expanded_secret_key_bincode() {
|
||||||
|
let expanded_secret_key = ExpandedSecretKey::from(&SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap());
|
||||||
|
let encoded_expanded_secret_key: Vec<u8> = bincode::serialize(&expanded_secret_key).unwrap();
|
||||||
|
let decoded_expanded_secret_key: ExpandedSecretKey = bincode::deserialize(&encoded_expanded_secret_key).unwrap();
|
||||||
|
|
||||||
|
for i in 0..EXPANDED_SECRET_KEY_LENGTH {
|
||||||
|
assert_eq!(expanded_secret_key.to_bytes()[i], decoded_expanded_secret_key.to_bytes()[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_deserialize_expanded_secret_key_json() {
|
||||||
|
let expanded_secret_key = ExpandedSecretKey::from(&SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap());
|
||||||
|
let encoded_expanded_secret_key = serde_json::to_string(&expanded_secret_key).unwrap();
|
||||||
|
let decoded_expanded_secret_key: ExpandedSecretKey = serde_json::from_str(&encoded_expanded_secret_key).unwrap();
|
||||||
|
|
||||||
|
for i in 0..EXPANDED_SECRET_KEY_LENGTH {
|
||||||
|
assert_eq!(expanded_secret_key.to_bytes()[i], decoded_expanded_secret_key.to_bytes()[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_deserialize_keypair_bincode() {
|
fn serialize_deserialize_keypair_bincode() {
|
||||||
let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap();
|
let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap();
|
||||||
let encoded_keypair: Vec<u8> = serialize(&keypair, Infinite).unwrap();
|
let encoded_keypair: Vec<u8> = bincode::serialize(&keypair).unwrap();
|
||||||
let decoded_keypair: Keypair = deserialize(&encoded_keypair).unwrap();
|
let decoded_keypair: Keypair = bincode::deserialize(&encoded_keypair).unwrap();
|
||||||
|
|
||||||
for i in 0..64 {
|
for i in 0..KEYPAIR_LENGTH {
|
||||||
|
assert_eq!(KEYPAIR_BYTES[i], decoded_keypair.to_bytes()[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_deserialize_keypair_json() {
|
||||||
|
let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap();
|
||||||
|
let encoded_keypair = serde_json::to_string(&keypair).unwrap();
|
||||||
|
let decoded_keypair: Keypair = serde_json::from_str(&encoded_keypair).unwrap();
|
||||||
|
|
||||||
|
for i in 0..KEYPAIR_LENGTH {
|
||||||
assert_eq!(KEYPAIR_BYTES[i], decoded_keypair.to_bytes()[i]);
|
assert_eq!(KEYPAIR_BYTES[i], decoded_keypair.to_bytes()[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -323,18 +385,30 @@ mod serialisation {
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_public_key_size() {
|
fn serialize_public_key_size() {
|
||||||
let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap();
|
let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap();
|
||||||
assert_eq!(serialized_size(&public_key) as usize, 40); // These sizes are specific to bincode==1.0.1
|
assert_eq!(bincode::serialized_size(&public_key).unwrap() as usize, BINCODE_INT_LENGTH + PUBLIC_KEY_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_signature_size() {
|
fn serialize_signature_size() {
|
||||||
let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap();
|
let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap();
|
||||||
assert_eq!(serialized_size(&signature) as usize, 64); // These sizes are specific to bincode==1.0.1
|
assert_eq!(bincode::serialized_size(&signature).unwrap() as usize, SIGNATURE_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_secret_key_size() {
|
fn serialize_secret_key_size() {
|
||||||
let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap();
|
let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap();
|
||||||
assert_eq!(serialized_size(&secret_key) as usize, 40); // These sizes are specific to bincode==1.0.1
|
assert_eq!(bincode::serialized_size(&secret_key).unwrap() as usize, BINCODE_INT_LENGTH + SECRET_KEY_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_expanded_secret_key_size() {
|
||||||
|
let expanded_secret_key = ExpandedSecretKey::from(&SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap());
|
||||||
|
assert_eq!(bincode::serialized_size(&expanded_secret_key).unwrap() as usize, BINCODE_INT_LENGTH + EXPANDED_SECRET_KEY_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_keypair_size() {
|
||||||
|
let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap();
|
||||||
|
assert_eq!(bincode::serialized_size(&keypair).unwrap() as usize, BINCODE_INT_LENGTH + KEYPAIR_LENGTH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue