Skip to content

Commit

Permalink
did-simple: added ed25519 pubkey type (#104)
Browse files Browse the repository at this point in the history
Includes validation logic for the pubkey.

Disclaimer, I consulted with a friend who is a security researcher on
how to validate the pubkey. But any additional feedback is appreciated.
  • Loading branch information
TheButlah authored May 22, 2024
1 parent 988ebac commit 2d50b49
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 2 deletions.
130 changes: 129 additions & 1 deletion Cargo.lock

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

8 changes: 7 additions & 1 deletion crates/did-simple/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ description = "Dead simple DIDs"
publish = true

[features]
default = []
default = ["ed25519"]
ed25519 = [
"dep:curve25519-dalek",
"dep:ed25519-dalek",
]

# Only applications should enable this! If you use did-simple as a dependency,
# don't enable this feature - let applications set it instead.
Expand All @@ -20,6 +24,8 @@ allow-unsafe = []
bs58 = "0.5.1"
bytes = "1.6.0"
thiserror = "1.0.60"
ed25519-dalek = { version = "2.1.1", optional = true }
curve25519-dalek = { version = "4.1.2", optional = true }

[dev-dependencies]
eyre = "0.6.12"
Expand Down
50 changes: 50 additions & 0 deletions crates/did-simple/src/crypto/ed25519.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use curve25519_dalek::edwards::CompressedEdwardsY;
use ed25519_dalek::VerifyingKey;

use crate::key_algos::StaticKeyAlgo as _;

/// An ed25519 public key.
#[allow(dead_code)]
pub struct PubKey(VerifyingKey);

impl PubKey {
pub const LEN: usize = Self::key_len();

/// Instantiates `PubKey` from some bytes. Performs all necessary validation
/// that the key is valid and of sufficient strength.
///
/// Note that we will reject any keys that are too weak (aka low order).
pub fn try_from(bytes: &[u8; Self::LEN]) -> Result<Self, TryFromBytesError> {
let compressed_edwards = CompressedEdwardsY(bytes.to_owned());
let Some(edwards) = compressed_edwards.decompress() else {
return Err(TryFromBytesError::NotOnCurve);
};
let key = VerifyingKey::from(edwards);
if key.is_weak() {
return Err(TryFromBytesError::WeakKey);
}
Ok(Self(key))
}

// TODO: Turn this into inline const when that feature stabilizes
const fn key_len() -> usize {
let len = crate::key_algos::Ed25519::PUB_KEY_LEN;
assert!(len == ed25519_dalek::PUBLIC_KEY_LENGTH);
len
}
}

#[derive(thiserror::Error, Debug)]
pub enum TryFromBytesError {
#[error(
"the provided bytes was not the y coordinate of a valid point on the curve"
)]
NotOnCurve,
#[error("public key has a low order and is too weak, which would allow the key to generate signatures that work for almost any message. To prevent this, we reject weak keys.")]
WeakKey,
}

/// Errors which may occur while processing signatures and keypairs.
#[derive(thiserror::Error, Debug)]
#[error("invalid signature")]
pub struct SignatureError(#[from] ed25519_dalek::SignatureError);
4 changes: 4 additions & 0 deletions crates/did-simple/src/crypto/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//! Implementations of cryptographic operations

#[cfg(feature = "ed25519")]
pub mod ed25519;
1 change: 1 addition & 0 deletions crates/did-simple/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

use std::str::FromStr;

pub mod crypto;
pub(crate) mod key_algos;
pub mod methods;
pub mod url;
Expand Down

0 comments on commit 2d50b49

Please sign in to comment.