Skip to content

Commit

Permalink
k256+p256: impl ff::Field trait for FieldElement
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 committed Dec 23, 2021
1 parent d321383 commit 27794cc
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 27794cc

Please sign in to comment.