geph5_broker_protocol/
signed.rs

1use std::marker::PhantomData;
2
3use ed25519_dalek::{Signature, Signer, SigningKey, VerifyingKey};
4
5use serde::{de::DeserializeOwned, Deserialize, Serialize};
6use serde_with::serde_as;
7use stdcode::StdcodeSerializeExt;
8use thiserror::Error;
9
10#[serde_as]
11#[derive(Serialize, Deserialize, Clone, Debug)]
12/// A signed value that internally uses stdcode, which only works with plain-old-data types that will never be extended.
13pub struct StdcodeSigned<T> {
14    pub inner: T,
15
16    pub signature: Signature,
17    pub pubkey: VerifyingKey,
18}
19
20impl<T: Serialize> StdcodeSigned<T> {
21    /// Creates a new Signed instance, which represents a piece of data signed by an ed25519 key.
22    pub fn new(inner: T, domain: &str, seckey: &SigningKey) -> Self {
23        let to_sign =
24            blake3::keyed_hash(blake3::hash(domain.as_bytes()).as_bytes(), &inner.stdcode());
25        let signature = seckey.sign(to_sign.as_bytes());
26        StdcodeSigned {
27            inner,
28            signature,
29            pubkey: seckey.verifying_key(),
30        }
31    }
32
33    /// Verifies the signed document, returning what's inside. This method handles checking that the included public key signs the included data, but the caller should pass in an argument that checks the validity of the public key itself.
34    pub fn verify(
35        self,
36        domain: &str,
37        is_valid_pk: impl FnOnce(&VerifyingKey) -> bool,
38    ) -> Result<T, VerifyError> {
39        if !is_valid_pk(&self.pubkey) {
40            return Err(VerifyError::InvalidPublicKey);
41        }
42        let to_sign = blake3::keyed_hash(
43            blake3::hash(domain.as_bytes()).as_bytes(),
44            &self.inner.stdcode(),
45        );
46        self.pubkey
47            .verify_strict(to_sign.as_bytes(), &self.signature)
48            .ok()
49            .ok_or(VerifyError::InvalidSignature)?;
50        Ok(self.inner)
51    }
52}
53
54#[serde_as]
55#[derive(Serialize, Deserialize, Clone, Debug)]
56/// A signed value that internally uses a fixed JSON string, allowing it to work with types that can grow over time.
57pub struct JsonSigned<T> {
58    inner_literal: String,
59
60    signature: Signature,
61    pubkey: VerifyingKey,
62
63    _phantom: PhantomData<T>,
64}
65
66impl<T: Serialize + DeserializeOwned> JsonSigned<T> {
67    /// Creates a new FlexiSigned instance, which represents a piece of data signed by an ed25519 key.
68    pub fn new(inner: T, domain: &str, seckey: &SigningKey) -> Self {
69        let inner_literal = serde_json::to_string(&inner).unwrap();
70        let to_sign = blake3::keyed_hash(
71            blake3::hash(domain.as_bytes()).as_bytes(),
72            inner_literal.as_bytes(),
73        );
74        let signature = seckey.sign(to_sign.as_bytes());
75        JsonSigned {
76            inner_literal,
77            signature,
78            pubkey: seckey.verifying_key(),
79
80            _phantom: PhantomData,
81        }
82    }
83
84    /// Gets the pubkey of this document.
85    pub fn pubkey(&self) -> VerifyingKey {
86        self.pubkey
87    }
88
89    /// Verifies the signed document, returning what's inside. This method handles checking that the included public key signs the included data, but the caller should pass in an argument that checks the validity of the public key itself.
90    pub fn verify(
91        self,
92        domain: &str,
93        is_valid_pk: impl FnOnce(&VerifyingKey) -> bool,
94    ) -> Result<T, VerifyError> {
95        if !is_valid_pk(&self.pubkey) {
96            return Err(VerifyError::InvalidPublicKey);
97        }
98        let to_sign = blake3::keyed_hash(
99            blake3::hash(domain.as_bytes()).as_bytes(),
100            self.inner_literal.as_bytes(),
101        );
102        self.pubkey
103            .verify_strict(to_sign.as_bytes(), &self.signature)
104            .ok()
105            .ok_or(VerifyError::InvalidSignature)?;
106        serde_json::from_str(&self.inner_literal).map_err(|_| VerifyError::CannotDeserialize)
107    }
108}
109
110#[derive(Error, Debug)]
111pub enum VerifyError {
112    #[error("Invalid public key")]
113    InvalidPublicKey,
114
115    #[error("Invalid signature")]
116    InvalidSignature,
117
118    #[error("Could not deserialize interior value")]
119    CannotDeserialize,
120}