hopr_crypto_sphinx/
ec_groups.rs1use curve25519_dalek::traits::IsIdentity;
2use hopr_crypto_types::errors::Result;
3
4#[cfg(feature = "secp256k1")]
5use elliptic_curve::{ops::MulByGenerator, Group};
6
7use crate::shared_keys::{Alpha, GroupElement, Scalar, SphinxSuite};
8
9#[cfg(any(feature = "x25519", feature = "ed25519"))]
10impl Scalar for curve25519_dalek::scalar::Scalar {
11 fn random() -> Self {
12 let bytes = hopr_crypto_random::random_bytes::<32>();
13 Self::from_bytes(&bytes).unwrap()
14 }
15
16 fn from_bytes(bytes: &[u8]) -> Result<Self> {
17 hopr_crypto_types::utils::x25519_scalar_from_bytes(bytes)
18 }
19
20 fn to_bytes(&self) -> Box<[u8]> {
21 self.to_bytes().into()
22 }
23}
24
25#[cfg(feature = "secp256k1")]
26impl Scalar for k256::Scalar {
27 fn random() -> Self {
28 let mut bytes = k256::FieldBytes::default();
30 loop {
31 hopr_crypto_random::random_fill(&mut bytes);
32 if let Ok(scalar) = Self::from_bytes(&bytes) {
33 return scalar;
34 }
35 }
36 }
37
38 fn from_bytes(bytes: &[u8]) -> Result<Self> {
39 hopr_crypto_types::utils::k256_scalar_from_bytes(bytes)
40 }
41
42 fn to_bytes(&self) -> Box<[u8]> {
43 let ret = self.to_bytes();
44 Box::<[u8]>::from(ret.as_slice())
45 }
46}
47
48#[cfg(feature = "x25519")]
49impl GroupElement<curve25519_dalek::scalar::Scalar> for curve25519_dalek::montgomery::MontgomeryPoint {
50 type AlphaLen = typenum::U32;
51
52 fn to_alpha(&self) -> Alpha<typenum::U32> {
53 self.0.into()
54 }
55
56 fn from_alpha(alpha: Alpha<typenum::U32>) -> Result<Self> {
57 Ok(curve25519_dalek::montgomery::MontgomeryPoint(alpha.into()))
58 }
59
60 fn generate(scalar: &curve25519_dalek::scalar::Scalar) -> Self {
61 scalar * curve25519_dalek::constants::X25519_BASEPOINT
62 }
63
64 fn is_valid(&self) -> bool {
65 !self.is_identity()
66 }
67}
68
69#[cfg(feature = "ed25519")]
70impl GroupElement<curve25519_dalek::scalar::Scalar> for curve25519_dalek::edwards::EdwardsPoint {
71 type AlphaLen = typenum::U32;
72
73 fn to_alpha(&self) -> Alpha<typenum::U32> {
74 self.compress().0.into()
75 }
76
77 fn from_alpha(alpha: Alpha<typenum::U32>) -> Result<Self> {
78 curve25519_dalek::edwards::CompressedEdwardsY(alpha.into())
79 .decompress()
80 .ok_or(hopr_crypto_types::errors::CryptoError::InvalidInputValue)
81 }
82
83 fn generate(scalar: &curve25519_dalek::scalar::Scalar) -> Self {
84 scalar * curve25519_dalek::constants::ED25519_BASEPOINT_POINT
85 }
86
87 fn is_valid(&self) -> bool {
88 self.is_torsion_free() && !self.is_identity()
89 }
90}
91
92#[cfg(feature = "secp256k1")]
93impl GroupElement<k256::Scalar> for k256::ProjectivePoint {
94 type AlphaLen = typenum::U33;
95
96 fn to_alpha(&self) -> Alpha<typenum::U33> {
97 let mut ret = Alpha::<typenum::U33>::default();
98 ret.copy_from_slice(
99 hopr_crypto_types::types::CurvePoint::from(self.to_affine())
100 .as_compressed()
101 .as_ref(),
102 );
103 ret
104 }
105
106 fn from_alpha(alpha: Alpha<typenum::U33>) -> Result<Self> {
107 let v: &[u8] = alpha.as_ref();
108 hopr_crypto_types::types::CurvePoint::try_from(v)
109 .map(|c| c.into_projective_point())
110 .map_err(|_| hopr_crypto_types::errors::CryptoError::InvalidInputValue)
111 }
112
113 fn generate(scalar: &k256::Scalar) -> Self {
114 k256::ProjectivePoint::mul_by_generator(scalar)
115 }
116
117 fn is_valid(&self) -> bool {
118 self.is_identity().unwrap_u8() == 0
119 }
120}
121
122#[cfg(feature = "secp256k1")]
124pub struct Secp256k1Suite;
125
126#[cfg(feature = "secp256k1")]
127impl SphinxSuite for Secp256k1Suite {
128 type P = hopr_crypto_types::keypairs::ChainKeypair;
129 type E = k256::Scalar;
130 type G = k256::ProjectivePoint;
131}
132
133#[cfg(feature = "ed25519")]
135pub struct Ed25519Suite;
136
137#[cfg(feature = "ed25519")]
138impl SphinxSuite for Ed25519Suite {
139 type P = hopr_crypto_types::keypairs::OffchainKeypair;
140 type E = curve25519_dalek::scalar::Scalar;
141 type G = curve25519_dalek::edwards::EdwardsPoint;
142}
143
144#[cfg(feature = "x25519")]
146pub struct X25519Suite;
147
148#[cfg(feature = "x25519")]
149impl SphinxSuite for X25519Suite {
150 type P = hopr_crypto_types::keypairs::OffchainKeypair;
151 type E = curve25519_dalek::scalar::Scalar;
152 type G = curve25519_dalek::montgomery::MontgomeryPoint;
153}
154
155#[cfg(test)]
156mod tests {
157 use crate::shared_keys::tests::generic_sphinx_suite_test;
158 use crate::shared_keys::GroupElement;
159 use hex_literal::hex;
160 use parameterized::parameterized;
161
162 #[test]
163 fn test_extract_key_from_group_element() {
164 let salt = [0xde, 0xad, 0xbe, 0xef];
165 let pt = k256::ProjectivePoint::GENERATOR;
166
167 let key = pt.extract_key(&salt);
168
169 let res = hex!("54bf34178075e153f481ce05b113c1530ecc45a2f1f13a3366d4389f65470de6");
170 assert_eq!(res, key.as_ref());
171 }
172
173 #[test]
174 fn test_expand_key_from_group_element() {
175 let salt = [0xde, 0xad, 0xbe, 0xef];
176 let pt = k256::ProjectivePoint::GENERATOR;
177
178 let key = pt.expand_key(&salt);
179
180 let res = hex!("d138d9367474911f7124b95be844d2f8a6d34e962694e37e8717bdbd3c15690b");
181 assert_eq!(res, key.as_ref());
182 }
183
184 #[cfg(feature = "secp256k1")]
185 #[parameterized(nodes = {4, 3, 2, 1})]
186 fn test_secp256k1_suite(nodes: usize) {
187 generic_sphinx_suite_test::<crate::ec_groups::Secp256k1Suite>(nodes)
188 }
189
190 #[cfg(feature = "ed25519")]
191 #[parameterized(nodes = {4, 3, 2, 1})]
192 fn test_ed25519_shared_keys(nodes: usize) {
193 generic_sphinx_suite_test::<crate::ec_groups::Ed25519Suite>(nodes)
194 }
195
196 #[cfg(feature = "x25519")]
197 #[parameterized(nodes = {4, 3, 2, 1})]
198 fn test_montgomery_shared_keys(nodes: usize) {
199 generic_sphinx_suite_test::<crate::ec_groups::X25519Suite>(nodes)
200 }
201}