pub const DJB_KEY_PREFIX: u8 = 0x05;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PublicKey([u8; 33]);
impl PublicKey {
pub fn new(bytes: [u8; 33]) -> Self {
Self(bytes)
}
pub fn as_crypto_bytes(&self) -> &[u8; 32] {
self.0[1..].try_into().expect("PublicKey must be 33 bytes")
}
pub fn as_bytes(&self) -> &[u8; 33] {
&self.0
}
pub fn try_from_bytes(bytes: &[u8]) -> std::result::Result<Self, String> {
if bytes.len() != 33 {
return Err(format!("Invalid key length: {} (expected 33 bytes with 0x05 prefix)", bytes.len()));
}
if bytes[0] != DJB_KEY_PREFIX {
return Err(format!("Invalid key prefix (expected 0x{:02x})", DJB_KEY_PREFIX));
}
let mut arr = [0u8; 33];
arr.copy_from_slice(bytes);
Ok(PublicKey(arr))
}
}
impl TryFrom<&[u8]> for PublicKey {
type Error = String;
fn try_from(bytes: &[u8]) -> std::result::Result<Self, Self::Error> {
PublicKey::try_from_bytes(bytes)
}
}
impl TryFrom<Vec<u8>> for PublicKey {
type Error = String;
fn try_from(bytes: Vec<u8>) -> std::result::Result<Self, Self::Error> {
PublicKey::try_from_bytes(&bytes)
}
}
impl From<PublicKey> for Vec<u8> {
fn from(key: PublicKey) -> Self {
key.0.to_vec()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Signature([u8; 64]);
impl Signature {
pub fn new(bytes: [u8; 64]) -> Self {
Self(bytes)
}
pub fn as_bytes(&self) -> &[u8; 64] {
&self.0
}
}
impl TryFrom<&[u8]> for Signature {
type Error = String;
fn try_from(bytes: &[u8]) -> std::result::Result<Self, Self::Error> {
if bytes.len() == 64 {
let mut arr = [0u8; 64];
arr.copy_from_slice(bytes);
Ok(Signature(arr))
} else {
Err(format!("Invalid signature length: {} (expected 64)", bytes.len()))
}
}
}
impl TryFrom<Vec<u8>> for Signature {
type Error = String;
fn try_from(bytes: Vec<u8>) -> std::result::Result<Self, Self::Error> {
Signature::try_from(bytes.as_slice())
}
}
impl From<Signature> for Vec<u8> {
fn from(sig: Signature) -> Self {
sig.0.to_vec()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_as_crypto_bytes() {
let mut bytes = [2u8; 33];
bytes[0] = DJB_KEY_PREFIX;
let inner = [3u8; 32];
bytes[1..].copy_from_slice(&inner);
let key = PublicKey::try_from_bytes(&bytes).unwrap();
assert_eq!(key.as_crypto_bytes(), &inner);
}
}