use crate::rand::{distributions::Standard, Rng, RngCore};
use crate::wallet::{Error, Result};
use bls::{serde_impl::SerdeSecret, PublicKey, SecretKey, PK_SIZE};
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
pub struct DerivationIndex(pub [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)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct UniquePubkey(PublicKey);
impl UniquePubkey {
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 public_key(&self) -> PublicKey {
self.0
}
pub fn to_hex(&self) -> String {
hex::encode(self.0.to_bytes())
}
pub fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self> {
let public_key = bls_public_from_hex(hex)?;
Ok(Self::new(public_key))
}
}
impl Serialize for UniquePubkey {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&self.to_hex())
}
}
impl<'de> Deserialize<'de> for UniquePubkey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(remote = "UniquePubkey")]
struct UniquePubkeyRep(PublicKey);
impl<'de> Deserialize<'de> for UniquePubkeyRep {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let key = <PublicKey>::deserialize(deserializer)?;
Ok(UniquePubkeyRep(key))
}
}
let deserialized = serde_json::Value::deserialize(deserializer)?;
if deserialized.is_string() {
let hex: String = serde::Deserialize::deserialize(deserialized).map_err(|e| {
serde::de::Error::custom(format!(
"Failed to deserialize UniquePubkey string representation: {e}",
))
})?;
UniquePubkey::from_hex(hex).map_err(|e| {
serde::de::Error::custom(format!(
"Failed to deserialize UniquePubkey from hex: {e}",
))
})
} else if deserialized.is_array() {
warn!("Detected old serialisation format for UniquePubkey, please update to the new format!");
let key: UniquePubkeyRep =
serde::Deserialize::deserialize(deserialized).map_err(|e| {
serde::de::Error::custom(format!(
"Failed to deserialize UniquePubkey array representation: {e}",
))
})?;
Ok(UniquePubkey(key.0))
} else {
Err(serde::de::Error::custom(
"Failed to deserialize UniquePubkey: unknown serialisation format",
))
}
}
}
impl std::fmt::Debug for UniquePubkey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl std::fmt::Display for UniquePubkey {
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 unique_pubkey(&self) -> UniquePubkey {
UniquePubkey(self.0.public_key())
}
pub(crate) 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 new_unique_pubkey(&self, index: &DerivationIndex) -> UniquePubkey {
UniquePubkey(self.0.derive_child(&index.0))
}
pub fn to_bytes(self) -> [u8; PK_SIZE] {
self.0.to_bytes()
}
pub fn public_key(&self) -> PublicKey {
self.0
}
pub fn to_hex(&self) -> String {
hex::encode(self.0.to_bytes())
}
pub fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self> {
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())
}
}
pub struct MainSecretKey(SerdeSecret<SecretKey>);
impl MainSecretKey {
pub fn new(secret_key: SecretKey) -> Self {
Self(SerdeSecret(secret_key))
}
pub fn secret_key(&self) -> &SecretKey {
&self.0
}
pub fn main_pubkey(&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(bls::SecretKey::random())
}
pub fn random_from_rng(rng: &mut impl RngCore) -> Self {
let sk: SecretKey = rng.sample(Standard);
Self::new(sk)
}
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<bls::PublicKey> {
let bytes = hex::decode(hex).map_err(|_| Error::FailedToDecodeHexToKey)?;
let bytes_fixed_len: [u8; bls::PK_SIZE] = bytes
.as_slice()
.try_into()
.map_err(|_| Error::FailedToParseBlsKey)?;
let pk = bls::PublicKey::from_bytes(bytes_fixed_len)?;
Ok(pk)
}
#[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.new_unique_pubkey(&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 = UniquePubkey::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_backwards_compatibility_deserialisation() -> eyre::Result<()> {
let pk = bls::SecretKey::random().public_key();
let main_pubkey = MainPubkey::new(pk);
let unique_pk =
main_pubkey.new_unique_pubkey(&DerivationIndex::random(&mut rand::thread_rng()));
let str_serialised = serde_json::to_string(&unique_pk)?;
println!("str_serialised: {str_serialised}");
let str_deserialised: UniquePubkey = serde_json::from_str(&str_serialised)?;
assert_eq!(str_deserialised, unique_pk);
let array_serialised = serde_json::to_string(&unique_pk.0)?;
println!("array_serialised: {array_serialised}");
let array_deserialised: UniquePubkey = serde_json::from_str(&array_serialised)?;
assert_eq!(array_deserialised, unique_pk);
Ok(())
}
}