diff --git a/Cargo.lock b/Cargo.lock index 741639c..cf446df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1330,6 +1330,7 @@ dependencies = [ "ref-cast", "serde", "serde_json", + "signature", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index be1dab9..cab4ac2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,5 @@ log = "0.4.11" ref-cast = "1.0.2" derivative = "2.1.1" ed25519-dalek = "1.0.1" - -[dev-dependencies] -rand = "0.7.3" +rand = "0.7.0" +signature = "1.3.0" diff --git a/bin/Cargo.lock b/bin/Cargo.lock index e18b23b..be06a28 100644 --- a/bin/Cargo.lock +++ b/bin/Cargo.lock @@ -1370,9 +1370,11 @@ dependencies = [ "failure", "fluence-fork-libp2p-core", "log", + "rand 0.7.3", "ref-cast", "serde", "serde_json", + "signature", ] [[package]] diff --git a/src/certificate.rs b/src/certificate.rs index 8f1b1a7..e242ac7 100644 --- a/src/certificate.rs +++ b/src/certificate.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -use crate::ed25519::PublicKey; +use ed25519_dalek::PublicKey; use crate::key_pair::KeyPair; use crate::trust::{Trust, TRUST_LEN}; use std::str::FromStr; diff --git a/src/key_pair.rs b/src/key_pair.rs index 0b2f686..41f463c 100644 --- a/src/key_pair.rs +++ b/src/key_pair.rs @@ -14,37 +14,43 @@ * limitations under the License. */ -use crate::ed25519::{Keypair as Libp2pKeyPair, PublicKey, SecretKey}; -use ed25519_dalek::SignatureError; -use libp2p_core::identity::error::DecodingError; -use std::fmt; +extern crate rand; -pub type Signature = Vec; +use crate::ed25519::{Keypair as Libp2pKeyPair}; +use ed25519_dalek::SignatureError; +use ed25519_dalek::{PublicKey, Signer}; +use signature::{Signature as SigSignature}; +use core::fmt::{Debug}; +use std::fmt; +use rand::rngs::OsRng; + +pub type Signature = ed25519_dalek::Signature; /// An Ed25519 keypair. -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct KeyPair { - pub key_pair: Libp2pKeyPair, + pub key_pair: ed25519_dalek::Keypair, } impl KeyPair { /// Generate a new Ed25519 keypair. #[allow(dead_code)] pub fn generate() -> Self { - let kp = Libp2pKeyPair::generate(); + let mut csprng = OsRng { }; + let kp = ed25519_dalek::Keypair::generate(&mut csprng); kp.into() } - pub fn from_bytes(sk_bytes: impl AsMut<[u8]>) -> Result { - let sk = SecretKey::from_bytes(sk_bytes)?; - Ok(Libp2pKeyPair::from(sk).into()) + pub fn from_bytes(sk_bytes: &[u8]) -> Result { + let kp = ed25519_dalek::Keypair::from_bytes(sk_bytes)?; + Ok(KeyPair {key_pair: kp}) } /// Encode the keypair into a byte array by concatenating the bytes /// of the secret scalar and the compressed public point/ #[allow(dead_code)] pub fn encode(&self) -> [u8; 64] { - self.key_pair.encode() + self.key_pair.to_bytes() } /// Decode a keypair from the format produced by `encode`. @@ -52,26 +58,27 @@ impl KeyPair { pub fn decode(kp: &[u8]) -> Result { let kp = ed25519_dalek::Keypair::from_bytes(kp)?; Ok(Self { - key_pair: kp.into(), + key_pair: kp, }) } /// Get the public key of this keypair. #[allow(dead_code)] pub fn public_key(&self) -> PublicKey { - self.key_pair.public() + self.key_pair.public } /// Sign a message using the private key of this keypair. - pub fn sign(&self, msg: &[u8]) -> Vec { + pub fn sign(&self, msg: &[u8]) -> Signature { self.key_pair.sign(msg) } /// Verify the Ed25519 signature on a message using the public key. - pub fn verify(pk: &PublicKey, msg: &[u8], signature: &[u8]) -> Result<(), String> { - if pk.verify(msg, signature) { - return Ok(()); - } + pub fn verify(pk: &PublicKey, msg: &[u8], signature: Signature) -> Result<(), String> { + // let signature = ed25519_dalek::Signature::from_bytes(signature) + // .map_err(|err| format!("Cannot convert bytes to a signature: {:?}", err))?; + let result = pk.verify_strict(msg, &signature) + .map_err(|err| format!("Signature verification failed: {:?}", err))?; Err("Signature is not valid.".to_string()) } @@ -79,6 +86,13 @@ impl KeyPair { impl From for KeyPair { fn from(kp: Libp2pKeyPair) -> Self { + let kp = ed25519_dalek::Keypair::from_bytes(&kp.encode()).unwrap(); + Self { key_pair: kp } + } +} + +impl From for KeyPair { + fn from(kp: ed25519_dalek::Keypair) -> Self { Self { key_pair: kp } } } diff --git a/src/public_key_hashable.rs b/src/public_key_hashable.rs index ddde308..811b337 100644 --- a/src/public_key_hashable.rs +++ b/src/public_key_hashable.rs @@ -14,24 +14,24 @@ * limitations under the License. */ -use crate::ed25519::PublicKey; +use ed25519_dalek::PublicKey; use ref_cast::RefCast; -use serde::Deserialize; use std::{ fmt::{Display, Formatter}, hash::{Hash, Hasher}, }; +use core::fmt; /// Wrapper to use PublicKey in HashMap -#[derive(PartialEq, Eq, Debug, Clone, RefCast, Deserialize)] +#[derive(PartialEq, Eq, Debug, Clone, RefCast)] #[repr(transparent)] pub struct PublicKeyHashable(PublicKey); #[allow(clippy::derive_hash_xor_eq)] impl Hash for PublicKeyHashable { fn hash(&self, state: &mut H) { - state.write(&self.0.encode()); + state.write(&self.0.to_bytes()); state.finish(); } @@ -42,7 +42,7 @@ impl Hash for PublicKeyHashable { // TODO check for overflow let mut bytes: Vec = Vec::with_capacity(data.len() * 32); for d in data { - bytes.extend_from_slice(&d.0.encode()) + bytes.extend_from_slice(&d.0.to_bytes()) } state.write(bytes.as_slice()); state.finish(); @@ -75,6 +75,46 @@ impl AsRef for PublicKey { impl Display for PublicKeyHashable { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", bs58::encode(self.0.encode()).into_string()) + write!(f, "{}", bs58::encode(self.0.to_bytes()).into_string()) + } +} + +impl <'de>serde::Deserialize<'de> for PublicKeyHashable { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de> { + use serde::de::{Error, Visitor}; + + struct PKVisitor; + + impl<'de> Visitor<'de> for PKVisitor { + type Value = PublicKeyHashable; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("byte array or base58 string") + } + + fn visit_str(self, s: &str) -> Result + where + E: Error, + { + bs58::decode(s) + .into_vec() + .map_err(|err| Error::custom(format!("Invalid string '{}': {}", s, err))) + .and_then(|v| self.visit_bytes(v.as_slice())) + .map_err(|err: E| Error::custom(format!("Parsed string '{}' as base58, but {}", s, err))) + } + + fn visit_bytes(self, b: &[u8]) -> Result + where + E: Error, + { + let pk = PublicKey::from_bytes(b) + .map_err(|err| Error::custom(format!("Invalid bytes {:?}: {}", b, err)))?; + Ok(PublicKeyHashable::from(pk)) + } + } + + deserializer.deserialize_str(PKVisitor) } } diff --git a/src/revoke.rs b/src/revoke.rs index b35be0e..5927e93 100644 --- a/src/revoke.rs +++ b/src/revoke.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -use crate::ed25519::PublicKey; +use ed25519_dalek::PublicKey; use crate::key_pair::KeyPair; use crate::key_pair::Signature; use crate::trust::{EXPIRATION_LEN, PK_LEN}; @@ -61,7 +61,7 @@ impl Revoke { fn signature_bytes(pk: &PublicKey, revoked_at: Duration) -> Vec { let mut msg = Vec::with_capacity(PK_LEN + EXPIRATION_LEN); - msg.extend_from_slice(&pk.encode()); + msg.extend_from_slice(&pk.to_bytes()); msg.extend_from_slice(&(revoked_at.as_secs() as u64).to_le_bytes()); msg @@ -71,14 +71,10 @@ impl Revoke { pub fn verify(revoke: &Revoke) -> Result<(), String> { let msg = Revoke::signature_bytes(&revoke.pk, revoke.revoked_at); - if !revoke + revoke .revoked_by - .verify(msg.as_slice(), revoke.signature.as_slice()) - { - return Err("Revoke has incorrect signature.".to_string()); - } - - Ok(()) + .verify_strict(msg.as_slice(), &revoke.signature) + .map_err(|err| format!("Revoke has incorrect signature: {:?}", err)) } } diff --git a/src/trust.rs b/src/trust.rs index 7f54f11..7794ef0 100644 --- a/src/trust.rs +++ b/src/trust.rs @@ -14,11 +14,12 @@ * limitations under the License. */ -use crate::ed25519::PublicKey; +use ed25519_dalek::{PublicKey}; use crate::key_pair::{KeyPair, Signature}; use derivative::Derivative; use std::convert::TryInto; use std::time::Duration; +use signature::{Signature as SigSignature}; pub const SIG_LEN: usize = 64; pub const PK_LEN: usize = 32; @@ -46,11 +47,11 @@ pub struct Trust { } fn show_pubkey(key: &PublicKey, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - write!(f, "{}", bs58::encode(key.encode()).into_string()) + write!(f, "{}", bs58::encode(&key.to_bytes()).into_string()) } -fn show_sig(sig: &[u8], f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - write!(f, "{}", bs58::encode(sig).into_string()) +fn show_sig(sig: &ed25519_dalek::Signature, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "{}", bs58::encode(&sig.to_bytes()).into_string()) } impl Trust { @@ -96,13 +97,13 @@ impl Trust { let msg: &[u8] = &Self::metadata_bytes(&trust.issued_for, trust.expires_at, trust.issued_at); - KeyPair::verify(issued_by, msg, trust.signature.as_slice())?; + KeyPair::verify(issued_by, msg, trust.signature)?; Ok(()) } fn metadata_bytes(pk: &PublicKey, expires_at: Duration, issued_at: Duration) -> [u8; 48] { - let pk_encoded = pk.encode(); + let pk_encoded = pk.to_bytes(); let expires_at_encoded: [u8; EXPIRATION_LEN] = (expires_at.as_secs() as u64).to_le_bytes(); let issued_at_encoded: [u8; ISSUED_LEN] = (issued_at.as_secs() as u64).to_le_bytes(); let mut metadata = [0; METADATA_LEN]; @@ -120,8 +121,8 @@ impl Trust { #[allow(dead_code)] pub fn encode(&self) -> Vec { let mut vec = Vec::with_capacity(TRUST_LEN); - vec.extend_from_slice(&self.issued_for.encode()); - vec.extend_from_slice(&self.signature.as_slice()); + vec.extend_from_slice(&self.issued_for.to_bytes()); + vec.extend_from_slice(&self.signature.to_bytes()); vec.extend_from_slice(&(self.expires_at.as_secs() as u64).to_le_bytes()); vec.extend_from_slice(&(self.issued_at.as_secs() as u64).to_le_bytes()); @@ -137,8 +138,10 @@ impl Trust { ); } - let pk = PublicKey::decode(&arr[0..PK_LEN]).map_err(|err| err.to_string())?; + let pk = PublicKey::from_bytes(&arr[0..PK_LEN]).map_err(|err| err.to_string())?; + let signature = &arr[PK_LEN..PK_LEN + SIG_LEN]; + let signature = Signature::from_bytes(signature).map_err(|err| err.to_string())?; let expiration_bytes = &arr[PK_LEN + SIG_LEN..PK_LEN + SIG_LEN + EXPIRATION_LEN]; let expiration_date = u64::from_le_bytes(expiration_bytes.try_into().unwrap()); @@ -150,7 +153,7 @@ impl Trust { Ok(Self { issued_for: pk, - signature: signature.to_vec(), + signature: signature, expires_at: expiration_date, issued_at: issued_date, }) @@ -183,7 +186,7 @@ impl Trust { ) -> Result { // PublicKey let issued_for_bytes = Self::bs58_str_to_vec(issued_for, "issued_for")?; - let issued_for = PublicKey::decode(issued_for_bytes.as_slice()).map_err(|e| { + let issued_for = PublicKey::from_bytes(issued_for_bytes.as_slice()).map_err(|e| { format!( "Cannot decode the public key: {} in the trust '{}'", issued_for, e @@ -192,6 +195,7 @@ impl Trust { // 64 bytes signature let signature = Self::bs58_str_to_vec(signature, "signature")?; + let signature = Signature::from_bytes(&signature).map_err(|err| err.to_string())?; // Duration let expires_at = Self::str_to_duration(expires_at, "expires_at")?; @@ -205,8 +209,8 @@ impl Trust { impl ToString for Trust { fn to_string(&self) -> String { - let issued_for = bs58::encode(self.issued_for.encode()).into_string(); - let signature = bs58::encode(self.signature.as_slice()).into_string(); + let issued_for = bs58::encode(self.issued_for.to_bytes()).into_string(); + let signature = bs58::encode(self.signature.to_bytes()).into_string(); let expires_at = (self.expires_at.as_secs() as u64).to_string(); let issued_at = (self.issued_at.as_secs() as u64).to_string(); diff --git a/src/trust_graph.rs b/src/trust_graph.rs index 44ef933..3da66aa 100644 --- a/src/trust_graph.rs +++ b/src/trust_graph.rs @@ -15,7 +15,7 @@ */ use crate::certificate::Certificate; -use crate::ed25519::PublicKey; +use ed25519_dalek::PublicKey; use crate::public_key_hashable::PublicKeyHashable; use crate::revoke::Revoke; use crate::trust::Trust; diff --git a/src/trust_graph_storage.rs b/src/trust_graph_storage.rs index aa2eae6..551e344 100644 --- a/src/trust_graph_storage.rs +++ b/src/trust_graph_storage.rs @@ -2,7 +2,7 @@ use crate::public_key_hashable::PublicKeyHashable; use crate::revoke::Revoke; use crate::trust_graph::Weight; use crate::trust_node::{Auth, TrustNode}; -use libp2p_core::identity::ed25519::PublicKey; +use ed25519_dalek::PublicKey; use std::collections::HashMap; use std::time::Duration; diff --git a/src/trust_node.rs b/src/trust_node.rs index 4850dfc..8e1675b 100644 --- a/src/trust_node.rs +++ b/src/trust_node.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -use crate::ed25519::PublicKey; +use ed25519_dalek::PublicKey; use crate::public_key_hashable::PublicKeyHashable; use crate::revoke::Revoke; use crate::trust::Trust;