elastic_elgamal/group/
curve25519.rs1use rand_core::{CryptoRng, RngCore};
2
3use core::convert::TryInto;
4
5use crate::curve25519::{
6 constants::{ED25519_BASEPOINT_POINT, ED25519_BASEPOINT_TABLE},
7 edwards::{CompressedEdwardsY, EdwardsPoint},
8 scalar::Scalar,
9 traits::{Identity, IsIdentity, MultiscalarMul, VartimeMultiscalarMul},
10};
11use crate::group::{ElementOps, Group, RandomBytesProvider, ScalarOps};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26#[cfg_attr(
27 docsrs,
28 doc(cfg(any(feature = "curve25519-dalek", feature = "curve25519-dalek-ng")))
29)]
30pub struct Curve25519Subgroup(());
31
32impl ScalarOps for Curve25519Subgroup {
33 type Scalar = Scalar;
34
35 const SCALAR_SIZE: usize = 32;
36
37 fn generate_scalar<R: CryptoRng + RngCore>(rng: &mut R) -> Self::Scalar {
38 let mut scalar_bytes = [0_u8; 64];
39 rng.fill_bytes(&mut scalar_bytes[..]);
40 Scalar::from_bytes_mod_order_wide(&scalar_bytes)
41 }
42
43 fn scalar_from_random_bytes(source: RandomBytesProvider<'_>) -> Self::Scalar {
44 let mut scalar_bytes = [0_u8; 64];
45 source.fill_bytes(&mut scalar_bytes);
46 Scalar::from_bytes_mod_order_wide(&scalar_bytes)
47 }
48
49 fn invert_scalar(scalar: Self::Scalar) -> Self::Scalar {
50 scalar.invert()
51 }
52
53 fn invert_scalars(scalars: &mut [Self::Scalar]) {
54 Scalar::batch_invert(scalars);
55 }
56
57 fn serialize_scalar(scalar: &Self::Scalar, buffer: &mut [u8]) {
58 buffer.copy_from_slice(&scalar.to_bytes());
59 }
60
61 #[cfg(feature = "curve25519-dalek")]
62 fn deserialize_scalar(buffer: &[u8]) -> Option<Self::Scalar> {
63 let bytes: &[u8; 32] = buffer.try_into().expect("input has incorrect byte size");
64 Scalar::from_canonical_bytes(*bytes).into()
65 }
66
67 #[cfg(feature = "curve25519-dalek-ng")]
68 fn deserialize_scalar(buffer: &[u8]) -> Option<Self::Scalar> {
69 let bytes: &[u8; 32] = buffer.try_into().expect("input has incorrect byte size");
70 Scalar::from_canonical_bytes(*bytes)
71 }
72}
73
74impl ElementOps for Curve25519Subgroup {
75 type Element = EdwardsPoint;
76
77 const ELEMENT_SIZE: usize = 32;
78
79 fn identity() -> Self::Element {
80 EdwardsPoint::identity()
81 }
82
83 fn is_identity(element: &Self::Element) -> bool {
84 element.is_identity()
85 }
86
87 fn generator() -> Self::Element {
88 ED25519_BASEPOINT_POINT
89 }
90
91 fn serialize_element(element: &Self::Element, buffer: &mut [u8]) {
92 buffer.copy_from_slice(&element.compress().to_bytes());
93 }
94
95 #[cfg(feature = "curve25519-dalek")]
96 fn deserialize_element(buffer: &[u8]) -> Option<Self::Element> {
97 CompressedEdwardsY::from_slice(buffer)
98 .ok()?
99 .decompress()
100 .filter(EdwardsPoint::is_torsion_free)
101 }
102
103 #[cfg(feature = "curve25519-dalek-ng")]
104 fn deserialize_element(buffer: &[u8]) -> Option<Self::Element> {
105 CompressedEdwardsY::from_slice(buffer)
106 .decompress()
107 .filter(EdwardsPoint::is_torsion_free)
108 }
109}
110
111impl Group for Curve25519Subgroup {
112 #[cfg(feature = "curve25519-dalek")]
113 fn mul_generator(k: &Scalar) -> Self::Element {
114 k * ED25519_BASEPOINT_TABLE
115 }
116
117 #[cfg(feature = "curve25519-dalek-ng")]
118 fn mul_generator(k: &Scalar) -> Self::Element {
119 k * &ED25519_BASEPOINT_TABLE
120 }
121
122 fn vartime_mul_generator(k: &Scalar) -> Self::Element {
123 #[cfg(feature = "curve25519-dalek")]
124 let zero = Scalar::ZERO;
125 #[cfg(feature = "curve25519-dalek-ng")]
126 let zero = Scalar::zero();
127
128 EdwardsPoint::vartime_double_scalar_mul_basepoint(&zero, &EdwardsPoint::identity(), k)
129 }
130
131 fn multi_mul<'a, I, J>(scalars: I, elements: J) -> Self::Element
132 where
133 I: IntoIterator<Item = &'a Self::Scalar>,
134 J: IntoIterator<Item = Self::Element>,
135 {
136 EdwardsPoint::multiscalar_mul(scalars, elements)
137 }
138
139 fn vartime_double_mul_generator(
140 k: &Scalar,
141 k_element: Self::Element,
142 r: &Scalar,
143 ) -> Self::Element {
144 EdwardsPoint::vartime_double_scalar_mul_basepoint(k, &k_element, r)
145 }
146
147 fn vartime_multi_mul<'a, I, J>(scalars: I, elements: J) -> Self::Element
148 where
149 I: IntoIterator<Item = &'a Self::Scalar>,
150 J: IntoIterator<Item = Self::Element>,
151 {
152 EdwardsPoint::vartime_multiscalar_mul(scalars, elements)
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use rand::thread_rng;
159
160 use super::*;
161 use crate::{
162 curve25519::{constants::EIGHT_TORSION, scalar::Scalar, traits::Identity},
163 PublicKeyConversionError,
164 };
165
166 type PublicKey = crate::PublicKey<Curve25519Subgroup>;
167
168 #[test]
169 fn mangled_point_is_invalid_public_key() {
170 let mut rng = thread_rng();
171 for _ in 0..100 {
172 let mut point =
173 Curve25519Subgroup::mul_generator(&Curve25519Subgroup::generate_scalar(&mut rng));
174 point += EIGHT_TORSION[1];
175 assert!(!point.is_torsion_free());
176 let bytes = point.compress().to_bytes();
177 assert!(matches!(
178 PublicKey::from_bytes(&bytes).unwrap_err(),
179 PublicKeyConversionError::InvalidGroupElement
180 ));
181 }
182 }
183
184 #[test]
185 fn small_order_points_are_invalid_public_keys() {
186 let small_order = Scalar::from(8_u32);
187 for point in EIGHT_TORSION.iter().skip(1) {
190 assert_eq!(point * small_order, EdwardsPoint::identity());
191 let bytes = point.compress().to_bytes();
192 assert!(matches!(
193 PublicKey::from_bytes(&bytes).unwrap_err(),
194 PublicKeyConversionError::InvalidGroupElement
195 ));
196 }
197 }
198}