core/src/identity: Implement Keypair::from_protobuf_encoding for ed25519 (#2090)

Implement `Keypair` decoding from Protobuf according to [peer id
specification]. For now support ed25519 keys only. Future commits might
add RSA secp256k1 and ecdsa.

[peer id specification]: https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#keys
This commit is contained in:
Max Inden 2021-06-07 10:17:46 +02:00 committed by GitHub
parent 3b0f5a4f96
commit a24e4221bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 0 deletions

View File

@ -40,6 +40,7 @@ ring = { version = "0.16.9", features = ["alloc", "std"], default-features = fal
[dev-dependencies]
async-std = { version = "1.6.2", features = ["attributes"] }
base64 = "0.13.0"
criterion = "0.3"
libp2p-mplex = { path = "../muxers/mplex" }
libp2p-noise = { path = "../transports/noise" }

View File

@ -115,6 +115,37 @@ impl Keypair {
Secp256k1(pair) => PublicKey::Secp256k1(pair.public().clone()),
}
}
/// Decode a private key from a protobuf structure and parse it as a [`Keypair`].
pub fn from_protobuf_encoding(bytes: &[u8]) -> Result<Keypair, DecodingError> {
use prost::Message;
let mut private_key = keys_proto::PrivateKey::decode(bytes)
.map_err(|e| DecodingError::new("Protobuf").source(e))
.map(zeroize::Zeroizing::new)?;
let key_type = keys_proto::KeyType::from_i32(private_key.r#type)
.ok_or_else(|| DecodingError::new(format!("unknown key type: {}", private_key.r#type)))?;
match key_type {
keys_proto::KeyType::Ed25519 => {
ed25519::Keypair::decode(&mut private_key.data).map(Keypair::Ed25519)
},
keys_proto::KeyType::Rsa => {
Err(DecodingError::new("Decoding RSA key from Protobuf is unsupported."))
},
keys_proto::KeyType::Secp256k1 => {
Err(DecodingError::new("Decoding Secp256k1 key from Protobuf is unsupported."))
},
}
}
}
impl zeroize::Zeroize for keys_proto::PrivateKey {
fn zeroize(&mut self) {
self.r#type.zeroize();
self.data.zeroize();
}
}
/// The public key of a node's identity keypair.
@ -219,3 +250,22 @@ impl PublicKey {
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn keypair_from_protobuf_encoding() {
// E.g. retrieved from an IPFS config file.
let base_64_encoded = "CAESQL6vdKQuznQosTrW7FWI9At+XX7EBf0BnZLhb6w+N+XSQSdfInl6c7U4NuxXJlhKcRBlBw9d0tj2dfBIVf6mcPA=";
let expected_peer_id = PeerId::from_str("12D3KooWEChVMMMzV8acJ53mJHrw1pQ27UAGkCxWXLJutbeUMvVu").unwrap();
let encoded = base64::decode(base_64_encoded).unwrap();
let keypair = Keypair::from_protobuf_encoding(&encoded).unwrap();
let peer_id = keypair.public().into_peer_id();
assert_eq!(expected_peer_id, peer_id);
}
}