Skip to main content

fedimint_mint_common/
common.rs

1use std::fmt::Debug;
2
3use bitcoin_hashes::{Hash, sha256};
4use fedimint_core::encoding::{
5    Decodable, DecodeError, Encodable, decode_field_from_finite_reader,
6    decode_legacy_system_time_from_finite_reader, encode_legacy_system_time, with_decoding_context,
7};
8use fedimint_core::module::registry::ModuleDecoderRegistry;
9use fedimint_core::secp256k1;
10use secp256k1::{Keypair, Message, PublicKey, SECP256K1, Secp256k1, Signing, Verification};
11use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Serialize, Deserialize)]
14pub struct BackupRequest {
15    pub id: PublicKey,
16    #[serde(with = "fedimint_core::hex::serde")]
17    pub payload: Vec<u8>,
18    pub timestamp: std::time::SystemTime,
19}
20
21impl Encodable for BackupRequest {
22    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
23        self.id.consensus_encode(writer)?;
24        self.payload.consensus_encode(writer)?;
25        encode_legacy_system_time(&self.timestamp, writer)
26    }
27}
28
29impl Decodable for BackupRequest {
30    fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
31        decoder: &mut D,
32        modules: &ModuleDecoderRegistry,
33    ) -> Result<Self, DecodeError> {
34        Ok(Self {
35            id: decode_field_from_finite_reader(
36                decoder,
37                modules,
38                "Decoding named block field: BackupRequest{ ... id ... }",
39            )?,
40            payload: decode_field_from_finite_reader(
41                decoder,
42                modules,
43                "Decoding named block field: BackupRequest{ ... payload ... }",
44            )?,
45            timestamp: with_decoding_context(
46                decode_legacy_system_time_from_finite_reader(decoder, modules),
47                "Decoding named block field: BackupRequest{ ... timestamp ... }",
48            )?,
49        })
50    }
51}
52
53impl BackupRequest {
54    fn hash(&self) -> sha256::Hash {
55        self.consensus_hash()
56    }
57
58    pub fn sign(self, keypair: &Keypair) -> anyhow::Result<SignedBackupRequest> {
59        let signature =
60            SECP256K1.sign_schnorr(&Message::from_digest(*self.hash().as_ref()), keypair);
61
62        Ok(SignedBackupRequest {
63            request: self,
64            signature,
65        })
66    }
67}
68
69#[derive(Debug, Serialize, Deserialize)]
70pub struct SignedBackupRequest {
71    #[serde(flatten)]
72    request: BackupRequest,
73    #[serde(with = "::fedimint_core::encoding::as_hex")]
74    pub signature: fedimint_core::secp256k1::schnorr::Signature,
75}
76
77impl SignedBackupRequest {
78    pub fn verify_valid<C>(&self, ctx: &Secp256k1<C>) -> Result<&BackupRequest, secp256k1::Error>
79    where
80        C: Signing + Verification,
81    {
82        ctx.verify_schnorr(
83            &self.signature,
84            &Message::from_digest_slice(&self.request.hash().to_byte_array()).expect("Can't fail"),
85            &self.request.id.x_only_public_key().0,
86        )?;
87
88        Ok(&self.request)
89    }
90}