crypto/
thread_operation.rs1use heddle_object_model::{
7 error::HeddleError,
8 object::thread_replication::{
9 GENESIS_FORMAT, OPERATION_FORMAT, ThreadGenesis, ThreadOperation,
10 },
11};
12use serde::{Deserialize, Serialize};
13
14use crate::{Ed25519Signer, Signer, SignerError};
15
16#[derive(Debug, thiserror::Error)]
17pub enum Error {
18 #[error("Thread operation: {0}")]
19 Operation(#[from] HeddleError),
20 #[error("Thread signature: {0}")]
21 Signature(#[from] SignerError),
22 #[error("publisher differs from signing key")]
23 Publisher,
24}
25
26#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
27pub struct SignedOperation {
28 pub canonical: Vec<u8>,
29 pub signature: Vec<u8>,
30}
31
32impl SignedOperation {
33 pub fn sign(operation: &ThreadOperation, signer: &impl Signer) -> Result<Self, Error> {
34 if signer.public_key() != operation.publisher {
35 return Err(Error::Publisher);
36 }
37 let canonical = operation.encode()?;
38 let signature = signer.sign(&signing_bytes(OPERATION_FORMAT, &canonical))?;
39 Ok(Self {
40 canonical,
41 signature,
42 })
43 }
44
45 pub fn verify(&self) -> Result<ThreadOperation, Error> {
46 let operation = ThreadOperation::decode(&self.canonical)?;
47 Ed25519Signer::verify_with_public_key(
48 &signing_bytes(OPERATION_FORMAT, &self.canonical),
49 &operation.publisher,
50 &self.signature,
51 )?;
52 Ok(operation)
53 }
54}
55
56fn signing_bytes(format: &str, canonical: &[u8]) -> Vec<u8> {
57 let mut bytes = format.as_bytes().to_vec();
58 bytes.push(0);
59 bytes.extend_from_slice(canonical);
60 bytes
61}
62
63#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
66pub struct SignedGenesis {
67 pub canonical: Vec<u8>,
68 pub signature: Vec<u8>,
69}
70impl SignedGenesis {
71 pub fn sign(genesis: &ThreadGenesis, signer: &impl Signer) -> Result<Self, Error> {
72 if signer.public_key() != genesis.creator {
73 return Err(Error::Publisher);
74 }
75 let canonical = genesis.encode()?;
76 let signature = signer.sign(&signing_bytes(GENESIS_FORMAT, &canonical))?;
77 Ok(Self {
78 canonical,
79 signature,
80 })
81 }
82 pub fn verify(&self) -> Result<ThreadGenesis, Error> {
83 let genesis = ThreadGenesis::decode(&self.canonical)?;
84 Ed25519Signer::verify_with_public_key(
85 &signing_bytes(GENESIS_FORMAT, &self.canonical),
86 &genesis.creator,
87 &self.signature,
88 )?;
89 Ok(genesis)
90 }
91}