Merge pull request #30 from dot-asm/repr-c

Add 'repr-c' feature to facilitate FFI.
This commit is contained in:
ebfull 2022-04-19 08:04:29 -06:00 committed by GitHub
commit a80ed3e8aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 19 additions and 18 deletions

View file

@ -6,6 +6,14 @@ and this project adheres to Rust's notion of
[Semantic Versioning](https://semver.org/spec/v2.0.0.html). [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [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.
- Omit 'infinity' field from affine coordinates structures and use (0, 0)
to denote the identity points.
## [0.3.0] - 2022-01-03 ## [0.3.0] - 2022-01-03
### Added ### Added

View file

@ -62,3 +62,4 @@ alloc = ["group/alloc", "blake2b_simd"]
bits = ["ff/bits"] bits = ["ff/bits"]
gpu = ["alloc", "ec-gpu"] gpu = ["alloc", "ec-gpu"]
sqrt-table = ["alloc", "lazy_static"] sqrt-table = ["alloc", "lazy_static"]
repr-c = []

View file

@ -29,6 +29,7 @@ macro_rules! new_curve_impl {
$curve_id:literal, $a_raw:expr, $b_raw:expr, $curve_type:ident) => { $curve_id:literal, $a_raw:expr, $b_raw:expr, $curve_type:ident) => {
/// Represents a point in the projective coordinate space. /// Represents a point in the projective coordinate space.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "repr-c", repr(C))]
$($privacy)* struct $name { $($privacy)* struct $name {
x: $base, x: $base,
y: $base, y: $base,
@ -48,15 +49,15 @@ macro_rules! new_curve_impl {
/// Represents a point in the affine coordinate space (or the point at /// Represents a point in the affine coordinate space (or the point at
/// infinity). /// infinity).
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
#[cfg_attr(feature = "repr-c", repr(C))]
$($privacy)* struct $name_affine { $($privacy)* struct $name_affine {
x: $base, x: $base,
y: $base, y: $base,
infinity: Choice,
} }
impl fmt::Debug for $name_affine { impl fmt::Debug for $name_affine {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
if self.infinity.into() { if self.is_identity().into() {
write!(f, "Infinity") write!(f, "Infinity")
} else { } else {
write!(f, "({:?}, {:?})", self.x, self.y) write!(f, "({:?}, {:?})", self.x, self.y)
@ -81,7 +82,6 @@ macro_rules! new_curve_impl {
let p = $name_affine { let p = $name_affine {
x, x,
y, y,
infinity: Choice::from(0u8),
}; };
break p.to_curve(); break p.to_curve();
} }
@ -200,7 +200,6 @@ macro_rules! new_curve_impl {
q.x = p.x * tmp2; q.x = p.x * tmp2;
q.y = p.y * tmp3; q.y = p.y * tmp3;
q.infinity = Choice::from(0u8);
*q = $name_affine::conditional_select(&q, &$name_affine::identity(), skip); *q = $name_affine::conditional_select(&q, &$name_affine::identity(), skip);
} }
@ -216,7 +215,6 @@ macro_rules! new_curve_impl {
let tmp = $name_affine { let tmp = $name_affine {
x, x,
y, y,
infinity: Choice::from(0u8),
}; };
$name_affine::conditional_select(&tmp, &$name_affine::identity(), zinv.is_zero()) $name_affine::conditional_select(&tmp, &$name_affine::identity(), zinv.is_zero())
@ -502,7 +500,6 @@ macro_rules! new_curve_impl {
$name_affine { $name_affine {
x: self.x, x: self.x,
y: -self.y, y: -self.y,
infinity: self.infinity,
} }
} }
} }
@ -621,19 +618,18 @@ macro_rules! new_curve_impl {
Self { Self {
x: $base::zero(), x: $base::zero(),
y: $base::zero(), y: $base::zero(),
infinity: Choice::from(1u8),
} }
} }
fn is_identity(&self) -> Choice { fn is_identity(&self) -> Choice {
self.infinity self.x.is_zero() & self.y.is_zero()
} }
fn to_curve(&self) -> Self::Curve { fn to_curve(&self) -> Self::Curve {
$name { $name {
x: self.x, x: self.x,
y: self.y, 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,7 +675,6 @@ macro_rules! new_curve_impl {
$name_affine { $name_affine {
x, x,
y, y,
infinity: Choice::from(0u8),
}, },
Choice::from(1u8), Choice::from(1u8),
) )
@ -717,7 +712,7 @@ macro_rules! new_curve_impl {
fn is_on_curve(&self) -> Choice { fn is_on_curve(&self) -> Choice {
// y^2 - x^3 - ax ?= b // 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.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<Coordinates<Self>> { fn coordinates(&self) -> CtOption<Coordinates<Self>> {
@ -726,7 +721,7 @@ macro_rules! new_curve_impl {
fn from_xy(x: Self::Base, y: Self::Base) -> CtOption<Self> { fn from_xy(x: Self::Base, y: Self::Base) -> CtOption<Self> {
let p = $name_affine { let p = $name_affine {
x, y, infinity: 0u8.into() x, y,
}; };
CtOption::new(p, p.is_on_curve()) CtOption::new(p, p.is_on_curve())
} }
@ -760,10 +755,7 @@ macro_rules! new_curve_impl {
impl ConstantTimeEq for $name_affine { impl ConstantTimeEq for $name_affine {
fn ct_eq(&self, other: &Self) -> Choice { fn ct_eq(&self, other: &Self) -> Choice {
let z1 = self.infinity; self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y)
let z2 = other.infinity;
(z1 & z2) | ((!z1) & (!z2) & (self.x.ct_eq(&other.x)) & (self.y.ct_eq(&other.y)))
} }
} }
@ -780,7 +772,6 @@ macro_rules! new_curve_impl {
$name_affine { $name_affine {
x: $base::conditional_select(&a.x, &b.x, choice), x: $base::conditional_select(&a.x, &b.x, choice),
y: $base::conditional_select(&a.y, &b.y, choice), y: $base::conditional_select(&a.y, &b.y, choice),
infinity: Choice::conditional_select(&a.infinity, &b.infinity, choice),
} }
} }
} }
@ -951,7 +942,6 @@ macro_rules! impl_affine_curve_specific {
Self { Self {
x: NEGATIVE_ONE, x: NEGATIVE_ONE,
y: TWO, y: TWO,
infinity: Choice::from(0u8),
} }
} }
}; };

View file

@ -26,6 +26,7 @@ use crate::arithmetic::SqrtTables;
// integers in little-endian order. `Fp` values are always in // integers in little-endian order. `Fp` values are always in
// Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^256. // Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^256.
#[derive(Clone, Copy, Eq)] #[derive(Clone, Copy, Eq)]
#[repr(transparent)]
pub struct Fp(pub(crate) [u64; 4]); pub struct Fp(pub(crate) [u64; 4]);
impl fmt::Debug for Fp { impl fmt::Debug for Fp {

View file

@ -26,6 +26,7 @@ use crate::arithmetic::SqrtTables;
// integers in little-endian order. `Fq` values are always in // integers in little-endian order. `Fq` values are always in
// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256. // Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256.
#[derive(Clone, Copy, Eq)] #[derive(Clone, Copy, Eq)]
#[repr(transparent)]
pub struct Fq(pub(crate) [u64; 4]); pub struct Fq(pub(crate) [u64; 4]);
impl fmt::Debug for Fq { impl fmt::Debug for Fq {