Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core/identity: Implement Hash and Ord for PublicKey #2915

Merged
merged 12 commits into from
Sep 22, 2022
6 changes: 6 additions & 0 deletions core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 0.36.1 - [unreleased]
futpib marked this conversation as resolved.
Show resolved Hide resolved

- Implement `Hash` and `Ord` for `PublicKey`. See [PR 2915].

[PR 2915]: https://github.com/libp2p/rust-libp2p/pull/2915

# 0.36.0

- Make RSA keypair support optional. To enable RSA support, `rsa` feature should be enabled.
Expand Down
20 changes: 19 additions & 1 deletion core/src/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ impl zeroize::Zeroize for keys_proto::PrivateKey {
}

/// The public key of a node's identity keypair.
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum PublicKey {
/// A public Ed25519 key.
Ed25519(ed25519::PublicKey),
Expand Down Expand Up @@ -379,4 +379,22 @@ mod tests {

assert_eq!(expected_peer_id, peer_id);
}

#[test]
fn public_key_implements_hash() {
use std::hash::Hash;

fn assert_implements_hash<T: Hash>() {}

assert_implements_hash::<PublicKey>();
}

#[test]
fn public_key_implements_ord() {
use std::cmp::Ord;

fn assert_implements_ord<T: Ord>() {}

assert_implements_ord::<PublicKey>();
}
}
16 changes: 15 additions & 1 deletion core/src/identity/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

use super::error::DecodingError;
use core::fmt;
use core::cmp;
use core::hash;
use p256::{
ecdsa::{
signature::{Signer, Verifier},
Expand Down Expand Up @@ -117,7 +119,7 @@ impl fmt::Debug for SecretKey {
}

/// An ECDSA public key.
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, Eq, PartialOrd, Ord)]
pub struct PublicKey(VerifyingKey);

impl PublicKey {
Expand Down Expand Up @@ -222,6 +224,18 @@ impl fmt::Debug for PublicKey {
}
}

impl cmp::PartialEq for PublicKey {
fn eq(&self, other: &Self) -> bool {
self.to_bytes().eq(&other.to_bytes())
}
}

impl hash::Hash for PublicKey {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.to_bytes().hash(state);
}
}
futpib marked this conversation as resolved.
Show resolved Hide resolved

#[cfg(test)]
mod tests {
use super::*;
Expand Down
28 changes: 27 additions & 1 deletion core/src/identity/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

use super::error::DecodingError;
use core::fmt;
use core::hash;
use core::cmp;
use ed25519_dalek::{self as ed25519, Signer as _, Verifier as _};
use rand::RngCore;
use std::convert::TryFrom;
Expand Down Expand Up @@ -113,7 +115,7 @@ impl From<SecretKey> for Keypair {
}

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

impl fmt::Debug for PublicKey {
Expand All @@ -126,6 +128,30 @@ impl fmt::Debug for PublicKey {
}
}

impl cmp::PartialEq for PublicKey {
fn eq(&self, other: &Self) -> bool {
self.0.as_bytes().eq(other.0.as_bytes())
}
}

impl hash::Hash for PublicKey {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.0.as_bytes().hash(state);
}
}

impl cmp::PartialOrd for PublicKey {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.0.as_bytes().partial_cmp(other.0.as_bytes())
}
}

impl cmp::Ord for PublicKey {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.0.as_bytes().cmp(other.0.as_bytes())
}
}

impl PublicKey {
/// Verify the Ed25519 signature on a message using the public key.
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool {
Expand Down
20 changes: 11 additions & 9 deletions core/src/identity/rsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl Keypair {
}

/// An RSA public key.
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct PublicKey(Vec<u8>);

impl PublicKey {
Expand Down Expand Up @@ -307,28 +307,30 @@ mod tests {
use super::*;
use quickcheck::*;
use rand07::seq::SliceRandom;
use std::fmt;

const KEY1: &'static [u8] = include_bytes!("test/rsa-2048.pk8");
const KEY2: &'static [u8] = include_bytes!("test/rsa-3072.pk8");
const KEY3: &'static [u8] = include_bytes!("test/rsa-4096.pk8");

#[derive(Clone)]
#[derive(Clone, Debug)]
struct SomeKeypair(Keypair);

impl fmt::Debug for SomeKeypair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SomeKeypair")
}
}

impl Arbitrary for SomeKeypair {
fn arbitrary<G: Gen>(g: &mut G) -> SomeKeypair {
let mut key = [KEY1, KEY2, KEY3].choose(g).unwrap().to_vec();
SomeKeypair(Keypair::from_pkcs8(&mut key).unwrap())
}
}

#[derive(Clone, Debug)]
struct SomePublicKey(PublicKey);

impl Arbitrary for SomePublicKey {
fn arbitrary<G: Gen>(g: &mut G) -> SomePublicKey {
SomePublicKey(SomeKeypair::arbitrary(g).0.public())
}
}

futpib marked this conversation as resolved.
Show resolved Hide resolved
#[test]
fn rsa_from_pkcs8() {
assert!(Keypair::from_pkcs8(&mut KEY1.to_vec()).is_ok());
Expand Down
28 changes: 27 additions & 1 deletion core/src/identity/secp256k1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
use super::error::{DecodingError, SigningError};
use asn1_der::typed::{DerDecodable, Sequence};
use core::fmt;
use core::hash;
use core::cmp;
use libsecp256k1::{Message, Signature};
use sha2::{Digest as ShaDigestTrait, Sha256};
use zeroize::Zeroize;
Expand Down Expand Up @@ -150,7 +152,7 @@ impl SecretKey {
}

/// A Secp256k1 public key.
#[derive(PartialEq, Eq, Clone)]
#[derive(Eq, Clone)]
pub struct PublicKey(libsecp256k1::PublicKey);

impl fmt::Debug for PublicKey {
Expand All @@ -163,6 +165,30 @@ impl fmt::Debug for PublicKey {
}
}

impl cmp::PartialEq for PublicKey {
fn eq(&self, other: &Self) -> bool {
self.encode().eq(&other.encode())
}
}

impl hash::Hash for PublicKey {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.encode().hash(state);
}
}
futpib marked this conversation as resolved.
Show resolved Hide resolved

impl cmp::PartialOrd for PublicKey {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.encode().partial_cmp(&other.encode())
}
}

impl cmp::Ord for PublicKey {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.encode().cmp(&other.encode())
}
}

impl PublicKey {
/// Verify the Secp256k1 signature on a message using the public key.
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool {
Expand Down