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