ssi_security/
ethereum_adress.rs

1use core::fmt;
2use linked_data::{
3    rdf_types::{Interpretation, Vocabulary},
4    LinkedDataPredicateObjects, LinkedDataSubject,
5};
6use serde::{Deserialize, Serialize};
7use std::{ops::Deref, str::FromStr};
8
9/// Value for the `ethereumAddress` property.
10///
11/// An `ethereumAddress` property is used to specify the Ethereum address (as per
12/// the [Ethereum Yellow Paper: ETHEREUM: A SECURE DECENTRALISED GENERALISED
13/// TRANSACTION LEDGER][1]) composed of the prefix "0x", a common identifier for
14/// hexadecimal, concatenated with the rightmost 20 bytes of the Keccak-256
15/// hash (big endian) of the ECDSA public key (the curve used is the so-called
16/// secp256k1).
17///
18/// In hexadecimal, 2 digits represent a byte, meaning addresses contain 40
19/// hexadecimal digits. The Ethereum address should also contain a checksum as
20/// per [EIP-55][2].
21///
22/// [1]: <https://ethereum.github.io/yellowpaper/paper.pdf>
23/// [2]: <https://eips.ethereum.org/EIPS/eip-55>
24#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
25#[serde(transparent)]
26pub struct EthereumAddressBuf(String);
27
28impl EthereumAddressBuf {
29    pub fn as_ethereum_address(&self) -> &EthereumAddress {
30        unsafe { std::mem::transmute(self.0.as_str()) }
31    }
32
33    pub fn into_string(self) -> String {
34        self.0
35    }
36}
37
38impl FromStr for EthereumAddressBuf {
39    type Err = std::convert::Infallible;
40
41    fn from_str(s: &str) -> Result<Self, Self::Err> {
42        Ok(Self(s.to_owned())) // TODO actually parse
43    }
44}
45
46impl Deref for EthereumAddressBuf {
47    type Target = EthereumAddress;
48
49    fn deref(&self) -> &Self::Target {
50        self.as_ethereum_address()
51    }
52}
53
54impl fmt::Display for EthereumAddressBuf {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        self.0.fmt(f)
57    }
58}
59
60impl<V: Vocabulary, I: Interpretation> linked_data::LinkedDataResource<I, V>
61    for EthereumAddressBuf
62{
63    fn interpretation(
64        &self,
65        _vocabulary: &mut V,
66        _interpretation: &mut I,
67    ) -> linked_data::ResourceInterpretation<I, V> {
68        use linked_data::{rdf_types::Term, CowRdfTerm, RdfLiteral, ResourceInterpretation};
69        ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Owned(Term::Literal(
70            RdfLiteral::Xsd(xsd_types::Value::String(self.to_string())),
71        ))))
72    }
73}
74
75impl<V: Vocabulary, I: Interpretation> LinkedDataPredicateObjects<I, V> for EthereumAddressBuf {
76    fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
77    where
78        S: linked_data::PredicateObjectsVisitor<I, V>,
79    {
80        visitor.object(self)?;
81        visitor.end()
82    }
83}
84
85impl<V: Vocabulary, I: Interpretation> LinkedDataSubject<I, V> for EthereumAddressBuf {
86    fn visit_subject<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
87    where
88        S: linked_data::SubjectVisitor<I, V>,
89    {
90        visitor.end()
91    }
92}
93
94/// Unsized value for the `ethereumAddress` property.
95///
96/// An `ethereumAddress` property is used to specify the Ethereum address (as per
97/// the [Ethereum Yellow Paper: ETHEREUM: A SECURE DECENTRALISED GENERALISED
98/// TRANSACTION LEDGER][1]) composed of the prefix "0x", a common identifier for
99/// hexadecimal, concatenated with the rightmost 20 bytes of the Keccak-256
100/// hash (big endian) of the ECDSA public key (the curve used is the so-called
101/// secp256k1).
102///
103/// In hexadecimal, 2 digits represent a byte, meaning addresses contain 40
104/// hexadecimal digits. The Ethereum address should also contain a checksum as
105/// per [EIP-55][2].
106///
107/// [1]: <https://ethereum.github.io/yellowpaper/paper.pdf>
108/// [2]: <https://eips.ethereum.org/EIPS/eip-55>
109pub struct EthereumAddress(str);
110
111impl EthereumAddress {
112    pub fn as_str(&self) -> &str {
113        &self.0
114    }
115}
116
117impl<V: Vocabulary, I: Interpretation> linked_data::LinkedDataResource<I, V> for EthereumAddress {
118    fn interpretation(
119        &self,
120        _vocabulary: &mut V,
121        _interpretation: &mut I,
122    ) -> linked_data::ResourceInterpretation<I, V> {
123        use linked_data::{rdf_types::Term, CowRdfTerm, RdfLiteralRef, ResourceInterpretation};
124        ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Borrowed(Term::Literal(
125            RdfLiteralRef::Xsd(xsd_types::ValueRef::String(&self.0)),
126        ))))
127    }
128}
129
130impl<V: Vocabulary, I: Interpretation> LinkedDataPredicateObjects<I, V> for EthereumAddress {
131    fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
132    where
133        S: linked_data::PredicateObjectsVisitor<I, V>,
134    {
135        visitor.object(self)?;
136        visitor.end()
137    }
138}
139
140impl<V: Vocabulary, I: Interpretation> LinkedDataSubject<I, V> for EthereumAddress {
141    fn visit_subject<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
142    where
143        S: linked_data::SubjectVisitor<I, V>,
144    {
145        visitor.end()
146    }
147}