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