use std::marker::PhantomData;
use ed25519_dalek::{Signature, Signer, SigningKey, VerifyingKey};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_with::serde_as;
use stdcode::StdcodeSerializeExt;
use thiserror::Error;
#[serde_as]
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct StdcodeSigned<T> {
pub inner: T,
pub signature: Signature,
pub pubkey: VerifyingKey,
}
impl<T: Serialize> StdcodeSigned<T> {
pub fn new(inner: T, domain: &str, seckey: &SigningKey) -> Self {
let to_sign =
blake3::keyed_hash(blake3::hash(domain.as_bytes()).as_bytes(), &inner.stdcode());
let signature = seckey.sign(to_sign.as_bytes());
StdcodeSigned {
inner,
signature,
pubkey: seckey.verifying_key(),
}
}
pub fn verify(
self,
domain: &str,
is_valid_pk: impl FnOnce(&VerifyingKey) -> bool,
) -> Result<T, VerifyError> {
if !is_valid_pk(&self.pubkey) {
return Err(VerifyError::InvalidPublicKey);
}
let to_sign = blake3::keyed_hash(
blake3::hash(domain.as_bytes()).as_bytes(),
&self.inner.stdcode(),
);
self.pubkey
.verify_strict(to_sign.as_bytes(), &self.signature)
.ok()
.ok_or(VerifyError::InvalidSignature)?;
Ok(self.inner)
}
}
#[serde_as]
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct JsonSigned<T> {
inner_literal: String,
signature: Signature,
pubkey: VerifyingKey,
_phantom: PhantomData<T>,
}
impl<T: Serialize + DeserializeOwned> JsonSigned<T> {
pub fn new(inner: T, domain: &str, seckey: &SigningKey) -> Self {
let inner_literal = serde_json::to_string(&inner).unwrap();
let to_sign = blake3::keyed_hash(
blake3::hash(domain.as_bytes()).as_bytes(),
inner_literal.as_bytes(),
);
let signature = seckey.sign(to_sign.as_bytes());
JsonSigned {
inner_literal,
signature,
pubkey: seckey.verifying_key(),
_phantom: PhantomData,
}
}
pub fn pubkey(&self) -> VerifyingKey {
self.pubkey
}
pub fn verify(
self,
domain: &str,
is_valid_pk: impl FnOnce(&VerifyingKey) -> bool,
) -> Result<T, VerifyError> {
if !is_valid_pk(&self.pubkey) {
return Err(VerifyError::InvalidPublicKey);
}
let to_sign = blake3::keyed_hash(
blake3::hash(domain.as_bytes()).as_bytes(),
self.inner_literal.as_bytes(),
);
self.pubkey
.verify_strict(to_sign.as_bytes(), &self.signature)
.ok()
.ok_or(VerifyError::InvalidSignature)?;
serde_json::from_str(&self.inner_literal).map_err(|_| VerifyError::CannotDeserialize)
}
}
#[derive(Error, Debug)]
pub enum VerifyError {
#[error("Invalid public key")]
InvalidPublicKey,
#[error("Invalid signature")]
InvalidSignature,
#[error("Could not deserialize interior value")]
CannotDeserialize,
}