use bls::{PK_SIZE, PublicKey, SecretKey, serde_impl::SerdeSecret};
use rand::RngCore;
use serde::{Deserialize, Serialize};
use std::fmt;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum KeyDecodeError {
#[error("Failed to decode hex to key")]
FailedToDecodeHexToKey,
#[error("Failed to parse BLS key")]
FailedToParseBlsKey,
#[error("Invalid key length")]
InvalidKeyLength,
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
pub struct DerivationIndex([u8; 32]);
impl fmt::Debug for DerivationIndex {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(
formatter,
"{:02x}{:02x}{:02x}..",
self.0[0], self.0[1], self.0[2]
)
}
}
impl DerivationIndex {
pub fn random(rng: &mut impl RngCore) -> DerivationIndex {
let mut bytes = [0u8; 32];
rng.fill_bytes(&mut bytes);
DerivationIndex(bytes)
}
pub fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
pub fn into_bytes(self) -> [u8; 32] {
self.0
}
pub fn from_bytes(bytes: [u8; 32]) -> Self {
Self(bytes)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct DerivedPubkey(PublicKey);
impl DerivedPubkey {
pub fn new<G: Into<PublicKey>>(public_key: G) -> Self {
Self(public_key.into())
}
pub fn to_bytes(&self) -> [u8; bls::PK_SIZE] {
self.0.to_bytes()
}
pub fn verify<M: AsRef<[u8]>>(&self, sig: &bls::Signature, msg: M) -> bool {
self.0.verify(sig, msg)
}
pub fn to_hex(&self) -> String {
hex::encode(self.0.to_bytes())
}
pub fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, KeyDecodeError> {
let public_key = bls_public_from_hex(hex)?;
Ok(Self::new(public_key))
}
}
impl Serialize for DerivedPubkey {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&self.to_hex())
}
}
impl<'de> Deserialize<'de> for DerivedPubkey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let hex = String::deserialize(deserializer)?;
DerivedPubkey::from_hex(hex).map_err(|e| {
serde::de::Error::custom(format!("Failed to deserialize DerivedPubkey from hex: {e}",))
})
}
}
impl std::fmt::Debug for DerivedPubkey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl std::fmt::Display for DerivedPubkey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DerivedSecretKey(SerdeSecret<SecretKey>);
impl DerivedSecretKey {
pub fn new<S: Into<SecretKey>>(secret_key: S) -> Self {
Self(SerdeSecret(secret_key.into()))
}
pub fn public_key(&self) -> DerivedPubkey {
DerivedPubkey(self.0.public_key())
}
pub fn sign(&self, msg: &[u8]) -> bls::Signature {
self.0.sign(msg)
}
}
#[derive(Copy, PartialEq, Eq, Ord, PartialOrd, Clone, Serialize, Deserialize, Hash)]
pub struct MainPubkey(pub PublicKey);
impl MainPubkey {
pub fn new(public_key: PublicKey) -> Self {
Self(public_key)
}
pub fn verify(&self, sig: &bls::Signature, msg: &[u8]) -> bool {
self.0.verify(sig, msg)
}
pub fn derive_key(&self, index: &DerivationIndex) -> DerivedPubkey {
DerivedPubkey(self.0.derive_child(&index.0))
}
pub fn to_bytes(self) -> [u8; PK_SIZE] {
self.0.to_bytes()
}
pub fn to_hex(&self) -> String {
hex::encode(self.0.to_bytes())
}
pub fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, KeyDecodeError> {
let public_key = bls_public_from_hex(hex)?;
Ok(Self::new(public_key))
}
}
impl std::fmt::Debug for MainPubkey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MainSecretKey(SerdeSecret<SecretKey>);
impl MainSecretKey {
pub fn new(secret_key: SecretKey) -> Self {
Self(SerdeSecret(secret_key))
}
pub fn public_key(&self) -> MainPubkey {
MainPubkey(self.0.public_key())
}
pub fn sign(&self, msg: &[u8]) -> bls::Signature {
self.0.sign(msg)
}
pub fn derive_key(&self, index: &DerivationIndex) -> DerivedSecretKey {
DerivedSecretKey::new(self.0.inner().derive_child(&index.0))
}
pub fn to_bytes(&self) -> Vec<u8> {
self.0.to_bytes().to_vec()
}
pub fn random() -> Self {
Self::new(SecretKey::random())
}
pub fn random_derived_key(&self, rng: &mut impl RngCore) -> DerivedSecretKey {
self.derive_key(&DerivationIndex::random(rng))
}
}
fn bls_public_from_hex<T: AsRef<[u8]>>(hex: T) -> Result<PublicKey, KeyDecodeError> {
let bytes = hex::decode(hex).map_err(|_| KeyDecodeError::FailedToDecodeHexToKey)?;
let bytes_fixed_len: [u8; bls::PK_SIZE] = bytes
.as_slice()
.try_into()
.map_err(|_| KeyDecodeError::InvalidKeyLength)?;
let pk =
PublicKey::from_bytes(bytes_fixed_len).map_err(|_| KeyDecodeError::FailedToParseBlsKey)?;
Ok(pk)
}
impl From<MainSecretKey> for SecretKey {
fn from(main_secret_key: MainSecretKey) -> Self {
main_secret_key.0.inner().to_owned()
}
}
impl From<DerivedSecretKey> for SecretKey {
fn from(derived_secret_key: DerivedSecretKey) -> Self {
derived_secret_key.0.inner().to_owned()
}
}
impl From<DerivedPubkey> for PublicKey {
fn from(derived_pubkey: DerivedPubkey) -> Self {
derived_pubkey.0
}
}
impl From<MainPubkey> for PublicKey {
fn from(main_pubkey: MainPubkey) -> Self {
main_pubkey.0
}
}
impl From<SecretKey> for MainSecretKey {
fn from(secret_key: SecretKey) -> Self {
MainSecretKey::new(secret_key)
}
}
impl From<SecretKey> for DerivedSecretKey {
fn from(secret_key: SecretKey) -> Self {
DerivedSecretKey::new(secret_key)
}
}
impl From<PublicKey> for MainPubkey {
fn from(public_key: PublicKey) -> Self {
MainPubkey::new(public_key)
}
}
impl From<PublicKey> for DerivedPubkey {
fn from(public_key: PublicKey) -> Self {
DerivedPubkey::new(public_key)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pubkeys_hex_conversion() -> eyre::Result<()> {
let sk = bls::SecretKey::random();
let pk = sk.public_key();
let main_pubkey = MainPubkey::new(pk);
let unique_pubkey =
main_pubkey.derive_key(&DerivationIndex::random(&mut rand::thread_rng()));
let main_pubkey_hex = main_pubkey.to_hex();
let unique_pubkey_hex = unique_pubkey.to_hex();
let main_pubkey_from_hex = MainPubkey::from_hex(main_pubkey_hex)?;
let unique_pubkey_from_hex = DerivedPubkey::from_hex(unique_pubkey_hex)?;
assert_eq!(main_pubkey, main_pubkey_from_hex);
assert_eq!(unique_pubkey, unique_pubkey_from_hex);
Ok(())
}
#[test]
fn test_serialisation() -> eyre::Result<()> {
let pk = SecretKey::random().public_key();
let main_pubkey = MainPubkey::new(pk);
let unique_pk = main_pubkey.derive_key(&DerivationIndex::random(&mut rand::thread_rng()));
let str_serialised = rmp_serde::to_vec_named(&unique_pk)?;
let str_deserialised: DerivedPubkey = rmp_serde::from_slice(&str_serialised)?;
assert_eq!(str_deserialised, unique_pk);
Ok(())
}
#[test]
fn verification_using_child_key() -> eyre::Result<()> {
let msg = "just a test string".as_bytes();
let main_sk = MainSecretKey::random();
let derived_sk = main_sk.random_derived_key(&mut rand::thread_rng());
let signature = main_sk.sign(msg);
assert!(main_sk.public_key().verify(&signature, msg));
assert!(!derived_sk.public_key().verify(&signature, msg));
let signature = derived_sk.sign(msg);
assert!(derived_sk.public_key().verify(&signature, msg));
assert!(!main_sk.public_key().verify(&signature, msg));
Ok(())
}
}