Decode multibase value when parsing did:key

This commit is contained in:
silverpill 2022-11-10 00:11:52 +00:00
parent 1bfb951df8
commit efb51c1be6
3 changed files with 54 additions and 5 deletions

7
Cargo.lock generated
View file

@ -446,6 +446,12 @@ dependencies = [
"alloc-stdlib",
]
[[package]]
name = "bs58"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3"
[[package]]
name = "bumpalo"
version = "3.6.1"
@ -1681,6 +1687,7 @@ dependencies = [
"ammonia",
"anyhow",
"base64",
"bs58",
"chrono",
"clap",
"comrak",

View file

@ -21,6 +21,8 @@ ammonia = "3.2.0"
anyhow = "1.0.58"
# Used for working with RSA keys, HTTP signatures and file uploads
base64 = "0.13.0"
# Used to decode base58btc
bs58 = "0.4.0"
# Used for working with dates
chrono = { version = "0.4.22", features = ["serde"] }
# Used to build admin CLI tool

View file

@ -10,7 +10,45 @@ const DID_KEY_RE: &str = r"did:key:(?P<key>z[a-km-zA-HJ-NP-Z1-9]+)";
#[derive(Clone, Debug, PartialEq)]
pub struct DidKey {
pub key: String,
pub key: Vec<u8>,
}
#[derive(thiserror::Error, Debug)]
enum MultibaseError {
#[error("invalid base string")]
InvalidBaseString,
#[error("unknown base")]
UnknownBase,
#[error(transparent)]
DecodeError(#[from] bs58::decode::Error),
}
/// Decodes multibase base58 (bitcoin) value
/// https://github.com/multiformats/multibase
fn decode_multibase_base58btc(value: &str)
-> Result<Vec<u8>, MultibaseError>
{
let base = value.chars().next()
.ok_or(MultibaseError::InvalidBaseString)?;
// z == base58btc
// https://github.com/multiformats/multibase#multibase-table
if base.to_string() != "z" {
return Err(MultibaseError::UnknownBase);
};
let encoded_data = &value[base.len_utf8()..];
let data = bs58::decode(encoded_data)
.with_alphabet(bs58::Alphabet::BITCOIN)
.into_vec()?;
Ok(data)
}
fn encode_multibase_base58btc(value: &[u8]) -> String {
let result = bs58::encode(value)
.with_alphabet(bs58::Alphabet::BITCOIN)
.into_string();
format!("z{}", result)
}
impl FromStr for DidKey {
@ -19,16 +57,17 @@ impl FromStr for DidKey {
fn from_str(value: &str) -> Result<Self, Self::Err> {
let did_key_re = Regex::new(DID_KEY_RE).unwrap();
let caps = did_key_re.captures(value).ok_or(DidParseError)?;
let did_key = Self {
key: caps["key"].to_string(),
};
let key = decode_multibase_base58btc(&caps["key"])
.map_err(|_| DidParseError)?;
let did_key = Self { key };
Ok(did_key)
}
}
impl fmt::Display for DidKey {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let did_str = format!("did:key:{}", self.key);
let encoded_key = encode_multibase_base58btc(&self.key);
let did_str = format!("did:key:{}", encoded_key);
write!(formatter, "{}", did_str)
}
}
@ -41,6 +80,7 @@ mod tests {
fn test_did_key_string_conversion() {
let did_str = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK";
let did_key: DidKey = did_str.parse().unwrap();
assert_eq!(did_key.key.len(), 34); // Ed25519 public key
assert_eq!(did_key.to_string(), did_str);
}
}