ant_protocol/storage/scratchpad.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
// Copyright 2024 MaidSafe.net limited.
//
// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. Please review the Licences for the specific language governing
// permissions and limitations relating to use of the SAFE Network Software.
use super::ScratchpadAddress;
use crate::error::{Error, Result};
use crate::Bytes;
use crate::NetworkAddress;
use bls::{Ciphertext, PublicKey, SecretKey, Signature};
use serde::{Deserialize, Serialize};
use xor_name::XorName;
/// Scratchpad, an mutable address for encrypted data
#[derive(
Hash, Eq, PartialEq, PartialOrd, Ord, Clone, custom_debug::Debug, Serialize, Deserialize,
)]
pub struct Scratchpad {
/// Network address. Omitted when serialising and
/// calculated from the `encrypted_data` when deserialising.
address: ScratchpadAddress,
/// Data encoding: custom apps using scratchpad should use this so they can identify the type of data they are storing
data_encoding: u64,
/// Contained data. This should be encrypted
#[debug(skip)]
encrypted_data: Bytes,
/// Monotonically increasing counter to track the number of times this has been updated.
counter: u64,
/// Signature over `Vec<counter>`.extend(Xorname::from_content(encrypted_data).to_vec()) from the owning key.
/// Required for scratchpad to be valid.
signature: Option<Signature>,
}
impl Scratchpad {
/// Creates a new instance of `Scratchpad`.
pub fn new(owner: PublicKey, data_encoding: u64) -> Self {
Self {
address: ScratchpadAddress::new(owner),
encrypted_data: Bytes::new(),
data_encoding,
counter: 0,
signature: None,
}
}
/// Return the current count
pub fn count(&self) -> u64 {
self.counter
}
/// Return the current data encoding
pub fn data_encoding(&self) -> u64 {
self.data_encoding
}
/// Increments the counter value.
pub fn increment(&mut self) -> u64 {
self.counter += 1;
self.counter
}
/// Returns the next counter value,
///
/// Encrypts data and updates the signature with provided sk
pub fn update_and_sign(&mut self, unencrypted_data: Bytes, sk: &SecretKey) -> u64 {
let next_count = self.increment();
let pk = self.owner();
self.encrypted_data = Bytes::from(pk.encrypt(unencrypted_data).to_bytes());
let encrypted_data_xorname = self.encrypted_data_hash().to_vec();
let mut bytes_to_sign = self.counter.to_be_bytes().to_vec();
bytes_to_sign.extend(encrypted_data_xorname);
self.signature = Some(sk.sign(&bytes_to_sign));
next_count
}
/// Verifies the signature and content of the scratchpad are valid for the
/// owner's public key.
pub fn is_valid(&self) -> bool {
if let Some(signature) = &self.signature {
let mut signing_bytes = self.counter.to_be_bytes().to_vec();
signing_bytes.extend(self.encrypted_data_hash().to_vec()); // add the count
self.owner().verify(signature, &signing_bytes)
} else {
false
}
}
/// Returns the encrypted_data.
pub fn encrypted_data(&self) -> &Bytes {
&self.encrypted_data
}
/// Returns the encrypted_data, decrypted via the passed SecretKey
pub fn decrypt_data(&self, sk: &SecretKey) -> Result<Bytes> {
let cipher = Ciphertext::from_bytes(&self.encrypted_data)
.map_err(|_| Error::ScratchpadCipherTextFailed)?;
let bytes = sk
.decrypt(&cipher)
.ok_or(Error::ScratchpadCipherTextInvalid)?;
Ok(Bytes::from(bytes))
}
/// Returns the encrypted_data hash
pub fn encrypted_data_hash(&self) -> XorName {
XorName::from_content(&self.encrypted_data)
}
/// Returns the owner.
pub fn owner(&self) -> &PublicKey {
self.address.owner()
}
/// Returns the address.
pub fn address(&self) -> &ScratchpadAddress {
&self.address
}
/// Returns the NetworkAddress.
pub fn network_address(&self) -> NetworkAddress {
NetworkAddress::ScratchpadAddress(self.address)
}
/// Returns a VEC with the XOR name.
pub fn to_xor_name_vec(&self) -> Vec<XorName> {
[self.network_address()]
.iter()
.filter_map(|f| f.as_xorname())
.collect::<Vec<XorName>>()
}
/// Returns the name.
pub fn name(&self) -> XorName {
self.address.xorname()
}
/// Returns size of contained encrypted_data.
pub fn payload_size(&self) -> usize {
self.encrypted_data.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_scratchpad_is_valid() {
let sk = SecretKey::random();
let pk = sk.public_key();
let mut scratchpad = Scratchpad::new(pk, 42);
scratchpad.update_and_sign(Bytes::from_static(b"data to be encrypted"), &sk);
assert!(scratchpad.is_valid());
}
}