diff --git a/CHANGELOG.md b/CHANGELOG.md index ffb7940..11bfab5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ ### Features - [\#121](https://github.com/arkworks-rs/curves/pull/121) Add the ed25519 curve. +- [\#124](https://github.com/arkworks-rs/curves/pull/124) Add the curve25519 curve. ### Improvements diff --git a/Cargo.toml b/Cargo.toml index c37d6e3..fc14cda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ members = [ "pallas", "vesta", + "curve25519", "ed25519", ] resolver = "2" diff --git a/curve25519/Cargo.toml b/curve25519/Cargo.toml new file mode 100644 index 0000000..00949b7 --- /dev/null +++ b/curve25519/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "ark-curve25519" +version = "0.3.0" +authors = [ "arkworks contributors" ] +description = "The curve25519 Montgomery curve" +homepage = "https://arkworks.rs" +repository = "https://github.com/arkworks-rs/curves" +documentation = "https://docs.rs/ark-curve25519/" +keywords = ["cryptography", "finite-fields", "elliptic-curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2021" + +[dependencies] +ark-ff = { version = "^0.3.0", default-features = false } +ark-ec = { version = "^0.3.0", default-features = false } +ark-std = { version = "^0.3.0", default-features = false } +ark-r1cs-std = { version = "^0.3.0", default-features = false, optional = true } + +[dev-dependencies] +ark-relations = { version = "^0.3.0", default-features = false } +ark-serialize = { version = "^0.3.0", default-features = false } +ark-algebra-test-templates = { version = "^0.3.0", default-features = false } +ark-curve-constraint-tests = { path = "../curve-constraint-tests", default-features = false } + +[features] +default = [] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std" ] +r1cs = [ "ark-r1cs-std" ] diff --git a/curve25519/LICENSE-APACHE b/curve25519/LICENSE-APACHE new file mode 120000 index 0000000..965b606 --- /dev/null +++ b/curve25519/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/curve25519/LICENSE-MIT b/curve25519/LICENSE-MIT new file mode 120000 index 0000000..76219eb --- /dev/null +++ b/curve25519/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/curve25519/scripts/fr.ipynb b/curve25519/scripts/fr.ipynb new file mode 100644 index 0000000..99e2b1b --- /dev/null +++ b/curve25519/scripts/fr.ipynb @@ -0,0 +1,91 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "04264893", + "metadata": {}, + "outputs": [], + "source": [ + "r = 7237005577332262213973186563042994240857116359379907606001950938285454250989" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "1603b293", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2^2 * 3 * 11 * 198211423230930754013084525763697 * 276602624281642239937218680557139826668747" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factor(r - 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "425ceac7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7237005577332262213973186563042994240857116359379907606001950938285454250988\n", + "1570463851528226261927580272323658009530148727742783848239914322803198255651\n", + "4908983020090465803374304318106080751443647916949975825112097080460587568629\n", + "7119675135705137915307919240607293966034195415655343409829245710729128040338\n", + "2975531125133123119648879457563281269120703404158613135195788908093573672641\n" + ] + } + ], + "source": [ + "gen = 2\n", + "print(pow(gen, (r - 1) / 2, r))\n", + "print(pow(gen, (r - 1) / 3, r))\n", + "print(pow(gen, (r - 1) / 11, r))\n", + "print(pow(gen, (r - 1) / 198211423230930754013084525763697, r))\n", + "print(pow(gen, (r - 1) / 276602624281642239937218680557139826668747, r))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4c58ca4", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "SageMath 9.2", + "language": "sage", + "name": "sagemath" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/curve25519/scripts/g1.ipynb b/curve25519/scripts/g1.ipynb new file mode 100644 index 0000000..3b7d3c7 --- /dev/null +++ b/curve25519/scripts/g1.ipynb @@ -0,0 +1,162 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "f890e69f", + "metadata": {}, + "outputs": [], + "source": [ + "q = pow(2,255) - 19" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "d90a7f0b", + "metadata": {}, + "outputs": [], + "source": [ + "A = 486662\n", + "B = 1" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "1b2aebc5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "486664\n", + "486660\n" + ] + } + ], + "source": [ + "a = (A + 2) * 1\n", + "d = (A - 2) * 1\n", + "print(a)\n", + "print(d)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "aae2f8bf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "9" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "u = 9\n", + "u" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "ea9a4d90", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "14781619447589544791020593568409986887264606134616475288964881837755586237401" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v = mod(u^3 + A * u^2 + u, q).sqrt()\n", + "v" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "95895004", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "38213832894368730265794714087330135568483813637251082400757400312561599933396" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "u * pow(v, -1, q) % q" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "1134cf74", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "46316835694926478169428394003475163141307993866256225615783033603165251855960" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(u - 1) * pow(u + 1, -1, q) % q" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ec089e21", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "SageMath 9.2", + "language": "sage", + "name": "sagemath" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/curve25519/src/constraints/curves.rs b/curve25519/src/constraints/curves.rs new file mode 100644 index 0000000..f27af6f --- /dev/null +++ b/curve25519/src/constraints/curves.rs @@ -0,0 +1,14 @@ +use ark_r1cs_std::groups::curves::twisted_edwards::{AffineVar, MontgomeryAffineVar}; + +use crate::{constraints::FqVar, *}; + +/// A variable that is the R1CS equivalent of `crate::EdwardsAffine`. +pub type EdwardsVar = AffineVar; + +/// A variable that is the R1CS equivalent of `crate::NonZeroMontgomeryAffine`. +pub type NonZeroMontgomeryVar = MontgomeryAffineVar; + +#[test] +fn test() { + ark_curve_constraint_tests::curves::te_test::().unwrap(); +} diff --git a/curve25519/src/constraints/fields.rs b/curve25519/src/constraints/fields.rs new file mode 100644 index 0000000..2c63654 --- /dev/null +++ b/curve25519/src/constraints/fields.rs @@ -0,0 +1,11 @@ +use ark_r1cs_std::fields::fp::FpVar; + +use crate::Fq; + +/// A variable that is the R1CS equivalent of `crate::Fq`. +pub type FqVar = FpVar; + +#[test] +fn test() { + ark_curve_constraint_tests::fields::field_test::<_, _, FqVar>().unwrap(); +} diff --git a/curve25519/src/constraints/mod.rs b/curve25519/src/constraints/mod.rs new file mode 100644 index 0000000..41d1032 --- /dev/null +++ b/curve25519/src/constraints/mod.rs @@ -0,0 +1,8 @@ +//! This module implements the R1CS equivalent of `ark_curve25519`. +//! It requires a curve that embeds curve25519. + +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*; diff --git a/curve25519/src/curves/mod.rs b/curve25519/src/curves/mod.rs new file mode 100644 index 0000000..5628dbc --- /dev/null +++ b/curve25519/src/curves/mod.rs @@ -0,0 +1,71 @@ +use crate::{Fq, Fr}; +use ark_ec::{ + models::CurveConfig, + twisted_edwards::{Affine, MontCurveConfig, MontgomeryAffine, Projective, TECurveConfig}, +}; +use ark_ff::MontFp; + +#[cfg(test)] +mod tests; + +pub type EdwardsAffine = Affine; +pub type EdwardsProjective = Projective; +pub type NonZeroMontgomeryAffine = MontgomeryAffine; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Curve25519Config; + +impl CurveConfig for Curve25519Config { + type BaseField = Fq; + type ScalarField = Fr; + + /// COFACTOR = 8 + const COFACTOR: &'static [u64] = &[8]; + + /// COFACTOR_INV (mod r) = + /// 2713877091499598330239944961141122840321418634767465352250731601857045344121 + const COFACTOR_INV: Fr = + MontFp!("2713877091499598330239944961141122840321418634767465352250731601857045344121"); +} + +// We want to emphasize that this twisted Edwards curve is not ed25519. +// Ed25519 has COEFF_A = -1 and COEFF_D = -121665 / 121666. +impl TECurveConfig for Curve25519Config { + /// COEFF_A = 486664 + const COEFF_A: Fq = MontFp!("486664"); + + /// COEFF_D = 486660 + const COEFF_D: Fq = MontFp!("486660"); + + /// Standard generators from . + /// The Montgomery form is + /// x = 0x09, + /// y = 0x20ae19a1b8a086b4e01edd2c7748d14c923d4d7e6d7c61b229e9c5a27eced3d9 + /// The twisted Edwards form is + /// x = 0x547c4350219f5e19dd26a3d6668b74346a8eb726eb2396e1228cfa397ffe6bd4 + /// y = 0x6666666666666666666666666666666666666666666666666666666666666658 + const GENERATOR: EdwardsAffine = EdwardsAffine::new_unchecked(GENERATOR_X, GENERATOR_Y); + + type MontCurveConfig = Curve25519Config; +} + +impl MontCurveConfig for Curve25519Config { + /// COEFF_A = 486662 + const COEFF_A: Fq = MontFp!("486662"); + + /// COEFF_B = 1 + const COEFF_B: Fq = MontFp!("1"); + + type TECurveConfig = Curve25519Config; +} + +/// GENERATOR_X = +/// 38213832894368730265794714087330135568483813637251082400757400312561599933396 +const GENERATOR_X: Fq = + MontFp!("38213832894368730265794714087330135568483813637251082400757400312561599933396"); + +/// GENERATOR_Y = +/// (4/5) +/// 46316835694926478169428394003475163141307993866256225615783033603165251855960 +const GENERATOR_Y: Fq = + MontFp!("46316835694926478169428394003475163141307993866256225615783033603165251855960"); diff --git a/curve25519/src/curves/tests.rs b/curve25519/src/curves/tests.rs new file mode 100644 index 0000000..7b1ea09 --- /dev/null +++ b/curve25519/src/curves/tests.rs @@ -0,0 +1,4 @@ +use crate::*; +use ark_algebra_test_templates::*; + +test_group!(te; EdwardsProjective; te); diff --git a/curve25519/src/fields/fq.rs b/curve25519/src/fields/fq.rs new file mode 100644 index 0000000..05dcf2f --- /dev/null +++ b/curve25519/src/fields/fq.rs @@ -0,0 +1,7 @@ +use ark_ff::fields::{Fp256, MontBackend, MontConfig}; + +#[derive(MontConfig)] +#[modulus = "57896044618658097711785492504343953926634992332820282019728792003956564819949"] +#[generator = "2"] +pub struct FqConfig; +pub type Fq = Fp256>; diff --git a/curve25519/src/fields/fr.rs b/curve25519/src/fields/fr.rs new file mode 100644 index 0000000..b387bff --- /dev/null +++ b/curve25519/src/fields/fr.rs @@ -0,0 +1,7 @@ +use ark_ff::fields::{Fp256, MontBackend, MontConfig}; + +#[derive(MontConfig)] +#[modulus = "7237005577332262213973186563042994240857116359379907606001950938285454250989"] +#[generator = "2"] +pub struct FrConfig; +pub type Fr = Fp256>; diff --git a/curve25519/src/fields/mod.rs b/curve25519/src/fields/mod.rs new file mode 100644 index 0000000..6160678 --- /dev/null +++ b/curve25519/src/fields/mod.rs @@ -0,0 +1,8 @@ +mod fq; +mod fr; + +pub use fq::*; +pub use fr::*; + +#[cfg(test)] +mod tests; diff --git a/curve25519/src/fields/tests.rs b/curve25519/src/fields/tests.rs new file mode 100644 index 0000000..bd978b4 --- /dev/null +++ b/curve25519/src/fields/tests.rs @@ -0,0 +1,5 @@ +use crate::{Fq, Fr}; +use ark_algebra_test_templates::*; + +test_field!(fr; Fr; mont_prime_field); +test_field!(fq; Fq; mont_prime_field); diff --git a/curve25519/src/lib.rs b/curve25519/src/lib.rs new file mode 100755 index 0000000..f4753a2 --- /dev/null +++ b/curve25519/src/lib.rs @@ -0,0 +1,28 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements the curve25519 Montgomery curve. +//! +//! Curve information: +//! * Base field: q = +//! 57896044618658097711785492504343953926634992332820282019728792003956564819949 +//! * Scalar field: r = +//! 7237005577332262213973186563042994240857116359379907606001950938285454250989 +//! * Curve equation: B * y^2 = x^3 + A * x^2 + x, where +//! * A = 486662 +//! * B = 1 + +#[cfg(feature = "r1cs")] +pub mod constraints; +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*;