primitives/algebra/elliptic_curve/
point.rs1use std::{
2 hash::Hash,
3 iter::Sum,
4 mem::MaybeUninit,
5 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
6};
7
8use elliptic_curve::group::{Group, GroupEncoding};
9use rand::{
10 distributions::{Distribution, Standard},
11 RngCore,
12};
13use serde::{Deserialize, Serialize};
14use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
15
16use crate::{
17 algebra::elliptic_curve::{
18 curve::{FromCoordinates, PointAtInfinityError, PointCoordinates, ToCoordinates},
19 Curve,
20 Scalar,
21 ScalarAsExtension,
22 },
23 errors::PrimitiveError,
24 random::{CryptoRngCore, Random},
25 sharing::unauthenticated::AdditiveShares,
26 utils::codec::InPlaceCodec,
27};
28
29#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Hash)]
31#[repr(transparent)]
32pub struct Point<C: Curve>(pub(crate) C::Point);
33
34unsafe impl<C: Curve> bytemuck::TransparentWrapper<C::Point> for Point<C> {}
36
37unsafe impl<C: Curve> InPlaceCodec for Point<C> {
42 const ENCODED_SIZE: usize = size_of::<<C::Point as GroupEncoding>::Repr>();
43
44 fn write_le_bytes(&self, out: &mut [MaybeUninit<u8>]) {
45 let mut bytes = self.0.to_bytes();
46 if C::POINT_BIG_ENDIAN {
47 bytes.as_mut().reverse();
48 }
49 for (slot, &b) in out.iter_mut().zip(bytes.as_ref()) {
50 slot.write(b);
51 }
52 }
53
54 fn read_le_bytes(bytes: &[u8]) -> Result<Self, PrimitiveError> {
55 let mut repr = <C::Point as GroupEncoding>::Repr::default();
56 if bytes.len() != repr.as_ref().len() {
57 return Err(PrimitiveError::InvalidSize(
58 repr.as_ref().len(),
59 bytes.len(),
60 ));
61 }
62 repr.as_mut().copy_from_slice(bytes);
63 if C::POINT_BIG_ENDIAN {
64 repr.as_mut().reverse();
65 }
66 Option::from(C::Point::from_bytes(&repr))
67 .map(Point)
68 .ok_or_else(|| {
69 PrimitiveError::DeserializationFailed("invalid curve point encoding".into())
70 })
71 }
72}
73
74impl<C: Curve> Serialize for Point<C> {
80 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
81 use serde::ser::SerializeTuple;
82 let bytes = self.to_inplace_bytes();
83 let mut tup = serializer.serialize_tuple(bytes.len())?;
84 for b in &bytes {
85 tup.serialize_element(b)?;
86 }
87 tup.end()
88 }
89}
90
91impl<'de, C: Curve> Deserialize<'de> for Point<C> {
92 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
93 struct PointVisitor<C>(std::marker::PhantomData<C>);
94
95 impl<'de, C: Curve> serde::de::Visitor<'de> for PointVisitor<C> {
96 type Value = Point<C>;
97
98 fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 write!(f, "{} bytes", Point::<C>::ENCODED_SIZE)
100 }
101
102 fn visit_seq<A: serde::de::SeqAccess<'de>>(
103 self,
104 mut seq: A,
105 ) -> Result<Self::Value, A::Error> {
106 let mut bytes = Vec::with_capacity(Point::<C>::ENCODED_SIZE);
107 while let Some(b) = seq.next_element::<u8>()? {
108 bytes.push(b);
109 }
110 Point::<C>::from_inplace_bytes(&bytes).map_err(serde::de::Error::custom)
111 }
112 }
113
114 deserializer.deserialize_tuple(
115 Point::<C>::ENCODED_SIZE,
116 PointVisitor(std::marker::PhantomData),
117 )
118 }
119}
120
121impl<C: Curve> Point<C> {
126 pub fn identity() -> Point<C> {
128 Point(C::Point::identity())
129 }
130
131 pub fn new(point: C::Point) -> Point<C> {
132 Point(point)
133 }
134
135 pub fn is_identity(&self) -> Choice {
137 self.ct_eq(&Point::identity())
138 }
139
140 pub fn inner(&self) -> C::Point {
142 self.0
143 }
144
145 pub fn generator() -> Point<C> {
147 Point(<C::Point as Group>::generator())
148 }
149
150 pub fn from_coordinates(coordinates: PointCoordinates<C>) -> Option<Point<C>> {
151 C::Point::from_coordinates(coordinates).map(Point)
152 }
153
154 pub fn to_coordinates(self) -> Result<PointCoordinates<C>, PointAtInfinityError> {
155 self.0.to_coordinates()
156 }
157}
158
159impl<C: Curve> Random for Point<C> {
160 #[inline]
161 fn random(rng: impl CryptoRngCore) -> Self {
162 Point(C::Point::random(rng))
163 }
164}
165
166impl<C: Curve> Distribution<Point<C>> for Standard {
167 #[inline]
168 fn sample<R: RngCore + ?Sized>(&self, rng: &mut R) -> Point<C> {
169 Point(C::Point::random(rng))
170 }
171}
172
173#[macros::op_variants(owned, borrowed, flipped_commutative)]
180impl<C: Curve> Add<&Point<C>> for Point<C> {
181 type Output = Point<C>;
182
183 #[inline]
184 fn add(mut self, rhs: &Point<C>) -> Self::Output {
185 self.0 += rhs.0;
186 self
187 }
188}
189
190#[macros::op_variants(owned)]
191impl<C: Curve> AddAssign<&Point<C>> for Point<C> {
192 #[inline]
193 fn add_assign(&mut self, rhs: &Point<C>) {
194 self.0 += rhs.0;
195 }
196}
197
198#[macros::op_variants(owned, borrowed, flipped)]
201impl<C: Curve> Sub<&Point<C>> for Point<C> {
202 type Output = Point<C>;
203
204 #[inline]
205 fn sub(mut self, rhs: &Point<C>) -> Self::Output {
206 self.0 -= rhs.0;
207 self
208 }
209}
210
211#[macros::op_variants(owned)]
212impl<C: Curve> SubAssign<&Point<C>> for Point<C> {
213 #[inline]
214 fn sub_assign(&mut self, rhs: &Point<C>) {
215 self.0 -= rhs.0;
216 }
217}
218
219#[macros::op_variants(borrowed)]
222impl<C: Curve> Neg for Point<C> {
223 type Output = Point<C>;
224
225 #[inline]
226 fn neg(self) -> Self::Output {
227 Point(-self.0)
228 }
229}
230
231#[macros::op_variants(owned, borrowed, flipped)]
234impl<C: Curve> Mul<&ScalarAsExtension<C>> for Point<C> {
235 type Output = Point<C>;
236
237 #[inline]
238 fn mul(mut self, rhs: &ScalarAsExtension<C>) -> Self::Output {
239 self.0 *= rhs.0;
240 self
241 }
242}
243
244#[macros::op_variants(owned, borrowed, flipped_commutative)]
245impl<C: Curve> Mul<&Point<C>> for ScalarAsExtension<C> {
246 type Output = Point<C>;
247
248 #[inline]
249 fn mul(self, rhs: &Point<C>) -> Self::Output {
250 Point(rhs.0 * self.0)
251 }
252}
253
254#[macros::op_variants(owned, borrowed, flipped)]
255impl<C: Curve> Mul<&Scalar<C>> for Point<C> {
256 type Output = Point<C>;
257
258 #[inline]
259 fn mul(self, rhs: &Scalar<C>) -> Self::Output {
260 Point(self.0 * rhs.0)
261 }
262}
263
264#[macros::op_variants(owned, borrowed, flipped_commutative)]
265impl<C: Curve> Mul<&Point<C>> for Scalar<C> {
266 type Output = Point<C>;
267
268 #[inline]
269 fn mul(self, rhs: &Point<C>) -> Self::Output {
270 Point(rhs.0 * self.0)
271 }
272}
273
274#[macros::op_variants(owned)]
277impl<C: Curve> MulAssign<&ScalarAsExtension<C>> for Point<C> {
278 #[inline]
279 fn mul_assign(&mut self, rhs: &ScalarAsExtension<C>) {
280 self.0 *= rhs.0;
281 }
282}
283
284#[macros::op_variants(owned)]
285impl<C: Curve> MulAssign<&Scalar<C>> for Point<C> {
286 #[inline]
287 fn mul_assign(&mut self, rhs: &Scalar<C>) {
288 self.0 *= rhs.0;
289 }
290}
291
292impl<C: Curve> ConstantTimeEq for Point<C> {
295 #[inline]
296 fn ct_eq(&self, other: &Self) -> Choice {
297 self.0.ct_eq(&other.0)
298 }
299}
300
301impl<C: Curve> ConditionallySelectable for Point<C> {
302 #[inline]
303 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
304 let selected = C::Point::conditional_select(&a.0, &b.0, choice);
305 Point(selected)
306 }
307}
308
309impl<C: Curve> AdditiveShares for Point<C> {}
312
313impl<C: Curve> Sum for Point<C> {
316 #[inline]
317 fn sum<I: Iterator<Item = Point<C>>>(iter: I) -> Self {
318 iter.fold(Point::identity(), |acc, x| acc + x)
319 }
320}
321
322impl<'a, C: Curve> Sum<&'a Point<C>> for Point<C> {
323 #[inline]
324 fn sum<I: Iterator<Item = &'a Point<C>>>(iter: I) -> Self {
325 iter.fold(Point::identity(), |acc, x| acc + x)
326 }
327}
328
329#[cfg(test)]
330mod tests {
331 use super::*;
332 use crate::{algebra::elliptic_curve::Curve25519Ristretto, utils::bincode_io};
333
334 #[test]
335 fn test_point_serialization() {
336 let point = Point::<Curve25519Ristretto>::generator();
337 let bytes = point.to_inplace_bytes();
338 let deserialized_point = Point::<Curve25519Ristretto>::from_inplace_bytes(&bytes).unwrap();
339 assert_eq!(point, deserialized_point);
340
341 let bytes = bytes[1..].to_vec(); let result = Point::<Curve25519Ristretto>::from_inplace_bytes(&bytes);
343 assert!(result.is_err());
344 }
345
346 #[test]
347 fn test_point_serde_roundtrip() {
348 let point = Point::<Curve25519Ristretto>::generator();
349 let serialized = bincode_io::serialize(&point).unwrap();
350 assert_eq!(serialized, point.to_inplace_bytes(), "no length prefix");
351 let deserialized: Point<Curve25519Ristretto> =
352 bincode_io::deserialize(&serialized).unwrap();
353 assert_eq!(point, deserialized);
354 }
355}