Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ async-trait = "0.1.80"
bs58 = "0.4.0"
bytes = "1.4.0"
cid = "0.10.1"
ed25519-dalek = "1.0.1"
ed25519-dalek = { version = "2.1.1", features = ["rand_core"] }
futures = "0.3.27"
futures-timer = "3.0.3"
hex-literal = "0.4.1"
Expand Down
123 changes: 50 additions & 73 deletions src/crypto/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,38 +24,40 @@
use crate::{error::Error, PeerId};

use ed25519_dalek::{self as ed25519, Signer as _, Verifier as _};
use rand::RngCore;
use std::fmt;
use zeroize::Zeroize;

use std::{cmp, convert::TryFrom, fmt};

/// An Ed25519 keypair.
pub struct Keypair(ed25519::Keypair);
#[derive(Clone)]
pub struct Keypair(ed25519::SigningKey);

impl Keypair {
/// Generate a new random Ed25519 keypair.
pub fn generate() -> Keypair {
Keypair::from(SecretKey::generate())
}

/// Encode the keypair into a byte array by concatenating the bytes
/// Convert the keypair into a byte array by concatenating the bytes
/// of the secret scalar and the compressed public point,
/// an informal standard for encoding Ed25519 keypairs.
pub fn encode(&self) -> [u8; 64] {
self.0.to_bytes()
pub fn to_bytes(&self) -> [u8; 64] {
self.0.to_keypair_bytes()
}

/// Decode a keypair from the [binary format](https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.5)
/// produced by [`Keypair::encode`], zeroing the input on success.
/// Try to parse a keypair from the [binary format](https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.5)
/// produced by [`Keypair::to_bytes`], zeroing the input on success.
///
/// Note that this binary format is the same as `ed25519_dalek`'s and `ed25519_zebra`'s.
pub fn decode(kp: &mut [u8]) -> crate::Result<Keypair> {
ed25519::Keypair::from_bytes(kp)
pub fn try_from_bytes(kp: &mut [u8]) -> Result<Keypair, Error> {
let bytes = <[u8; 64]>::try_from(&*kp)
.map_err(|e| Error::Other(format!("Failed to parse ed25519 keypair: {e}")))?;

ed25519::SigningKey::from_keypair_bytes(&bytes)
.map(|k| {
kp.zeroize();
Keypair(k)
})
.map_err(|error| Error::Other(format!("Failed to parse keypair: {error:?}")))
.map_err(|e| Error::Other(format!("Failed to parse ed25519 keypair: {e}")))
}

/// Sign a message using the private key of this keypair.
Expand All @@ -65,56 +67,39 @@ impl Keypair {

/// Get the public key of this keypair.
pub fn public(&self) -> PublicKey {
PublicKey(self.0.public)
PublicKey(self.0.verifying_key())
}

/// Get the secret key of this keypair.
pub fn secret(&self) -> SecretKey {
SecretKey::from_bytes(&mut self.0.secret.to_bytes())
.expect("ed25519::SecretKey::from_bytes(to_bytes(k)) != k")
SecretKey(self.0.to_bytes())
}
}

impl fmt::Debug for Keypair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Keypair").field("public", &self.0.public).finish()
}
}

impl Clone for Keypair {
fn clone(&self) -> Keypair {
let mut sk_bytes = self.0.secret.to_bytes();
let secret = SecretKey::from_bytes(&mut sk_bytes)
.expect("ed25519::SecretKey::from_bytes(to_bytes(k)) != k")
.0;
let public = ed25519::PublicKey::from_bytes(&self.0.public.to_bytes())
.expect("ed25519::PublicKey::from_bytes(to_bytes(k)) != k");
Keypair(ed25519::Keypair { secret, public })
f.debug_struct("Keypair").field("public", &self.0.verifying_key()).finish()
}
}

/// Demote an Ed25519 keypair to a secret key.
impl From<Keypair> for SecretKey {
fn from(kp: Keypair) -> SecretKey {
SecretKey(kp.0.secret)
SecretKey(kp.0.to_bytes())
}
}

/// Promote an Ed25519 secret key into a keypair.
impl From<SecretKey> for Keypair {
fn from(sk: SecretKey) -> Keypair {
let secret: ed25519::ExpandedSecretKey = (&sk.0).into();
let public = ed25519::PublicKey::from(&secret);
Keypair(ed25519::Keypair {
secret: sk.0,
public,
})
let signing = ed25519::SigningKey::from_bytes(&sk.0);
Keypair(signing)
}
}

/// An Ed25519 public key.
#[derive(Eq, Clone)]
pub struct PublicKey(ed25519::PublicKey);
pub struct PublicKey(ed25519::VerifyingKey);

impl fmt::Debug for PublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand All @@ -126,7 +111,7 @@ impl fmt::Debug for PublicKey {
}
}

impl cmp::PartialEq for PublicKey {
impl PartialEq for PublicKey {
fn eq(&self, other: &Self) -> bool {
self.0.as_bytes().eq(other.0.as_bytes())
}
Expand All @@ -138,16 +123,19 @@ impl PublicKey {
ed25519::Signature::try_from(sig).and_then(|s| self.0.verify(msg, &s)).is_ok()
}

/// Encode the public key into a byte array in compressed form, i.e.
/// Convert the public key to a byte array in compressed form, i.e.
/// where one coordinate is represented by a single bit.
pub fn encode(&self) -> [u8; 32] {
pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
}

/// Decode a public key from a byte array as produced by `encode`.
pub fn decode(k: &[u8]) -> crate::Result<PublicKey> {
ed25519::PublicKey::from_bytes(k)
.map_err(|error| Error::Other(format!("Failed to parse keypair: {error:?}")))
/// Try to parse a public key from a byte array containing the actual key as produced by
/// `to_bytes`.
pub fn try_from_bytes(k: &[u8]) -> crate::Result<PublicKey> {
let k = <[u8; 32]>::try_from(k)
.map_err(|e| Error::Other(format!("Failed to parse ed25519 public key: {e}")))?;
ed25519::VerifyingKey::from_bytes(&k)
.map_err(|e| Error::Other(format!("Failed to parse ed25519 public key: {e}")))
.map(PublicKey)
}

Expand All @@ -158,19 +146,13 @@ impl PublicKey {
}

/// An Ed25519 secret key.
#[derive(Clone)]
pub struct SecretKey(ed25519::SecretKey);

/// View the bytes of the secret key.
impl AsRef<[u8]> for SecretKey {
fn as_ref(&self) -> &[u8] {
self.0.as_bytes()
}
}

impl Clone for SecretKey {
fn clone(&self) -> SecretKey {
let mut sk_bytes = self.0.to_bytes();
Self::from_bytes(&mut sk_bytes).expect("ed25519::SecretKey::from_bytes(to_bytes(k)) != k")
&self.0[..]
}
}

Expand All @@ -183,29 +165,24 @@ impl fmt::Debug for SecretKey {
impl SecretKey {
/// Generate a new Ed25519 secret key.
pub fn generate() -> SecretKey {
let mut bytes = [0u8; 32];
rand::thread_rng().fill_bytes(&mut bytes);
SecretKey(
ed25519::SecretKey::from_bytes(&bytes).expect(
"this returns `Err` only if the length is wrong; the length is correct; qed",
),
)
let signing = ed25519::SigningKey::generate(&mut rand::rngs::OsRng);
SecretKey(signing.to_bytes())
}

/// Create an Ed25519 secret key from a byte slice, zeroing the input on success.
/// Try to parse an Ed25519 secret key from a byte slice
/// containing the actual key, zeroing the input on success.
/// If the bytes do not constitute a valid Ed25519 secret key, an error is
/// returned.
pub fn from_bytes(mut sk_bytes: impl AsMut<[u8]>) -> crate::Result<SecretKey> {
pub fn try_from_bytes(mut sk_bytes: impl AsMut<[u8]>) -> crate::Result<SecretKey> {
let sk_bytes = sk_bytes.as_mut();
let secret = ed25519::SecretKey::from_bytes(&*sk_bytes)
.map_err(|error| Error::Other(format!("Failed to parse keypair: {error:?}")))?;
let secret = <[u8; 32]>::try_from(&*sk_bytes)
.map_err(|e| Error::Other(format!("Failed to parse ed25519 secret key: {e}")))?;
sk_bytes.zeroize();
Ok(SecretKey(secret))
}

/// Convert this secret key to a byte array.
pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
self.0
}
}

Expand All @@ -215,15 +192,15 @@ mod tests {
use quickcheck::*;

fn eq_keypairs(kp1: &Keypair, kp2: &Keypair) -> bool {
kp1.public() == kp2.public() && kp1.0.secret.as_bytes() == kp2.0.secret.as_bytes()
kp1.public() == kp2.public() && kp1.0.to_bytes() == kp2.0.to_bytes()
}

#[test]
fn ed25519_keypair_encode_decode() {
fn prop() -> bool {
let kp1 = Keypair::generate();
let mut kp1_enc = kp1.encode();
let kp2 = Keypair::decode(&mut kp1_enc).unwrap();
let mut kp1_enc = kp1.to_bytes();
let kp2 = Keypair::try_from_bytes(&mut kp1_enc).unwrap();
eq_keypairs(&kp1, &kp2) && kp1_enc.iter().all(|b| *b == 0)
}
QuickCheck::new().tests(10).quickcheck(prop as fn() -> _);
Expand All @@ -233,8 +210,8 @@ mod tests {
fn ed25519_keypair_from_secret() {
fn prop() -> bool {
let kp1 = Keypair::generate();
let mut sk = kp1.0.secret.to_bytes();
let kp2 = Keypair::from(SecretKey::from_bytes(&mut sk).unwrap());
let mut sk = kp1.0.to_bytes();
let kp2 = Keypair::from(SecretKey::try_from_bytes(&mut sk).unwrap());
eq_keypairs(&kp1, &kp2) && sk == [0u8; 32]
}
QuickCheck::new().tests(10).quickcheck(prop as fn() -> _);
Expand Down Expand Up @@ -269,13 +246,13 @@ mod tests {
tracing::trace!("public: {:?}", key.public());

let new_key = Keypair::from(key.secret());
assert!(new_key.secret().as_ref() == key.secret().as_ref());
assert!(new_key.public() == key.public());
assert_eq!(new_key.secret().as_ref(), key.secret().as_ref());
assert_eq!(new_key.public(), key.public());

let new_secret = SecretKey::from(new_key.clone());
assert!(new_secret.as_ref() == new_key.secret().as_ref());
assert_eq!(new_secret.as_ref(), new_key.secret().as_ref());

let cloned_secret = new_secret.clone();
assert!(cloned_secret.as_ref() == new_secret.as_ref());
assert_eq!(cloned_secret.as_ref(), new_secret.as_ref());
}
}
4 changes: 2 additions & 2 deletions src/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl From<&PublicKey> for keys_proto::PublicKey {
match key {
PublicKey::Ed25519(key) => keys_proto::PublicKey {
r#type: keys_proto::KeyType::Ed25519 as i32,
data: key.encode().to_vec(),
data: key.to_bytes().to_vec(),
},
}
}
Expand All @@ -99,7 +99,7 @@ impl TryFrom<keys_proto::PublicKey> for PublicKey {

match key_type {
keys_proto::KeyType::Ed25519 =>
Ok(ed25519::PublicKey::decode(&pubkey.data).map(PublicKey::Ed25519)?),
Ok(ed25519::PublicKey::try_from_bytes(&pubkey.data).map(PublicKey::Ed25519)?),
_ => Err(Error::Other(format!(
"Unsupported key type: {}",
key_type.as_str_name()
Expand Down