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