nettext/src/crypto/mod.rs

159 lines
4.6 KiB
Rust

//! 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<sign::PublicKey, sign::SecretKey>);
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<Hash, dec::TypeError>;
/// Try to interpret this string as an ed25519 signature
/// (64 bytes base64 encoded, prefixed by `sig.ed25519:`)
fn signature(&self) -> Result<Signature, dec::TypeError>;
/// Try to interpret this string as an ed25519 keypair
/// (64 bytes base64 encoded, prefixed by `sk.ed25519:`)
fn keypair(&self) -> Result<SigningKeyPair, dec::TypeError>;
/// Try to interpret this string as an ed25519 public key
/// (32 bytes base64 encoded, prefixed by `pk.ed25519:`)
fn public_key(&self) -> Result<SigningPublicKey, dec::TypeError>;
}
impl<'a, 'b> CryptoDec for dec::Term<'a, 'b> {
fn hash(&self) -> Result<Hash, dec::TypeError> {
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<Signature, dec::TypeError> {
Ok(Signature(sign::Signature::from(
self.marked_bytes_exact(BM_SIGNATURE)?,
)))
}
fn keypair(&self) -> Result<SigningKeyPair, dec::TypeError> {
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<SigningPublicKey, dec::TypeError> {
Ok(SigningPublicKey(sign::PublicKey::from(
self.marked_bytes_exact(BM_SIGN_PUBKEY)?,
)))
}
}