ant_protocol/storage/
scratchpad.rs

1// Copyright 2024 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
4// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
5// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
6// KIND, either express or implied. Please review the Licences for the specific language governing
7// permissions and limitations relating to use of the SAFE Network Software.
8
9use super::ScratchpadAddress;
10use crate::Bytes;
11use crate::NetworkAddress;
12use crate::error::{Error, Result};
13use bls::{Ciphertext, PublicKey, SecretKey, Signature};
14use serde::{Deserialize, Serialize};
15use std::mem::size_of;
16
17use xor_name::XorName;
18
19/// Scratchpad, a mutable space for encrypted data on the Network
20#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
21pub struct Scratchpad {
22    /// Network address. Omitted when serialising and
23    /// calculated from the `encrypted_data` when deserialising.
24    address: ScratchpadAddress,
25    /// Data encoding: custom apps using scratchpad should use this so they can identify the type of data they are storing
26    data_encoding: u64,
27    /// Encrypted data stored in the scratchpad, it is encrypted automatically by the [`Scratchpad::new`] and [`Scratchpad::update`] methods
28    encrypted_data: Bytes,
29    /// Monotonically increasing counter to track the number of times this has been updated.
30    /// When pushed to the network, the scratchpad with the highest counter is kept.
31    counter: u64,
32    /// Signature over the above fields
33    signature: Signature,
34}
35
36impl std::fmt::Debug for Scratchpad {
37    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38        f.debug_struct("Scratchpad")
39            .field("address", &self.address)
40            .field("data_encoding", &self.data_encoding)
41            .field(
42                "encrypted_data",
43                &format!("({} bytes of encrypted data)", self.encrypted_data.len()),
44            )
45            .field("counter", &self.counter)
46            .field("signature", &hex::encode(self.signature.to_bytes()))
47            .finish()
48    }
49}
50
51impl Scratchpad {
52    /// Max Scratchpad size is 4MB including the metadata
53    pub const MAX_SIZE: usize = 4 * 1024 * 1024;
54
55    /// Creates a new instance of `Scratchpad`. Encrypts the data, and signs all the elements.
56    pub fn new(
57        owner: &SecretKey,
58        data_encoding: u64,
59        unencrypted_data: &Bytes,
60        counter: u64,
61    ) -> Self {
62        let pk = owner.public_key();
63        let encrypted_data = Bytes::from(pk.encrypt(unencrypted_data).to_bytes());
64        let addr = ScratchpadAddress::new(pk);
65        let signature = owner.sign(Self::bytes_for_signature(
66            addr,
67            data_encoding,
68            &encrypted_data,
69            counter,
70        ));
71        Self {
72            address: addr,
73            encrypted_data,
74            data_encoding,
75            counter,
76            signature,
77        }
78    }
79
80    /// Create a new Scratchpad without provding the secret key
81    /// It is the caller's responsibility to ensure the signature is valid (signs [`Scratchpad::bytes_for_signature`]) and the data is encrypted
82    /// It is recommended to use the [`Scratchpad::new`] method instead when possible
83    pub fn new_with_signature(
84        owner: PublicKey,
85        data_encoding: u64,
86        encrypted_data: Bytes,
87        counter: u64,
88        signature: Signature,
89    ) -> Self {
90        Self {
91            address: ScratchpadAddress::new(owner),
92            encrypted_data,
93            data_encoding,
94            counter,
95            signature,
96        }
97    }
98
99    /// Returns the bytes to sign for the signature
100    pub fn bytes_for_signature(
101        address: ScratchpadAddress,
102        data_encoding: u64,
103        encrypted_data: &Bytes,
104        counter: u64,
105    ) -> Vec<u8> {
106        let mut bytes_to_sign = data_encoding.to_be_bytes().to_vec();
107        bytes_to_sign.extend(address.to_hex().as_bytes());
108        bytes_to_sign.extend(counter.to_be_bytes().to_vec());
109        bytes_to_sign.extend(encrypted_data.to_vec());
110        bytes_to_sign
111    }
112
113    /// Get the counter of the Scratchpad, the higher the counter, the more recent the Scratchpad is
114    /// Similarly to counter CRDTs only the latest version (highest counter) of the Scratchpad is kept on the network
115    pub fn counter(&self) -> u64 {
116        self.counter
117    }
118
119    /// Return the current data encoding
120    pub fn data_encoding(&self) -> u64 {
121        self.data_encoding
122    }
123
124    /// Updates the content and encrypts it, increments the counter, re-signs the scratchpad
125    pub fn update(&mut self, unencrypted_data: &Bytes, sk: &SecretKey) {
126        self.counter += 1;
127        let pk = self.owner();
128        let address = ScratchpadAddress::new(*pk);
129        self.encrypted_data = Bytes::from(pk.encrypt(unencrypted_data).to_bytes());
130
131        let bytes_to_sign = Self::bytes_for_signature(
132            address,
133            self.data_encoding,
134            &self.encrypted_data,
135            self.counter,
136        );
137        self.signature = sk.sign(&bytes_to_sign);
138        debug_assert!(
139            self.verify_signature(),
140            "Must be valid after being signed. This is a bug, please report it by opening an issue on our github"
141        );
142    }
143
144    /// Verifies that the Scratchpad signature is valid
145    pub fn verify_signature(&self) -> bool {
146        let signing_bytes = Self::bytes_for_signature(
147            self.address,
148            self.data_encoding,
149            &self.encrypted_data,
150            self.counter,
151        );
152        self.owner().verify(&self.signature, &signing_bytes)
153    }
154
155    /// Returns the encrypted_data.
156    pub fn encrypted_data(&self) -> &Bytes {
157        &self.encrypted_data
158    }
159
160    /// Returns the encrypted_data, decrypted via the passed SecretKey
161    pub fn decrypt_data(&self, sk: &SecretKey) -> Result<Bytes> {
162        let cipher = Ciphertext::from_bytes(&self.encrypted_data)
163            .map_err(|_| Error::ScratchpadCipherTextFailed)?;
164        let bytes = sk
165            .decrypt(&cipher)
166            .ok_or(Error::ScratchpadCipherTextInvalid)?;
167        Ok(Bytes::from(bytes))
168    }
169
170    /// Returns the encrypted_data hash
171    pub fn encrypted_data_hash(&self) -> XorName {
172        XorName::from_content(&self.encrypted_data)
173    }
174
175    /// Returns the owner of the scratchpad
176    pub fn owner(&self) -> &PublicKey {
177        self.address.owner()
178    }
179
180    /// Returns the address of the scratchpad
181    pub fn address(&self) -> &ScratchpadAddress {
182        &self.address
183    }
184
185    /// Returns the NetworkAddress.
186    pub fn network_address(&self) -> NetworkAddress {
187        NetworkAddress::ScratchpadAddress(self.address)
188    }
189
190    /// Returns the xorname.
191    pub fn xorname(&self) -> XorName {
192        self.address.xorname()
193    }
194
195    /// Returns size of contained encrypted_data.
196    pub fn payload_size(&self) -> usize {
197        self.encrypted_data.len()
198    }
199
200    /// Size of the scratchpad
201    pub fn size(&self) -> usize {
202        size_of::<Scratchpad>() + self.payload_size()
203    }
204
205    /// Returns true if the scratchpad is too big
206    pub fn is_too_big(&self) -> bool {
207        self.size() > Self::MAX_SIZE
208    }
209
210    /// Returns the signature of the scratchpad
211    pub fn signature(&self) -> &Signature {
212        &self.signature
213    }
214
215    /// Returns the hash of the entire scratchpad (including all fields)
216    pub fn scratchpad_hash(&self) -> XorName {
217        let mut content = Vec::new();
218        content.extend(self.address.to_hex().as_bytes());
219        content.extend(self.data_encoding.to_be_bytes());
220        content.extend(&self.encrypted_data);
221        content.extend(self.counter.to_be_bytes());
222        content.extend(self.signature.to_bytes());
223        XorName::from_content(&content)
224    }
225}
226
227#[cfg(test)]
228mod tests {
229    use super::*;
230
231    #[test]
232    fn test_scratchpad_sig_and_update() {
233        let sk = SecretKey::random();
234        let raw_data = Bytes::from_static(b"data to be encrypted");
235        let mut scratchpad = Scratchpad::new(&sk, 42, &raw_data, 0);
236        assert!(scratchpad.verify_signature());
237        assert_eq!(scratchpad.counter(), 0);
238        assert_ne!(scratchpad.encrypted_data(), &raw_data);
239
240        let raw_data2 = Bytes::from_static(b"data to be encrypted v2");
241        scratchpad.update(&raw_data2, &sk);
242        assert!(scratchpad.verify_signature());
243        assert_eq!(scratchpad.counter(), 1);
244        assert_ne!(scratchpad.encrypted_data(), &raw_data);
245        assert_ne!(scratchpad.encrypted_data(), &raw_data2);
246    }
247
248    #[test]
249    fn test_scratchpad_encryption() {
250        let sk = SecretKey::random();
251        let raw_data = Bytes::from_static(b"data to be encrypted");
252        let scratchpad = Scratchpad::new(&sk, 42, &raw_data, 0);
253
254        let decrypted_data = scratchpad.decrypt_data(&sk).unwrap();
255        assert_eq!(decrypted_data, raw_data);
256    }
257
258    #[test]
259    fn test_bls_determinism() {
260        let secret_key = SecretKey::random();
261        let public_key = secret_key.public_key();
262        let message = b"test message";
263
264        let mut ciphertexts = Vec::new();
265        for _ in 0..5 {
266            let ciphertext = public_key.encrypt(message);
267            ciphertexts.push(ciphertext.to_bytes());
268        }
269        let encryption_deterministic = ciphertexts.iter().all(|c| c == &ciphertexts[0]);
270
271        let mut signatures = Vec::new();
272        for _ in 0..5 {
273            let signature = secret_key.sign(message);
274            signatures.push(signature.to_bytes());
275        }
276        let signature_deterministic = signatures.iter().all(|s| s == &signatures[0]);
277
278        assert!(
279            !encryption_deterministic,
280            "BLS encryption should be non-deterministic"
281        );
282        assert!(
283            signature_deterministic,
284            "BLS signatures should be deterministic"
285        );
286    }
287}