use sodiumoxide::randombytes::randombytes_into; use sodiumoxide::crypto::sign::{self,Seed,SEEDBYTES,PUBLICKEYBYTES}; use hex; use crate::Result; /// /// Keys for signing or verifying signatures. Small convenience /// wrapper around `sodiumoxide::crypto::sign`. /// /// #[derive(Clone)] pub struct PublicKey(sign::PublicKey); pub struct KeyPair(Seed); pub struct Signature(sign::Signature); impl PublicKey { pub fn from_hex(hex: &str) -> Result { let bytes = hex::decode(hex) .map_err(context!("error hex decoding public key"))?; if bytes.len() != PUBLICKEYBYTES { bail!("hex encoded public key has invalid length: {}", bytes.len()); } let pubkey = sign::PublicKey::from_slice(&bytes) .expect("PublicKey::from_slice() failed"); Ok(PublicKey(pubkey)) } pub fn to_hex(&self) -> String { hex::encode(&(self.0).0) } pub fn verify(&self, data: &[u8], signature: &[u8]) -> bool { let sig = sign::Signature::from_slice(signature) .expect("Signature::from_slice() failed"); sign::verify_detached(&sig, data, &self.0) } } impl KeyPair { /// Create a new pair of signing/verifying keys by generating a random seed /// The secret and public keys can be derived from the seed. pub fn generate() -> KeyPair { let mut seedbuf = [0; SEEDBYTES]; randombytes_into(&mut seedbuf); KeyPair(sign::Seed(seedbuf)) } pub fn from_hex(hex: &str) -> Result { let bytes = hex::decode(hex) .map_err(context!("Error hex decoding key pair"))?; KeyPair::from_bytes(&bytes) } pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != SEEDBYTES { bail!("hex encoded keypair has incorrect length"); } let seed = sign::Seed::from_slice(&bytes).expect("Seed::from_slice() failed"); Ok(KeyPair(seed)) } pub fn public_key(&self) -> PublicKey { let (pk,_) = sign::keypair_from_seed(&self.0); PublicKey(pk) } pub fn to_hex(&self) -> String { hex::encode(&(self.0).0) } pub fn sign(&self, data: &[u8]) -> Signature { let (_,sk) = sign::keypair_from_seed(&self.0); let signature = sign::sign_detached(data, &sk); Signature(signature) } pub fn verify(&self, data: &[u8], signature: &[u8]) -> bool { self.public_key().verify(data, signature) } } impl Signature { pub fn to_bytes(&self) -> &[u8] { &(self.0).0 } }