use std::sync::atomic::{AtomicU64, Ordering};
use fastcrypto::{
bls12381, ed25519,
encoding::{self, Encoding},
error::FastCryptoError,
traits::{KeyPair as _, Signer as _, ToFromBytes, VerifyingKey},
};
use rand::SeedableRng;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct AuthorityPublicKey(bls12381::min_sig::BLS12381PublicKey);
impl AuthorityPublicKey {
pub const LENGTH: usize = bls12381::BLS_G2_LENGTH;
pub fn new(key: bls12381::min_sig::BLS12381PublicKey) -> Self {
Self(key)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
Ok(Self(bls12381::min_sig::BLS12381PublicKey::from_bytes(
bytes,
)?))
}
pub fn new_unique() -> Self {
static I: AtomicU64 = AtomicU64::new(1);
let seed = I.fetch_add(1, Ordering::Relaxed);
let mut rng = rand::rngs::StdRng::seed_from_u64(seed);
Self(
bls12381::min_sig::BLS12381KeyPair::generate(&mut rng)
.public()
.clone(),
)
}
pub fn inner(&self) -> &bls12381::min_sig::BLS12381PublicKey {
&self.0
}
pub const fn len() -> usize {
Self::LENGTH
}
pub fn to_bytes(&self) -> [u8; Self::LENGTH] {
let mut bytes = [0u8; Self::LENGTH];
bytes.copy_from_slice(self.0.as_bytes());
bytes
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct ProtocolPublicKey(ed25519::Ed25519PublicKey);
impl ProtocolPublicKey {
pub const LENGTH: usize = 32;
pub fn new(key: ed25519::Ed25519PublicKey) -> Self {
Self(key)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
Ok(Self(ed25519::Ed25519PublicKey::from_bytes(bytes)?))
}
pub fn verify(
&self,
message: &[u8],
signature: &ProtocolKeySignature,
) -> Result<(), FastCryptoError> {
self.0.verify(message, signature.inner())
}
pub fn to_bytes(&self) -> [u8; Self::LENGTH] {
self.0 .0.to_bytes()
}
}
#[derive(Serialize, Deserialize)]
pub struct ProtocolKeySignature(ed25519::Ed25519Signature);
impl ProtocolKeySignature {
pub const LENGTH: usize = 64;
pub fn from_inner(sig: ed25519::Ed25519Signature) -> Self {
Self(sig)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
Ok(Self(ed25519::Ed25519Signature::from_bytes(bytes)?))
}
pub fn to_bytes(&self) -> [u8; Self::LENGTH] {
let mut bytes = [0u8; Self::LENGTH];
bytes.copy_from_slice(self.0.as_bytes());
bytes
}
pub fn inner(&self) -> &ed25519::Ed25519Signature {
&self.0
}
}
pub type GenesisSignature = ProtocolKeySignature;
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct NetworkPublicKey(ed25519::Ed25519PublicKey);
impl NetworkPublicKey {
pub const LENGTH: usize = 32;
pub fn new(key: ed25519::Ed25519PublicKey) -> Self {
Self(key)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
Ok(Self(ed25519::Ed25519PublicKey::from_bytes(bytes)?))
}
pub fn into_inner(self) -> ed25519::Ed25519PublicKey {
self.0
}
pub fn to_bytes(&self) -> [u8; Self::LENGTH] {
self.0 .0.to_bytes()
}
pub fn verify(
&self,
message: &[u8],
signature: &GenesisSignature,
) -> Result<(), FastCryptoError> {
self.0.verify(message, signature.inner())
}
}
#[derive(Serialize, Deserialize)]
pub struct NetworkPrivateKey(ed25519::Ed25519PrivateKey);
impl NetworkPrivateKey {
pub fn into_inner(self) -> ed25519::Ed25519PrivateKey {
self.0
}
}
pub struct NetworkKeyPair(ed25519::Ed25519KeyPair);
impl NetworkKeyPair {
pub fn new(keypair: ed25519::Ed25519KeyPair) -> Self {
Self(keypair)
}
pub fn generate<R: rand::Rng + fastcrypto::traits::AllowedRng>(rng: &mut R) -> Self {
Self(ed25519::Ed25519KeyPair::generate(rng))
}
pub fn public(&self) -> NetworkPublicKey {
NetworkPublicKey::new(self.0.public().clone())
}
pub fn sign(&self, message: &[u8]) -> GenesisSignature {
GenesisSignature::from_inner(self.0.sign(message))
}
pub fn private_key(self) -> NetworkPrivateKey {
NetworkPrivateKey(self.0.copy().private())
}
pub fn private_key_bytes(self) -> [u8; 32] {
self.0.private().0.to_bytes()
}
pub fn to_base64(&self) -> String {
let secret_bytes = self.0.copy().private().0.to_bytes();
let mut key_bytes = Vec::new();
key_bytes.extend_from_slice(&secret_bytes);
encoding::Base64::encode(&key_bytes)
}
pub fn from_base64(encoded: &str) -> Result<Self, FastCryptoError> {
let key_bytes = encoding::Base64::decode(encoded)?;
let secret = ed25519::Ed25519PrivateKey::from_bytes(&key_bytes)?;
let keypair = ed25519::Ed25519KeyPair::from(secret);
Ok(NetworkKeyPair(keypair))
}
}
impl Clone for NetworkKeyPair {
fn clone(&self) -> Self {
Self(self.0.copy())
}
}
impl Serialize for NetworkKeyPair {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_base64())
}
}
impl<'de> Deserialize<'de> for NetworkKeyPair {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::Error;
let s = String::deserialize(deserializer)?;
NetworkKeyPair::from_base64(&s)
.map_err(|e| Error::custom(format!("Failed to deserialize NetworkKeyPair: {e}")))
}
}
pub struct ProtocolKeyPair(ed25519::Ed25519KeyPair);
impl ProtocolKeyPair {
pub fn new(keypair: ed25519::Ed25519KeyPair) -> Self {
Self(keypair)
}
pub fn generate<R: rand::Rng + fastcrypto::traits::AllowedRng>(rng: &mut R) -> Self {
Self(ed25519::Ed25519KeyPair::generate(rng))
}
pub fn public(&self) -> ProtocolPublicKey {
ProtocolPublicKey::new(self.0.public().clone())
}
pub fn sign(&self, message: &[u8]) -> ProtocolKeySignature {
ProtocolKeySignature::from_inner(self.0.sign(message))
}
pub fn to_base64(&self) -> String {
let secret_bytes = self.0.copy().private().0.to_bytes();
let mut key_bytes = Vec::new();
key_bytes.extend_from_slice(&secret_bytes);
encoding::Base64::encode(&key_bytes)
}
pub fn from_base64(encoded: &str) -> Result<Self, FastCryptoError> {
let key_bytes = encoding::Base64::decode(encoded)?;
let secret = ed25519::Ed25519PrivateKey::from_bytes(&key_bytes)?;
let keypair = ed25519::Ed25519KeyPair::from(secret);
Ok(ProtocolKeyPair(keypair))
}
}
impl Clone for ProtocolKeyPair {
fn clone(&self) -> Self {
Self(self.0.copy())
}
}
impl Serialize for ProtocolKeyPair {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_base64())
}
}
impl<'de> Deserialize<'de> for ProtocolKeyPair {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::Error;
let s = String::deserialize(deserializer)?;
ProtocolKeyPair::from_base64(&s)
.map_err(|e| Error::custom(format!("Failed to deserialize ProtocolKeyPair: {e}")))
}
}
#[cfg(test)]
mod tests {
use super::*;
const TEST_RNG_SEED_BASE: u64 = 42;
#[test]
fn test_authority_key_bytes_roundtrip() {
let mut rng = rand::rngs::StdRng::seed_from_u64(TEST_RNG_SEED_BASE);
let keypair = bls12381::min_sig::BLS12381KeyPair::generate(&mut rng);
let pubkey = AuthorityPublicKey::new(keypair.public().clone());
let bytes = pubkey.to_bytes();
let restored = AuthorityPublicKey::from_bytes(&bytes).expect("from_bytes should succeed");
assert_eq!(
pubkey.to_bytes(),
restored.to_bytes(),
"Bytes should be identical after roundtrip"
);
assert_eq!(pubkey, restored, "Keys should be equal after roundtrip");
}
#[test]
fn test_protocol_key_bytes_roundtrip() {
let mut rng = rand::rngs::StdRng::seed_from_u64(TEST_RNG_SEED_BASE + 1);
let keypair = ed25519::Ed25519KeyPair::generate(&mut rng);
let pubkey = ProtocolPublicKey::new(keypair.public().clone());
let bytes = pubkey.to_bytes();
let restored = ProtocolPublicKey::from_bytes(&bytes).expect("from_bytes should succeed");
assert_eq!(
pubkey.to_bytes(),
restored.to_bytes(),
"Bytes should be identical after roundtrip"
);
assert_eq!(pubkey, restored, "Keys should be equal after roundtrip");
}
#[test]
fn test_network_key_bytes_roundtrip() {
let mut rng = rand::rngs::StdRng::seed_from_u64(TEST_RNG_SEED_BASE + 2);
let keypair = ed25519::Ed25519KeyPair::generate(&mut rng);
let pubkey = NetworkPublicKey::new(keypair.public().clone());
let bytes = pubkey.to_bytes();
let restored = NetworkPublicKey::from_bytes(&bytes).expect("from_bytes should succeed");
assert_eq!(
pubkey.to_bytes(),
restored.to_bytes(),
"Bytes should be identical after roundtrip"
);
assert_eq!(pubkey, restored, "Keys should be equal after roundtrip");
}
#[test]
fn test_authority_key_invalid_bytes() {
let short_bytes = [0u8; 32];
assert!(AuthorityPublicKey::from_bytes(&short_bytes).is_err());
let invalid_bytes = [0u8; 96];
assert!(AuthorityPublicKey::from_bytes(&invalid_bytes).is_err());
}
#[test]
fn test_authority_key_new_unique() {
let key1 = AuthorityPublicKey::new_unique();
let key2 = AuthorityPublicKey::new_unique();
assert_ne!(key1, key2, "new_unique should generate different keys");
}
#[test]
fn test_authority_key_bytes_consistency() {
let key = AuthorityPublicKey::new_unique();
let bytes = key.to_bytes();
assert_eq!(bytes.len(), 96, "Authority key should be 96 bytes");
let restored = AuthorityPublicKey::from_bytes(&bytes).expect("from_bytes should succeed");
assert_eq!(key, restored, "Roundtrip should preserve key");
}
#[test]
fn test_protocol_key_bytes_consistency() {
let mut rng = rand::rngs::StdRng::seed_from_u64(TEST_RNG_SEED_BASE + 3);
let keypair = ed25519::Ed25519KeyPair::generate(&mut rng);
let key = ProtocolPublicKey::new(keypair.public().clone());
let bytes = key.to_bytes();
assert_eq!(bytes.len(), 32, "Protocol key should be 32 bytes");
}
#[test]
fn test_network_key_bytes_consistency() {
let mut rng = rand::rngs::StdRng::seed_from_u64(TEST_RNG_SEED_BASE + 4);
let keypair = ed25519::Ed25519KeyPair::generate(&mut rng);
let key = NetworkPublicKey::new(keypair.public().clone());
let bytes = key.to_bytes();
assert_eq!(bytes.len(), 32, "Network key should be 32 bytes");
}
#[test]
fn test_network_keypair_export_import() {
let mut rng = rand::thread_rng();
let keypair = NetworkKeyPair::generate(&mut rng);
let exported = keypair.to_base64();
let imported = NetworkKeyPair::from_base64(&exported).expect("Failed to import key pair");
assert_eq!(keypair.public().to_bytes(), imported.public().to_bytes());
assert_eq!(keypair.private_key_bytes(), imported.private_key_bytes());
}
#[test]
fn test_network_keypair_import_invalid_base64() {
let result = NetworkKeyPair::from_base64("invalid_base64_string");
assert!(result.is_err());
}
#[test]
fn test_protocol_keypair_export_import() {
let mut rng = rand::thread_rng();
let keypair = ProtocolKeyPair::generate(&mut rng);
let exported = keypair.to_base64();
let imported = ProtocolKeyPair::from_base64(&exported).expect("Failed to import key pair");
assert_eq!(keypair.public().to_bytes(), imported.public().to_bytes());
}
#[test]
fn test_protocol_keypair_sign_verify() {
let mut rng = rand::thread_rng();
let keypair = ProtocolKeyPair::generate(&mut rng);
let message = b"test message";
let signature = keypair.sign(message);
let result = keypair.public().verify(message, &signature);
assert!(result.is_ok(), "Signature verification should succeed");
let wrong_result = keypair.public().verify(b"wrong message", &signature);
assert!(
wrong_result.is_err(),
"Signature verification should fail with wrong message"
);
}
}