diff --git a/atrium-crypto/src/algorithm.rs b/atrium-crypto/src/algorithm.rs index 7c6e85f1..884421b1 100644 --- a/atrium-crypto/src/algorithm.rs +++ b/atrium-crypto/src/algorithm.rs @@ -1,8 +1,4 @@ -use crate::error::Result; -use ecdsa::VerifyingKey; -use k256::Secp256k1; use multibase::Base; -use p256::NistP256; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Algorithm { @@ -27,111 +23,10 @@ impl Algorithm { _ => None, } } - pub fn format_multikey(&self, key: &[u8]) -> Result { - Ok(self.format_mulikey_compressed(&self.compress_pubkey(key)?)) - } pub(crate) fn format_mulikey_compressed(&self, key: &[u8]) -> String { let mut v = Vec::with_capacity(2 + key.len()); v.extend_from_slice(&self.prefix()); v.extend_from_slice(key); multibase::encode(Base::Base58Btc, v) } - pub(crate) fn compress_pubkey(&self, key: &[u8]) -> Result> { - self.pubkey_bytes(key, true) - } - pub(crate) fn decompress_pubkey(&self, key: &[u8]) -> Result> { - self.pubkey_bytes(key, false) - } - fn pubkey_bytes(&self, key: &[u8], compress: bool) -> Result> { - Ok(match self { - Algorithm::P256 => VerifyingKey::::from_sec1_bytes(key)? - .to_encoded_point(compress) - .as_bytes() - .to_vec(), - Algorithm::Secp256k1 => VerifyingKey::::from_sec1_bytes(key)? - .to_encoded_point(compress) - .as_bytes() - .to_vec(), - }) - } -} - -#[cfg(test)] -mod tests { - use super::Algorithm; - use crate::did::parse_did_key; - use crate::keypair::{Did, P256Keypair, Secp256k1Keypair}; - use rand::rngs::ThreadRng; - - #[test] - fn p256_compress_decompress() { - let did = P256Keypair::create(&mut ThreadRng::default()).did(); - let (alg, key) = parse_did_key(&did).expect("parsing did key should succeed"); - assert_eq!(alg, Algorithm::P256); - // compress a key to the correct length - let compressed = alg - .pubkey_bytes(&key, true) - .expect("compressing public key should succeed"); - assert_eq!(compressed.len(), 33); - // decompress a key to the original - let decompressed = alg - .pubkey_bytes(&compressed, false) - .expect("decompressing public key should succeed"); - assert_eq!(decompressed.len(), 65); - assert_eq!(key, decompressed); - - // works consitesntly - let keys = (0..100) - .map(|_| { - let did = P256Keypair::create(&mut ThreadRng::default()).did(); - let (_, key) = parse_did_key(&did).expect("parsing did key should succeed"); - key - }) - .collect::>(); - let compressed = keys - .iter() - .filter_map(|key| alg.pubkey_bytes(key, true).ok()) - .collect::>(); - let decompressed = compressed - .iter() - .filter_map(|key| alg.pubkey_bytes(key, false).ok()) - .collect::>(); - assert_eq!(keys, decompressed); - } - - #[test] - fn secp256k1_compress_decompress() { - let did = Secp256k1Keypair::create(&mut ThreadRng::default()).did(); - let (alg, key) = parse_did_key(&did).expect("parsing did key should succeed"); - assert_eq!(alg, Algorithm::Secp256k1); - // compress a key to the correct length - let compressed = alg - .pubkey_bytes(&key, true) - .expect("compressing public key should succeed"); - assert_eq!(compressed.len(), 33); - // decompress a key to the original - let decompressed = alg - .pubkey_bytes(&compressed, false) - .expect("decompressing public key should succeed"); - assert_eq!(decompressed.len(), 65); - assert_eq!(key, decompressed); - - // works consitesntly - let keys = (0..100) - .map(|_| { - let did = Secp256k1Keypair::create(&mut ThreadRng::default()).did(); - let (_, key) = parse_did_key(&did).expect("parsing did key should succeed"); - key - }) - .collect::>(); - let compressed = keys - .iter() - .filter_map(|key| alg.pubkey_bytes(key, true).ok()) - .collect::>(); - let decompressed = compressed - .iter() - .filter_map(|key| alg.pubkey_bytes(key, false).ok()) - .collect::>(); - assert_eq!(keys, decompressed); - } } diff --git a/atrium-crypto/src/did.rs b/atrium-crypto/src/did.rs index 7beaea4d..9635c600 100644 --- a/atrium-crypto/src/did.rs +++ b/atrium-crypto/src/did.rs @@ -1,11 +1,12 @@ -use super::error::{Error, Result}; -use super::{Algorithm, DID_KEY_PREFIX}; +use crate::encoding::{compress_pubkey, decompress_pubkey}; +use crate::error::{Error, Result}; +use crate::{Algorithm, DID_KEY_PREFIX}; pub fn parse_multikey(multikey: &str) -> Result<(Algorithm, Vec)> { let (_, decoded) = multibase::decode(multikey)?; if let Ok(prefix) = decoded[..2].try_into() { if let Some(alg) = Algorithm::from_prefix(prefix) { - return Ok((alg, alg.decompress_pubkey(&decoded[2..])?)); + return Ok((alg, decompress_pubkey(alg, &decoded[2..])?)); } } Err(Error::UnsupportedMultikeyType) @@ -19,13 +20,10 @@ pub fn parse_did_key(did: &str) -> Result<(Algorithm, Vec)> { } } -pub fn format_did_key_str(alg: Algorithm, s: &str) -> Result { - let (_, key) = multibase::decode(s)?; - format_did_key(alg, &key) -} - pub fn format_did_key(alg: Algorithm, key: &[u8]) -> Result { - Ok(prefix_did_key(&alg.format_multikey(key)?)) + Ok(prefix_did_key( + &alg.format_mulikey_compressed(&compress_pubkey(alg, key)?), + )) } pub(crate) fn prefix_did_key(multikey: &str) -> String { diff --git a/atrium-crypto/src/encoding.rs b/atrium-crypto/src/encoding.rs new file mode 100644 index 00000000..50a43c96 --- /dev/null +++ b/atrium-crypto/src/encoding.rs @@ -0,0 +1,100 @@ +use crate::{error::Result, Algorithm}; +use ecdsa::VerifyingKey; +use k256::Secp256k1; +use p256::NistP256; + +pub(crate) fn compress_pubkey(alg: Algorithm, key: &[u8]) -> Result> { + pubkey_bytes(alg, key, true) +} + +pub(crate) fn decompress_pubkey(alg: Algorithm, key: &[u8]) -> Result> { + pubkey_bytes(alg, key, false) +} + +fn pubkey_bytes(alg: Algorithm, key: &[u8], compress: bool) -> Result> { + Ok(match alg { + Algorithm::P256 => VerifyingKey::::from_sec1_bytes(key)? + .to_encoded_point(compress) + .as_bytes() + .to_vec(), + Algorithm::Secp256k1 => VerifyingKey::::from_sec1_bytes(key)? + .to_encoded_point(compress) + .as_bytes() + .to_vec(), + }) +} + +#[cfg(test)] +mod tests { + use super::{compress_pubkey, decompress_pubkey}; + use crate::did::parse_did_key; + use crate::keypair::{Did, P256Keypair, Secp256k1Keypair}; + use crate::Algorithm; + use rand::rngs::ThreadRng; + + #[test] + fn p256_compress_decompress() { + let did = P256Keypair::create(&mut ThreadRng::default()).did(); + let (alg, key) = parse_did_key(&did).expect("parsing did key should succeed"); + assert_eq!(alg, Algorithm::P256); + // compress a key to the correct length + let compressed = compress_pubkey(alg, &key).expect("compressing public key should succeed"); + assert_eq!(compressed.len(), 33); + // decompress a key to the original + let decompressed = + decompress_pubkey(alg, &compressed).expect("decompressing public key should succeed"); + assert_eq!(decompressed.len(), 65); + assert_eq!(key, decompressed); + + // works consitesntly + let keys = (0..100) + .map(|_| { + let did = P256Keypair::create(&mut ThreadRng::default()).did(); + let (_, key) = parse_did_key(&did).expect("parsing did key should succeed"); + key + }) + .collect::>(); + let compressed = keys + .iter() + .filter_map(|key| compress_pubkey(alg, &key).ok()) + .collect::>(); + let decompressed = compressed + .iter() + .filter_map(|key| decompress_pubkey(alg, &key).ok()) + .collect::>(); + assert_eq!(keys, decompressed); + } + + #[test] + fn secp256k1_compress_decompress() { + let did = Secp256k1Keypair::create(&mut ThreadRng::default()).did(); + let (alg, key) = parse_did_key(&did).expect("parsing did key should succeed"); + assert_eq!(alg, Algorithm::Secp256k1); + // compress a key to the correct length + let compressed = compress_pubkey(alg, &key).expect("compressing public key should succeed"); + assert_eq!(compressed.len(), 33); + // decompress a key to the original + let decompressed = + decompress_pubkey(alg, &compressed).expect("decompressing public key should succeed"); + assert_eq!(decompressed.len(), 65); + assert_eq!(key, decompressed); + + // works consitesntly + let keys = (0..100) + .map(|_| { + let did = Secp256k1Keypair::create(&mut ThreadRng::default()).did(); + let (_, key) = parse_did_key(&did).expect("parsing did key should succeed"); + key + }) + .collect::>(); + let compressed = keys + .iter() + .filter_map(|key| compress_pubkey(alg, key).ok()) + .collect::>(); + let decompressed = compressed + .iter() + .filter_map(|key| decompress_pubkey(alg, key).ok()) + .collect::>(); + assert_eq!(keys, decompressed); + } +} diff --git a/atrium-crypto/src/keypair.rs b/atrium-crypto/src/keypair.rs index 867e33fe..e5ca79fc 100644 --- a/atrium-crypto/src/keypair.rs +++ b/atrium-crypto/src/keypair.rs @@ -1,4 +1,6 @@ -use crate::{did::prefix_did_key, error::Result, Algorithm}; +use crate::did::prefix_did_key; +use crate::error::Result; +use crate::Algorithm; use ecdsa::elliptic_curve::{ generic_array::ArrayLength, ops::Invert, diff --git a/atrium-crypto/src/lib.rs b/atrium-crypto/src/lib.rs index 10da2f0a..ae973a3d 100644 --- a/atrium-crypto/src/lib.rs +++ b/atrium-crypto/src/lib.rs @@ -1,10 +1,12 @@ #![doc = include_str!("../README.md")] mod algorithm; pub mod did; +mod encoding; pub mod error; pub mod keypair; pub mod verify; pub use algorithm::Algorithm; +pub use multibase; const DID_KEY_PREFIX: &str = "did:key:"; diff --git a/atrium-crypto/src/verify.rs b/atrium-crypto/src/verify.rs index d31d4cd2..8f800438 100644 --- a/atrium-crypto/src/verify.rs +++ b/atrium-crypto/src/verify.rs @@ -1,8 +1,7 @@ -use crate::{ - did::parse_did_key, - error::{Error, Result}, - Algorithm, -}; +use crate::did::parse_did_key; +use crate::error::{Error, Result}; +use crate::Algorithm; +use ecdsa::der::{MaxOverhead, MaxSize}; use ecdsa::elliptic_curve::{ generic_array::ArrayLength, sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint}, @@ -12,6 +11,7 @@ use ecdsa::hazmat::{DigestPrimitive, VerifyPrimitive}; use ecdsa::{SignatureSize, VerifyingKey}; use k256::Secp256k1; use p256::NistP256; +use std::ops::Add; pub fn verify_signature(did_key: &str, msg: &[u8], signature: &[u8]) -> Result<()> { let (alg, public_key) = parse_did_key(did_key)?; @@ -23,8 +23,6 @@ pub struct Verifier { allow_malleable: bool, } -use ecdsa::der::{MaxOverhead, MaxSize}; -use std::ops::Add; impl Verifier { pub fn new(allow_malleable: bool) -> Self { Self { allow_malleable } @@ -47,7 +45,6 @@ impl Verifier { AffinePoint: VerifyPrimitive + FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, SignatureSize: ArrayLength, - MaxSize: ArrayLength, as Add>::Output: Add + ArrayLength, { @@ -160,7 +157,7 @@ mod tests { } #[test] - fn verify_high_s_signatures() { + fn verify_high_s() { let vectors = test_vectors(Some("high-s")); assert!(vectors.len() >= 2); let verifier = Verifier::new(true);