tiny_curve/
curve16.rs

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 = 0xfe93;
24const FIELD_MODULUS: u64 = 0xffa7;
25
26impl PrimeFieldConstants<u16> for Modulus<u16, FIELD_MODULUS> {
27    type Repr = FieldBytes<TinyCurve16>;
28    const MODULUS_STR: &'static str = "0xffa7";
29    const MODULUS: u16 = FIELD_MODULUS as u16;
30    const NUM_BITS: u32 = 16;
31    const CAPACITY: u32 = 15;
32    const TWO_INV: u16 = 0x7fd4;
33    const MULTIPLICATIVE_GENERATOR: u16 = 5;
34    const S: u32 = 1;
35    const ROOT_OF_UNITY: u16 = 0xffa6;
36    const ROOT_OF_UNITY_INV: u16 = 0xffa6;
37    const DELTA: u16 = 25;
38}
39
40impl PrimeFieldConstants<u16> for Modulus<u16, ORDER> {
41    type Repr = FieldBytes<TinyCurve16>;
42    const MODULUS_STR: &'static str = "0xfe93";
43    const MODULUS: u16 = ORDER as u16;
44    const NUM_BITS: u32 = 16;
45    const CAPACITY: u32 = 15;
46    const TWO_INV: u16 = 0x7f4a;
47    const MULTIPLICATIVE_GENERATOR: u16 = 2;
48    const S: u32 = 1;
49    const ROOT_OF_UNITY: u16 = 0xfe92;
50    const ROOT_OF_UNITY_INV: u16 = 0xfe92;
51    const DELTA: u16 = 4;
52}
53
54/// An elliptic curve with a 16-bit order.
55#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
56pub struct TinyCurve16;
57
58impl Curve for TinyCurve16 {
59    type FieldBytesSize = ReprSizeTypenum;
60    type Uint = ReprUint;
61    const ORDER: Self::Uint = Self::Uint::from_u64(ORDER);
62}
63
64impl FieldBytesEncoding<TinyCurve16> for <TinyCurve16 as Curve>::Uint {}
65
66impl CurveArithmetic for TinyCurve16 {
67    type Scalar = FieldElement<u16, ORDER>;
68    type AffinePoint = AffinePoint<Self>;
69    type ProjectivePoint = ProjectivePoint<Self>;
70}
71
72impl PrimeCurve for TinyCurve16 {}
73
74impl PrimeCurveParams for TinyCurve16 {
75    type FieldElement = FieldElement<u16, FIELD_MODULUS>;
76    type PointArithmetic = EquationAIsMinusThree;
77
78    const EQUATION_A: Self::FieldElement = FieldElement::new_unchecked(FIELD_MODULUS as u16 - 3);
79    const EQUATION_B: Self::FieldElement = FieldElement::new_unchecked(7);
80    const GENERATOR: (Self::FieldElement, Self::FieldElement) = (
81        FieldElement::new_unchecked(23947),
82        FieldElement::new_unchecked(53757),
83    );
84}
85
86impl PointCompression for TinyCurve16 {
87    const COMPRESS_POINTS: bool = true;
88}
89
90#[cfg(feature = "ecdsa")]
91impl VerifyPrimitive<TinyCurve16> for AffinePoint<TinyCurve16> {}
92
93#[cfg(feature = "ecdsa")]
94impl DigestPrimitive for TinyCurve16 {
95    type Digest = TinyHash<2>;
96}
97
98#[cfg(feature = "pkcs8")]
99impl AssociatedOid for TinyCurve16 {
100    const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.202767.1");
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::TinyCurve16;
118    use crate::prime_field::ReprUint;
119
120    type Scalar = <TinyCurve16 as CurveArithmetic>::Scalar;
121    type Point = ProjectivePoint<TinyCurve16>;
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<TinyCurve16>>::default();
134
135        // `s` now contains the value `M - 1`.
136        let s = -Scalar::new_unchecked(1);
137        let s_uint: ReprUint = s.into();
138
139        // Check that to_repr/from_repr work normally
140        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        // Now construct a representation of the value `M` (which would be out of range)
147        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        /// Generate a random odd modulus.
155        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::TinyCurve16;
175
176    type F = <TinyCurve16 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    // t = (modulus - 1) >> S
183    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::TinyCurve16;
192
193    type F = <TinyCurve16 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    // t = (modulus - 1) >> S
200    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::TinyCurve16;
210
211    #[test]
212    fn sign_and_verify() {
213        let prehash = b"123456781234567812345678";
214        let sk = SigningKey::<TinyCurve16>::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::TinyCurve16;
231
232    #[test]
233    fn serialize_secret_key() {
234        let sk = SecretKey::<TinyCurve16>::random(&mut OsRng);
235        let der = sk.to_pkcs8_der().unwrap();
236        let sk_back = SecretKey::<TinyCurve16>::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::<TinyCurve16>::random(&mut OsRng);
243        let pk = sk.public_key();
244        let der = pk.to_public_key_der().unwrap();
245        let pk_back = PublicKey::<TinyCurve16>::from_public_key_der(der.as_bytes()).unwrap();
246        assert_eq!(pk, pk_back);
247    }
248}