ant_protocol/storage/pointer.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
// 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 crate::storage::{ChunkAddress, GraphEntryAddress, PointerAddress, ScratchpadAddress};
use bls::{PublicKey, SecretKey, Signature};
use serde::{Deserialize, Serialize};
use xor_name::XorName;
/// Pointer, a mutable address pointing to other data on the Network
/// It is stored at the owner's public key and can only be updated by the owner
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd)]
pub struct Pointer {
owner: PublicKey,
counter: u32,
target: PointerTarget,
signature: Signature,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd)]
pub enum PointerTarget {
ChunkAddress(ChunkAddress),
GraphEntryAddress(GraphEntryAddress),
PointerAddress(PointerAddress),
ScratchpadAddress(ScratchpadAddress),
}
impl PointerTarget {
pub fn xorname(&self) -> XorName {
match self {
PointerTarget::ChunkAddress(addr) => *addr.xorname(),
PointerTarget::GraphEntryAddress(addr) => *addr.xorname(),
PointerTarget::PointerAddress(ptr) => *ptr.xorname(),
PointerTarget::ScratchpadAddress(addr) => addr.xorname(),
}
}
}
impl Pointer {
/// Create a new pointer, signing it with the provided secret key.
/// This pointer would be stored on the network at the provided key's public key.
/// There can only be one pointer at a time at the same address (one per key).
pub fn new(owner: &SecretKey, counter: u32, target: PointerTarget) -> Self {
let pubkey = owner.public_key();
let bytes_to_sign = Self::bytes_to_sign(&pubkey, counter, &target);
let signature = owner.sign(&bytes_to_sign);
Self {
owner: pubkey,
counter,
target,
signature,
}
}
/// Create a new pointer with an existing signature
pub fn new_with_signature(
owner: PublicKey,
counter: u32,
target: PointerTarget,
signature: Signature,
) -> Self {
Self {
owner,
counter,
target,
signature,
}
}
/// Get the bytes that the signature is calculated from
fn bytes_to_sign(owner: &PublicKey, counter: u32, target: &PointerTarget) -> Vec<u8> {
let mut bytes = Vec::new();
// Add owner public key bytes
bytes.extend_from_slice(&owner.to_bytes());
// Add counter
bytes.extend_from_slice(&counter.to_le_bytes());
// Add target bytes using MessagePack serialization
if let Ok(target_bytes) = rmp_serde::to_vec(target) {
bytes.extend_from_slice(&target_bytes);
}
bytes
}
/// Get the address of the pointer
pub fn address(&self) -> PointerAddress {
PointerAddress::from_owner(self.owner)
}
/// Get the owner of the pointer
pub fn owner(&self) -> &PublicKey {
&self.owner
}
/// Get the target of the pointer
pub fn target(&self) -> &PointerTarget {
&self.target
}
/// Get the bytes that were signed for this pointer
pub fn bytes_for_signature(&self) -> Vec<u8> {
Self::bytes_to_sign(&self.owner, self.counter, &self.target)
}
pub fn xorname(&self) -> XorName {
self.target.xorname()
}
/// Get the counter of the pointer, the higher the counter, the more recent the pointer is
/// Similarly to counter CRDTs only the latest version (highest counter) of the pointer is kept on the network
pub fn counter(&self) -> u32 {
self.counter
}
/// Verifies if the pointer has a valid signature
pub fn verify_signature(&self) -> bool {
let bytes = self.bytes_for_signature();
self.owner.verify(&self.signature, &bytes)
}
/// Size of the pointer
pub fn size() -> usize {
size_of::<Pointer>()
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::thread_rng;
#[test]
fn test_pointer_creation_and_validation() {
let owner_sk = SecretKey::random();
let counter = 1;
let mut rng = thread_rng();
let target =
PointerTarget::GraphEntryAddress(GraphEntryAddress::new(XorName::random(&mut rng)));
// Create and sign pointer
let pointer = Pointer::new(&owner_sk, counter, target.clone());
assert!(pointer.verify_signature()); // Should be valid with correct signature
// Create pointer with wrong signature
let wrong_sk = SecretKey::random();
let sig = wrong_sk.sign(pointer.bytes_for_signature());
let wrong_pointer =
Pointer::new_with_signature(owner_sk.public_key(), counter, target.clone(), sig);
assert!(!wrong_pointer.verify_signature()); // Should be invalid with wrong signature
}
}