From 35d753ecc9aa18575705c2357d167632a868f0f5 Mon Sep 17 00:00:00 2001 From: mariari Date: Sat, 5 Aug 2023 06:23:42 +0800 Subject: [PATCH 1/2] Added Rustler for BEAM NIF integration Here we add rustler as a dependency and create serialization derivations for the various types found within pasta_curves. Some extra arguments are given to the new_curve_impl as I could not figure out how to splice strings in rust's macro system --- Cargo.toml | 1 + src/curves.rs | 27 ++++++++++++++++++++------- src/fields/fp.rs | 15 +++++++++++++++ src/fields/fq.rs | 15 +++++++++++++++ 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 93091a5..962b449 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ harness = false required-features = ["alloc"] [dependencies] +rustler = "0.29.1" ff = { version = "0.13", default-features = false } group = { version = "0.13", default-features = false } rand = { version = "0.8", default-features = false } diff --git a/src/curves.rs b/src/curves.rs index 41ccb9a..39073da 100644 --- a/src/curves.rs +++ b/src/curves.rs @@ -16,6 +16,7 @@ use group::{ Curve as _, Group as _, GroupEncoding, }; use rand::RngCore; +use rustler::NifRecord; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; #[cfg(feature = "alloc")] @@ -26,12 +27,15 @@ use super::{Fp, Fq}; #[cfg(feature = "alloc")] use crate::arithmetic::{Coordinates, CurveAffine, CurveExt}; +use alloc::format; + macro_rules! new_curve_impl { (($($privacy:tt)*), $name:ident, $name_affine:ident, $iso:ident, $base:ident, $scalar:ident, - $curve_id:literal, $a_raw:expr, $b_raw:expr, $curve_type:ident) => { + $curve_id:literal, $a_raw:expr, $b_raw:expr, $curve_type:ident, $name_string:literal, $name_affine_string:literal) => { /// Represents a point in the projective coordinate space. - #[derive(Copy, Clone, Debug)] + #[derive(Copy, Clone, Debug, NifRecord)] #[cfg_attr(feature = "repr-c", repr(C))] + #[tag = $name_string] $($privacy)* struct $name { x: $base, y: $base, @@ -50,8 +54,9 @@ macro_rules! new_curve_impl { /// Represents a point in the affine coordinate space (or the point at /// infinity). - #[derive(Copy, Clone)] + #[derive(Copy, Clone, NifRecord)] #[cfg_attr(feature = "repr-c", repr(C))] + #[tag = $name_affine_string] $($privacy)* struct $name_affine { x: $base, y: $base, @@ -955,7 +960,9 @@ new_curve_impl!( "pallas", [0, 0, 0, 0], [5, 0, 0, 0], - special_a0_b5 + special_a0_b5, + "Ep", + "EpAffine" ); new_curve_impl!( (pub), @@ -967,7 +974,9 @@ new_curve_impl!( "vesta", [0, 0, 0, 0], [5, 0, 0, 0], - special_a0_b5 + special_a0_b5, + "Eq", + "EqAffine" ); new_curve_impl!( (pub(crate)), @@ -984,7 +993,9 @@ new_curve_impl!( 0x18354a2eb0ea8c9c, ], [1265, 0, 0, 0], - general + general, + "IsoEp", + "IsoEpAffine" ); new_curve_impl!( (pub(crate)), @@ -1001,7 +1012,9 @@ new_curve_impl!( 0x267f9b2ee592271a, ], [1265, 0, 0, 0], - general + general, + "IsoEq", + "IsoEqAffine" ); impl Ep { diff --git a/src/fields/fp.rs b/src/fields/fp.rs index 3264cba..20533eb 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -5,6 +5,8 @@ use ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use rustler::{Decoder, Encoder, Env, NifResult, Term}; + #[cfg(feature = "sqrt-table")] use lazy_static::lazy_static; @@ -185,6 +187,19 @@ impl> ::core::iter::Product for Fp { } } +impl Encoder for Fp { + fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { + (self.0[0], self.0[1], self.0[2], self.0[3]).encode(env) + } +} + +impl<'a> Decoder<'a> for Fp { + fn decode(term: Term<'a>) -> NifResult { + let tuple: NifResult<(u64, u64, u64, u64)> = Decoder::decode(term); + tuple.map(|res| Fp([res.0, res.1, res.2, res.3])) + } +} + /// INV = -(p^{-1} mod 2^64) mod 2^64 const INV: u64 = 0x992d30ecffffffff; diff --git a/src/fields/fq.rs b/src/fields/fq.rs index 8177fa4..54ec2b7 100644 --- a/src/fields/fq.rs +++ b/src/fields/fq.rs @@ -5,6 +5,8 @@ use ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use rustler::{Decoder, Encoder, Env, NifResult, Term}; + #[cfg(feature = "sqrt-table")] use lazy_static::lazy_static; @@ -103,6 +105,19 @@ impl ConditionallySelectable for Fq { } } +impl Encoder for Fq { + fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { + (self.0[0], self.0[1], self.0[2], self.0[3]).encode(env) + } +} + +impl<'a> Decoder<'a> for Fq { + fn decode(term: Term<'a>) -> NifResult { + let tuple: NifResult<(u64, u64, u64, u64)> = Decoder::decode(term); + tuple.map(|res| Fq([res.0, res.1, res.2, res.3])) + } +} + /// Constant representing the modulus /// q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 const MODULUS: Fq = Fq([ From bb6340fd95e4b44d3fda83bb89ba56178c8c8181 Mon Sep 17 00:00:00 2001 From: mariari Date: Thu, 24 Aug 2023 05:11:16 +0800 Subject: [PATCH 2/2] Add a feature flag for NIF derivation This makes it so that all the changes included have no effect upon the code, if the desired changes are wanted, then add: --features=repr-erlang when using cargo to successuflly have the feature enabled --- Cargo.toml | 3 ++- src/curves.rs | 12 ++++++++---- src/fields/fp.rs | 3 +++ src/fields/fq.rs | 3 +++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 962b449..d2780d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ harness = false required-features = ["alloc"] [dependencies] -rustler = "0.29.1" +rustler = { version = "0.29.1", optional = true} ff = { version = "0.13", default-features = false } group = { version = "0.13", default-features = false } rand = { version = "0.8", default-features = false } @@ -74,3 +74,4 @@ sqrt-table = ["alloc", "lazy_static"] repr-c = [] uninline-portable = [] serde = ["hex", "serde_crate"] +repr-erlang=["rustler"] \ No newline at end of file diff --git a/src/curves.rs b/src/curves.rs index 39073da..5a6b3ee 100644 --- a/src/curves.rs +++ b/src/curves.rs @@ -16,6 +16,7 @@ use group::{ Curve as _, Group as _, GroupEncoding, }; use rand::RngCore; +#[cfg(feature = "repr-erlang")] use rustler::NifRecord; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; @@ -27,15 +28,17 @@ use super::{Fp, Fq}; #[cfg(feature = "alloc")] use crate::arithmetic::{Coordinates, CurveAffine, CurveExt}; +#[cfg(feature = "repr-erlang")] use alloc::format; macro_rules! new_curve_impl { (($($privacy:tt)*), $name:ident, $name_affine:ident, $iso:ident, $base:ident, $scalar:ident, $curve_id:literal, $a_raw:expr, $b_raw:expr, $curve_type:ident, $name_string:literal, $name_affine_string:literal) => { /// Represents a point in the projective coordinate space. - #[derive(Copy, Clone, Debug, NifRecord)] + #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "repr-c", repr(C))] - #[tag = $name_string] + #[cfg_attr(feature = "repr-erlang", derive(NifRecord))] + #[cfg_attr(feature = "repr-erlang", tag = $name_string)] $($privacy)* struct $name { x: $base, y: $base, @@ -54,9 +57,10 @@ macro_rules! new_curve_impl { /// Represents a point in the affine coordinate space (or the point at /// infinity). - #[derive(Copy, Clone, NifRecord)] + #[derive(Copy, Clone)] + #[cfg_attr(feature = "repr-erlang", derive(NifRecord))] + #[cfg_attr(feature = "repr-erlang", tag = $name_affine_string)] #[cfg_attr(feature = "repr-c", repr(C))] - #[tag = $name_affine_string] $($privacy)* struct $name_affine { x: $base, y: $base, diff --git a/src/fields/fp.rs b/src/fields/fp.rs index 20533eb..09d387b 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -5,6 +5,7 @@ use ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +#[cfg(feature = "repr-erlang")] use rustler::{Decoder, Encoder, Env, NifResult, Term}; #[cfg(feature = "sqrt-table")] @@ -187,12 +188,14 @@ impl> ::core::iter::Product for Fp { } } +#[cfg(feature = "repr-erlang")] impl Encoder for Fp { fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { (self.0[0], self.0[1], self.0[2], self.0[3]).encode(env) } } +#[cfg(feature = "repr-erlang")] impl<'a> Decoder<'a> for Fp { fn decode(term: Term<'a>) -> NifResult { let tuple: NifResult<(u64, u64, u64, u64)> = Decoder::decode(term); diff --git a/src/fields/fq.rs b/src/fields/fq.rs index 54ec2b7..d3e1424 100644 --- a/src/fields/fq.rs +++ b/src/fields/fq.rs @@ -5,6 +5,7 @@ use ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +#[cfg(feature = "repr-erlang")] use rustler::{Decoder, Encoder, Env, NifResult, Term}; #[cfg(feature = "sqrt-table")] @@ -105,12 +106,14 @@ impl ConditionallySelectable for Fq { } } +#[cfg(feature = "repr-erlang")] impl Encoder for Fq { fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { (self.0[0], self.0[1], self.0[2], self.0[3]).encode(env) } } +#[cfg(feature = "repr-erlang")] impl<'a> Decoder<'a> for Fq { fn decode(term: Term<'a>) -> NifResult { let tuple: NifResult<(u64, u64, u64, u64)> = Decoder::decode(term);