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::error::{Error, Result};
11use crate::Bytes;
12use crate::NetworkAddress;
13use bls::{Ciphertext, PublicKey, SecretKey, Signature};
14use serde::{Deserialize, Serialize};
15
16use xor_name::XorName;
17
18/// Scratchpad, a mutable space for encrypted data on the Network
19#[derive(
20    Hash, Eq, PartialEq, PartialOrd, Ord, Clone, custom_debug::Debug, Serialize, Deserialize,
21)]
22pub struct Scratchpad {
23    /// Network address. Omitted when serialising and
24    /// calculated from the `encrypted_data` when deserialising.
25    address: ScratchpadAddress,
26    /// Data encoding: custom apps using scratchpad should use this so they can identify the type of data they are storing
27    data_encoding: u64,
28    /// Encrypted data stored in the scratchpad, it is encrypted automatically by the [`Scratchpad::new`] and [`Scratchpad::update`] methods
29    #[debug(skip)]
30    encrypted_data: Bytes,
31    /// Monotonically increasing counter to track the number of times this has been updated.
32    /// When pushed to the network, the scratchpad with the highest counter is kept.
33    counter: u64,
34    /// Signature over the above fields
35    signature: Signature,
36}
37
38impl Scratchpad {
39    /// Max Scratchpad size is 4MB including the metadata
40    pub const MAX_SIZE: usize = 4 * 1024 * 1024;
41
42    /// Creates a new instance of `Scratchpad`. Encrypts the data, and signs all the elements.
43    pub fn new(
44        owner: &SecretKey,
45        data_encoding: u64,
46        unencrypted_data: &Bytes,
47        counter: u64,
48    ) -> Self {
49        let pk = owner.public_key();
50        let encrypted_data = Bytes::from(pk.encrypt(unencrypted_data).to_bytes());
51        let addr = ScratchpadAddress::new(pk);
52        let signature = owner.sign(Self::bytes_for_signature(
53            addr,
54            data_encoding,
55            &encrypted_data,
56            counter,
57        ));
58        Self {
59            address: addr,
60            encrypted_data,
61            data_encoding,
62            counter,
63            signature,
64        }
65    }
66
67    /// Create a new Scratchpad without provding the secret key
68    /// It is the caller's responsibility to ensure the signature is valid (signs [`Scratchpad::bytes_for_signature`]) and the data is encrypted
69    /// It is recommended to use the [`Scratchpad::new`] method instead when possible
70    pub fn new_with_signature(
71        owner: PublicKey,
72        data_encoding: u64,
73        encrypted_data: Bytes,
74        counter: u64,
75        signature: Signature,
76    ) -> Self {
77        Self {
78            address: ScratchpadAddress::new(owner),
79            encrypted_data,
80            data_encoding,
81            counter,
82            signature,
83        }
84    }
85
86    /// Returns the bytes to sign for the signature
87    pub fn bytes_for_signature(
88        address: ScratchpadAddress,
89        data_encoding: u64,
90        encrypted_data: &Bytes,
91        counter: u64,
92    ) -> Vec<u8> {
93        let mut bytes_to_sign = data_encoding.to_be_bytes().to_vec();
94        bytes_to_sign.extend(address.to_hex().as_bytes());
95        bytes_to_sign.extend(counter.to_be_bytes().to_vec());
96        bytes_to_sign.extend(encrypted_data.to_vec());
97        bytes_to_sign
98    }
99
100    /// Get the counter of the Scratchpad, the higher the counter, the more recent the Scratchpad is
101    /// Similarly to counter CRDTs only the latest version (highest counter) of the Scratchpad is kept on the network
102    pub fn counter(&self) -> u64 {
103        self.counter
104    }
105
106    /// Return the current data encoding
107    pub fn data_encoding(&self) -> u64 {
108        self.data_encoding
109    }
110
111    /// Updates the content and encrypts it, increments the counter, re-signs the scratchpad
112    pub fn update(&mut self, unencrypted_data: &Bytes, sk: &SecretKey) {
113        self.counter += 1;
114        let pk = self.owner();
115        let address = ScratchpadAddress::new(*pk);
116        self.encrypted_data = Bytes::from(pk.encrypt(unencrypted_data).to_bytes());
117
118        let bytes_to_sign = Self::bytes_for_signature(
119            address,
120            self.data_encoding,
121            &self.encrypted_data,
122            self.counter,
123        );
124        self.signature = sk.sign(&bytes_to_sign);
125        debug_assert!(self.verify_signature(), "Must be valid after being signed. This is a bug, please report it by opening an issue on our github");
126    }
127
128    /// Verifies that the Scratchpad signature is valid
129    pub fn verify_signature(&self) -> bool {
130        let signing_bytes = Self::bytes_for_signature(
131            self.address,
132            self.data_encoding,
133            &self.encrypted_data,
134            self.counter,
135        );
136        self.owner().verify(&self.signature, &signing_bytes)
137    }
138
139    /// Returns the encrypted_data.
140    pub fn encrypted_data(&self) -> &Bytes {
141        &self.encrypted_data
142    }
143
144    /// Returns the encrypted_data, decrypted via the passed SecretKey
145    pub fn decrypt_data(&self, sk: &SecretKey) -> Result<Bytes> {
146        let cipher = Ciphertext::from_bytes(&self.encrypted_data)
147            .map_err(|_| Error::ScratchpadCipherTextFailed)?;
148        let bytes = sk
149            .decrypt(&cipher)
150            .ok_or(Error::ScratchpadCipherTextInvalid)?;
151        Ok(Bytes::from(bytes))
152    }
153
154    /// Returns the encrypted_data hash
155    pub fn encrypted_data_hash(&self) -> XorName {
156        XorName::from_content(&self.encrypted_data)
157    }
158
159    /// Returns the owner of the scratchpad
160    pub fn owner(&self) -> &PublicKey {
161        self.address.owner()
162    }
163
164    /// Returns the address of the scratchpad
165    pub fn address(&self) -> &ScratchpadAddress {
166        &self.address
167    }
168
169    /// Returns the NetworkAddress.
170    pub fn network_address(&self) -> NetworkAddress {
171        NetworkAddress::ScratchpadAddress(self.address)
172    }
173
174    /// Returns the xorname.
175    pub fn xorname(&self) -> XorName {
176        self.address.xorname()
177    }
178
179    /// Returns size of contained encrypted_data.
180    pub fn payload_size(&self) -> usize {
181        self.encrypted_data.len()
182    }
183
184    /// Size of the scratchpad
185    pub fn size(&self) -> usize {
186        size_of::<Scratchpad>() + self.payload_size()
187    }
188
189    /// Returns true if the scratchpad is too big
190    pub fn is_too_big(&self) -> bool {
191        self.size() > Self::MAX_SIZE
192    }
193}
194
195#[cfg(test)]
196mod tests {
197    use super::*;
198
199    #[test]
200    fn test_scratchpad_sig_and_update() {
201        let sk = SecretKey::random();
202        let raw_data = Bytes::from_static(b"data to be encrypted");
203        let mut scratchpad = Scratchpad::new(&sk, 42, &raw_data, 0);
204        assert!(scratchpad.verify_signature());
205        assert_eq!(scratchpad.counter(), 0);
206        assert_ne!(scratchpad.encrypted_data(), &raw_data);
207
208        let raw_data2 = Bytes::from_static(b"data to be encrypted v2");
209        scratchpad.update(&raw_data2, &sk);
210        assert!(scratchpad.verify_signature());
211        assert_eq!(scratchpad.counter(), 1);
212        assert_ne!(scratchpad.encrypted_data(), &raw_data);
213        assert_ne!(scratchpad.encrypted_data(), &raw_data2);
214    }
215
216    #[test]
217    fn test_scratchpad_encryption() {
218        let sk = SecretKey::random();
219        let raw_data = Bytes::from_static(b"data to be encrypted");
220        let scratchpad = Scratchpad::new(&sk, 42, &raw_data, 0);
221
222        let decrypted_data = scratchpad.decrypt_data(&sk).unwrap();
223        assert_eq!(decrypted_data, raw_data);
224    }
225}