Skip to content

Commit

Permalink
k256+p256: impl ff::Field trait for FieldElement (#498)
Browse files Browse the repository at this point in the history
Allows for writing code which is generic over field elements, such as
the optimized SWU implementation added in RustCrypto/traits#854
  • Loading branch information
tarcieri authored Dec 23, 2021
1 parent d321383 commit f60fc7f
Show file tree
Hide file tree
Showing 7 changed files with 273 additions and 81 deletions.
3 changes: 3 additions & 0 deletions k256/src/arithmetic/affine.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
//! Affine points

#![allow(clippy::op_ref)]

use super::{FieldElement, ProjectivePoint, CURVE_EQUATION_B};
use crate::{CompressedPoint, EncodedPoint, FieldBytes, Scalar, Secp256k1};
use core::ops::{Mul, Neg};
use elliptic_curve::{
ff::Field,
generic_array::arr,
group::{prime::PrimeCurveAffine, GroupEncoding},
sec1::{self, FromEncodedPoint, ToEncodedPoint},
Expand Down
167 changes: 139 additions & 28 deletions k256/src/arithmetic/field.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Field arithmetic modulo p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1

#![allow(clippy::assign_op_pattern, clippy::op_ref)]

use cfg_if::cfg_if;

cfg_if! {
Expand Down Expand Up @@ -30,10 +32,12 @@ cfg_if! {
}

use crate::FieldBytes;
use core::ops::{Add, AddAssign, Mul, MulAssign};
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use elliptic_curve::{
ff::Field,
rand_core::RngCore,
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
zeroize::Zeroize,
zeroize::DefaultIsZeroes,
};

#[cfg(test)]
Expand All @@ -43,17 +47,52 @@ use num_bigint::{BigUint, ToBigUint};
#[derive(Clone, Copy, Debug)]
pub struct FieldElement(FieldElementImpl);

impl FieldElement {
/// Returns the zero element.
pub const fn zero() -> Self {
Self(FieldElementImpl::zero())
impl Field for FieldElement {
fn random(mut rng: impl RngCore) -> Self {
let mut bytes = FieldBytes::default();

loop {
rng.fill_bytes(&mut bytes);
if let Some(fe) = Self::from_bytes(&bytes).into() {
return fe;
}
}
}

fn zero() -> Self {
Self::ZERO
}

fn one() -> Self {
Self::ONE
}

/// Returns the multiplicative identity.
pub const fn one() -> Self {
Self(FieldElementImpl::one())
#[must_use]
fn square(&self) -> Self {
self.square()
}

#[must_use]
fn double(&self) -> Self {
self.double()
}

fn invert(&self) -> CtOption<Self> {
self.invert()
}

fn sqrt(&self) -> CtOption<Self> {
self.sqrt()
}
}

impl FieldElement {
/// Zero element.
pub const ZERO: Self = Self(FieldElementImpl::zero());

/// Multiplicative identity.
pub const ONE: Self = Self(FieldElementImpl::one());

/// Determine if this `FieldElement` is zero.
///
/// # Returns
Expand Down Expand Up @@ -133,7 +172,8 @@ impl FieldElement {
Self(self.0.mul(&(rhs.0)))
}

/// Returns self * self
/// Returns self * self.
///
/// Brings the magnitude to 1 (but doesn't normalize the result).
/// The magnitudes of arguments should be <= 8.
pub fn square(&self) -> Self {
Expand Down Expand Up @@ -227,9 +267,15 @@ impl FieldElement {
}
}

impl PartialEq for FieldElement {
fn eq(&self, other: &Self) -> bool {
self.0.ct_eq(&(other.0)).into()
impl ConditionallySelectable for FieldElement {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self(FieldElementImpl::conditional_select(&(a.0), &(b.0), choice))
}
}

impl ConstantTimeEq for FieldElement {
fn ct_eq(&self, other: &Self) -> Choice {
self.0.ct_eq(&(other.0))
}
}

Expand All @@ -239,27 +285,33 @@ impl Default for FieldElement {
}
}

impl ConditionallySelectable for FieldElement {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self(FieldElementImpl::conditional_select(&(a.0), &(b.0), choice))
impl DefaultIsZeroes for FieldElement {}

impl Eq for FieldElement {}

impl PartialEq for FieldElement {
fn eq(&self, other: &Self) -> bool {
self.0.ct_eq(&(other.0)).into()
}
}

impl ConstantTimeEq for FieldElement {
fn ct_eq(&self, other: &Self) -> Choice {
self.0.ct_eq(&(other.0))
impl Add<FieldElement> for FieldElement {
type Output = FieldElement;

fn add(self, other: FieldElement) -> FieldElement {
FieldElement(self.0.add(&(other.0)))
}
}

impl Add<&FieldElement> for &FieldElement {
impl Add<&FieldElement> for FieldElement {
type Output = FieldElement;

fn add(self, other: &FieldElement) -> FieldElement {
FieldElement(self.0.add(&(other.0)))
}
}

impl Add<&FieldElement> for FieldElement {
impl Add<&FieldElement> for &FieldElement {
type Output = FieldElement;

fn add(self, other: &FieldElement) -> FieldElement {
Expand All @@ -268,15 +320,49 @@ impl Add<&FieldElement> for FieldElement {
}

impl AddAssign<FieldElement> for FieldElement {
fn add_assign(&mut self, rhs: FieldElement) {
*self = *self + &rhs;
fn add_assign(&mut self, other: FieldElement) {
*self = *self + &other;
}
}

impl Mul<&FieldElement> for &FieldElement {
impl AddAssign<&FieldElement> for FieldElement {
fn add_assign(&mut self, other: &FieldElement) {
*self = *self + other;
}
}

impl Sub<FieldElement> for FieldElement {
type Output = FieldElement;

fn mul(self, other: &FieldElement) -> FieldElement {
fn sub(self, other: FieldElement) -> FieldElement {
self + -other
}
}

impl Sub<&FieldElement> for FieldElement {
type Output = FieldElement;

fn sub(self, other: &FieldElement) -> FieldElement {
self + -other
}
}

impl SubAssign<FieldElement> for FieldElement {
fn sub_assign(&mut self, other: FieldElement) {
*self = *self + -other;
}
}

impl SubAssign<&FieldElement> for FieldElement {
fn sub_assign(&mut self, other: &FieldElement) {
*self = *self + -other;
}
}

impl Mul<FieldElement> for FieldElement {
type Output = FieldElement;

fn mul(self, other: FieldElement) -> FieldElement {
FieldElement(self.0.mul(&(other.0)))
}
}
Expand All @@ -289,20 +375,45 @@ impl Mul<&FieldElement> for FieldElement {
}
}

impl Mul<&FieldElement> for &FieldElement {
type Output = FieldElement;

fn mul(self, other: &FieldElement) -> FieldElement {
FieldElement(self.0.mul(&(other.0)))
}
}

impl MulAssign<FieldElement> for FieldElement {
fn mul_assign(&mut self, rhs: FieldElement) {
*self = *self * &rhs;
}
}

impl Zeroize for FieldElement {
fn zeroize(&mut self) {
self.0.zeroize();
impl MulAssign<&FieldElement> for FieldElement {
fn mul_assign(&mut self, rhs: &FieldElement) {
*self = *self * rhs;
}
}

impl Neg for FieldElement {
type Output = FieldElement;

fn neg(self) -> FieldElement {
self.negate(1)
}
}

impl Neg for &FieldElement {
type Output = FieldElement;

fn neg(self) -> FieldElement {
self.negate(1)
}
}

#[cfg(test)]
mod tests {
use elliptic_curve::ff::Field;
use num_bigint::{BigUint, ToBigUint};
use proptest::prelude::*;

Expand Down
8 changes: 5 additions & 3 deletions k256/src/arithmetic/projective.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Projective points

#![allow(clippy::op_ref)]

use super::{AffinePoint, FieldElement, Scalar, CURVE_EQUATION_B_SINGLE};
use crate::{CompressedPoint, EncodedPoint, Secp256k1};
use core::{
Expand Down Expand Up @@ -102,9 +104,9 @@ impl ProjectivePoint {
/// "point at infinity".
pub const fn identity() -> ProjectivePoint {
ProjectivePoint {
x: FieldElement::zero(),
y: FieldElement::one(),
z: FieldElement::zero(),
x: FieldElement::ZERO,
y: FieldElement::ONE,
z: FieldElement::ZERO,
}
}

Expand Down
8 changes: 4 additions & 4 deletions p256/src/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ use projective::ProjectivePoint;
use scalar::Scalar;

/// a = -3
const CURVE_EQUATION_A: FieldElement = FieldElement::zero()
.subtract(&FieldElement::one())
.subtract(&FieldElement::one())
.subtract(&FieldElement::one());
const CURVE_EQUATION_A: FieldElement = FieldElement::ZERO
.subtract(&FieldElement::ONE)
.subtract(&FieldElement::ONE)
.subtract(&FieldElement::ONE);

/// b = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B
const CURVE_EQUATION_B: FieldElement = FieldElement([
Expand Down
6 changes: 4 additions & 2 deletions p256/src/arithmetic/affine.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Affine points

#![allow(clippy::op_ref)]

use super::{FieldElement, ProjectivePoint, CURVE_EQUATION_A, CURVE_EQUATION_B, MODULUS};
use crate::{CompressedPoint, EncodedPoint, FieldBytes, NistP256, Scalar};
use core::ops::{Mul, Neg};
Expand Down Expand Up @@ -49,8 +51,8 @@ impl PrimeCurveAffine for AffinePoint {
/// Returns the identity of the group: the point at infinity.
fn identity() -> AffinePoint {
Self {
x: FieldElement::zero(),
y: FieldElement::zero(),
x: FieldElement::ZERO,
y: FieldElement::ZERO,
infinity: Choice::from(1),
}
}
Expand Down
Loading

0 comments on commit f60fc7f

Please sign in to comment.