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