1use primeorder::{
2 elliptic_curve::{
3 point::PointCompression, Curve, CurveArithmetic, FieldBytes, FieldBytesEncoding,
4 },
5 point_arithmetic::EquationAIsMinusThree,
6 AffinePoint, PrimeCurve, PrimeCurveParams, ProjectivePoint,
7};
8
9#[cfg(feature = "ecdsa")]
10use ::ecdsa::hazmat::{DigestPrimitive, VerifyPrimitive};
11
12#[cfg(feature = "pkcs8")]
13use primeorder::elliptic_curve::pkcs8::{AssociatedOid, ObjectIdentifier};
14
15use crate::{
16 prime_field::{FieldElement, ReprSizeTypenum, ReprUint},
17 traits::{Modulus, PrimeFieldConstants},
18};
19
20#[cfg(feature = "ecdsa")]
21use crate::hash::TinyHash;
22
23const ORDER: u64 = 0xffff0f07;
24const FIELD_MODULUS: u64 = 0xffffff67;
25
26impl PrimeFieldConstants<u32> for Modulus<u32, FIELD_MODULUS> {
27 type Repr = FieldBytes<TinyCurve32>;
28 const MODULUS_STR: &'static str = "0xffffff67";
29 const MODULUS: u32 = FIELD_MODULUS as u32;
30 const NUM_BITS: u32 = 32;
31 const CAPACITY: u32 = 31;
32 const TWO_INV: u32 = 0x7fffffb4;
33 const MULTIPLICATIVE_GENERATOR: u32 = 3;
34 const S: u32 = 1;
35 const ROOT_OF_UNITY: u32 = 0xffffff66;
36 const ROOT_OF_UNITY_INV: u32 = 0xffffff66;
37 const DELTA: u32 = 9;
38}
39
40impl PrimeFieldConstants<u32> for Modulus<u32, ORDER> {
41 type Repr = FieldBytes<TinyCurve32>;
42 const MODULUS_STR: &'static str = "0xffff0f07";
43 const MODULUS: u32 = ORDER as u32;
44 const NUM_BITS: u32 = 32;
45 const CAPACITY: u32 = 31;
46 const TWO_INV: u32 = 0x7fff8784;
47 const MULTIPLICATIVE_GENERATOR: u32 = 3;
48 const S: u32 = 1;
49 const ROOT_OF_UNITY: u32 = 0xffff0f06;
50 const ROOT_OF_UNITY_INV: u32 = 0xffff0f06;
51 const DELTA: u32 = 9;
52}
53
54#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
56pub struct TinyCurve32;
57
58impl Curve for TinyCurve32 {
59 type FieldBytesSize = ReprSizeTypenum;
60 type Uint = ReprUint;
61 const ORDER: Self::Uint = Self::Uint::from_u64(ORDER);
62}
63
64impl FieldBytesEncoding<TinyCurve32> for <TinyCurve32 as Curve>::Uint {}
65
66impl CurveArithmetic for TinyCurve32 {
67 type Scalar = FieldElement<u32, ORDER>;
68 type AffinePoint = AffinePoint<Self>;
69 type ProjectivePoint = ProjectivePoint<Self>;
70}
71
72impl PrimeCurve for TinyCurve32 {}
73
74impl PrimeCurveParams for TinyCurve32 {
75 type FieldElement = FieldElement<u32, FIELD_MODULUS>;
76 type PointArithmetic = EquationAIsMinusThree;
77
78 const EQUATION_A: Self::FieldElement = FieldElement::new_unchecked(FIELD_MODULUS as u32 - 3);
79 const EQUATION_B: Self::FieldElement = FieldElement::new_unchecked(8);
80 const GENERATOR: (Self::FieldElement, Self::FieldElement) = (
81 FieldElement::new_unchecked(4274000713),
82 FieldElement::new_unchecked(443355223),
83 );
84}
85
86impl PointCompression for TinyCurve32 {
87 const COMPRESS_POINTS: bool = true;
88}
89
90#[cfg(feature = "ecdsa")]
91impl VerifyPrimitive<TinyCurve32> for AffinePoint<TinyCurve32> {}
92
93#[cfg(feature = "ecdsa")]
94impl DigestPrimitive for TinyCurve32 {
95 type Digest = TinyHash<4>;
96}
97
98#[cfg(feature = "pkcs8")]
99impl AssociatedOid for TinyCurve32 {
100 const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.202767.2");
101}
102
103#[cfg(test)]
104mod tests {
105 use primeorder::{
106 elliptic_curve::{
107 bigint::Encoding,
108 generic_array::GenericArray,
109 ops::{MulByGenerator, Reduce},
110 CurveArithmetic, Field, FieldBytesSize, ProjectivePoint,
111 },
112 PrimeField,
113 };
114 use proptest::prelude::*;
115 use rand_core::OsRng;
116
117 use super::TinyCurve32;
118 use crate::prime_field::ReprUint;
119
120 type Scalar = <TinyCurve32 as CurveArithmetic>::Scalar;
121 type Point = ProjectivePoint<TinyCurve32>;
122
123 #[test]
124 fn identity() {
125 let x = Scalar::random(&mut OsRng);
126 let y = Scalar::ZERO - x;
127 let p = Point::mul_by_generator(&x) + Point::mul_by_generator(&y);
128 assert_eq!(p, Point::IDENTITY);
129 }
130
131 #[test]
132 fn to_and_from_repr() {
133 let mut repr = GenericArray::<u8, FieldBytesSize<TinyCurve32>>::default();
134
135 let s = -Scalar::new_unchecked(1);
137 let s_uint: ReprUint = s.into();
138
139 let s_uint_repr = s_uint.to_be_bytes();
141 repr.copy_from_slice(&s_uint_repr);
142 let s_repr = s.to_repr();
143 assert_eq!(repr, s_repr);
144 assert_eq!(Scalar::from_repr(repr).unwrap(), s);
145
146 let x_uint = s_uint.wrapping_add(&ReprUint::ONE);
148 let x_uint_repr = x_uint.to_be_bytes();
149 repr.copy_from_slice(&x_uint_repr);
150 assert!(bool::from(Scalar::from_repr(repr).is_none()));
151 }
152
153 prop_compose! {
154 fn scalar()(n in any::<u64>()) -> Scalar {
156 Scalar::reduce(ReprUint::from(n))
157 }
158 }
159
160 proptest! {
161 #[test]
162 fn mul_by_generator(x in scalar(), y in scalar()) {
163 let p1 = Point::mul_by_generator(&x) + Point::mul_by_generator(&y);
164 let p2 = Point::mul_by_generator(&(x + y));
165 assert_eq!(p1, p2);
166 }
167 }
168}
169
170#[cfg(test)]
171mod tests_scalar {
172 use primeorder::{elliptic_curve::CurveArithmetic, Field, PrimeField};
173
174 use super::TinyCurve32;
175
176 type F = <TinyCurve32 as CurveArithmetic>::Scalar;
177
178 primeorder::impl_field_identity_tests!(F);
179 primeorder::impl_field_invert_tests!(F);
180 primeorder::impl_field_sqrt_tests!(F);
181
182 const T: [u64; 1] = [(F::MODULUS - 1) as u64 >> F::S];
184 primeorder::impl_primefield_tests!(F, T);
185}
186
187#[cfg(test)]
188mod tests_field_element {
189 use primeorder::{Field, PrimeCurveParams, PrimeField};
190
191 use super::TinyCurve32;
192
193 type F = <TinyCurve32 as PrimeCurveParams>::FieldElement;
194
195 primeorder::impl_field_identity_tests!(F);
196 primeorder::impl_field_invert_tests!(F);
197 primeorder::impl_field_sqrt_tests!(F);
198
199 const T: [u64; 1] = [(F::MODULUS - 1) as u64 >> F::S];
201 primeorder::impl_primefield_tests!(F, T);
202}
203
204#[cfg(all(test, feature = "ecdsa"))]
205mod tests_ecdsa {
206 use ecdsa::{SigningKey, VerifyingKey};
207 use rand_core::OsRng;
208
209 use super::TinyCurve32;
210
211 #[test]
212 fn sign_and_verify() {
213 let prehash = b"123456781234567812345678";
214 let sk = SigningKey::<TinyCurve32>::random(&mut OsRng);
215
216 let (signature, recovery_id) = sk.sign_prehash_recoverable(prehash).unwrap();
217 let vk = VerifyingKey::recover_from_prehash(prehash, &signature, recovery_id).unwrap();
218 assert_eq!(sk.verifying_key(), &vk);
219 }
220}
221
222#[cfg(all(test, feature = "pkcs8"))]
223mod tests_pkcs8 {
224 use primeorder::elliptic_curve::{
225 pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey},
226 PublicKey, SecretKey,
227 };
228 use rand_core::OsRng;
229
230 use super::TinyCurve32;
231
232 #[test]
233 fn serialize_secret_key() {
234 let sk = SecretKey::<TinyCurve32>::random(&mut OsRng);
235 let der = sk.to_pkcs8_der().unwrap();
236 let sk_back = SecretKey::<TinyCurve32>::from_pkcs8_der(der.as_bytes()).unwrap();
237 assert_eq!(sk, sk_back);
238 }
239
240 #[test]
241 fn serialize_public_key() {
242 let sk = SecretKey::<TinyCurve32>::random(&mut OsRng);
243 let pk = sk.public_key();
244 let der = pk.to_public_key_der().unwrap();
245 let pk_back = PublicKey::<TinyCurve32>::from_public_key_der(der.as_bytes()).unwrap();
246 assert_eq!(pk, pk_back);
247 }
248}