hopr_crypto_sphinx/
ec_groups.rs

1use 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        // Beware, this is not constant-time
31        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;
81        self.is_torsion_free() && !self.is_identity() && !self.is_small_order()
82    }
83}
84
85#[cfg(feature = "secp256k1")]
86impl GroupElement<k256::Scalar> for k256::ProjectivePoint {
87    type AlphaLen = typenum::U33;
88
89    fn to_alpha(&self) -> Alpha<typenum::U33> {
90        let mut ret = Alpha::<typenum::U33>::default();
91        ret.copy_from_slice(self.to_affine().to_encoded_point(true).as_ref());
92        ret
93    }
94
95    fn from_alpha(alpha: Alpha<typenum::U33>) -> Result<Self> {
96        EncodedPoint::from_bytes(&alpha)
97            .map_err(|_| CryptoError::InvalidInputValue("alpha"))
98            .and_then(|ep| {
99                AffinePoint::from_encoded_point(&ep)
100                    .into_option()
101                    .ok_or(CryptoError::InvalidInputValue("alpha"))
102            })
103            .map(k256::ProjectivePoint::from)
104    }
105
106    fn generate(scalar: &k256::Scalar) -> Self {
107        k256::ProjectivePoint::mul_by_generator(scalar)
108    }
109
110    fn is_valid(&self) -> bool {
111        !bool::from(self.is_identity())
112    }
113}
114
115/// Represents an instantiation of the Sphinx protocol using secp256k1 elliptic curve and `ChainKeypair`
116#[cfg(feature = "secp256k1")]
117#[derive(Clone, Copy, Debug, PartialEq, Eq)]
118#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
119pub struct Secp256k1Suite;
120
121#[cfg(feature = "secp256k1")]
122impl SphinxSuite for Secp256k1Suite {
123    type E = k256::Scalar;
124    type G = k256::ProjectivePoint;
125    type P = hopr_crypto_types::keypairs::ChainKeypair;
126    type PRP = hopr_crypto_types::lioness::LionessBlake3ChaCha20<typenum::U1022>;
127}
128
129/// Represents an instantiation of the Sphinx protocol using the ed25519 curve and `OffchainKeypair`
130#[cfg(feature = "ed25519")]
131#[derive(Clone, Copy, Debug, PartialEq, Eq)]
132#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
133pub struct Ed25519Suite;
134
135#[cfg(feature = "ed25519")]
136impl SphinxSuite for Ed25519Suite {
137    type E = curve25519_dalek::scalar::Scalar;
138    type G = curve25519_dalek::edwards::EdwardsPoint;
139    type P = hopr_crypto_types::keypairs::OffchainKeypair;
140    type PRP = hopr_crypto_types::lioness::LionessBlake3ChaCha20<typenum::U1022>;
141}
142
143/// Represents an instantiation of the Sphinx protocol using the Curve25519 curve and `OffchainKeypair`
144#[cfg(feature = "x25519")]
145#[derive(Clone, Copy, Debug, PartialEq, Eq)]
146#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
147pub struct X25519Suite;
148
149#[cfg(feature = "x25519")]
150impl SphinxSuite for X25519Suite {
151    type E = curve25519_dalek::scalar::Scalar;
152    type G = curve25519_dalek::montgomery::MontgomeryPoint;
153    type P = hopr_crypto_types::keypairs::OffchainKeypair;
154    type PRP = hopr_crypto_types::lioness::LionessBlake3ChaCha20<typenum::U1022>;
155}
156
157#[cfg(test)]
158mod tests {
159    use parameterized::parameterized;
160
161    use crate::shared_keys::tests::generic_sphinx_suite_test;
162
163    #[cfg(feature = "secp256k1")]
164    #[test]
165    fn test_extract_key_from_group_element() {
166        use crate::shared_keys::GroupElement;
167
168        let salt = [0xde, 0xad, 0xbe, 0xef];
169        let pt = k256::ProjectivePoint::GENERATOR;
170
171        let key = pt.extract_key("test", &salt);
172        assert_eq!(
173            "08112a22609819a4c698d6c92f404628ca925f3d731d53594126ffdf19ef6fa9",
174            hex::encode(key)
175        );
176    }
177
178    #[cfg(feature = "secp256k1")]
179    #[test]
180    fn test_expand_key_from_group_element() {
181        use crate::shared_keys::GroupElement;
182
183        let salt = [0xde, 0xad, 0xbe, 0xef];
184        let pt = k256::ProjectivePoint::GENERATOR;
185
186        let key = pt.extract_key("test", &salt);
187
188        assert_eq!(
189            "08112a22609819a4c698d6c92f404628ca925f3d731d53594126ffdf19ef6fa9",
190            hex::encode(key)
191        );
192    }
193
194    #[cfg(feature = "secp256k1")]
195    #[parameterized(nodes = {4, 3, 2, 1})]
196    fn test_secp256k1_suite(nodes: usize) {
197        generic_sphinx_suite_test::<crate::ec_groups::Secp256k1Suite>(nodes)
198    }
199
200    #[cfg(feature = "ed25519")]
201    #[parameterized(nodes = {4, 3, 2, 1})]
202    fn test_ed25519_shared_keys(nodes: usize) {
203        generic_sphinx_suite_test::<crate::ec_groups::Ed25519Suite>(nodes)
204    }
205
206    #[cfg(feature = "x25519")]
207    #[parameterized(nodes = {4, 3, 2, 1})]
208    fn test_montgomery_shared_keys(nodes: usize) {
209        generic_sphinx_suite_test::<crate::ec_groups::X25519Suite>(nodes)
210    }
211}