mithril_common/messages/
register_signature.rs

1use std::fmt::{Debug, Formatter};
2
3use anyhow::anyhow;
4use serde::{Deserialize, Serialize};
5
6use crate::{
7    StdResult,
8    crypto_helper::{ProtocolSingleSignature, TryFromBytes, TryToBytes},
9    entities::{HexEncodedSingleSignature, LotteryIndex, PartyId, SignedEntityType},
10};
11
12/// Message structure to register single signature through HTTP.
13#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
14pub struct RegisterSignatureMessageHttp {
15    /// Signed entity type
16    #[serde(rename = "entity_type")]
17    pub signed_entity_type: SignedEntityType,
18
19    /// The unique identifier of the signer
20    pub party_id: PartyId,
21
22    /// The single signature of the digest
23    pub signature: HexEncodedSingleSignature,
24
25    /// The indexes of the won lotteries that lead to the single signature
26    #[serde(rename = "indexes")]
27    pub won_indexes: Vec<LotteryIndex>,
28
29    /// Message that is signed by the signer
30    ///
31    /// Used to buffer the signature for later if the aggregator has yet to create an open message
32    /// for the signed entity type.
33    pub signed_message: String,
34}
35
36impl Debug for RegisterSignatureMessageHttp {
37    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
38        let is_pretty_printing = f.alternate();
39        let mut debug = f.debug_struct("RegisterSignatureMessageHttp");
40        debug
41            .field(
42                "signed_entity_type",
43                &format_args!("{:?}", self.signed_entity_type),
44            )
45            .field("party_id", &self.party_id)
46            .field("won_indexes", &format_args!("{:?}", self.won_indexes));
47
48        match is_pretty_printing {
49            true => debug.field("signature", &self.signature).finish(),
50            false => debug.finish_non_exhaustive(),
51        }
52    }
53}
54
55/// Message structure to register single signature through the DMQ network.
56#[derive(Clone, PartialEq, Eq)]
57pub struct RegisterSignatureMessageDmq {
58    /// Signed entity type
59    pub signed_entity_type: SignedEntityType,
60
61    /// The single signature.
62    pub signature: ProtocolSingleSignature,
63}
64
65impl RegisterSignatureMessageDmq {
66    /// Convert a `RegisterSignatureMessageDmq` into bytes
67    ///
68    /// # Layout
69    /// * Signed entity type length (u16)
70    /// * Signed entity type
71    /// * Protocol signature length (u32)
72    /// * Protocol signature
73    pub fn try_to_bytes_vec(&self) -> StdResult<Vec<u8>> {
74        let mut bytes = Vec::new();
75
76        let signed_entity_bytes = self.signed_entity_type.to_bytes_vec()?;
77        bytes.extend_from_slice(&(signed_entity_bytes.len() as u16).to_be_bytes());
78        bytes.extend_from_slice(&signed_entity_bytes);
79
80        let signature_bytes = self.signature.to_bytes_vec()?;
81        bytes.extend_from_slice(&(signature_bytes.len() as u32).to_be_bytes());
82        bytes.extend_from_slice(&signature_bytes);
83
84        Ok(bytes)
85    }
86
87    /// Extract a `RegisterSignatureMessageDmq` from bytes.
88    pub fn try_from_bytes_vec(bytes: &[u8]) -> StdResult<Self> {
89        const SIGNED_ENTITY_TYPE_LENGTH_BYTES_SIZE: usize = 2;
90        const SIGNATURE_LENGTH_BYTES_SIZE: usize = 4;
91        let mut bytes_index = 0;
92
93        let mut u16_bytes = [0u8; SIGNED_ENTITY_TYPE_LENGTH_BYTES_SIZE];
94        u16_bytes.copy_from_slice(
95            bytes
96                .get(bytes_index..bytes_index + SIGNED_ENTITY_TYPE_LENGTH_BYTES_SIZE)
97                .ok_or(anyhow!("Failed to read `Signed entity type length` bytes"))?,
98        );
99        let signed_entity_bytes_length = u16::from_be_bytes(u16_bytes) as usize;
100        bytes_index += SIGNED_ENTITY_TYPE_LENGTH_BYTES_SIZE;
101
102        let signed_entity_bytes = bytes
103            .get(bytes_index..bytes_index + signed_entity_bytes_length)
104            .ok_or(anyhow!("Failed to read `Signed entity type` bytes"))?;
105        let signed_entity_type = SignedEntityType::try_from_bytes(signed_entity_bytes)?;
106        bytes_index += signed_entity_bytes_length;
107
108        let mut u32_bytes = [0u8; SIGNATURE_LENGTH_BYTES_SIZE];
109        u32_bytes.copy_from_slice(
110            bytes
111                .get(bytes_index..bytes_index + SIGNATURE_LENGTH_BYTES_SIZE)
112                .ok_or(anyhow!("Failed to read `Signature length` bytes"))?,
113        );
114        let signature_bytes_length = u32::from_be_bytes(u32_bytes) as usize;
115        bytes_index += SIGNATURE_LENGTH_BYTES_SIZE;
116
117        let signature_bytes = bytes
118            .get(bytes_index..bytes_index + signature_bytes_length)
119            .ok_or(anyhow!("Failed to read `Signature` bytes"))?;
120        let signature = ProtocolSingleSignature::from_bytes(signature_bytes)?;
121
122        Ok(Self {
123            signed_entity_type,
124            signature,
125        })
126    }
127}
128
129impl Debug for RegisterSignatureMessageDmq {
130    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
131        let is_pretty_printing = f.alternate();
132        let mut debug = f.debug_struct("RegisterSignatureMessageDmq");
133        debug.field(
134            "signed_entity_type",
135            &format_args!("{:?}", self.signed_entity_type),
136        );
137
138        match is_pretty_printing {
139            true => debug.field("signature", &self.signature).finish(),
140            false => debug.finish_non_exhaustive(),
141        }
142    }
143}
144
145impl TryFromBytes for RegisterSignatureMessageDmq {
146    fn try_from_bytes(bytes: &[u8]) -> StdResult<Self> {
147        Self::try_from_bytes_vec(bytes)
148    }
149}
150
151impl TryToBytes for RegisterSignatureMessageDmq {
152    fn to_bytes_vec(&self) -> StdResult<Vec<u8>> {
153        self.try_to_bytes_vec()
154    }
155}
156
157#[cfg(test)]
158mod tests {
159    use super::*;
160
161    mod golden_http_message {
162        use crate::entities::{CardanoDbBeacon, Epoch};
163
164        use super::*;
165
166        const CURRENT_JSON: &str = r#"{
167        "entity_type": {
168            "CardanoImmutableFilesFull": {
169                "epoch": 10,
170                "immutable_file_number": 1728
171            }
172        },
173        "party_id": "party_id",
174        "signature": "7b227369676d61223a5b3133302c3137372c31352c3232392c32342c3235312c3234372c3137312c3139362c3231302c3134332c3131332c38362c3138392c39322c35362c3131322c33332c3139332c3231322c35342c3231342c32382c3231362c3232372c3137332c3130302c3132372c3137382c34302c39382c38372c32392c3138312c3235352c3131312c3135372c3232342c3233352c34362c3130302c3136392c3233322c3138392c3235322c38322c3133392c33365d2c22696e6465786573223a5b302c312c332c342c362c382c392c31302c31312c31322c31342c31382c32312c32322c32332c32352c32362c32372c33302c33332c33342c33382c34312c34332c35302c35382c35392c36302c36312c36322c36372c36392c37312c37332c37352c37362c37372c38312c38322c38332c38342c39302c39312c39322c39332c39372c39385d2c227369676e65725f696e646578223a327d",
175        "indexes": [1, 3],
176        "signed_message": "6a7e737c312972d2346b65ac3075696e04286d046dddaf8004121e3d5e27cc0d"
177    }"#;
178
179        fn golden_message_current() -> RegisterSignatureMessageHttp {
180            RegisterSignatureMessageHttp {
181            signed_entity_type: SignedEntityType::CardanoImmutableFilesFull(
182                CardanoDbBeacon::new(*Epoch(10), 1728),
183            ),
184            party_id: "party_id".to_string(),
185            signature: "7b227369676d61223a5b3133302c3137372c31352c3232392c32342c3235312c3234372c3137312c3139362c3231302c3134332c3131332c38362c3138392c39322c35362c3131322c33332c3139332c3231322c35342c3231342c32382c3231362c3232372c3137332c3130302c3132372c3137382c34302c39382c38372c32392c3138312c3235352c3131312c3135372c3232342c3233352c34362c3130302c3136392c3233322c3138392c3235322c38322c3133392c33365d2c22696e6465786573223a5b302c312c332c342c362c382c392c31302c31312c31322c31342c31382c32312c32322c32332c32352c32362c32372c33302c33332c33342c33382c34312c34332c35302c35382c35392c36302c36312c36322c36372c36392c37312c37332c37352c37362c37372c38312c38322c38332c38342c39302c39312c39322c39332c39372c39385d2c227369676e65725f696e646578223a327d".to_string(),
186            won_indexes: vec![1, 3],
187            signed_message: "6a7e737c312972d2346b65ac3075696e04286d046dddaf8004121e3d5e27cc0d".to_string(),
188        }
189        }
190
191        #[test]
192        fn test_current_json_deserialized_into_current_message() {
193            let json = CURRENT_JSON;
194            let message: RegisterSignatureMessageHttp = serde_json::from_str(json).unwrap();
195
196            assert_eq!(golden_message_current(), message);
197        }
198
199        #[test]
200        fn test_json_until_open_api_0_1_45_deserialized_into_current_message() {
201            let json = r#"{
202            "entity_type": {
203                "CardanoImmutableFilesFull": {
204                    "network": "testnet",
205                    "epoch": 10,
206                    "immutable_file_number": 1728
207                }
208            },
209            "party_id": "party_id",
210            "signature": "7b227369676d61223a5b3133302c3137372c31352c3232392c32342c3235312c3234372c3137312c3139362c3231302c3134332c3131332c38362c3138392c39322c35362c3131322c33332c3139332c3231322c35342c3231342c32382c3231362c3232372c3137332c3130302c3132372c3137382c34302c39382c38372c32392c3138312c3235352c3131312c3135372c3232342c3233352c34362c3130302c3136392c3233322c3138392c3235322c38322c3133392c33365d2c22696e6465786573223a5b302c312c332c342c362c382c392c31302c31312c31322c31342c31382c32312c32322c32332c32352c32362c32372c33302c33332c33342c33382c34312c34332c35302c35382c35392c36302c36312c36322c36372c36392c37312c37332c37352c37362c37372c38312c38322c38332c38342c39302c39312c39322c39332c39372c39385d2c227369676e65725f696e646578223a327d",
211            "indexes": [1, 3],
212            "signed_message": "6a7e737c312972d2346b65ac3075696e04286d046dddaf8004121e3d5e27cc0d"
213        }"#;
214            let message: RegisterSignatureMessageHttp = serde_json::from_str(json).unwrap();
215
216            assert_eq!(golden_message_current(), message);
217        }
218    }
219
220    mod golden_dmq_message {
221        use hex::FromHex;
222
223        use crate::entities::{CardanoDbBeacon, Epoch};
224
225        use super::*;
226
227        const CURRENT_BYTES_HEX: &str = r#"0005020afbc006000001b8000000000000002f0000000000000000000000000000000100000000000000030000000000000004000000000000000600000000000000080000000000000009000000000000000a000000000000000b000000000000000c000000000000000e00000000000000120000000000000015000000000000001600000000000000170000000000000019000000000000001a000000000000001b000000000000001e0000000000000021000000000000002200000000000000260000000000000029000000000000002b0000000000000032000000000000003a000000000000003b000000000000003c000000000000003d000000000000003e0000000000000043000000000000004500000000000000470000000000000049000000000000004b000000000000004c000000000000004d0000000000000051000000000000005200000000000000530000000000000054000000000000005a000000000000005b000000000000005c000000000000005d0000000000000061000000000000006282b10fe518fbf7abc4d28f7156bd5c387021c1d436d61cd8e3ad647fb22862571db5ff6f9de0eb2e64a9e8bdfc528b240000000000000002"#;
228
229        fn golden_message_current() -> RegisterSignatureMessageDmq {
230            RegisterSignatureMessageDmq {
231            signed_entity_type: SignedEntityType::CardanoImmutableFilesFull(
232                CardanoDbBeacon::new(*Epoch(10), 1728),
233            ),
234            signature: "7b227369676d61223a5b3133302c3137372c31352c3232392c32342c3235312c3234372c3137312c3139362c3231302c3134332c3131332c38362c3138392c39322c35362c3131322c33332c3139332c3231322c35342c3231342c32382c3231362c3232372c3137332c3130302c3132372c3137382c34302c39382c38372c32392c3138312c3235352c3131312c3135372c3232342c3233352c34362c3130302c3136392c3233322c3138392c3235322c38322c3133392c33365d2c22696e6465786573223a5b302c312c332c342c362c382c392c31302c31312c31322c31342c31382c32312c32322c32332c32352c32362c32372c33302c33332c33342c33382c34312c34332c35302c35382c35392c36302c36312c36322c36372c36392c37312c37332c37352c37362c37372c38312c38322c38332c38342c39302c39312c39322c39332c39372c39385d2c227369676e65725f696e646578223a327d".to_string().try_into().unwrap(),
235        }
236        }
237
238        #[test]
239        fn test_current_bytes_decoded_into_current_message() {
240            let message_from_bytes_hex = RegisterSignatureMessageDmq::try_from_bytes_vec(
241                &Vec::from_hex(CURRENT_BYTES_HEX).unwrap(),
242            )
243            .unwrap();
244
245            assert_eq!(golden_message_current(), message_from_bytes_hex);
246        }
247
248        #[test]
249        fn test_current_bijective_bytes_codec() {
250            let message_to_bytes = golden_message_current().try_to_bytes_vec().unwrap();
251            let message_from_bytes =
252                RegisterSignatureMessageDmq::try_from_bytes_vec(&message_to_bytes).unwrap();
253            let message_from_bytes_to_bytes = message_from_bytes.try_to_bytes_vec().unwrap();
254
255            assert_eq!(golden_message_current(), message_from_bytes);
256            assert_eq!(message_to_bytes, message_from_bytes_to_bytes);
257        }
258    }
259}