#![no_std]
extern crate alloc;
mod error;
pub mod hash;
pub mod trust_anchor;
pub use error::{IdentityError, Result};
pub use trust_anchor::{
Ed25519SingleSigner, Ed25519Verifier, FrostThresholdSigner, TrustAnchorSigner,
TrustAnchorVerifier,
};
use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
use serde::{Deserialize, Serialize};
use zeroize::ZeroizeOnDrop;
#[cfg(feature = "std")]
use {alloc::vec::Vec, secrecy::Secret};
use rand_core::{CryptoRng, RngCore};
#[derive(ZeroizeOnDrop)]
pub struct Identity {
keypair: SigningKey,
}
impl Identity {
pub fn generate<R>(csprng: &mut R) -> Result<Self>
where
R: RngCore + CryptoRng,
{
Ok(Self {
keypair: SigningKey::generate(csprng),
})
}
pub fn from_seed(seed: &[u8; 32]) -> Result<Self> {
let keypair = SigningKey::from_bytes(seed);
Ok(Self { keypair })
}
pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self> {
let keypair = SigningKey::from_bytes(bytes);
Ok(Self { keypair })
}
pub fn verifying_key(&self) -> VerifyingKey {
self.keypair.verifying_key()
}
pub fn public_key_hash(&self) -> [u8; 32] {
let bytes = self.keypair.verifying_key().to_bytes();
hash::hash(&bytes)
}
pub fn sign(&self, message: &[u8]) -> Signature {
self.keypair.sign(message)
}
#[cfg(feature = "std")]
pub fn signing_key_bytes(&self) -> Secret<Vec<u8>> {
Secret::new(self.keypair.to_bytes().to_vec())
}
}
pub fn verify_signature(
verifying_key: &VerifyingKey,
message: &[u8],
signature: &Signature,
) -> Result<()> {
verifying_key
.verify(message, signature)
.map_err(|_| IdentityError::InvalidSignature)
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct SerializableVerifyingKey([u8; 32]);
impl SerializableVerifyingKey {
pub fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
}
impl From<&VerifyingKey> for SerializableVerifyingKey {
fn from(vk: &VerifyingKey) -> Self {
Self(vk.to_bytes())
}
}
impl TryFrom<SerializableVerifyingKey> for VerifyingKey {
type Error = IdentityError;
fn try_from(svk: SerializableVerifyingKey) -> Result<Self> {
VerifyingKey::from_bytes(&svk.0).map_err(|_| IdentityError::InvalidPublicKey)
}
}
#[cfg(kani)]
mod kani_proofs {
#[kani::proof]
#[kani::unwind(0)]
fn proof_ed25519_pubkey_size() {
const ED25519_PUBKEY_LEN: usize = 32;
kani::assert(
ED25519_PUBKEY_LEN == 32,
"Ed25519 public key must be 32 bytes",
);
}
#[kani::proof]
#[kani::unwind(0)]
fn proof_ed25519_signature_size() {
const ED25519_SIG_LEN: usize = 64;
kani::assert(ED25519_SIG_LEN == 64, "Ed25519 signature must be 64 bytes");
}
#[kani::proof]
#[kani::unwind(0)]
fn proof_ed25519_seed_size() {
const ED25519_SEED_LEN: usize = 32;
kani::assert(ED25519_SEED_LEN == 32, "Ed25519 seed must be 32 bytes");
}
#[kani::proof]
#[kani::unwind(0)]
fn proof_blake3_hash_size() {
const BLAKE3_OUTPUT_LEN: usize = 32;
kani::assert(BLAKE3_OUTPUT_LEN == 32, "Blake3 hash must be 32 bytes");
}
}