diff --git a/Cargo.lock b/Cargo.lock index 256e5cac..d2209256 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,8 +372,7 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914" +source = "git+https://github.com/ycscaly/traits?branch=batch_invert#017fa2972f23b9e67bcbff2ccca2f1905b8f4aa3" dependencies = [ "base16ct", "base64ct", diff --git a/Cargo.toml b/Cargo.toml index 15523c0f..2428e2a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,6 @@ members = [ [profile.dev] opt-level = 2 + +[patch.crates-io] +elliptic-curve = { git = "https://github.com/RustCrypto/traits" } \ No newline at end of file diff --git a/bign256/src/arithmetic/field.rs b/bign256/src/arithmetic/field.rs index feb0030c..8ac83475 100644 --- a/bign256/src/arithmetic/field.rs +++ b/bign256/src/arithmetic/field.rs @@ -36,6 +36,7 @@ use core::{ ops::{AddAssign, MulAssign, Neg, SubAssign}, }; use elliptic_curve::bigint::Limb; +use elliptic_curve::ops::Invert; use elliptic_curve::{ ff::PrimeField, subtle::{Choice, ConstantTimeEq, CtOption}, @@ -140,6 +141,14 @@ impl PrimeField for FieldElement { const DELTA: Self = Self::from_u64(4); } +impl Invert for FieldElement { + type Output = CtOption; + + fn invert(&self) -> CtOption { + self.invert() + } +} + #[cfg(test)] mod tests { use super::FieldElement; diff --git a/bp256/src/arithmetic/field.rs b/bp256/src/arithmetic/field.rs index 38cc3ede..4f44f3b4 100644 --- a/bp256/src/arithmetic/field.rs +++ b/bp256/src/arithmetic/field.rs @@ -21,6 +21,7 @@ use core::{ iter::{Product, Sum}, ops::{AddAssign, MulAssign, Neg, SubAssign}, }; +use elliptic_curve::ops::Invert; use elliptic_curve::{ bigint::{ArrayEncoding, Integer, Limb}, ff::PrimeField, @@ -288,6 +289,14 @@ impl PrimeField for FieldElement { } } +impl Invert for FieldElement { + type Output = CtOption; + + fn invert(&self) -> CtOption { + self.invert() + } +} + #[cfg(test)] mod tests { use super::FieldElement; diff --git a/bp384/src/arithmetic/field.rs b/bp384/src/arithmetic/field.rs index e96320e2..7075c2ba 100644 --- a/bp384/src/arithmetic/field.rs +++ b/bp384/src/arithmetic/field.rs @@ -21,6 +21,7 @@ use core::{ iter::{Product, Sum}, ops::{AddAssign, MulAssign, Neg, SubAssign}, }; +use elliptic_curve::ops::Invert; use elliptic_curve::{ bigint::{ArrayEncoding, Integer, Limb}, ff::PrimeField, @@ -289,6 +290,14 @@ impl PrimeField for FieldElement { } } +impl Invert for FieldElement { + type Output = CtOption; + + fn invert(&self) -> CtOption { + self.invert() + } +} + #[cfg(test)] mod tests { use super::FieldElement; diff --git a/k256/src/arithmetic/field.rs b/k256/src/arithmetic/field.rs index 7e68f1b4..6956169e 100644 --- a/k256/src/arithmetic/field.rs +++ b/k256/src/arithmetic/field.rs @@ -38,6 +38,7 @@ use core::{ }; use elliptic_curve::{ ff::{self, Field, PrimeField}, + ops::Invert, rand_core::RngCore, subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, zeroize::DefaultIsZeroes, @@ -245,6 +246,14 @@ impl FieldElement { } } +impl Invert for FieldElement { + type Output = CtOption; + + fn invert(&self) -> CtOption { + self.invert() + } +} + impl Field for FieldElement { const ZERO: Self = Self::ZERO; const ONE: Self = Self::ONE; @@ -500,8 +509,10 @@ impl<'a> Product<&'a FieldElement> for FieldElement { #[cfg(test)] mod tests { use elliptic_curve::ff::{Field, PrimeField}; + use elliptic_curve::ops::BatchInvert; use num_bigint::{BigUint, ToBigUint}; use proptest::prelude::*; + use rand_core::OsRng; use super::FieldElement; use crate::{ @@ -510,6 +521,9 @@ mod tests { FieldBytes, }; + #[cfg(feature = "alloc")] + use alloc::vec::Vec; + impl From<&BigUint> for FieldElement { fn from(x: &BigUint) -> Self { let bytes = biguint_to_bytes(x); @@ -672,6 +686,31 @@ mod tests { assert_eq!((two * &inv_two).normalize(), one); } + #[test] + fn batch_invert_array() { + let k: FieldElement = FieldElement::random(&mut OsRng); + let l: FieldElement = FieldElement::random(&mut OsRng); + + let expected = [k.invert().unwrap(), l.invert().unwrap()]; + assert_eq!( + >::batch_invert(&[k, l]).unwrap(), + expected + ); + } + + #[test] + #[cfg(feature = "alloc")] + fn batch_invert() { + let k: FieldElement = FieldElement::random(&mut OsRng); + let l: FieldElement = FieldElement::random(&mut OsRng); + + let expected = vec![k.invert().unwrap(), l.invert().unwrap()]; + let field_elements = vec![k, l]; + let res: Vec<_> = + >::batch_invert(field_elements.as_slice()).unwrap(); + assert_eq!(res, expected); + } + #[test] fn sqrt() { let one = FieldElement::ONE; diff --git a/k256/src/arithmetic/projective.rs b/k256/src/arithmetic/projective.rs index 560769e4..fbabf3e5 100644 --- a/k256/src/arithmetic/projective.rs +++ b/k256/src/arithmetic/projective.rs @@ -8,6 +8,7 @@ use core::{ iter::Sum, ops::{Add, AddAssign, Neg, Sub, SubAssign}, }; +use elliptic_curve::ops::BatchInvert; use elliptic_curve::{ group::{ ff::Field, @@ -18,9 +19,12 @@ use elliptic_curve::{ sec1::{FromEncodedPoint, ToEncodedPoint}, subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, zeroize::DefaultIsZeroes, - Error, Result, + BatchNormalize, Error, Result, }; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + #[rustfmt::skip] const ENDOMORPHISM_BETA: FieldElement = FieldElement::from_bytes_unchecked(&[ 0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10, @@ -34,7 +38,7 @@ const ENDOMORPHISM_BETA: FieldElement = FieldElement::from_bytes_unchecked(&[ pub struct ProjectivePoint { x: FieldElement, y: FieldElement, - z: FieldElement, + pub(super) z: FieldElement, } impl ProjectivePoint { @@ -65,18 +69,20 @@ impl ProjectivePoint { Self::GENERATOR } - /// Returns the affine representation of this point, or `None` if it is the identity. + /// Returns the affine representation of this point. pub fn to_affine(&self) -> AffinePoint { self.z .invert() - .map(|zinv| { - let x = self.x * &zinv; - let y = self.y * &zinv; - AffinePoint::new(x.normalize(), y.normalize()) - }) + .map(|zinv| self.to_affine_internal(zinv)) .unwrap_or_else(|| AffinePoint::IDENTITY) } + pub(super) fn to_affine_internal(self, zinv: FieldElement) -> AffinePoint { + let x = self.x * &zinv; + let y = self.y * &zinv; + AffinePoint::new(x.normalize(), y.normalize()) + } + /// Returns `-self`. fn neg(&self) -> ProjectivePoint { ProjectivePoint { @@ -250,6 +256,72 @@ impl From for ProjectivePoint { } } +impl BatchNormalize<&[ProjectivePoint; N]> for ProjectivePoint { + type Output = [Self::AffineRepr; N]; + + fn batch_normalize( + points: &[Self; N], + ) -> >::Output { + let mut zs = [FieldElement::ONE; N]; + + for i in 0..N { + if points[i].z != FieldElement::ZERO { + // Even a single zero value will fail inversion for the entire batch. + // Put a dummy value (above `FieldElement::ONE`) so inversion succeeds + // and treat that case specially later-on. + zs[i] = points[i].z; + } + } + + // This is safe to unwrap since we assured that all elements are non-zero + let zs_inverses = >::batch_invert(&zs).unwrap(); + + let mut affine_points = [AffinePoint::IDENTITY; N]; + for i in 0..N { + if points[i].z != FieldElement::ZERO { + // If the `z` coordinate is non-zero, we can use it to invert; + // otherwise it defaults to the `IDENTITY` value in initialization. + affine_points[i] = points[i].to_affine_internal(zs_inverses[i]) + } + } + + affine_points + } +} + +#[cfg(feature = "alloc")] +impl BatchNormalize<&[ProjectivePoint]> for ProjectivePoint { + type Output = Vec; + + fn batch_normalize(points: &[Self]) -> >::Output { + let mut zs: Vec<_> = vec![FieldElement::ONE; points.len()]; + + for i in 0..points.len() { + if points[i].z != FieldElement::ZERO { + // Even a single zero value will fail inversion for the entire batch. + // Put a dummy value (above `FieldElement::ONE`) so inversion succeeds + // and treat that case specially later-on. + zs[i] = points[i].z; + } + } + + // This is safe to unwrap since we assured that all elements are non-zero + let zs_inverses: Vec<_> = + >::batch_invert(zs.as_slice()).unwrap(); + + let mut affine_points: Vec<_> = vec![AffinePoint::IDENTITY; points.len()]; + for i in 0..points.len() { + if points[i].z != FieldElement::ZERO { + // If the `z` coordinate is non-zero, we can use it to invert; + // otherwise it defaults to the `IDENTITY` value in initialization. + affine_points[i] = points[i].to_affine_internal(zs_inverses[i]) + } + } + + affine_points.into_iter().collect() + } +} + impl From<&AffinePoint> for ProjectivePoint { fn from(p: &AffinePoint) -> Self { Self::from(*p) @@ -387,6 +459,14 @@ impl Curve for ProjectivePoint { fn to_affine(&self) -> AffinePoint { ProjectivePoint::to_affine(self) } + + #[cfg(feature = "alloc")] + fn batch_normalize(p: &[Self], q: &mut [Self::AffineRepr]) { + assert_eq!(p.len(), q.len()); + + let affine_points: Vec<_> = >::batch_normalize(p); + q.copy_from_slice(&affine_points); + } } impl PrimeCurve for ProjectivePoint { @@ -609,6 +689,13 @@ mod tests { Scalar, }; use elliptic_curve::group::{ff::PrimeField, prime::PrimeCurveAffine}; + use elliptic_curve::ops::MulByGenerator; + use elliptic_curve::Field; + use elliptic_curve::{group, BatchNormalize}; + use rand_core::OsRng; + + #[cfg(feature = "alloc")] + use alloc::vec::Vec; #[test] fn affine_to_projective() { @@ -627,6 +714,69 @@ mod tests { )); } + #[test] + fn batch_normalize_array() { + let k: Scalar = Scalar::random(&mut OsRng); + let l: Scalar = Scalar::random(&mut OsRng); + let g = ProjectivePoint::mul_by_generator(&k); + let h = ProjectivePoint::mul_by_generator(&l); + + let mut res = [AffinePoint::IDENTITY; 2]; + let expected = [g.to_affine(), h.to_affine()]; + assert_eq!( + >::batch_normalize(&[g, h]), + expected + ); + + ::batch_normalize(&[g, h], &mut res); + assert_eq!(res, expected); + + let expected = [g.to_affine(), AffinePoint::IDENTITY]; + assert_eq!( + >::batch_normalize(&[ + g, + ProjectivePoint::IDENTITY + ]), + expected + ); + + ::batch_normalize( + &[g, ProjectivePoint::IDENTITY], + &mut res, + ); + assert_eq!(res, expected); + } + + #[test] + #[cfg(feature = "alloc")] + fn batch_normalize_slice() { + let k: Scalar = Scalar::random(&mut OsRng); + let l: Scalar = Scalar::random(&mut OsRng); + let g = ProjectivePoint::mul_by_generator(&k); + let h = ProjectivePoint::mul_by_generator(&l); + + let expected = vec![g.to_affine(), h.to_affine()]; + let scalars = vec![g, h]; + let mut res: Vec<_> = + >::batch_normalize(scalars.as_slice()); + assert_eq!(res, expected); + + ::batch_normalize(&[g, h], res.as_mut()); + assert_eq!(res.to_vec(), expected); + + let expected = vec![g.to_affine(), AffinePoint::IDENTITY]; + let scalars = vec![g, ProjectivePoint::IDENTITY]; + res = >::batch_normalize(scalars.as_slice()); + + assert_eq!(res, expected); + + ::batch_normalize( + &[g, ProjectivePoint::IDENTITY], + res.as_mut(), + ); + assert_eq!(res.to_vec(), expected); + } + #[test] fn projective_identity_addition() { let identity = ProjectivePoint::IDENTITY; diff --git a/k256/src/arithmetic/scalar.rs b/k256/src/arithmetic/scalar.rs index 72232b6c..cd63eec0 100644 --- a/k256/src/arithmetic/scalar.rs +++ b/k256/src/arithmetic/scalar.rs @@ -802,6 +802,11 @@ mod tests { use num_bigint::{BigUint, ToBigUint}; use num_traits::Zero; use proptest::prelude::*; + use rand_core::OsRng; + + #[cfg(feature = "alloc")] + use alloc::vec::Vec; + use elliptic_curve::ops::BatchInvert; impl From<&BigUint> for Scalar { fn from(x: &BigUint) -> Self { @@ -949,6 +954,30 @@ mod tests { ); } + #[test] + fn batch_invert_array() { + let k: Scalar = Scalar::random(&mut OsRng); + let l: Scalar = Scalar::random(&mut OsRng); + + let expected = [k.invert().unwrap(), l.invert().unwrap()]; + assert_eq!( + >::batch_invert(&[k, l]).unwrap(), + expected + ); + } + + #[test] + #[cfg(feature = "alloc")] + fn batch_invert() { + let k: Scalar = Scalar::random(&mut OsRng); + let l: Scalar = Scalar::random(&mut OsRng); + + let expected = vec![k.invert().unwrap(), l.invert().unwrap()]; + let scalars = vec![k, l]; + let res: Vec<_> = >::batch_invert(scalars.as_slice()).unwrap(); + assert_eq!(res, expected); + } + #[test] fn negate() { let zero_neg = -Scalar::ZERO; diff --git a/k256/src/lib.rs b/k256/src/lib.rs index 65b30f94..6d7aa77e 100644 --- a/k256/src/lib.rs +++ b/k256/src/lib.rs @@ -26,6 +26,11 @@ //! //! Please see type-specific documentation for more information. +#[cfg(feature = "alloc")] +#[allow(unused_imports)] +#[macro_use] +extern crate alloc; + #[cfg(feature = "arithmetic")] mod arithmetic; diff --git a/p192/src/arithmetic/field.rs b/p192/src/arithmetic/field.rs index 6ca1bc40..4ea2348e 100644 --- a/p192/src/arithmetic/field.rs +++ b/p192/src/arithmetic/field.rs @@ -31,6 +31,7 @@ use core::{ iter::{Product, Sum}, ops::{AddAssign, MulAssign, Neg, SubAssign}, }; +use elliptic_curve::ops::Invert; use elliptic_curve::{ bigint::Limb, ff::PrimeField, @@ -136,6 +137,14 @@ impl PrimeField for FieldElement { } } +impl Invert for FieldElement { + type Output = CtOption; + + fn invert(&self) -> CtOption { + self.invert() + } +} + #[cfg(test)] mod tests { use super::FieldElement; diff --git a/p224/src/arithmetic/field.rs b/p224/src/arithmetic/field.rs index 0c6712d6..58f2e5e6 100644 --- a/p224/src/arithmetic/field.rs +++ b/p224/src/arithmetic/field.rs @@ -31,6 +31,7 @@ use core::{ iter::{Product, Sum}, ops::{AddAssign, MulAssign, Neg, SubAssign}, }; +use elliptic_curve::ops::Invert; use elliptic_curve::{ ff::PrimeField, subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, @@ -332,6 +333,14 @@ impl Debug for FieldElement { } } +impl Invert for FieldElement { + type Output = CtOption; + + fn invert(&self) -> CtOption { + self.invert() + } +} + #[cfg(test)] mod tests { use super::FieldElement; diff --git a/p256/src/arithmetic/field.rs b/p256/src/arithmetic/field.rs index 86462f6a..eb54746d 100644 --- a/p256/src/arithmetic/field.rs +++ b/p256/src/arithmetic/field.rs @@ -10,6 +10,7 @@ use core::{ iter::{Product, Sum}, ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; +use elliptic_curve::ops::Invert; use elliptic_curve::{ bigint::{ArrayEncoding, U256}, ff::{Field, PrimeField}, @@ -507,6 +508,14 @@ impl PartialEq for FieldElement { } } +impl Invert for FieldElement { + type Output = CtOption; + + fn invert(&self) -> CtOption { + self.invert() + } +} + impl Add for FieldElement { type Output = FieldElement; diff --git a/p384/src/arithmetic/field.rs b/p384/src/arithmetic/field.rs index 36d30053..cd677d92 100644 --- a/p384/src/arithmetic/field.rs +++ b/p384/src/arithmetic/field.rs @@ -30,6 +30,7 @@ use core::{ iter::{Product, Sum}, ops::{AddAssign, MulAssign, Neg, SubAssign}, }; +use elliptic_curve::ops::Invert; use elliptic_curve::{ bigint::{Limb, U384}, ff::PrimeField, @@ -160,6 +161,14 @@ impl Debug for FieldElement { } } +impl Invert for FieldElement { + type Output = CtOption; + + fn invert(&self) -> CtOption { + self.invert() + } +} + #[cfg(test)] mod tests { use super::FieldElement; diff --git a/p521/src/arithmetic/field.rs b/p521/src/arithmetic/field.rs index 62948995..ef31365a 100644 --- a/p521/src/arithmetic/field.rs +++ b/p521/src/arithmetic/field.rs @@ -34,6 +34,7 @@ use core::{ iter::{Product, Sum}, ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; +use elliptic_curve::ops::Invert; use elliptic_curve::{ ff::{self, Field, PrimeField}, generic_array::GenericArray, @@ -656,6 +657,14 @@ impl<'a> Product<&'a FieldElement> for FieldElement { } } +impl Invert for FieldElement { + type Output = CtOption; + + fn invert(&self) -> CtOption { + self.invert() + } +} + #[cfg(test)] mod tests { use super::FieldElement; diff --git a/primeorder/src/lib.rs b/primeorder/src/lib.rs index cee5c19f..c7e78f27 100644 --- a/primeorder/src/lib.rs +++ b/primeorder/src/lib.rs @@ -21,6 +21,8 @@ pub use elliptic_curve::{ self, generic_array, point::Double, Field, FieldBytes, PrimeCurve, PrimeField, }; +use elliptic_curve::ops::Invert; +use elliptic_curve::subtle::CtOption; use elliptic_curve::CurveArithmetic; /// Parameters for elliptic curves of prime order which can be described by the @@ -32,7 +34,8 @@ pub trait PrimeCurveParams: + CurveArithmetic> { /// Base field element type. - type FieldElement: PrimeField>; + type FieldElement: PrimeField> + + Invert>; /// [Point arithmetic](point_arithmetic) implementation, might be optimized for this specific curve type PointArithmetic: point_arithmetic::PointArithmetic; diff --git a/primeorder/src/projective.rs b/primeorder/src/projective.rs index dc30f532..a75249ba 100644 --- a/primeorder/src/projective.rs +++ b/primeorder/src/projective.rs @@ -8,6 +8,7 @@ use core::{ iter::Sum, ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; +use elliptic_curve::ops::BatchInvert; use elliptic_curve::{ bigint::{ArrayEncoding, Integer}, generic_array::ArrayLength, @@ -26,7 +27,7 @@ use elliptic_curve::{ }, subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, zeroize::DefaultIsZeroes, - Error, FieldBytes, FieldBytesSize, PublicKey, Result, Scalar, + BatchNormalize, Error, FieldBytes, FieldBytesSize, PublicKey, Result, Scalar, }; /// Point on a Weierstrass curve in projective coordinates. @@ -57,16 +58,19 @@ where /// Returns the affine representation of this point, or `None` if it is the identity. pub fn to_affine(&self) -> AffinePoint { - self.z - .invert() - .map(|zinv| AffinePoint { - x: self.x * &zinv, - y: self.y * &zinv, - infinity: 0, - }) + ::invert(&self.z) + .map(|zinv| self.to_affine_internal(zinv)) .unwrap_or(AffinePoint::IDENTITY) } + pub(super) fn to_affine_internal(self, zinv: C::FieldElement) -> AffinePoint { + AffinePoint { + x: self.x * &zinv, + y: self.y * &zinv, + infinity: 0, + } + } + /// Returns `-self`. pub fn neg(&self) -> Self { Self { @@ -326,6 +330,90 @@ where fn to_affine(&self) -> AffinePoint { ProjectivePoint::to_affine(self) } + + #[cfg(feature = "alloc")] + fn batch_normalize(p: &[Self], q: &mut [Self::AffineRepr]) { + assert_eq!(p.len(), q.len()); + + let affine_points: Vec<_> = ::batch_normalize_vec(p); + q.copy_from_slice(affine_points) + } +} + +impl BatchNormalize<&[ProjectivePoint; N]> for ProjectivePoint +where + Self: Double, + C: PrimeCurveParams, +{ + type Output = [Self::AffineRepr; N]; + + fn batch_normalize( + points: &[Self; N], + ) -> ; N]>>::Output { + let mut zs = [C::FieldElement::ONE; N]; + + for i in 0..N { + if points[i].z != C::FieldElement::ZERO { + // Even a single zero value will fail inversion for the entire batch. + // Put a dummy value (above `FieldElement::ONE`) so inversion succeeds + // and treat that case specially later-on. + zs[i] = points[i].z; + } + } + + // This is safe to unwrap since we assured that all elements are non-zero + let zs_inverses = >::batch_invert(&zs).unwrap(); + + let mut affine_points = [AffinePoint::IDENTITY; N]; + for i in 0..N { + if points[i].z != C::FieldElement::ZERO { + // If the `z` coordinate is non-zero, we can use it to invert; + // otherwise it defaults to the `IDENTITY` value in initialization. + affine_points[i] = points[i].to_affine_internal(zs_inverses[i]) + } + } + + affine_points + } +} + +#[cfg(feature = "alloc")] +impl BatchNormalize<&[ProjectivePoint]> for ProjectivePoint +where + Self: Double, + C: PrimeCurveParams, +{ + type Output = Vec; + + fn batch_normalize( + points: &[Self; N], + ) -> ; N]>>::Output { + let mut zs: Vec<_> = vec![C::FieldElement::ONE; points.len()]; + + for i in 0..points.len() { + if points[i].z != C::FieldElement::ZERO { + // Even a single zero value will fail inversion for the entire batch. + // Put a dummy value (above `C::FieldElement::ONE`) so inversion succeeds + // and treat that case specially later-on. + zs[i] = points[i].z; + } + } + + // This is safe to unwrap since we assured that all elements are non-zero + let zs_inverses: Vec<_> = + ::batch_invert_vec(zs.as_vec()).unwrap(); + + let mut affine_points: Vec<_> = vec![AffinePoint::IDENTITY; points.len()]; + for i in 0..points.len() { + if points[i].z != C::FieldElement::ZERO { + // If the `z` coordinate is non-zero, we can use it to invert; + // otherwise it defaults to the `IDENTITY` value in initialization. + affine_points[i] = points[i].to_affine_internal(zs_inverses[i]) + } + } + + affine_points.into_iter().collect() + } } impl LinearCombination for ProjectivePoint diff --git a/sm2/src/arithmetic/field.rs b/sm2/src/arithmetic/field.rs index 200fd99c..e0d7c77d 100644 --- a/sm2/src/arithmetic/field.rs +++ b/sm2/src/arithmetic/field.rs @@ -35,6 +35,7 @@ use core::{ iter::{Product, Sum}, ops::{AddAssign, MulAssign, Neg, SubAssign}, }; +use elliptic_curve::ops::Invert; use elliptic_curve::{ bigint::Limb, ff::PrimeField, @@ -145,6 +146,14 @@ impl PrimeField for FieldElement { } } +impl Invert for FieldElement { + type Output = CtOption; + + fn invert(&self) -> CtOption { + self.invert() + } +} + #[cfg(test)] mod tests { use super::FieldElement; diff --git a/sm2/src/arithmetic/scalar.rs b/sm2/src/arithmetic/scalar.rs index 922b0a73..3cbd1cd8 100644 --- a/sm2/src/arithmetic/scalar.rs +++ b/sm2/src/arithmetic/scalar.rs @@ -34,7 +34,7 @@ use core::{ use elliptic_curve::{ bigint::Limb, ff::PrimeField, - ops::{Invert, Reduce}, + ops::Reduce, scalar::{FromUintUnchecked, IsHigh}, subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, CtOption}, Curve as _, Error, Result, ScalarPrimitive, @@ -48,6 +48,7 @@ use serdect::serde::{de, ser, Deserialize, Serialize}; #[cfg(doc)] use core::ops::{Add, Mul, Sub}; +use elliptic_curve::ops::Invert; /// Scalars are elements in the finite field modulo `n`. /// @@ -161,14 +162,6 @@ impl FromUintUnchecked for Scalar { } } -impl Invert for Scalar { - type Output = CtOption; - - fn invert(&self) -> CtOption { - self.invert() - } -} - impl IsHigh for Scalar { fn is_high(&self) -> Choice { const MODULUS_SHR1: U256 = Sm2::ORDER.shr_vartime(1); @@ -339,6 +332,14 @@ impl<'de> Deserialize<'de> for Scalar { } } +impl Invert for Scalar { + type Output = CtOption; + + fn invert(&self) -> CtOption { + self.invert() + } +} + #[cfg(test)] mod tests { use super::Scalar;