From 872065c8a14078b5c7a881a4606736823fb833b0 Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Thu, 17 Feb 2022 17:06:02 +0100 Subject: [PATCH 1/5] Add 'repr-c' feature to facilitate FFI. --- Cargo.toml | 1 + src/curves.rs | 32 +++++++++++++++++++++++++------- src/fields/fp.rs | 1 + src/fields/fq.rs | 1 + 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6b1429f..c9a124e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,3 +58,4 @@ default = ["bits", "sqrt-table"] alloc = ["group/alloc", "blake2b_simd"] bits = ["ff/bits"] sqrt-table = ["alloc", "lazy_static"] +repr-c = [] diff --git a/src/curves.rs b/src/curves.rs index 7c16ead..3518ae3 100644 --- a/src/curves.rs +++ b/src/curves.rs @@ -29,6 +29,7 @@ macro_rules! new_curve_impl { $curve_id:literal, $a_raw:expr, $b_raw:expr, $curve_type:ident) => { /// Represents a point in the projective coordinate space. #[derive(Copy, Clone, Debug)] + #[cfg_attr(feature = "repr-c", repr(C))] $($privacy)* struct $name { x: $base, y: $base, @@ -48,15 +49,17 @@ macro_rules! new_curve_impl { /// Represents a point in the affine coordinate space (or the point at /// infinity). #[derive(Copy, Clone)] + #[cfg_attr(feature = "repr-c", repr(C))] $($privacy)* struct $name_affine { x: $base, y: $base, + #[cfg(not(feature = "repr-c"))] infinity: Choice, } impl fmt::Debug for $name_affine { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - if self.infinity.into() { + if self.is_identity().into() { write!(f, "Infinity") } else { write!(f, "({:?}, {:?})", self.x, self.y) @@ -81,6 +84,7 @@ macro_rules! new_curve_impl { let p = $name_affine { x, y, + #[cfg(not(feature = "repr-c"))] infinity: Choice::from(0u8), }; break p.to_curve(); @@ -200,7 +204,8 @@ macro_rules! new_curve_impl { q.x = p.x * tmp2; q.y = p.y * tmp3; - q.infinity = Choice::from(0u8); + #[cfg(not(feature = "repr-c"))] + { q.infinity = Choice::from(0u8); } *q = $name_affine::conditional_select(&q, &$name_affine::identity(), skip); } @@ -216,6 +221,7 @@ macro_rules! new_curve_impl { let tmp = $name_affine { x, y, + #[cfg(not(feature = "repr-c"))] infinity: Choice::from(0u8), }; @@ -502,6 +508,7 @@ macro_rules! new_curve_impl { $name_affine { x: self.x, y: -self.y, + #[cfg(not(feature = "repr-c"))] infinity: self.infinity, } } @@ -621,19 +628,25 @@ macro_rules! new_curve_impl { Self { x: $base::zero(), y: $base::zero(), + #[cfg(not(feature = "repr-c"))] infinity: Choice::from(1u8), } } + #[cfg(not(feature = "repr-c"))] fn is_identity(&self) -> Choice { self.infinity } + #[cfg(feature = "repr-c")] + fn is_identity(&self) -> Choice { + self.x.is_zero() & self.y.is_zero() + } fn to_curve(&self) -> Self::Curve { $name { x: self.x, y: self.y, - z: $base::conditional_select(&$base::one(), &$base::zero(), self.infinity), + z: $base::conditional_select(&$base::one(), &$base::zero(), self.is_identity()), } } } @@ -679,6 +692,7 @@ macro_rules! new_curve_impl { $name_affine { x, y, + #[cfg(not(feature = "repr-c"))] infinity: Choice::from(0u8), }, Choice::from(1u8), @@ -717,7 +731,7 @@ macro_rules! new_curve_impl { fn is_on_curve(&self) -> Choice { // y^2 - x^3 - ax ?= b (self.y.square() - (self.x.square() + &$name::curve_constant_a()) * self.x).ct_eq(&$name::curve_constant_b()) - | self.infinity + | self.is_identity() } fn coordinates(&self) -> CtOption> { @@ -726,7 +740,9 @@ macro_rules! new_curve_impl { fn from_xy(x: Self::Base, y: Self::Base) -> CtOption { let p = $name_affine { - x, y, infinity: 0u8.into() + x, y, + #[cfg(not(feature = "repr-c"))] + infinity: 0u8.into() }; CtOption::new(p, p.is_on_curve()) } @@ -760,8 +776,8 @@ macro_rules! new_curve_impl { impl ConstantTimeEq for $name_affine { fn ct_eq(&self, other: &Self) -> Choice { - let z1 = self.infinity; - let z2 = other.infinity; + let z1 = self.is_identity(); + let z2 = other.is_identity(); (z1 & z2) | ((!z1) & (!z2) & (self.x.ct_eq(&other.x)) & (self.y.ct_eq(&other.y))) } @@ -780,6 +796,7 @@ macro_rules! new_curve_impl { $name_affine { x: $base::conditional_select(&a.x, &b.x, choice), y: $base::conditional_select(&a.y, &b.y, choice), + #[cfg(not(feature = "repr-c"))] infinity: Choice::conditional_select(&a.infinity, &b.infinity, choice), } } @@ -951,6 +968,7 @@ macro_rules! impl_affine_curve_specific { Self { x: NEGATIVE_ONE, y: TWO, + #[cfg(not(feature = "repr-c"))] infinity: Choice::from(0u8), } } diff --git a/src/fields/fp.rs b/src/fields/fp.rs index 17be5d6..b1d1b20 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -26,6 +26,7 @@ use crate::arithmetic::SqrtTables; // integers in little-endian order. `Fp` values are always in // Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^256. #[derive(Clone, Copy, Eq)] +#[repr(transparent)] pub struct Fp(pub(crate) [u64; 4]); impl fmt::Debug for Fp { diff --git a/src/fields/fq.rs b/src/fields/fq.rs index 618bf54..cfb0f4e 100644 --- a/src/fields/fq.rs +++ b/src/fields/fq.rs @@ -26,6 +26,7 @@ use crate::arithmetic::SqrtTables; // integers in little-endian order. `Fq` values are always in // Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256. #[derive(Clone, Copy, Eq)] +#[repr(transparent)] pub struct Fq(pub(crate) [u64; 4]); impl fmt::Debug for Fq { From 3507ba6ffe4c95faff947709031f6ddc7697f0d1 Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Wed, 13 Apr 2022 22:23:23 +0200 Subject: [PATCH 2/5] Omit 'infinity' field from affine coordinates structure. --- src/curves.rs | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/curves.rs b/src/curves.rs index 3518ae3..8f0c261 100644 --- a/src/curves.rs +++ b/src/curves.rs @@ -53,8 +53,6 @@ macro_rules! new_curve_impl { $($privacy)* struct $name_affine { x: $base, y: $base, - #[cfg(not(feature = "repr-c"))] - infinity: Choice, } impl fmt::Debug for $name_affine { @@ -84,8 +82,6 @@ macro_rules! new_curve_impl { let p = $name_affine { x, y, - #[cfg(not(feature = "repr-c"))] - infinity: Choice::from(0u8), }; break p.to_curve(); } @@ -204,8 +200,6 @@ macro_rules! new_curve_impl { q.x = p.x * tmp2; q.y = p.y * tmp3; - #[cfg(not(feature = "repr-c"))] - { q.infinity = Choice::from(0u8); } *q = $name_affine::conditional_select(&q, &$name_affine::identity(), skip); } @@ -221,8 +215,6 @@ macro_rules! new_curve_impl { let tmp = $name_affine { x, y, - #[cfg(not(feature = "repr-c"))] - infinity: Choice::from(0u8), }; $name_affine::conditional_select(&tmp, &$name_affine::identity(), zinv.is_zero()) @@ -508,8 +500,6 @@ macro_rules! new_curve_impl { $name_affine { x: self.x, y: -self.y, - #[cfg(not(feature = "repr-c"))] - infinity: self.infinity, } } } @@ -628,16 +618,9 @@ macro_rules! new_curve_impl { Self { x: $base::zero(), y: $base::zero(), - #[cfg(not(feature = "repr-c"))] - infinity: Choice::from(1u8), } } - #[cfg(not(feature = "repr-c"))] - fn is_identity(&self) -> Choice { - self.infinity - } - #[cfg(feature = "repr-c")] fn is_identity(&self) -> Choice { self.x.is_zero() & self.y.is_zero() } @@ -692,8 +675,6 @@ macro_rules! new_curve_impl { $name_affine { x, y, - #[cfg(not(feature = "repr-c"))] - infinity: Choice::from(0u8), }, Choice::from(1u8), ) @@ -741,8 +722,6 @@ macro_rules! new_curve_impl { fn from_xy(x: Self::Base, y: Self::Base) -> CtOption { let p = $name_affine { x, y, - #[cfg(not(feature = "repr-c"))] - infinity: 0u8.into() }; CtOption::new(p, p.is_on_curve()) } @@ -796,8 +775,6 @@ macro_rules! new_curve_impl { $name_affine { x: $base::conditional_select(&a.x, &b.x, choice), y: $base::conditional_select(&a.y, &b.y, choice), - #[cfg(not(feature = "repr-c"))] - infinity: Choice::conditional_select(&a.infinity, &b.infinity, choice), } } } @@ -968,8 +945,6 @@ macro_rules! impl_affine_curve_specific { Self { x: NEGATIVE_ONE, y: TWO, - #[cfg(not(feature = "repr-c"))] - infinity: Choice::from(0u8), } } }; From ef39fba64cfbdf4ec4dff743985b2de896d1f062 Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Mon, 18 Apr 2022 19:04:03 +0200 Subject: [PATCH 3/5] Simplify $name_affine.ct_eq(). By @ebfull's suggestion. --- src/curves.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/curves.rs b/src/curves.rs index 8f0c261..8efc206 100644 --- a/src/curves.rs +++ b/src/curves.rs @@ -755,10 +755,7 @@ macro_rules! new_curve_impl { impl ConstantTimeEq for $name_affine { fn ct_eq(&self, other: &Self) -> Choice { - let z1 = self.is_identity(); - let z2 = other.is_identity(); - - (z1 & z2) | ((!z1) & (!z2) & (self.x.ct_eq(&other.x)) & (self.y.ct_eq(&other.y))) + self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y) } } From 73eb83d52dedd4ffc4618f1272666eb13ba84781 Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Tue, 19 Apr 2022 00:12:55 +0200 Subject: [PATCH 4/5] Document recent changes in CHANGELOG.md. --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b723ca3..ee0c1f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to Rust's notion of [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Add `repr-c` cargo feature to facilitate FFI by conditionally adding + `repr(C)` attribute to point structures. + +### Changed +- Add `repr(transparent)` attribute to Fp/Fq structures. ## [0.3.0] - 2022-01-03 ### Added From 1bee4d2989f3bc70cf66c2742e88d6b1645f06a9 Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Tue, 19 Apr 2022 08:13:51 +0200 Subject: [PATCH 5/5] fixup! Document recent changes in CHANGELOG.md. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee0c1f7..c56a6ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to Rust's notion of ### Changed - Add `repr(transparent)` attribute to Fp/Fq structures. +- Omit 'infinity' field from affine coordinates structures and use (0, 0) + to denote the identity points. ## [0.3.0] - 2022-01-03 ### Added