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:
40
crypto/secq256k1/Cargo.toml
Normal file
40
crypto/secq256k1/Cargo.toml
Normal file
@@ -0,0 +1,40 @@
|
||||
[package]
|
||||
name = "secq256k1"
|
||||
version = "0.1.0"
|
||||
description = "An implementation of the curve secp256k1 cycles with"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/secq256k1"
|
||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||
keywords = ["secp256k1", "secq256k1", "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 }
|
||||
|
||||
generic-array = { version = "1", default-features = false }
|
||||
k256 = { version = "0.13", default-features = false, features = ["arithmetic"] }
|
||||
prime-field = { path = "../prime-field", default-features = false }
|
||||
short-weierstrass = { path = "../short-weierstrass", 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", "generic-array/alloc", "k256/alloc", "prime-field/alloc", "short-weierstrass/alloc", "ciphersuite/alloc", "generalized-bulletproofs-ec-gadgets"]
|
||||
std = ["alloc", "std-shims/std", "k256/std", "prime-field/std", "blake2/std", "ciphersuite/std", "generalized-bulletproofs-ec-gadgets/std"]
|
||||
default = ["std"]
|
||||
21
crypto/secq256k1/LICENSE
Normal file
21
crypto/secq256k1/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.
|
||||
5
crypto/secq256k1/README.md
Normal file
5
crypto/secq256k1/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# secq256k1
|
||||
|
||||
An implementation of the curve secp256k1 cycles with.
|
||||
|
||||
Scalars and field elements are encoded in their big-endian formats.
|
||||
184
crypto/secq256k1/src/lib.rs
Normal file
184
crypto/secq256k1/src/lib.rs
Normal file
@@ -0,0 +1,184 @@
|
||||
#![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(feature = "alloc")]
|
||||
use std_shims::io::{self, Read};
|
||||
|
||||
// Doesn't use the `generic-array 0.14` exported by `k256::elliptic_curve` as we need `1.0`
|
||||
use generic_array::{
|
||||
typenum::{U, U33},
|
||||
GenericArray,
|
||||
};
|
||||
use k256::elliptic_curve::{
|
||||
subtle::{Choice, ConstantTimeEq, ConditionallySelectable},
|
||||
zeroize::Zeroize,
|
||||
group::{
|
||||
ff::{PrimeField, FromUniformBytes},
|
||||
Group,
|
||||
},
|
||||
sec1::Tag,
|
||||
};
|
||||
|
||||
prime_field::odd_prime_field!(
|
||||
Scalar,
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
|
||||
"03",
|
||||
true
|
||||
);
|
||||
|
||||
pub use k256::Scalar as FieldElement;
|
||||
|
||||
use short_weierstrass::{ShortWeierstrass, Affine, Projective};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct Secq256k1;
|
||||
impl Zeroize for Secq256k1 {
|
||||
fn zeroize(&mut self) {}
|
||||
}
|
||||
|
||||
impl ShortWeierstrass for Secq256k1 {
|
||||
type FieldElement = FieldElement;
|
||||
const A: FieldElement = FieldElement::ZERO;
|
||||
const B: FieldElement = {
|
||||
let two = FieldElement::ONE.add(&FieldElement::ONE);
|
||||
let four = two.add(&two);
|
||||
let six = four.add(&two);
|
||||
six.add(&FieldElement::ONE)
|
||||
};
|
||||
const PRIME_ORDER: bool = true;
|
||||
const GENERATOR: Affine<Self> = Affine::from_xy_unchecked(FieldElement::ONE, {
|
||||
let y_be =
|
||||
hex_literal::hex!("0c7c97045a2074634909abdf82c9bd0248916189041f2af0c1b800d1ffc278c0");
|
||||
let mut res = FieldElement::ZERO;
|
||||
let mut i = 0;
|
||||
while i < 32 {
|
||||
let mut j = 0;
|
||||
while j < 8 {
|
||||
// Shift over the existing result
|
||||
res = res.add(&res);
|
||||
// Add this bit, if set
|
||||
if ((y_be[i] >> (8 - 1 - j)) & 1) == 1 {
|
||||
res = res.add(&FieldElement::ONE);
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
res
|
||||
});
|
||||
type Scalar = Scalar;
|
||||
|
||||
type Repr = GenericArray<u8, U33>;
|
||||
/// Use the SEC1-encoded identity point, which happens to be all zeroes
|
||||
const IDENTITY: Self::Repr = GenericArray::from_array([0; 33]);
|
||||
fn encode_compressed(x: Self::FieldElement, odd_y: Choice) -> Self::Repr {
|
||||
let mut res = GenericArray::default();
|
||||
res[0] =
|
||||
<_>::conditional_select(&(Tag::CompressedEvenY as u8), &(Tag::CompressedOddY as u8), odd_y);
|
||||
{
|
||||
let res: &mut [u8] = res.as_mut();
|
||||
res[1 ..].copy_from_slice(x.to_repr().as_ref());
|
||||
}
|
||||
res
|
||||
}
|
||||
fn decode_compressed(bytes: &Self::Repr) -> (<Self::FieldElement as PrimeField>::Repr, Choice) {
|
||||
// Parse out if `y` is odd
|
||||
let odd_y = bytes[0].ct_eq(&(Tag::CompressedOddY as u8));
|
||||
// Check if the tag was malleated
|
||||
let expected_tag =
|
||||
<_>::conditional_select(&(Tag::CompressedEvenY as u8), &(Tag::CompressedOddY as u8), odd_y);
|
||||
let invalid = !bytes[0].ct_eq(&expected_tag);
|
||||
|
||||
// Copy the alleged `x` coordinate, overwriting with `0xffffff...` if the sign byte was
|
||||
// malleated (causing the `x` coordinate to be invalid)
|
||||
let mut x = <Self::FieldElement as PrimeField>::Repr::default();
|
||||
{
|
||||
let x: &mut [u8] = x.as_mut();
|
||||
for i in 0 .. 32 {
|
||||
x[i] = <_>::conditional_select(&bytes[1 + i], &u8::MAX, invalid);
|
||||
}
|
||||
}
|
||||
|
||||
(x, 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<Secq256k1>;
|
||||
|
||||
impl ciphersuite::Ciphersuite for Secq256k1 {
|
||||
type F = Scalar;
|
||||
type G = Point;
|
||||
type H = blake2::Blake2b512;
|
||||
|
||||
const ID: &'static [u8] = b"secq256k1";
|
||||
|
||||
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 Secq256k1 {
|
||||
type ScalarBits = U<{ Scalar::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::GroupEncoding;
|
||||
assert_eq!(
|
||||
Point::generator(),
|
||||
Point::from_bytes(GenericArray::from_slice(&hex_literal::hex!(
|
||||
"020000000000000000000000000000000000000000000000000000000000000001"
|
||||
)))
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_x_is_off_curve() {
|
||||
assert!(bool::from(Affine::<Secq256k1>::decompress(FieldElement::ZERO, 1.into()).is_none()));
|
||||
}
|
||||
|
||||
// Checks random won't infinitely loop
|
||||
#[test]
|
||||
fn random() {
|
||||
Point::random(&mut rand_core::OsRng);
|
||||
}
|
||||
Reference in New Issue
Block a user