From 66d580019b36141927684949682639af06f79e4f Mon Sep 17 00:00:00 2001 From: Alexis Sellier Date: Tue, 30 Aug 2022 21:09:30 +0200 Subject: [PATCH] node: Create crypto module Signed-off-by: Alexis Sellier --- node/src/crypto.rs | 65 ++++++++++++++++++++++++++++++++++ node/src/identity.rs | 71 ++++---------------------------------- node/src/lib.rs | 1 + node/src/test/arbitrary.rs | 5 +-- 4 files changed, 76 insertions(+), 66 deletions(-) create mode 100644 node/src/crypto.rs diff --git a/node/src/crypto.rs b/node/src/crypto.rs new file mode 100644 index 00000000..9e3e17ba --- /dev/null +++ b/node/src/crypto.rs @@ -0,0 +1,65 @@ +use std::{fmt, ops::Deref, str::FromStr}; + +use ed25519_consensus as ed25519; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +#[derive(Serialize, Deserialize, Eq, Debug, Clone)] +#[serde(transparent)] +pub struct PublicKey(pub ed25519::VerificationKey); + +#[derive(Error, Debug)] +pub enum PublicKeyError { + #[error("invalid length {0}")] + InvalidLength(usize), + #[error("invalid multibase string: {0}")] + Multibase(#[from] multibase::Error), + #[error("invalid key: {0}")] + InvalidKey(#[from] ed25519_consensus::Error), +} + +impl std::hash::Hash for PublicKey { + fn hash(&self, state: &mut H) { + self.0.as_bytes().hash(state) + } +} + +impl fmt::Display for PublicKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.encode()) + } +} + +impl PartialEq for PublicKey { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl PublicKey { + pub fn encode(&self) -> String { + multibase::encode(multibase::Base::Base58Btc, &self.0) + } +} + +impl FromStr for PublicKey { + type Err = PublicKeyError; + + fn from_str(s: &str) -> Result { + let (_, bytes) = multibase::decode(s)?; + let array: [u8; 32] = bytes + .try_into() + .map_err(|v: Vec| PublicKeyError::InvalidLength(v.len()))?; + let key = ed25519::VerificationKey::try_from(ed25519::VerificationKeyBytes::from(array))?; + + Ok(Self(key)) + } +} + +impl Deref for PublicKey { + type Target = ed25519::VerificationKey; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/node/src/identity.rs b/node/src/identity.rs index e1dede62..3aa8541c 100644 --- a/node/src/identity.rs +++ b/node/src/identity.rs @@ -1,13 +1,16 @@ -use std::{ffi::OsString, fmt, io, ops::Deref, str::FromStr}; +use std::{ffi::OsString, fmt, io, str::FromStr}; -use ed25519_consensus::{VerificationKey, VerificationKeyBytes}; use nonempty::NonEmpty; use radicle_git_ext::Oid; use serde::{Deserialize, Serialize}; use thiserror::Error; +use crate::crypto; use crate::hash; +/// A user's identifier is simply their public key. +pub type UserId = crypto::PublicKey; + #[derive(Error, Debug)] pub enum ProjIdError { #[error("invalid digest: {0}")] @@ -59,10 +62,10 @@ impl From for ProjId { } #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug, Clone)] -pub struct Did(UserId); +pub struct Did(crypto::PublicKey); impl Did { - fn encode(&self) -> String { + pub fn encode(&self) -> String { format!("did:key:{}", self.0.encode()) } } @@ -73,66 +76,6 @@ impl fmt::Display for Did { } } -#[derive(Serialize, Deserialize, Eq, Debug, Clone)] -#[serde(transparent)] -pub struct UserId(pub VerificationKey); - -impl std::hash::Hash for UserId { - fn hash(&self, state: &mut H) { - self.0.as_bytes().hash(state) - } -} - -impl fmt::Display for UserId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.encode()) - } -} - -impl PartialEq for UserId { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} - -impl UserId { - fn encode(&self) -> String { - multibase::encode(multibase::Base::Base58Btc, &self.0) - } -} - -impl FromStr for UserId { - type Err = UserIdError; - - fn from_str(s: &str) -> Result { - let (_, bytes) = multibase::decode(s)?; - let array: [u8; 32] = bytes - .try_into() - .map_err(|v: Vec| UserIdError::InvalidLength(v.len()))?; - let key = VerificationKey::try_from(VerificationKeyBytes::from(array))?; - - Ok(Self(key)) - } -} - -impl Deref for UserId { - type Target = VerificationKey; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Error, Debug)] -pub enum UserIdError { - #[error("invalid length {0}")] - InvalidLength(usize), - #[error("invalid multibase string: {0}")] - Multibase(#[from] multibase::Error), - #[error("invalid key: {0}")] - InvalidKey(#[from] ed25519_consensus::Error), -} - #[derive(Error, Debug)] pub enum DocError { #[error("toml: {0}")] diff --git a/node/src/lib.rs b/node/src/lib.rs index d8693459..7276de1b 100644 --- a/node/src/lib.rs +++ b/node/src/lib.rs @@ -5,6 +5,7 @@ mod address_book; mod address_manager; mod clock; mod collections; +mod crypto; mod decoder; mod git; mod hash; diff --git a/node/src/test/arbitrary.rs b/node/src/test/arbitrary.rs index aebca5a5..5b52040f 100644 --- a/node/src/test/arbitrary.rs +++ b/node/src/test/arbitrary.rs @@ -3,6 +3,7 @@ use std::hash::Hash; use std::ops::RangeBounds; use crate::collections::HashMap; +use crate::crypto::PublicKey; use crate::hash; use crate::identity::{ProjId, UserId}; use crate::storage; @@ -76,7 +77,7 @@ impl quickcheck::Arbitrary for hash::Digest { } } -impl quickcheck::Arbitrary for UserId { +impl quickcheck::Arbitrary for PublicKey { fn arbitrary(g: &mut quickcheck::Gen) -> Self { use ed25519_consensus::SigningKey; @@ -88,6 +89,6 @@ impl quickcheck::Arbitrary for UserId { let sk = SigningKey::from(bytes); let vk = sk.verification_key(); - UserId(vk) + PublicKey(vk) } }