elastic_elgamal/group/
generic.rs1use core::marker::PhantomData;
2
3use elliptic_curve::{
4 CurveArithmetic, Field, FieldBytesSize, Group as _, ProjectivePoint, Scalar,
5 array::{Array, typenum::Unsigned},
6 ff::PrimeField,
7 rand_core::{CryptoRng, RngCore},
8 sec1::{EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint},
9 zeroize::Zeroize,
10};
11
12use super::{ElementOps, Group, ScalarOps};
13
14#[derive(Debug)]
24pub struct Generic<C>(PhantomData<C>);
25
26impl<C> Clone for Generic<C> {
27 fn clone(&self) -> Self {
28 *self
29 }
30}
31
32impl<C> Copy for Generic<C> {}
33
34impl<C> ScalarOps for Generic<C>
35where
36 C: CurveArithmetic,
37 Scalar<C>: Zeroize,
38{
39 type Scalar = Scalar<C>;
40
41 const SCALAR_SIZE: usize = <FieldBytesSize<C> as Unsigned>::USIZE;
42
43 fn generate_scalar<R: CryptoRng + RngCore>(rng: &mut R) -> Self::Scalar {
44 Scalar::<C>::random(rng)
45 }
46
47 fn invert_scalar(scalar: Self::Scalar) -> Self::Scalar {
48 scalar.invert().unwrap()
49 }
50
51 fn serialize_scalar(scalar: &Self::Scalar, buffer: &mut [u8]) {
52 buffer.copy_from_slice(scalar.to_repr().as_ref());
53 }
54
55 fn deserialize_scalar(buffer: &[u8]) -> Option<Self::Scalar> {
56 Scalar::<C>::from_repr(Array::try_from(buffer).unwrap().clone()).into()
58 }
59}
60
61impl<C> ElementOps for Generic<C>
62where
63 C: CurveArithmetic,
64 Scalar<C>: Zeroize,
65 FieldBytesSize<C>: ModulusSize,
66 ProjectivePoint<C>: ToEncodedPoint<C> + FromEncodedPoint<C>,
67{
68 type Element = ProjectivePoint<C>;
69
70 const ELEMENT_SIZE: usize = <FieldBytesSize<C> as Unsigned>::USIZE + 1;
71
72 #[inline]
73 fn identity() -> Self::Element {
74 C::ProjectivePoint::identity()
75 }
76
77 #[inline]
78 fn is_identity(element: &Self::Element) -> bool {
79 element.is_identity().into()
80 }
81
82 #[inline]
83 fn generator() -> Self::Element {
84 C::ProjectivePoint::generator()
85 }
86
87 fn serialize_element(element: &Self::Element, buffer: &mut [u8]) {
88 let encoded_point = element.to_encoded_point(true);
89 buffer.copy_from_slice(encoded_point.as_bytes());
90 }
91
92 fn deserialize_element(input: &[u8]) -> Option<Self::Element> {
93 let encoded_point = EncodedPoint::<C>::from_bytes(input).ok()?;
94 ProjectivePoint::<C>::from_encoded_point(&encoded_point).into()
95 }
96}
97
98impl<C> Group for Generic<C>
99where
100 C: CurveArithmetic + 'static,
101 Scalar<C>: Zeroize,
102 FieldBytesSize<C>: ModulusSize,
103 ProjectivePoint<C>: ToEncodedPoint<C> + FromEncodedPoint<C>,
104{
105 }
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 type K256 = Generic<k256::Secp256k1>;
113
114 #[test]
115 fn scalar_roundtrip() {
116 let mut rng = rand::rng();
117 let mut buffer = [0_u8; K256::SCALAR_SIZE];
118 for _ in 0..100 {
119 let scalar = K256::generate_scalar(&mut rng);
120 K256::serialize_scalar(&scalar, &mut buffer);
121 assert_eq!(K256::deserialize_scalar(&buffer).unwrap(), scalar);
122 }
123 }
124
125 #[test]
126 fn point_roundtrip() {
127 let mut rng = rand::rng();
128 let mut buffer = [0_u8; K256::ELEMENT_SIZE];
129 for _ in 0..100 {
130 let point = K256::mul_generator(&K256::generate_scalar(&mut rng));
131 K256::serialize_element(&point, &mut buffer);
132 assert_eq!(K256::deserialize_element(&buffer).unwrap(), point);
133 }
134 }
135}