use crate::storage::{ChunkAddress, GraphEntryAddress, PointerAddress, ScratchpadAddress};
use bls::{PublicKey, SecretKey, Signature};
use serde::{Deserialize, Serialize};
use xor_name::XorName;
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd)]
pub struct Pointer {
owner: PublicKey,
counter: u64,
target: PointerTarget,
signature: Signature,
}
impl std::fmt::Debug for Pointer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Pointer")
.field("owner", &self.owner.to_hex())
.field("counter", &self.counter)
.field("target", &self.target)
.field("signature", &hex::encode(self.signature.to_bytes()))
.finish()
}
}
#[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(addr) => addr.xorname(),
PointerTarget::ScratchpadAddress(addr) => addr.xorname(),
}
}
pub fn to_hex(&self) -> String {
match self {
PointerTarget::ChunkAddress(addr) => addr.to_hex(),
PointerTarget::GraphEntryAddress(addr) => addr.to_hex(),
PointerTarget::PointerAddress(addr) => addr.to_hex(),
PointerTarget::ScratchpadAddress(addr) => addr.to_hex(),
}
}
}
impl Pointer {
pub fn new(owner: &SecretKey, counter: u64, 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,
}
}
pub fn new_with_signature(
owner: PublicKey,
counter: u64,
target: PointerTarget,
signature: Signature,
) -> Self {
Self {
owner,
counter,
target,
signature,
}
}
fn bytes_to_sign(owner: &PublicKey, counter: u64, target: &PointerTarget) -> Vec<u8> {
let counter_bytes: Vec<u8> = if counter > u32::MAX as u64 {
counter.to_le_bytes().to_vec()
} else {
let u32_counter = counter as u32;
u32_counter.to_le_bytes().to_vec()
};
let mut bytes = Vec::new();
bytes.extend_from_slice(&owner.to_bytes());
bytes.extend_from_slice(&counter_bytes);
if let Ok(target_bytes) = rmp_serde::to_vec(target) {
bytes.extend_from_slice(&target_bytes);
}
bytes
}
pub fn address(&self) -> PointerAddress {
PointerAddress::new(self.owner)
}
pub fn owner(&self) -> &PublicKey {
&self.owner
}
pub fn target(&self) -> &PointerTarget {
&self.target
}
pub fn bytes_for_signature(&self) -> Vec<u8> {
Self::bytes_to_sign(&self.owner, self.counter, &self.target)
}
pub fn xorname(&self) -> XorName {
self.address().xorname()
}
pub fn counter(&self) -> u64 {
self.counter
}
pub fn verify_signature(&self) -> bool {
let bytes = self.bytes_for_signature();
self.owner.verify(&self.signature, &bytes)
}
pub fn size() -> usize {
size_of::<Pointer>()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pointer_creation_and_validation() {
let owner_sk = SecretKey::random();
let counter = 1;
let pk = SecretKey::random().public_key();
let target = PointerTarget::GraphEntryAddress(GraphEntryAddress::new(pk));
let pointer = Pointer::new(&owner_sk, counter, target.clone());
assert!(pointer.verify_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()); }
#[test]
fn test_pointer_deserialize_counter_compatibility() {
#[derive(Serialize, Deserialize)]
struct OldPointer {
owner: PublicKey,
counter: u32,
target: PointerTarget,
signature: Signature,
}
fn bytes_to_sign_old_pointer(
owner: &PublicKey,
counter: u32,
target: &PointerTarget,
) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.extend_from_slice(&owner.to_bytes());
bytes.extend_from_slice(&counter.to_le_bytes());
if let Ok(target_bytes) = rmp_serde::to_vec(target) {
bytes.extend_from_slice(&target_bytes);
}
bytes
}
let xor = XorName::random(&mut rand::thread_rng());
let sk = SecretKey::random();
let old_pointer = OldPointer {
owner: sk.public_key(),
counter: 42u32,
target: PointerTarget::ChunkAddress(ChunkAddress::new(xor)),
signature: sk.sign(bytes_to_sign_old_pointer(
&sk.public_key(),
42u32,
&PointerTarget::ChunkAddress(ChunkAddress::new(xor)),
)),
};
let serialized_old =
rmp_serde::to_vec(&old_pointer).expect("Failed to serialize old pointer");
let deserialized_as_new: Pointer =
rmp_serde::from_slice(&serialized_old).expect("Failed to deserialize");
assert_eq!(deserialized_as_new.counter(), 42u64);
assert_eq!(deserialized_as_new.owner(), &old_pointer.owner);
assert_eq!(deserialized_as_new.target(), &old_pointer.target);
assert_eq!(deserialized_as_new.signature, old_pointer.signature);
let new_pointer =
Pointer::new(&sk, 42, PointerTarget::ChunkAddress(ChunkAddress::new(xor)));
let serialized_new =
rmp_serde::to_vec(&new_pointer).expect("Failed to serialize new pointer");
let deserialized_new: Pointer =
rmp_serde::from_slice(&serialized_new).expect("Failed to deserialize");
assert_eq!(deserialized_new.counter(), 42u64);
assert_eq!(deserialized_new.owner(), &new_pointer.owner);
assert_eq!(deserialized_new.target(), &new_pointer.target);
assert_eq!(deserialized_new.signature, new_pointer.signature);
let deserialized_as_old: OldPointer =
rmp_serde::from_slice(&serialized_new).expect("Failed to deserialize");
assert_eq!(deserialized_as_old.counter, 42u32);
assert_eq!(deserialized_as_old.owner, new_pointer.owner);
assert_eq!(deserialized_as_old.target, new_pointer.target);
assert_eq!(deserialized_as_old.signature, new_pointer.signature);
assert_eq!(old_pointer.counter as u64, new_pointer.counter);
assert_eq!(old_pointer.owner, new_pointer.owner);
assert_eq!(old_pointer.target, new_pointer.target);
assert_eq!(old_pointer.signature, new_pointer.signature);
}
}