Initial commit

This commit is contained in:
Pratyush Mishra
2020-10-11 19:50:41 -07:00
commit 43ca2132fd
209 changed files with 18825 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
[package]
name = "ark-ed-on-bls12-381"
version = "0.1.0"
authors = [ "arkworks contributors" ]
description = "A Twisted Edwards curve defined over the scalar field of the BLS12-381 curve"
homepage = "https://arworks.rs"
repository = "https://github.com/arkworks/algebra"
documentation = "https://docs.rs/ark-ed-on-bls12-381/"
keywords = ["cryptography", "finite fields", "elliptic curves" ]
categories = ["cryptography"]
include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
license = "MIT/Apache-2.0"
edition = "2018"
[dependencies]
ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false }
ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false }
ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false }
ark-bls12-381 = { path = "../bls12_381", default-features = false, features = [ "scalar_field" ] }
[dev-dependencies]
ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false }
ark-curve-tests = { path = "../curve-tests", default-features = false }
rand = { version = "0.7", default-features = false }
rand_xorshift = "0.2"
[features]
default = []
std = [ "ark-std/std", "ark-ff/std", "ark-ec/std", "ark-bls12-381/std" ]

View File

@@ -0,0 +1,121 @@
use crate::{Fq, Fr};
use ark_ec::{
models::{ModelParameters, MontgomeryModelParameters, TEModelParameters},
twisted_edwards_extended::{GroupAffine, GroupProjective},
};
use ark_ff::{biginteger::BigInteger256, field_new};
#[cfg(test)]
mod tests;
pub type EdwardsAffine = GroupAffine<EdwardsParameters>;
pub type EdwardsProjective = GroupProjective<EdwardsParameters>;
#[rustfmt::skip]
const GENERATOR_X: Fq = field_new!(Fq, BigInteger256([
14080349899812819339,
4104857150246327429,
8293216003873356624,
7400363483732984990,
]));
#[rustfmt::skip]
const GENERATOR_Y: Fq = field_new!(Fq, BigInteger256([
13388310974700241893,
7654361511478576605,
8037907163910805792,
5188938133920569885,
]));
/// `JubJub` is a twisted Edwards curve. These curves have equations of the
/// form: ax² + y² = 1 - dx²y².
/// over some base finite field Fq.
///
/// JubJub's curve equation: -x² + y² = 1 - (10240/10241)x²y²
///
/// q = 52435875175126190479447740508185965837690552500527637822603658699938581184513.
///
/// a = -1.
/// d = (10240/10241) mod q
/// = 19257038036680949359750312669786877991949435402254120286184196891950884077233.
///
/// Sage script to calculate these:
///
/// ```text
/// q = 52435875175126190479447740508185965837690552500527637822603658699938581184513
/// Fq = GF(q)
/// d = -(Fq(10240)/Fq(10241))
/// ```
/// These parameters and the sage script obtained from:
/// <https://github.com/zcash/zcash/issues/2230#issuecomment-317182190>
#[derive(Clone, Default, PartialEq, Eq)]
pub struct EdwardsParameters;
impl ModelParameters for EdwardsParameters {
type BaseField = Fq;
type ScalarField = Fr;
}
impl TEModelParameters for EdwardsParameters {
/// COEFF_A = -1
#[rustfmt::skip]
const COEFF_A: Fq = field_new!(Fq, BigInteger256([
18446744060824649731,
18102478225614246908,
11073656695919314959,
6613806504683796440,
]));
/// COEFF_D = (10240/10241) mod q
#[rustfmt::skip]
const COEFF_D: Fq = field_new!(Fq, BigInteger256([
3049539848285517488,
18189135023605205683,
8793554888777148625,
6339087681201251886,
]));
/// COFACTOR = 8
const COFACTOR: &'static [u64] = &[8];
/// COFACTOR^(-1) mod r =
/// 819310549611346726241370945440405716213240158234039660170669895299022906775
#[rustfmt::skip]
const COFACTOR_INV: Fr = field_new!(Fr, BigInteger256([
6832491983681988242,
12911748493335322362,
17523939349049608702,
217463794347581613,
]));
/// AFFINE_GENERATOR_COEFFS = (GENERATOR_X, GENERATOR_Y)
const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = (GENERATOR_X, GENERATOR_Y);
type MontgomeryModelParameters = EdwardsParameters;
/// Multiplication by `a` is simply negation here.
#[inline(always)]
fn mul_by_a(elem: &Self::BaseField) -> Self::BaseField {
-(*elem)
}
}
impl MontgomeryModelParameters for EdwardsParameters {
/// COEFF_A = 0xA002
#[rustfmt::skip]
const COEFF_A: Fq = field_new!(Fq, BigInteger256([
388496971701930u64,
6855257088226130262u64,
553476580979119549u64,
6516741293351590684u64,
]));
/// COEFF_B = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFEFFFF5FFD
#[rustfmt::skip]
const COEFF_B: Fq = field_new!(Fq, BigInteger256([
18446355550968045916u64,
10902955289292811939u64,
3147092737149958754u64,
6710871716016002197u64,
]));
type TEModelParameters = EdwardsParameters;
}

View File

@@ -0,0 +1,106 @@
use ark_ec::{AffineCurve, ProjectiveCurve};
use ark_ff::{bytes::FromBytes, test_rng, Zero};
use core::str::FromStr;
use rand::Rng;
use crate::*;
use ark_curve_tests::{curves::*, groups::*};
#[test]
fn test_projective_curve() {
curve_tests::<EdwardsProjective>();
edwards_tests::<EdwardsParameters>();
}
#[test]
fn test_projective_group() {
let mut rng = test_rng();
let a = rng.gen();
let b = rng.gen();
for _i in 0..100 {
group_test::<EdwardsProjective>(a, b);
}
}
#[test]
fn test_affine_group() {
let mut rng = test_rng();
let a: EdwardsAffine = rng.gen();
let b: EdwardsAffine = rng.gen();
for _i in 0..100 {
group_test::<EdwardsAffine>(a, b);
}
}
#[test]
fn test_generator() {
let generator = EdwardsAffine::prime_subgroup_generator();
assert!(generator.is_on_curve());
assert!(generator.is_in_correct_subgroup_assuming_on_curve());
}
#[test]
fn test_conversion() {
let mut rng = test_rng();
let a: EdwardsAffine = rng.gen();
let b: EdwardsAffine = rng.gen();
let a_b = {
use ark_ec::group::Group;
(a + &b).double().double()
};
let a_b2 = (a.into_projective() + &b.into_projective())
.double()
.double();
assert_eq!(a_b, a_b2.into_affine());
assert_eq!(a_b.into_projective(), a_b2);
}
#[test]
fn test_scalar_multiplication() {
let f1 = Fr::from_str(
"4691331900926794624732159288782398864809513177368446695323460897088210774597",
)
.unwrap();
let f2 = Fr::from_str(
"1305028103380024953477151132159456965337646722479526711736847301646466538045",
)
.unwrap();
let g = EdwardsAffine::from_str(
"(1158870117176967269192899343636553522971009777237254192973081388797299308391, \
36933624999642413792569726058244472742169727126562409632889593958355839948294)",
)
.unwrap();
let f1f2g = EdwardsAffine::from_str(
"(12638652891150111215300246576936483137884466359309882317048163368620501191944, \
38385045634663742820428406709832518145724237919360177362175527604556651918148)",
)
.unwrap();
assert!(!g.is_zero());
assert!(!f1f2g.is_zero());
let f1g = g.mul(f1).into_affine();
assert_eq!(g.mul(f1 * &f2).into_affine(), f1f2g);
assert_eq!(f1g.mul(f2).into_affine(), f1f2g);
}
#[test]
fn test_bytes() {
let g_from_repr = EdwardsAffine::from_str(
"(1158870117176967269192899343636553522971009777237254192973081388797299308391, \
36933624999642413792569726058244472742169727126562409632889593958355839948294)",
)
.unwrap();
let g_bytes = ark_ff::to_bytes![g_from_repr].unwrap();
let g = EdwardsAffine::read(g_bytes.as_slice()).unwrap();
assert_eq!(g_from_repr, g);
}
#[test]
fn test_montgomery_conversion() {
montgomery_conversion_test::<EdwardsParameters>();
}

View File

@@ -0,0 +1 @@
pub use ark_bls12_381::{Fr as Fq, FrParameters as FqParameters};

View File

@@ -0,0 +1,81 @@
use ark_ff::{
biginteger::BigInteger256 as BigInteger,
fields::{FftParameters, Fp256, Fp256Parameters, FpParameters},
};
pub type Fr = Fp256<FrParameters>;
pub struct FrParameters;
impl Fp256Parameters for FrParameters {}
impl FftParameters for FrParameters {
type BigInt = BigInteger;
const TWO_ADICITY: u32 = 1;
#[rustfmt::skip]
const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([
0xaa9f02ab1d6124de,
0xb3524a6466112932,
0x7342261215ac260b,
0x4d6b87b1da259e2,
]);
}
impl FpParameters for FrParameters {
/// MODULUS = 6554484396890773809930967563523245729705921265872317281365359162392183254199.
#[rustfmt::skip]
const MODULUS: BigInteger = BigInteger([
0xd0970e5ed6f72cb7,
0xa6682093ccc81082,
0x6673b0101343b00,
0xe7db4ea6533afa9,
]);
const MODULUS_BITS: u32 = 252;
const CAPACITY: u32 = Self::MODULUS_BITS - 1;
const REPR_SHAVE_BITS: u32 = 4;
#[rustfmt::skip]
const R: BigInteger = BigInteger([
0x25f80bb3b99607d9,
0xf315d62f66b6e750,
0x932514eeeb8814f4,
0x9a6fc6f479155c6,
]);
#[rustfmt::skip]
const R2: BigInteger = BigInteger([
0x67719aa495e57731,
0x51b0cef09ce3fc26,
0x69dab7fac026e9a5,
0x4f6547b8d127688,
]);
const INV: u64 = 0x1ba3a358ef788ef9;
#[rustfmt::skip]
const GENERATOR: BigInteger = BigInteger([
0x720b1b19d49ea8f1,
0xbf4aa36101f13a58,
0x5fa8cc968193ccbb,
0xe70cbdc7dccf3ac,
]);
const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([
7515249040934278747,
5995434913520945217,
9454073218019761536,
522094803716528084,
]);
const T: BigInteger = Self::MODULUS_MINUS_ONE_DIV_TWO;
const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([
12980996557321915181,
2997717456760472608,
4727036609009880768,
261047401858264042,
]);
}

View File

@@ -0,0 +1,8 @@
pub mod fq;
pub mod fr;
pub use fq::*;
pub use fr::*;
#[cfg(all(feature = "ed_on_bls12_381", test))]
mod tests;

View File

@@ -0,0 +1,426 @@
use crate::{Fq, Fr};
use ark_ff::{
biginteger::BigInteger256 as BigInteger,
bytes::{FromBytes, ToBytes},
fields::{Field, LegendreSymbol::*, SquareRootField},
test_rng, One, Zero,
};
use ark_curve_tests::fields::*;
use core::str::FromStr;
use rand::Rng;
#[test]
fn test_fr() {
let mut rng = test_rng();
let a: Fr = rng.gen();
let b: Fr = rng.gen();
field_test(a, b);
primefield_test::<Fr>();
}
#[test]
fn test_fq() {
let mut rng = test_rng();
let a: Fq = rng.gen();
let b: Fq = rng.gen();
field_test(a, b);
primefield_test::<Fq>();
}
#[test]
fn test_fq_add() {
let f1 = Fq::from_str(
"18386742314266644595564329008376577163854043021652781768352795308532764650733",
)
.unwrap();
let f2 = Fq::from_str(
"39786307610986038981023499868190793548353538256264351797285876981647142458383",
)
.unwrap();
let f3 = Fq::from_str(
"5737174750126493097140088368381404874517028777389495743035013590241325924603",
)
.unwrap();
assert!(!f1.is_zero());
assert!(!f2.is_zero());
assert!(!f3.is_zero());
assert_eq!(f1 + &f2, f3);
}
#[test]
fn test_fq_add_one() {
let f1 = Fq::from_str(
"4946875394261337176810256604189376311946643975348516311606738923340201185904",
)
.unwrap();
let f2 = Fq::from_str(
"4946875394261337176810256604189376311946643975348516311606738923340201185905",
)
.unwrap();
assert!(!f1.is_zero());
assert!(!f2.is_zero());
assert_eq!(f1 + &Fq::one(), f2);
}
#[test]
fn test_fq_mul() {
let f1 = Fq::from_str(
"24703123148064348394273033316595937198355721297494556079070134653139656190956",
)
.unwrap();
let f2 = Fq::from_str(
"38196797080882758914424853878212529985425118523754343117256179679117054302131",
)
.unwrap();
let f3 = Fq::from_str(
"38057113854472161555556064369220825628027487067886761874351491955834635348140",
)
.unwrap();
assert!(!f1.is_zero());
assert!(!f2.is_zero());
assert!(!f3.is_zero());
assert_eq!(f1 * &f2, f3);
}
#[test]
fn test_fq_triple_mul() {
let f1 = Fq::from_str(
"23834398828139479510988224171342199299644042568628082836691700490363123893905",
)
.unwrap();
let f2 = Fq::from_str(
"48343809612844640454129919255697536258606705076971130519928764925719046689317",
)
.unwrap();
let f3 = Fq::from_str(
"22704845471524346880579660022678666462201713488283356385810726260959369106033",
)
.unwrap();
let f4 = Fq::from_str(
"18897508522635316277030308074760673440128491438505204942623624791502972539393",
)
.unwrap();
assert!(!f1.is_zero());
assert!(!f2.is_zero());
assert!(!f3.is_zero());
assert_eq!(f1 * &f2 * &f3, f4);
}
#[test]
fn test_fq_div() {
let f1 = Fq::from_str(
"31892744363926593013886463524057935370302352424137349660481695792871889573091",
)
.unwrap();
let f2 = Fq::from_str(
"47695868328933459965610498875668250916462767196500056002116961816137113470902",
)
.unwrap();
let f3 = Fq::from_str(
"29049672724678710659792141917402891276693777283079976086581207190825261000580",
)
.unwrap();
assert!(!f1.is_zero());
assert!(!f2.is_zero());
assert!(!f3.is_zero());
assert_eq!(f1 / &f2, f3);
}
#[test]
fn test_fq_sub() {
let f1 = Fq::from_str(
"18695869713129401390241150743745601908470616448391638969502807001833388904079",
)
.unwrap();
let f2 = Fq::from_str(
"10105476028534616828778879109836101003805485072436929139123765141153277007373",
)
.unwrap();
let f3 = Fq::from_str(
"8590393684594784561462271633909500904665131375954709830379041860680111896706",
)
.unwrap();
assert!(!f1.is_zero());
assert!(!f2.is_zero());
assert!(!f3.is_zero());
assert_eq!(f1 - &f2, f3);
}
#[test]
fn test_fq_double_in_place() {
let mut f1 = Fq::from_str(
"29729289787452206300641229002276778748586801323231253291984198106063944136114",
)
.unwrap();
let f3 = Fq::from_str(
"7022704399778222121834717496367591659483050145934868761364737512189307087715",
)
.unwrap();
assert!(!f1.is_zero());
assert!(!f3.is_zero());
f1.double_in_place();
assert_eq!(f1, f3);
}
#[test]
fn test_fq_double_in_place_thrice() {
let mut f1 = Fq::from_str(
"32768907806651393940832831055386272949401004221411141755415956893066040832473",
)
.unwrap();
let f3 = Fq::from_str(
"52407761752706389608871686410346320244445823769178582752913020344774001921732",
)
.unwrap();
assert!(!f1.is_zero());
assert!(!f3.is_zero());
f1.double_in_place();
f1.double_in_place();
f1.double_in_place();
assert_eq!(f1, f3);
}
#[test]
fn test_fq_generate_random_ed_on_bls12_381_point() {
let d = Fq::from_str(
"19257038036680949359750312669786877991949435402254120286184196891950884077233",
)
.unwrap();
let y = Fq::from_str(
"20269054604167148422407276086932743904275456233139568486008667107872965128512",
)
.unwrap();
let x2 = Fq::from_str(
"35041048504708632193693740149219726446678304552734087046982753200179718192840",
)
.unwrap();
let computed_y2 = y.square();
let y2 = Fq::from_str(
"22730681238307918419349440108285755984465605552827817317611903495170775437833",
)
.unwrap();
assert_eq!(y2, computed_y2);
let computed_dy2 = d * &computed_y2;
let dy2 = Fq::from_str(
"24720347560552809545835752815204882739669031262711919770503096707526812943411",
)
.unwrap();
assert_eq!(dy2, computed_dy2);
let computed_divisor = computed_dy2 + &Fq::one();
let divisor = Fq::from_str(
"24720347560552809545835752815204882739669031262711919770503096707526812943412",
)
.unwrap();
assert_eq!(divisor, computed_divisor);
let computed_x2 = (computed_y2 - &Fq::one()) / &computed_divisor;
assert_eq!(x2, computed_x2);
let x = Fq::from_str(
"15337652609730546173818014678723269532482775720866471265774032070871608223361",
)
.unwrap();
let computed_x = computed_x2.sqrt().unwrap();
assert_eq!(computed_x.square(), x2);
assert_eq!(x, computed_x);
fn add<'a>(curr: (Fq, Fq), other: &'a (Fq, Fq)) -> (Fq, Fq) {
let y1y2 = curr.1 * &other.1;
let x1x2 = curr.0 * &other.0;
let d = Fq::from_str(
"19257038036680949359750312669786877991949435402254120286184196891950884077233",
)
.unwrap();
let dx1x2y1y2 = d * &y1y2 * &x1x2;
let d1 = Fq::one() + &dx1x2y1y2;
let d2 = Fq::one() - &dx1x2y1y2;
let x1y2 = curr.0 * &other.1;
let y1x2 = curr.1 * &other.0;
let x = (x1y2 + &y1x2) / &d1;
let y = (y1y2 + &x1x2) / &d2;
(x, y)
}
let result = add((x, y), &(x, y));
let result = add(result, &result);
let result = add(result, &result);
let point_x = Fq::from_str(
"47259664076168047050113154262636619161204477920503059672059915868534495873964",
)
.unwrap();
let point_y = Fq::from_str(
"19016409245280491801573912449420132838852726543024859389273314249842195919690",
)
.unwrap();
assert_eq!((point_x, point_y), result);
}
#[test]
fn test_fq_square_in_place() {
let mut f1 = Fq::from_str(
"34864651240005695523200639428464570946052769938774601449735727714436878540682",
)
.unwrap();
let f3 =
Fq::from_str("213133100629336594719108316042277780359104840987226496279264105585804377948")
.unwrap();
assert!(!f1.is_zero());
assert!(!f3.is_zero());
f1.square_in_place();
assert_eq!(f1, f3);
}
#[test]
fn test_fq_sqrt() {
let f1 = Fq::from_str(
"10875927553327821418567659853801220899541454800710193788767706167237535308235",
)
.unwrap();
let f3 = Fq::from_str(
"10816221372957505053219354782681292880545918527618367765651802809826238616708",
)
.unwrap();
assert_eq!(f1.sqrt().unwrap(), f3);
}
#[test]
fn test_fq_from_str() {
let f1_from_repr = Fq::from(BigInteger([
0xab8a2535947d1a77,
0x9ba74cbfda0bbcda,
0xe928b59724d60baf,
0x1cccaaeb9bb1680a,
]));
let f1 = Fq::from_str(
"13026376210409056429264774981357153555336288129100724591327877625017068755575",
)
.unwrap();
let f2_from_repr = Fq::from(BigInteger([
0x97e9103775d2f35c,
0xbe6756b6c587544b,
0x6ee38c3afd88ef4b,
0x2bacd150f540c677,
]));
let f2 = Fq::from_str(
"19754794831832707859764530223239420866832328728734160755396495950822165902172",
)
.unwrap();
assert_eq!(f1_from_repr, f1);
assert_eq!(f2_from_repr, f2);
}
#[test]
fn test_fq_legendre() {
assert_eq!(QuadraticResidue, Fq::one().legendre());
assert_eq!(Zero, Fq::zero().legendre());
let e = BigInteger([
0x0dbc5349cd5664da,
0x8ac5b6296e3ae29d,
0x127cb819feceaa3b,
0x3a6b21fb03867191,
]);
assert_eq!(QuadraticResidue, Fq::from(e).legendre());
let e = BigInteger([
0x96341aefd047c045,
0x9b5f4254500a4d65,
0x1ee08223b68ac240,
0x31d9cd545c0ec7c6,
]);
assert_eq!(QuadraticNonResidue, Fq::from(e).legendre());
}
#[test]
fn test_fq_bytes() {
let f1_from_repr = Fq::from(BigInteger([
0xab8a2535947d1a77,
0x9ba74cbfda0bbcda,
0xe928b59724d60baf,
0x1cccaaeb9bb1680a,
]));
let mut f1_bytes = [0u8; 32];
f1_from_repr.write(f1_bytes.as_mut()).unwrap();
let f1 = Fq::read(f1_bytes.as_ref()).unwrap();
assert_eq!(f1_from_repr, f1);
}
#[test]
fn test_fr_add() {
let f1 = Fr::from(BigInteger([
0xc81265fb4130fe0c,
0xb308836c14e22279,
0x699e887f96bff372,
0x84ecc7e76c11ad,
]));
let f2 = Fr::from(BigInteger([
0x71875719b422efb8,
0x43658e68a93612,
0x9fa756be2011e833,
0xaa2b2cb08dac497,
]));
let f3 = Fr::from(BigInteger([
0x3999bd14f553edc4,
0xb34be8fa7d8b588c,
0x945df3db6d1dba5,
0xb279f92f046d645,
]));
assert_eq!(f1 + &f2, f3);
}
#[test]
fn test_fr_mul() {
let f1 = Fr::from(BigInteger([
0xc81265fb4130fe0c,
0xb308836c14e22279,
0x699e887f96bff372,
0x84ecc7e76c11ad,
]));
let f2 = Fr::from(BigInteger([
0x71875719b422efb8,
0x43658e68a93612,
0x9fa756be2011e833,
0xaa2b2cb08dac497,
]));
let f3 = Fr::from(BigInteger([
0x6d6618ac6b4a8381,
0x5b9eb35d711ee1da,
0xce83310e6ac4105d,
0x98032e0f206320a,
]));
assert_eq!(f1 * &f2, f3);
}
#[test]
fn test_fr_bytes() {
let f1_from_repr = Fr::from(BigInteger([
0xc81265fb4130fe0c,
0xb308836c14e22279,
0x699e887f96bff372,
0x84ecc7e76c11ad,
]));
let mut f1_bytes = [0u8; 32];
f1_from_repr.write(f1_bytes.as_mut()).unwrap();
let f1 = Fr::read(f1_bytes.as_ref()).unwrap();
assert_eq!(f1_from_repr, f1);
}
#[test]
fn test_fr_from_str() {
let f100_from_repr = Fr::from(BigInteger([0x64, 0, 0, 0]));
let f100 = Fr::from_str("100").unwrap();
assert_eq!(f100_from_repr, f100);
}

View File

@@ -0,0 +1,29 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(
warnings,
unused,
future_incompatible,
nonstandard_style,
rust_2018_idioms
)]
#![forbid(unsafe_code)]
//! This library implements a twisted Edwards curve whose base field is the scalar field of the
//! curve BLS12-377. This allows defining cryptographic primitives that use elliptic curves over
//! the scalar field of the latter curve. This curve was generated by Sean Bowe, and is also known
//! as [Jubjub](https://github.com/zkcrypto/jubjub).
//!
//! Curve information:
//! * Base field: q = 52435875175126190479447740508185965837690552500527637822603658699938581184513
//! * Scalar field: r = 6554484396890773809930967563523245729705921265872317281365359162392183254199
//! * Valuation(q - 1, 2) = 32
//! * Valuation(r - 1, 2) = 1
//! * Curve equation: ax^2 + y^2 =1 + dx^2y^2, where
//! * a = -1
//! * d = -(10240/10241)
mod curves;
mod fields;
pub use curves::*;
pub use fields::*;