ed448_goldilocks_plus/
lib.rs

1//! This crate provides a pure Rust implementation of Curve448, Edwards, Decaf, and Ristretto.
2//! It is intended to be portable, fast, and safe.
3//!
4//! # Usage
5//! ```
6//! use ed448_goldilocks_plus::{EdwardsPoint, CompressedEdwardsY, Scalar, elliptic_curve::hash2curve::ExpandMsgXof, sha3::Shake256};
7//! use rand_core::OsRng;
8//!
9//! let secret_key = Scalar::TWO;
10//! let public_key = EdwardsPoint::GENERATOR * &secret_key;
11//!
12//! assert_eq!(public_key, EdwardsPoint::GENERATOR + EdwardsPoint::GENERATOR);
13//!
14//! let secret_key = Scalar::random(&mut OsRng);
15//! let public_key = EdwardsPoint::GENERATOR * &secret_key;
16//! let compressed_public_key = public_key.compress();
17//!
18//! assert_eq!(compressed_public_key.to_bytes().len(), 57);
19//!
20//! let hashed_scalar = Scalar::hash::<ExpandMsgXof<Shake256>>(b"test", b"edwards448_XOF:SHAKE256_ELL2_RO_");
21//! let input = hex_literal::hex!("c8c6c8f584e0c25efdb6af5ad234583c56dedd7c33e0c893468e96740fa0cf7f1a560667da40b7bde340a39252e89262fcf707d1180fd43400");
22//! let expected_scalar = Scalar::from_canonical_bytes(&input.into()).unwrap();
23//! assert_eq!(hashed_scalar, expected_scalar);
24//!
25//! let hashed_point = EdwardsPoint::hash::<ExpandMsgXof<Shake256>>(b"test", b"edwards448_XOF:SHAKE256_ELL2_RO_");
26//! let expected = hex_literal::hex!("d15c4427b5c5611a53593c2be611fd3635b90272d331c7e6721ad3735e95dd8b9821f8e4e27501ce01aa3c913114052dce2e91e8ca050f4980");
27//! let expected_point = CompressedEdwardsY(expected).decompress().unwrap();
28//! assert_eq!(hashed_point, expected_point);
29//!
30//! let hashed_point = EdwardsPoint::hash_with_defaults(b"test");
31//! assert_eq!(hashed_point, expected_point);
32//! ```
33//!
34//! [`EdwardsPoint`] implements the [`elliptic_curve::Group`] and [`elliptic_curve::group::GroupEncoding`]
35//! and [`Scalar`] implements [`elliptic_curve::Field`] and [`elliptic_curve::PrimeField`] traits.
36// XXX: Change this to deny later on
37#![warn(unused_attributes, unused_imports, unused_mut, unused_must_use)]
38#![allow(non_snake_case)]
39#![cfg_attr(all(not(feature = "alloc"), not(feature = "std")), no_std)]
40#![cfg_attr(docsrs, feature(doc_auto_cfg))]
41#![warn(
42    missing_docs,
43    missing_debug_implementations,
44    missing_copy_implementations,
45    trivial_casts,
46    trivial_numeric_casts,
47    unused,
48    clippy::mod_module_files
49)]
50#![deny(clippy::unwrap_used)]
51
52#[cfg(all(feature = "alloc", not(feature = "std")))]
53extern crate alloc;
54#[cfg(feature = "std")]
55extern crate std;
56
57#[cfg(all(feature = "alloc", not(feature = "std")))]
58use alloc::{boxed::Box, vec::Vec};
59
60// Internal macros. Must come first!
61#[macro_use]
62pub(crate) mod macros;
63
64pub use elliptic_curve;
65pub use rand_core;
66pub use sha3;
67pub use subtle;
68
69// As usual, we will use this file to carefully define the API/ what we expose to the user
70pub(crate) mod constants;
71pub(crate) mod curve;
72pub(crate) mod decaf;
73pub(crate) mod field;
74pub(crate) mod ristretto;
75#[cfg(feature = "signing")]
76pub(crate) mod sign;
77
78pub(crate) use field::{GOLDILOCKS_BASE_POINT, TWISTED_EDWARDS_BASE_POINT};
79
80pub use curve::{
81    AffinePoint, CompressedEdwardsY, EdwardsPoint, MontgomeryPoint, ProjectiveMontgomeryPoint,
82};
83pub use decaf::{AffinePoint as DecafAffinePoint, CompressedDecaf, DecafPoint};
84pub use field::{Scalar, ScalarBytes, WideScalarBytes, MODULUS_LIMBS, ORDER, WIDE_ORDER};
85pub use ristretto::{CompressedRistretto, RistrettoPoint};
86#[cfg(feature = "signing")]
87pub use sign::*;
88
89use elliptic_curve::{
90    bigint::{ArrayEncoding, ByteArray, U448},
91    generic_array::typenum::U57,
92    point::PointCompression,
93    Curve, FieldBytesEncoding, PrimeCurve,
94};
95
96/// Edwards448 curve.
97#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
98pub struct Ed448;
99
100/// Bytes of the Ed448 field
101pub type Ed448FieldBytes = elliptic_curve::FieldBytes<Ed448>;
102
103/// Scalar bits of the Ed448 scalar
104pub type Ed448ScalarBits = elliptic_curve::scalar::ScalarBits<Ed448>;
105
106/// Non-zero scalar of the Ed448 scalar
107pub type Ed448NonZeroScalar = elliptic_curve::NonZeroScalar<Ed448>;
108
109unsafe impl Send for Ed448 {}
110unsafe impl Sync for Ed448 {}
111
112impl Curve for Ed448 {
113    type FieldBytesSize = U57;
114    type Uint = U448;
115
116    const ORDER: U448 = ORDER;
117}
118
119impl PrimeCurve for Ed448 {}
120
121impl PointCompression for Ed448 {
122    const COMPRESS_POINTS: bool = true;
123}
124
125impl FieldBytesEncoding<Ed448> for U448 {
126    fn decode_field_bytes(field_bytes: &Ed448FieldBytes) -> Self {
127        let data = ByteArray::<U448>::from_slice(field_bytes);
128        U448::from_le_byte_array(*data)
129    }
130
131    fn encode_field_bytes(&self) -> Ed448FieldBytes {
132        let mut data = Ed448FieldBytes::default();
133        data.copy_from_slice(&self.to_le_byte_array()[..]);
134        data
135    }
136}
137
138#[cfg(feature = "zeroize")]
139impl elliptic_curve::CurveArithmetic for Ed448 {
140    type AffinePoint = AffinePoint;
141    type ProjectivePoint = EdwardsPoint;
142    type Scalar = Scalar;
143}
144
145/// Decaf448 curve.
146#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
147pub struct Decaf448;
148
149/// Bytes of the Decaf448 field
150pub type Decaf448FieldBytes = elliptic_curve::FieldBytes<Decaf448>;
151
152/// Scalar bits of the Decaf448 scalar
153pub type Decaf448ScalarBits = elliptic_curve::scalar::ScalarBits<Decaf448>;
154
155/// Non-zero scalar of the Decaf448 scalar
156pub type Decaf448NonZeroScalar = elliptic_curve::NonZeroScalar<Decaf448>;
157
158unsafe impl Send for Decaf448 {}
159unsafe impl Sync for Decaf448 {}
160
161impl Curve for Decaf448 {
162    type FieldBytesSize = U57;
163    type Uint = U448;
164
165    const ORDER: U448 = ORDER;
166}
167
168impl PrimeCurve for Decaf448 {}
169
170impl PointCompression for Decaf448 {
171    const COMPRESS_POINTS: bool = true;
172}
173
174impl FieldBytesEncoding<Decaf448> for U448 {
175    fn decode_field_bytes(field_bytes: &Decaf448FieldBytes) -> Self {
176        let data = ByteArray::<U448>::from_slice(field_bytes);
177        U448::from_le_byte_array(*data)
178    }
179
180    fn encode_field_bytes(&self) -> Decaf448FieldBytes {
181        let mut data = Decaf448FieldBytes::default();
182        data.copy_from_slice(&self.to_le_byte_array()[..]);
183        data
184    }
185}
186
187#[cfg(feature = "zeroize")]
188impl elliptic_curve::CurveArithmetic for Decaf448 {
189    type AffinePoint = DecafAffinePoint;
190    type ProjectivePoint = DecafPoint;
191    type Scalar = Scalar;
192}