mirror of
https://github.com/dalek-cryptography/ed25519-dalek.git
synced 2026-01-10 11:37:58 -05:00
Merge pull request #62 from isislovecruft/feature/61-decompress-caching
Cache decompressed PublicKey points
This commit is contained in:
@@ -71,7 +71,6 @@ pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + E
|
||||
/// been signed.
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Copy, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct Signature {
|
||||
/// `R` is an `EdwardsPoint`, formed by using an hash function with
|
||||
/// 512-bits output to produce the digest of:
|
||||
@@ -166,7 +165,6 @@ impl<'d> Deserialize<'d> for Signature {
|
||||
}
|
||||
|
||||
/// An EdDSA secret key.
|
||||
#[repr(C)]
|
||||
#[derive(Default)] // we derive Default in order to use the clear() method in Drop
|
||||
pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]);
|
||||
|
||||
@@ -386,7 +384,6 @@ impl<'d> Deserialize<'d> for SecretKey {
|
||||
// same signature scheme, and which both fail in exactly the same way. For a
|
||||
// better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on
|
||||
// "generalised EdDSA" and "VXEdDSA".
|
||||
#[repr(C)]
|
||||
#[derive(Default)] // we derive Default in order to use the clear() method in Drop
|
||||
pub struct ExpandedSecretKey {
|
||||
pub (crate) key: Scalar,
|
||||
@@ -717,12 +714,14 @@ impl<'d> Deserialize<'d> for ExpandedSecretKey {
|
||||
|
||||
/// An ed25519 public key.
|
||||
#[derive(Copy, Clone, Default, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct PublicKey(pub (crate) CompressedEdwardsY);
|
||||
pub struct PublicKey(
|
||||
pub (crate) CompressedEdwardsY,
|
||||
pub (crate) EdwardsPoint,
|
||||
);
|
||||
|
||||
impl Debug for PublicKey {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
write!(f, "PublicKey( CompressedEdwardsY( {:?} ))", self.0)
|
||||
write!(f, "PublicKey({:?}), {:?})", self.0, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,7 +789,10 @@ impl PublicKey {
|
||||
let mut bits: [u8; 32] = [0u8; 32];
|
||||
bits.copy_from_slice(&bytes[..32]);
|
||||
|
||||
Ok(PublicKey(CompressedEdwardsY(bits)))
|
||||
let compressed = CompressedEdwardsY(bits);
|
||||
let point = compressed.decompress().ok_or(SignatureError(InternalError::PointDecompressionError))?;
|
||||
|
||||
Ok(PublicKey(compressed, point))
|
||||
}
|
||||
|
||||
/// Derive this public key from its corresponding `SecretKey`.
|
||||
@@ -825,9 +827,10 @@ impl PublicKey {
|
||||
bits[31] &= 127;
|
||||
bits[31] |= 64;
|
||||
|
||||
let pk = (&Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE).compress().to_bytes();
|
||||
let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE;
|
||||
let compressed = point.compress();
|
||||
|
||||
PublicKey(CompressedEdwardsY(pk))
|
||||
PublicKey(compressed, point)
|
||||
}
|
||||
|
||||
/// Verify a signature on a message with this keypair's public key.
|
||||
@@ -842,18 +845,14 @@ impl PublicKey {
|
||||
let mut h: D = D::default();
|
||||
let R: EdwardsPoint;
|
||||
let k: Scalar;
|
||||
|
||||
let A: EdwardsPoint = match self.0.decompress() {
|
||||
Some(x) => x,
|
||||
None => return Err(SignatureError(InternalError::PointDecompressionError)),
|
||||
};
|
||||
let minus_A: EdwardsPoint = -self.1;
|
||||
|
||||
h.input(signature.R.as_bytes());
|
||||
h.input(self.as_bytes());
|
||||
h.input(&message);
|
||||
|
||||
k = Scalar::from_hash(h);
|
||||
R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s);
|
||||
R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s);
|
||||
|
||||
if R.compress() == signature.R {
|
||||
Ok(())
|
||||
@@ -894,10 +893,7 @@ impl PublicKey {
|
||||
let ctx: &[u8] = context.unwrap_or(b"");
|
||||
debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets.");
|
||||
|
||||
let A: EdwardsPoint = match self.0.decompress() {
|
||||
Some(x) => x,
|
||||
None => return Err(SignatureError(InternalError::PointDecompressionError)),
|
||||
};
|
||||
let minus_A: EdwardsPoint = -self.1;
|
||||
|
||||
h.input(b"SigEd25519 no Ed25519 collisions");
|
||||
h.input(&[1]); // Ed25519ph
|
||||
@@ -908,7 +904,7 @@ impl PublicKey {
|
||||
h.input(prehashed_message.result().as_slice());
|
||||
|
||||
k = Scalar::from_hash(h);
|
||||
R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s);
|
||||
R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s);
|
||||
|
||||
if R.compress() == signature.R {
|
||||
Ok(())
|
||||
@@ -1022,7 +1018,7 @@ pub fn verify_batch<D>(messages: &[&[u8]],
|
||||
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| pk.0.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
|
||||
@@ -1068,7 +1064,6 @@ impl<'d> Deserialize<'d> for PublicKey {
|
||||
|
||||
/// An ed25519 keypair.
|
||||
#[derive(Debug, Default)] // we derive Default in order to use the clear() method in Drop
|
||||
#[repr(C)]
|
||||
pub struct Keypair {
|
||||
/// The secret half of this keypair.
|
||||
pub secret: SecretKey,
|
||||
@@ -1404,11 +1399,11 @@ mod test {
|
||||
use super::*;
|
||||
|
||||
#[cfg(all(test, feature = "serde"))]
|
||||
static PUBLIC_KEY: PublicKey = PublicKey(CompressedEdwardsY([
|
||||
static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [
|
||||
130, 039, 155, 015, 062, 076, 188, 063,
|
||||
124, 122, 026, 251, 233, 253, 225, 220,
|
||||
014, 041, 166, 120, 108, 035, 254, 077,
|
||||
160, 083, 172, 058, 219, 042, 086, 120, ]));
|
||||
160, 083, 172, 058, 219, 042, 086, 120, ];
|
||||
|
||||
#[cfg(all(test, feature = "serde"))]
|
||||
static SECRET_KEY: SecretKey = SecretKey([
|
||||
@@ -1612,12 +1607,17 @@ mod test {
|
||||
215, 090, 152, 001, 130, 177, 010, 183,
|
||||
213, 075, 254, 211, 201, 100, 007, 058,
|
||||
014, 225, 114, 243, 218, 166, 035, 037,
|
||||
175, 002, 026, 104, 247, 007, 081, 026, ]))))
|
||||
175, 002, 026, 104, 247, 007, 081, 026, ]),
|
||||
CompressedEdwardsY([
|
||||
215, 090, 152, 001, 130, 177, 010, 183,
|
||||
213, 075, 254, 211, 201, 100, 007, 058,
|
||||
014, 225, 114, 243, 218, 166, 035, 037,
|
||||
175, 002, 026, 104, 247, 007, 081, 026, ]).decompress().unwrap())))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keypair_clear_on_drop() {
|
||||
let mut keypair: Keypair = Keypair::from_bytes(&[15u8; KEYPAIR_LENGTH][..]).unwrap();
|
||||
let mut keypair: Keypair = Keypair::from_bytes(&[1u8; KEYPAIR_LENGTH][..]).unwrap();
|
||||
|
||||
keypair.clear();
|
||||
|
||||
@@ -1660,10 +1660,12 @@ mod test {
|
||||
#[cfg(all(test, feature = "serde"))]
|
||||
#[test]
|
||||
fn serialize_deserialize_public_key() {
|
||||
let encoded_public_key: Vec<u8> = serialize(&PUBLIC_KEY, Infinite).unwrap();
|
||||
let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap();
|
||||
let encoded_public_key: Vec<u8> = serialize(&public_key, Infinite).unwrap();
|
||||
let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap();
|
||||
|
||||
assert_eq!(PUBLIC_KEY, decoded_public_key);
|
||||
assert_eq!(&PUBLIC_KEY_BYTES[..], &encoded_public_key[encoded_public_key.len() - 32..]);
|
||||
assert_eq!(public_key, decoded_public_key);
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "serde"))]
|
||||
@@ -1680,7 +1682,8 @@ mod test {
|
||||
#[cfg(all(test, feature = "serde"))]
|
||||
#[test]
|
||||
fn serialize_public_key_size() {
|
||||
assert_eq!(serialized_size(&PUBLIC_KEY) as usize, 40); // These sizes are specific to bincode==1.0.1
|
||||
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
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "serde"))]
|
||||
|
||||
Reference in New Issue
Block a user