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
use std::borrow::Borrow;
use std::convert::TryFrom;

use anyhow::Result;

use crate::adnl;
use crate::proto;

/// Full overlay id
///
/// See [`PublicKey::Overlay`]
///
/// [`PublicKey::Overlay`]: everscale_crypto::tl::PublicKey::Overlay
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct IdFull([u8; 32]);

impl IdFull {
    /// Constructs full overlay id for the catchain overlay
    pub fn for_catchain_overlay<'tl, I>(unique_hash: &'tl [u8; 32], nodes: I) -> Self
    where
        I: Iterator<Item = &'tl [u8; 32]> + ExactSizeIterator + Clone,
    {
        Self(tl_proto::hash(proto::overlay::CatchainFirstBlock {
            unique_hash,
            nodes: tl_proto::IterRef(&nodes),
        }))
    }

    /// Constructs full overlay id for the workchain overlay
    pub fn for_workchain_overlay(workchain: i32, zero_state_file_hash: &[u8; 32]) -> Self {
        Self(tl_proto::hash(proto::overlay::ShardPublicOverlayId {
            workchain,
            shard: 1u64 << 63,
            zero_state_file_hash,
        }))
    }

    /// Returns inner bytes
    pub fn as_slice(&self) -> &[u8; 32] {
        &self.0
    }

    /// Hashes inner public key
    pub fn compute_short_id(&self) -> IdShort {
        let key = everscale_crypto::tl::PublicKey::Overlay { name: &self.0 };
        IdShort(tl_proto::hash(key))
    }
}

/// Short overlay id
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct IdShort([u8; 32]);

impl IdShort {
    /// Constructs short overlay id from public key hash
    #[inline(always)]
    pub const fn new(id: [u8; 32]) -> Self {
        Self(id)
    }

    /// Checks overlay node object (overlay id, signature)
    pub fn verify_overlay_node(&self, node: &proto::overlay::Node) -> Result<()> {
        if node.overlay != &self.0 {
            return Err(OverlayIdError::OverlayIdMismatch.into());
        }

        let peer_id_full = adnl::NodeIdFull::try_from(node.id)?;
        let peer_id = peer_id_full.compute_short_id();

        let node_to_sign = proto::overlay::NodeToSign {
            id: peer_id.as_slice(),
            overlay: node.overlay,
            version: node.version,
        };

        peer_id_full.verify(&node_to_sign, node.signature)?;

        Ok(())
    }

    /// Returns inner bytes
    #[inline(always)]
    pub const fn as_slice(&self) -> &[u8; 32] {
        &self.0
    }
}

impl PartialEq<[u8]> for IdShort {
    fn eq(&self, other: &[u8]) -> bool {
        self.0.eq(other)
    }
}

impl PartialEq<[u8; 32]> for IdShort {
    fn eq(&self, other: &[u8; 32]) -> bool {
        self.0.eq(other)
    }
}

impl From<IdShort> for [u8; 32] {
    fn from(id: IdShort) -> Self {
        id.0
    }
}

impl From<&IdShort> for [u8; 32] {
    fn from(id: &IdShort) -> Self {
        id.0
    }
}

impl From<[u8; 32]> for IdShort {
    fn from(id: [u8; 32]) -> Self {
        Self(id)
    }
}

impl Borrow<[u8; 32]> for IdShort {
    fn borrow(&self) -> &[u8; 32] {
        &self.0
    }
}

impl<'a> Borrow<[u8; 32]> for &'a IdShort {
    fn borrow(&self) -> &[u8; 32] {
        &self.0
    }
}

impl std::fmt::Display for IdShort {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.write_str(&hex::encode(self.0))
    }
}

#[derive(thiserror::Error, Debug)]
enum OverlayIdError {
    #[error("Overlay id mismatch")]
    OverlayIdMismatch,
}