//! Helpers to use cryptographic data types in nettext pub use dryoc; use dryoc::types::Bytes; use dryoc::*; use crate::dec; use crate::enc; const BM_HASH: &str = "h.b2"; const BM_SIGNATURE: &str = "sig.ed25519"; const BM_SIGN_KEYPAIR: &str = "sk.ed25519"; const BM_SIGN_PUBKEY: &str = "pk.ed25519"; // ---- types ---- #[derive(Eq, PartialEq, Clone, Debug)] pub struct Hash(pub generichash::Hash); #[derive(Eq, PartialEq, Clone, Debug)] pub struct Signature(pub sign::Signature); #[derive(Eq, PartialEq, Clone, Debug)] pub struct SigningPublicKey(pub sign::PublicKey); #[derive(PartialEq, Clone, Debug)] pub struct SigningKeyPair(pub sign::SigningKeyPair); impl SigningKeyPair { /// Return the public key of this keypair pub fn public_key(&self) -> SigningPublicKey { SigningPublicKey(self.0.public_key.clone()) } } // ---- encoding ---- impl enc::Encode for Hash { fn term(&self) -> enc::Result<'_> { enc::marked_bytes(BM_HASH, self.0.as_slice()) } } impl enc::Encode for Signature { fn term(&self) -> enc::Result<'_> { enc::marked_bytes(BM_SIGNATURE, self.0.as_slice()) } } impl enc::Encode for SigningPublicKey { fn term(&self) -> enc::Result<'_> { enc::marked_bytes(BM_SIGN_PUBKEY, self.0.as_slice()) } } impl enc::Encode for SigningKeyPair { fn term(&self) -> enc::Result<'_> { enc::marked_bytes(BM_SIGN_KEYPAIR, self.0.secret_key.as_slice()) } } // ---- calculating hashes, signatures, etc ---- /// Compute the hash of a payload with default dryoc parameters and optionnal key pub fn compute_hash(bytes: &[u8], key: Option<&[u8; 32]>) -> Hash { Hash(generichash::GenericHash::hash_with_defaults(bytes, key).unwrap()) } /// Generate a new signing keypair pub fn gen_signing_keypair() -> SigningKeyPair { SigningKeyPair(sign::SigningKeyPair::gen_with_defaults()) } /// Compute the ed25519 signature of a message using a secret key pub fn compute_signature(message: &[u8], keypair: &SigningKeyPair) -> Signature { Signature( keypair .0 .sign_with_defaults(message) .unwrap() .into_parts() .0, ) } /// Verify the ed25519 signature of a message using a public key pub fn verify_signature( signature: &Signature, message: &[u8], public_key: &SigningPublicKey, ) -> bool { sign::SignedMessage::from_parts(signature.0.clone(), message.to_vec()) .verify(&public_key.0) .is_ok() } // ---- decode helpers ---- pub trait CryptoDec { /// Try to interpret this string as a Blake2b512 digest /// (32-bytes base64 encoded, prefixed by `h.b2:`) /// /// Example: /// /// ``` /// use nettext::dec::decode; /// use nettext::crypto::{compute_hash, CryptoDec}; /// /// let term = decode(b"{ /// message = hello; /// hash = h.b2:Mk3PAn3UowqTLEQfNlol6GsXPe-kuOWJSCU0cbgbcs8; /// }").unwrap(); /// let [msg, hash] = term.dict_of(["message", "hash"], false).unwrap(); /// let expected_hash = compute_hash(msg.raw(), None); /// assert_eq!(hash.hash().unwrap(), expected_hash); /// ``` fn hash(&self) -> Result; /// Try to interpret this string as an ed25519 signature /// (64 bytes base64 encoded, prefixed by `sig.ed25519:`) fn signature(&self) -> Result; /// Try to interpret this string as an ed25519 keypair /// (64 bytes base64 encoded, prefixed by `sk.ed25519:`) fn keypair(&self) -> Result; /// Try to interpret this string as an ed25519 public key /// (32 bytes base64 encoded, prefixed by `pk.ed25519:`) fn public_key(&self) -> Result; } impl<'a, 'b> CryptoDec for dec::Term<'a, 'b> { fn hash(&self) -> Result { Ok(Hash(generichash::Hash::from( self.marked_bytes_exact(BM_HASH)?, ))) } /// Try to interpret this string as an ed25519 signature (64 bytes base64 encoded) fn signature(&self) -> Result { Ok(Signature(sign::Signature::from( self.marked_bytes_exact(BM_SIGNATURE)?, ))) } fn keypair(&self) -> Result { let secret_key = sign::SecretKey::from(self.marked_bytes_exact(BM_SIGN_KEYPAIR)?); Ok(SigningKeyPair(sign::SigningKeyPair::from_secret_key( secret_key, ))) } fn public_key(&self) -> Result { Ok(SigningPublicKey(sign::PublicKey::from( self.marked_bytes_exact(BM_SIGN_PUBKEY)?, ))) } }