#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use crate::common::error::Result;
pub mod hash;
pub mod single;
pub mod sum;
pub mod test_vectors;
pub use hash::{Blake2b224, Blake2b256, Blake2b512, KesHashAlgorithm};
pub use single::{CompactSingleKes, CompactSingleSig, OptimizedKesSignature, SingleKes};
pub use sum::{
CompactSum0Kes, CompactSum1Kes, CompactSum2Kes, CompactSum3Kes, CompactSum4Kes, CompactSum5Kes,
CompactSum6Kes, CompactSum7Kes, CompactSumKes, Sum0Kes, Sum1Kes, Sum2Kes, Sum3Kes, Sum4Kes,
Sum5Kes, Sum6Kes, Sum7Kes, SumKes,
};
pub type Period = u64;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum KesError {
PeriodOutOfRange {
period: Period,
max_period: Period,
},
KeyExpired,
VerificationFailed,
InvalidSeedLength {
expected: usize,
actual: usize,
},
UpdateFailed,
}
impl core::fmt::Display for KesError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::PeriodOutOfRange { period, max_period } => {
write!(f, "Period {} out of range (max: {})", period, max_period)
}
Self::KeyExpired => write!(f, "KES key has expired"),
Self::VerificationFailed => write!(f, "KES signature verification failed"),
Self::InvalidSeedLength { expected, actual } => {
write!(
f,
"Invalid seed length: expected {} bytes, got {}",
expected, actual
)
}
Self::UpdateFailed => write!(f, "KES key update failed"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for KesError {}
pub trait KesAlgorithm {
type VerificationKey;
type SigningKey;
type Signature;
type Context;
const ALGORITHM_NAME: &'static str;
const SEED_SIZE: usize;
const VERIFICATION_KEY_SIZE: usize;
const SIGNING_KEY_SIZE: usize;
const SIGNATURE_SIZE: usize;
fn total_periods() -> Period;
fn gen_key_kes_from_seed_bytes(seed: &[u8]) -> Result<Self::SigningKey>;
fn derive_verification_key(signing_key: &Self::SigningKey) -> Result<Self::VerificationKey>;
fn sign_kes(
context: &Self::Context,
period: Period,
message: &[u8],
signing_key: &Self::SigningKey,
) -> Result<Self::Signature>;
fn verify_kes(
context: &Self::Context,
verification_key: &Self::VerificationKey,
period: Period,
message: &[u8],
signature: &Self::Signature,
) -> Result<()>;
fn update_kes(
context: &Self::Context,
signing_key: Self::SigningKey,
period: Period,
) -> Result<Option<Self::SigningKey>>;
#[cfg(feature = "alloc")]
fn raw_serialize_verification_key_kes(key: &Self::VerificationKey) -> Vec<u8>;
fn raw_deserialize_verification_key_kes(bytes: &[u8]) -> Option<Self::VerificationKey>;
#[cfg(feature = "alloc")]
fn raw_serialize_signature_kes(signature: &Self::Signature) -> Vec<u8>;
fn raw_deserialize_signature_kes(bytes: &[u8]) -> Option<Self::Signature>;
fn forget_signing_key_kes(signing_key: Self::SigningKey);
#[cfg(feature = "alloc")]
fn hash_verification_key<H: crate::hash::HashAlgorithm>(
key: &Self::VerificationKey,
) -> Vec<u8> {
let raw = Self::raw_serialize_verification_key_kes(key);
H::hash(&raw)
}
}
pub struct SignedKes<K: KesAlgorithm> {
pub signature: K::Signature,
}
impl<K: KesAlgorithm> core::fmt::Debug for SignedKes<K>
where
K::Signature: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SignedKes")
.field("signature", &self.signature)
.finish()
}
}
impl<K: KesAlgorithm> Clone for SignedKes<K>
where
K::Signature: Clone,
{
fn clone(&self) -> Self {
Self {
signature: self.signature.clone(),
}
}
}
impl<K: KesAlgorithm> SignedKes<K> {
pub fn sign(
context: &K::Context,
period: Period,
message: &[u8],
signing_key: &K::SigningKey,
) -> Result<Self> {
let signature = K::sign_kes(context, period, message, signing_key)?;
Ok(Self { signature })
}
pub fn verify(
&self,
context: &K::Context,
verification_key: &K::VerificationKey,
period: Period,
message: &[u8],
) -> Result<()> {
K::verify_kes(context, verification_key, period, message, &self.signature)
}
pub fn get_signature(&self) -> &K::Signature {
&self.signature
}
pub fn from_signature(signature: K::Signature) -> Self {
Self { signature }
}
}
pub struct SignKeyWithPeriodKes<K: KesAlgorithm> {
pub signing_key: K::SigningKey,
pub period: Period,
}
impl<K: KesAlgorithm> core::fmt::Debug for SignKeyWithPeriodKes<K> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SignKeyWithPeriodKes")
.field("signing_key", &"<redacted>")
.field("period", &self.period)
.finish()
}
}
impl<K: KesAlgorithm> SignKeyWithPeriodKes<K> {
pub fn new(signing_key: K::SigningKey, period: Period) -> Self {
Self {
signing_key,
period,
}
}
pub fn period(&self) -> Period {
self.period
}
pub fn signing_key(&self) -> &K::SigningKey {
&self.signing_key
}
pub fn update(self, context: &K::Context) -> Result<Option<Self>> {
let current = self.period;
match K::update_kes(context, self.signing_key, current)? {
Some(new_key) => Ok(Some(Self {
signing_key: new_key,
period: current + 1,
})),
None => Ok(None),
}
}
}
pub type KesSigningKey<K> = <K as KesAlgorithm>::SigningKey;
pub type KesVerificationKey<K> = <K as KesAlgorithm>::VerificationKey;
pub type KesSignature<K> = <K as KesAlgorithm>::Signature;
pub struct KesKeyPair<K: KesAlgorithm> {
pub signing_key_with_period: SignKeyWithPeriodKes<K>,
pub verification_key: K::VerificationKey,
}
impl<K: KesAlgorithm> core::fmt::Debug for KesKeyPair<K>
where
K::VerificationKey: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("KesKeyPair")
.field("signing_key", &"<redacted>")
.field("period", &self.signing_key_with_period.period)
.field("verification_key", &self.verification_key)
.finish()
}
}
impl<K: KesAlgorithm> KesKeyPair<K> {
pub fn generate(seed: &[u8]) -> Result<Self> {
let signing_key = K::gen_key_kes_from_seed_bytes(seed)?;
let verification_key = K::derive_verification_key(&signing_key)?;
Ok(Self {
signing_key_with_period: SignKeyWithPeriodKes::new(signing_key, 0),
verification_key,
})
}
pub fn period(&self) -> Period {
self.signing_key_with_period.period()
}
pub fn signing_key(&self) -> &K::SigningKey {
self.signing_key_with_period.signing_key()
}
pub fn update(self, context: &K::Context) -> Result<Option<Self>> {
match self.signing_key_with_period.update(context)? {
Some(new_sk) => Ok(Some(Self {
signing_key_with_period: new_sk,
verification_key: self.verification_key,
})),
None => Ok(None),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_period_type() {
let period: Period = 42;
assert_eq!(period, 42u64);
}
}