use crate::{AdultDuties, Duty, ElderDuties, PublicKey, Result, Signature, SignatureShare};
use ed25519_dalek::PublicKey as Ed25519PublicKey;
use ed25519_dalek::Signature as Ed25519Signature;
use hex_fmt::HexFmt;
use serde::{Deserialize, Serialize};
use signature::Verifier;
use std::{
fmt::{self, Debug, Display, Formatter},
hash::Hash,
};
use threshold_crypto::{
PublicKey as BlsPublicKey, PublicKeySet as BlsPublicKeySet,
PublicKeyShare as BlsPublicKeyShare, Signature as BlsSignature,
SignatureShare as BlsSignatureShare,
};
pub use xor_name::Prefix;
use xor_name::{XorName, XOR_NAME_LEN};
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct MsgSender {
entity: Entity,
sig: Option<EntitySignature>,
}
#[derive(Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct TransientSectionKey {
pub bls_key: BlsPublicKey,
}
impl Debug for TransientSectionKey {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "TransientSectionKey::")?;
write!(
formatter,
"Bls({:<8})",
HexFmt(&self.bls_key.to_bytes()[..XOR_NAME_LEN])
)
}
}
impl Display for TransientSectionKey {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
Debug::fmt(self, formatter)
}
}
#[derive(Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct TransientElderKey {
pub node_id: Ed25519PublicKey,
pub bls_key: BlsPublicKeyShare,
pub bls_share_index: usize,
pub bls_public_key_set: BlsPublicKeySet,
}
impl Debug for TransientElderKey {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "TransientElderKey::")?;
write!(
formatter,
"Ed25519({:<8})",
HexFmt(&self.node_id.to_bytes())
)?;
write!(
formatter,
"BlsShare({:<8})",
HexFmt(&self.bls_key.to_bytes()[..XOR_NAME_LEN])
)
}
}
impl Display for TransientElderKey {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
Debug::fmt(self, formatter)
}
}
#[derive(Eq, PartialEq, Clone, Serialize, Deserialize)]
pub enum Entity {
Client(PublicKey),
AnyNode(Ed25519PublicKey, Duty),
AdultNode(Ed25519PublicKey, AdultDuties),
ElderNode(TransientElderKey, ElderDuties),
Section(TransientSectionKey, ElderDuties),
}
impl Debug for Entity {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "Entity::")?;
match self {
Self::Client(key) => Debug::fmt(key, formatter),
Self::AnyNode(key, duty) => {
write!(formatter, "Ed25519({:<8})", HexFmt(&key.to_bytes()))?;
write!(formatter, "AnyNode({:?})", duty)
}
Self::AdultNode(key, duty) => {
write!(formatter, "Ed25519({:<8})", HexFmt(&key.to_bytes()))?;
write!(formatter, "AdultNode({:?})", duty)
}
Self::ElderNode(key, duty) => {
Debug::fmt(key, formatter)?;
write!(formatter, "ElderNode({:?})", duty)
}
Self::Section(key, duty) => {
Debug::fmt(key, formatter)?;
write!(formatter, "Section({:?})", duty)
}
}
}
}
impl Display for Entity {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
Debug::fmt(self, formatter)
}
}
pub enum EntityId {
Client(PublicKey),
Node(Ed25519PublicKey),
Section(BlsPublicKey),
}
impl Debug for EntityId {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "EntityId::")?;
match self {
Self::Client(pub_key) => Debug::fmt(pub_key, formatter),
Self::Node(pub_key) => write!(formatter, "Ed25519({:<8})", HexFmt(&pub_key.to_bytes())),
Self::Section(pub_key) => write!(
formatter,
"Bls({:<8})",
HexFmt(&pub_key.to_bytes()[..XOR_NAME_LEN])
),
}
}
}
impl Display for EntityId {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
Debug::fmt(self, formatter)
}
}
#[derive(Eq, PartialEq, Clone, Serialize, Deserialize)]
pub enum EntitySignature {
Client(Signature),
Node(Ed25519Signature),
Elder(BlsSignatureShare),
Section(BlsSignature),
}
impl Debug for EntitySignature {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "EntitySignature::")?;
match self {
Self::Client(sig) => {
write!(formatter, "Client::")?;
Debug::fmt(sig, formatter)
}
Self::Node(_) => {
write!(formatter, "Node::")?;
write!(formatter, "Ed25519(..)")
}
Self::Elder(_) => {
write!(formatter, "Elder::")?;
write!(formatter, "BlsShare(..)")
}
Self::Section(_) => {
write!(formatter, "Section::")?;
write!(formatter, "Bls(..)")
}
}
}
}
impl Display for EntitySignature {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
Debug::fmt(self, formatter)
}
}
#[derive(Debug, Hash, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub enum Address {
Client(XorName),
Node(XorName),
Section(XorName),
}
impl Address {
pub fn xorname(&self) -> XorName {
use Address::*;
match self {
Client(xorname) | Node(xorname) | Section(xorname) => *xorname,
}
}
}
impl EntityId {
pub fn public_key(&self) -> PublicKey {
match self {
Self::Client(key) => *key,
Self::Node(key) => PublicKey::Ed25519(*key),
Self::Section(key) => PublicKey::Bls(*key),
}
}
}
impl MsgSender {
pub fn client(key: PublicKey, sig: Signature) -> Result<Self> {
Ok(Self {
entity: Entity::Client(key),
sig: Some(EntitySignature::Client(sig)),
})
}
pub fn any_node(key: Ed25519PublicKey, duty: Duty, sig: Ed25519Signature) -> Result<Self> {
Ok(Self {
entity: Entity::AnyNode(key, duty),
sig: Some(EntitySignature::Node(sig)),
})
}
pub fn adult(key: Ed25519PublicKey, duty: AdultDuties, sig: Ed25519Signature) -> Result<Self> {
Ok(Self {
entity: Entity::AdultNode(key, duty),
sig: Some(EntitySignature::Node(sig)),
})
}
pub fn elder(
key: TransientElderKey,
duty: ElderDuties,
sig: BlsSignatureShare,
) -> Result<Self> {
Ok(Self {
entity: Entity::ElderNode(key, duty),
sig: Some(EntitySignature::Elder(sig)),
})
}
pub fn section(key: TransientSectionKey, duty: ElderDuties) -> Result<Self> {
Ok(Self {
entity: Entity::Section(key, duty),
sig: None,
})
}
pub fn id(&self) -> EntityId {
self.entity.id()
}
pub fn address(&self) -> Address {
self.entity.address()
}
pub fn duty(&self) -> Option<Duty> {
use Entity::*;
match self.entity {
Client(_) => None,
AnyNode(_, duty) => Some(duty),
AdultNode(_, duty) => Some(Duty::Adult(duty)),
ElderNode(_, duty) | Section(_, duty) => Some(Duty::Elder(duty)),
}
}
pub fn verify(&self, payload: &[u8]) -> bool {
self.entity.try_verify(self.sig.clone(), payload)
}
pub fn group_key_set(&self) -> Option<BlsPublicKeySet> {
if let Entity::ElderNode(key, _) = &self.entity {
Some(key.bls_public_key_set.clone())
} else {
None
}
}
pub fn group_sig_share(&self) -> Option<SignatureShare> {
if let Entity::ElderNode(key, _) = &self.entity {
if let Some(EntitySignature::Elder(sig)) = &self.sig {
return Some(SignatureShare {
index: key.bls_share_index,
share: sig.clone(),
});
} else {
unreachable!("Should not be possible to instantiate such a combination.")
}
}
None
}
pub fn is_client(&self) -> bool {
matches!(self.entity, Entity::Client(_))
}
pub fn is_any_node(&self) -> bool {
matches!(self.entity, Entity::AnyNode { .. })
}
pub fn is_adult(&self) -> bool {
matches!(self.entity, Entity::AdultNode { .. })
}
pub fn is_elder(&self) -> bool {
matches!(self.entity, Entity::ElderNode { .. })
}
pub fn is_section(&self) -> bool {
matches!(self.entity, Entity::Section { .. })
}
}
impl Entity {
pub fn id(&self) -> EntityId {
use Entity::*;
match self {
Client(key) => EntityId::Client(*key),
AnyNode(node_id, ..) | AdultNode(node_id, ..) => EntityId::Node(*node_id),
ElderNode(key, ..) => EntityId::Node(key.node_id),
Section(key, ..) => EntityId::Section(key.bls_key),
}
}
pub fn address(&self) -> Address {
use Entity::*;
match self {
Client(key) => Address::Client((*key).into()),
AnyNode(key, ..) | AdultNode(key, ..) => Address::Node(PublicKey::Ed25519(*key).into()),
ElderNode(key, ..) => Address::Node(PublicKey::Ed25519(key.node_id).into()),
Section(key, ..) => Address::Section(PublicKey::Bls(key.bls_key).into()),
}
}
pub fn try_verify(&self, sig: Option<EntitySignature>, data: &[u8]) -> bool {
use Entity::*;
match self {
Client(key) => {
if let Some(EntitySignature::Client(sig)) = sig {
key.verify(&sig, data).is_ok()
} else {
false
}
}
AnyNode(key, ..) | AdultNode(key, ..) => {
if let Some(EntitySignature::Node(sig)) = sig {
key.verify(data, &sig).is_ok()
} else {
false
}
}
ElderNode(key, ..) => {
if let Some(EntitySignature::Elder(sig)) = sig {
key.bls_key.verify(&sig, data)
} else if let Some(EntitySignature::Node(sig)) = sig {
key.node_id.verify(data, &sig).is_ok()
} else {
false
}
}
Section(..) => true,
}
}
}