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
    }
}