mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Move the contents of the evrf/ folder to the crypto/ folder
It was justified when it had several libraries, which it no longer does thanks to the upstreaming with monero-oxide.
This commit is contained in:
45
crypto/embedwards25519/Cargo.toml
Normal file
45
crypto/embedwards25519/Cargo.toml
Normal file
@@ -0,0 +1,45 @@
|
||||
[package]
|
||||
name = "embedwards25519"
|
||||
version = "0.1.0"
|
||||
description = "A curve defined over the Ed25519 scalar field"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/embedwards25519"
|
||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||
keywords = ["curve25519", "ed25519", "ristretto255", "group"]
|
||||
edition = "2021"
|
||||
rust-version = "1.86"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[dependencies]
|
||||
hex-literal = { version = "0.4", default-features = false }
|
||||
|
||||
std-shims = { version = "0.1", path = "../../common/std-shims", default-features = false, optional = true }
|
||||
|
||||
zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] }
|
||||
|
||||
generic-array = { version = "1", default-features = false }
|
||||
|
||||
prime-field = { path = "../prime-field", default-features = false }
|
||||
short-weierstrass = { path = "../short-weierstrass", default-features = false }
|
||||
curve25519-dalek = { version = "4", default-features = false, features = ["legacy_compatibility"] }
|
||||
dalek-ff-group = { path = "../dalek-ff-group", version = "0.4", default-features = false }
|
||||
|
||||
blake2 = { version = "0.10", default-features = false }
|
||||
ciphersuite = { path = "../ciphersuite", version = "0.4", default-features = false }
|
||||
|
||||
generalized-bulletproofs-ec-gadgets = { git = "https://github.com/monero-oxide/monero-oxide", rev = "a6f8797007e768488568b821435cf5006517a962", default-features = false, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
hex = "0.4"
|
||||
|
||||
rand_core = { version = "0.6", features = ["std"] }
|
||||
|
||||
ff-group-tests = { path = "../ff-group-tests" }
|
||||
|
||||
[features]
|
||||
alloc = ["std-shims", "zeroize/alloc", "prime-field/alloc", "short-weierstrass/alloc", "curve25519-dalek/alloc", "ciphersuite/alloc", "generalized-bulletproofs-ec-gadgets"]
|
||||
std = ["alloc", "std-shims/std", "zeroize/std", "prime-field/std", "short-weierstrass/std", "blake2/std", "ciphersuite/std", "generalized-bulletproofs-ec-gadgets/std"]
|
||||
default = ["std"]
|
||||
21
crypto/embedwards25519/LICENSE
Normal file
21
crypto/embedwards25519/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022-2025 Luke Parker
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
21
crypto/embedwards25519/README.md
Normal file
21
crypto/embedwards25519/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# embedwards25519
|
||||
|
||||
A curve defined over the Ed25519 scalar field.
|
||||
|
||||
This curve was found via
|
||||
[tevador's script](https://gist.github.com/tevador/4524c2092178df08996487d4e272b096)
|
||||
for finding curves (specifically, curve cycles), modified to search for curves
|
||||
whose field is the Ed25519 scalar field (not the Ed25519 field).
|
||||
|
||||
```ignore
|
||||
p = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed
|
||||
q = 0x0fffffffffffffffffffffffffffffffe53f4debb78ff96877063f0306eef96b
|
||||
D = -420435
|
||||
y^2 = x^3 - 3*x + 4188043517836764736459661287169077812555441231147410753119540549773825148767
|
||||
```
|
||||
|
||||
The embedding degree is `(q-1)/2`.
|
||||
|
||||
This curve should not be used with single-coordinate ladders, and points should
|
||||
always be represented in a compressed form (preventing receiving off-curve
|
||||
points).
|
||||
151
crypto/embedwards25519/src/lib.rs
Normal file
151
crypto/embedwards25519/src/lib.rs
Normal file
@@ -0,0 +1,151 @@
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use std_shims::prelude::*;
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
use std_shims::io::{self, Read};
|
||||
|
||||
use prime_field::{subtle::Choice, zeroize::Zeroize};
|
||||
use ciphersuite::group::{
|
||||
ff::{Field, PrimeField, FromUniformBytes},
|
||||
Group,
|
||||
};
|
||||
|
||||
use curve25519_dalek::Scalar as DalekScalar;
|
||||
pub use dalek_ff_group::Scalar as FieldElement;
|
||||
|
||||
use short_weierstrass::{ShortWeierstrass, Affine, Projective};
|
||||
|
||||
prime_field::odd_prime_field!(
|
||||
Scalar,
|
||||
"0fffffffffffffffffffffffffffffffe53f4debb78ff96877063f0306eef96b",
|
||||
"0a",
|
||||
false
|
||||
);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
|
||||
pub struct Embedwards25519;
|
||||
|
||||
#[allow(deprecated)] // No other way to construct arbitrary `FieldElement` at compile-time :/
|
||||
impl ShortWeierstrass for Embedwards25519 {
|
||||
type FieldElement = FieldElement;
|
||||
const A: FieldElement = FieldElement(DalekScalar::from_bits(hex_literal::hex!(
|
||||
"ead3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"
|
||||
)));
|
||||
const B: FieldElement = FieldElement(DalekScalar::from_bits(hex_literal::hex!(
|
||||
"5f07603a853f20370b682036210d463e64903a23ea669d07ca26cfc13f594209"
|
||||
)));
|
||||
const PRIME_ORDER: bool = true;
|
||||
const GENERATOR: Affine<Self> = Affine::from_xy_unchecked(
|
||||
FieldElement::ONE,
|
||||
FieldElement(DalekScalar::from_bits(hex_literal::hex!(
|
||||
"2e4118080a484a3dfbafe2199a0e36b7193581d676c0dadfa376b0265616020c"
|
||||
))),
|
||||
);
|
||||
type Scalar = Scalar;
|
||||
|
||||
type Repr = [u8; 32];
|
||||
// Use an all-zero encoding for the identity as `0` isn't the `x` coordinate of an on-curve point
|
||||
const IDENTITY: [u8; 32] = [0; 32];
|
||||
fn encode_compressed(x: Self::FieldElement, odd_y: Choice) -> Self::Repr {
|
||||
// The LE `x` coordinate, with if `y` is odd in the unused 256th bit
|
||||
let mut res = [0; 32];
|
||||
res.as_mut().copy_from_slice(x.to_repr().as_ref());
|
||||
res[31] |= odd_y.unwrap_u8() << 7;
|
||||
res
|
||||
}
|
||||
fn decode_compressed(bytes: &Self::Repr) -> (<Self::FieldElement as PrimeField>::Repr, Choice) {
|
||||
// Extract and clear the sign bit
|
||||
let mut bytes = *bytes;
|
||||
let odd_y = Choice::from(bytes[31] >> 7);
|
||||
bytes[31] &= u8::MAX >> 1;
|
||||
|
||||
// Copy from the point's representation to the field's
|
||||
let mut repr = <Self::FieldElement as PrimeField>::Repr::default();
|
||||
repr.as_mut().copy_from_slice(&bytes);
|
||||
|
||||
(repr, odd_y)
|
||||
}
|
||||
// No points have a torsion element as this a prime-order curve
|
||||
fn has_torsion_element(_point: Projective<Self>) -> Choice {
|
||||
0.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub type Point = Projective<Embedwards25519>;
|
||||
|
||||
impl ciphersuite::Ciphersuite for Embedwards25519 {
|
||||
type F = Scalar;
|
||||
type G = Point;
|
||||
type H = blake2::Blake2b512;
|
||||
|
||||
const ID: &'static [u8] = b"embedwards25519";
|
||||
|
||||
fn generator() -> Self::G {
|
||||
Point::generator()
|
||||
}
|
||||
|
||||
/// `hash_to_F` is implemented with a naive concatenation of the `dst` and `data`, allowing
|
||||
/// transposition between the two. This means `dst: b"abc", data: b"def"`, will produce the same
|
||||
/// scalar as `dst: "abcdef", data: b""`. Please use carefully, not letting `dst` valuess be
|
||||
/// substrings of each other.
|
||||
fn hash_to_F(dst: &[u8], data: &[u8]) -> Self::F {
|
||||
use blake2::Digest;
|
||||
<Scalar as FromUniformBytes<64>>::from_uniform_bytes(
|
||||
&Self::H::digest([dst, data].concat()).into(),
|
||||
)
|
||||
}
|
||||
|
||||
// We override the provided impl, which compares against the reserialization, because
|
||||
// we already require canonicity
|
||||
#[cfg(feature = "alloc")]
|
||||
#[allow(non_snake_case)]
|
||||
fn read_G<R: Read>(reader: &mut R) -> io::Result<Self::G> {
|
||||
use ciphersuite::group::GroupEncoding;
|
||||
|
||||
let mut encoding = <Self::G as GroupEncoding>::Repr::default();
|
||||
reader.read_exact(encoding.as_mut())?;
|
||||
|
||||
let point = Option::<Self::G>::from(Self::G::from_bytes(&encoding))
|
||||
.ok_or_else(|| io::Error::other("invalid point"))?;
|
||||
Ok(point)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl generalized_bulletproofs_ec_gadgets::DiscreteLogParameter for Embedwards25519 {
|
||||
type ScalarBits = generic_array::typenum::U<{ <Scalar as PrimeField>::NUM_BITS as usize }>;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_curve() {
|
||||
ff_group_tests::group::test_prime_group_bits::<_, Point>(&mut rand_core::OsRng);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generator() {
|
||||
use ciphersuite::group::{Group, GroupEncoding};
|
||||
assert_eq!(
|
||||
Point::generator(),
|
||||
Point::from_bytes(&hex_literal::hex!(
|
||||
"0100000000000000000000000000000000000000000000000000000000000000"
|
||||
))
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_x_is_off_curve() {
|
||||
assert!(bool::from(
|
||||
Affine::<Embedwards25519>::decompress(FieldElement::ZERO, 1.into()).is_none()
|
||||
));
|
||||
}
|
||||
|
||||
// Checks random won't infinitely loop
|
||||
#[test]
|
||||
fn random() {
|
||||
use ciphersuite::group::Group;
|
||||
Point::random(&mut rand_core::OsRng);
|
||||
}
|
||||
Reference in New Issue
Block a user