chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

489
vendor/primeorder/src/affine.rs vendored Normal file
View File

@@ -0,0 +1,489 @@
//! Affine curve points.
#![allow(clippy::op_ref)]
use crate::{PrimeCurveParams, ProjectivePoint};
use core::{
borrow::Borrow,
ops::{Mul, Neg},
};
use elliptic_curve::{
ff::{Field, PrimeField},
generic_array::ArrayLength,
group::{prime::PrimeCurveAffine, GroupEncoding},
point::{AffineCoordinates, DecompactPoint, DecompressPoint, Double},
sec1::{
self, CompressedPoint, EncodedPoint, FromEncodedPoint, ModulusSize, ToCompactEncodedPoint,
ToEncodedPoint, UncompressedPointSize,
},
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, CtOption},
zeroize::DefaultIsZeroes,
Error, FieldBytes, FieldBytesEncoding, FieldBytesSize, PublicKey, Result, Scalar,
};
#[cfg(feature = "serde")]
use serdect::serde::{de, ser, Deserialize, Serialize};
/// Point on a Weierstrass curve in affine coordinates.
#[derive(Clone, Copy, Debug)]
pub struct AffinePoint<C: PrimeCurveParams> {
/// x-coordinate
pub(crate) x: C::FieldElement,
/// y-coordinate
pub(crate) y: C::FieldElement,
/// Is this point the point at infinity? 0 = no, 1 = yes
///
/// This is a proxy for [`Choice`], but uses `u8` instead to permit `const`
/// constructors for `IDENTITY` and `GENERATOR`.
pub(crate) infinity: u8,
}
impl<C> AffinePoint<C>
where
C: PrimeCurveParams,
{
/// Additive identity of the group a.k.a. the point at infinity.
pub const IDENTITY: Self = Self {
x: C::FieldElement::ZERO,
y: C::FieldElement::ZERO,
infinity: 1,
};
/// Base point of the curve.
pub const GENERATOR: Self = Self {
x: C::GENERATOR.0,
y: C::GENERATOR.1,
infinity: 0,
};
/// Is this point the point at infinity?
pub fn is_identity(&self) -> Choice {
Choice::from(self.infinity)
}
/// Conditionally negate [`AffinePoint`] for use with point compaction.
fn to_compact(self) -> Self {
let neg_self = -self;
let choice = C::Uint::decode_field_bytes(&self.y.to_repr())
.ct_gt(&C::Uint::decode_field_bytes(&neg_self.y.to_repr()));
Self {
x: self.x,
y: C::FieldElement::conditional_select(&self.y, &neg_self.y, choice),
infinity: self.infinity,
}
}
}
impl<C> AffineCoordinates for AffinePoint<C>
where
C: PrimeCurveParams,
{
type FieldRepr = FieldBytes<C>;
fn x(&self) -> FieldBytes<C> {
self.x.to_repr()
}
fn y_is_odd(&self) -> Choice {
self.y.is_odd()
}
}
impl<C> ConditionallySelectable for AffinePoint<C>
where
C: PrimeCurveParams,
{
#[inline(always)]
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self {
x: C::FieldElement::conditional_select(&a.x, &b.x, choice),
y: C::FieldElement::conditional_select(&a.y, &b.y, choice),
infinity: u8::conditional_select(&a.infinity, &b.infinity, choice),
}
}
}
impl<C> ConstantTimeEq for AffinePoint<C>
where
C: PrimeCurveParams,
{
fn ct_eq(&self, other: &Self) -> Choice {
self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y) & self.infinity.ct_eq(&other.infinity)
}
}
impl<C> Default for AffinePoint<C>
where
C: PrimeCurveParams,
{
fn default() -> Self {
Self::IDENTITY
}
}
impl<C> DefaultIsZeroes for AffinePoint<C> where C: PrimeCurveParams {}
impl<C> DecompressPoint<C> for AffinePoint<C>
where
C: PrimeCurveParams,
FieldBytes<C>: Copy,
{
fn decompress(x_bytes: &FieldBytes<C>, y_is_odd: Choice) -> CtOption<Self> {
C::FieldElement::from_repr(*x_bytes).and_then(|x| {
let alpha = x * &x * &x + &(C::EQUATION_A * &x) + &C::EQUATION_B;
let beta = alpha.sqrt();
beta.map(|beta| {
let y = C::FieldElement::conditional_select(
&-beta,
&beta,
beta.is_odd().ct_eq(&y_is_odd),
);
Self { x, y, infinity: 0 }
})
})
}
}
impl<C> DecompactPoint<C> for AffinePoint<C>
where
C: PrimeCurveParams,
FieldBytes<C>: Copy,
{
fn decompact(x_bytes: &FieldBytes<C>) -> CtOption<Self> {
Self::decompress(x_bytes, Choice::from(0)).map(|point| point.to_compact())
}
}
impl<C> Eq for AffinePoint<C> where C: PrimeCurveParams {}
impl<C> FromEncodedPoint<C> for AffinePoint<C>
where
C: PrimeCurveParams,
FieldBytes<C>: Copy,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
{
/// Attempts to parse the given [`EncodedPoint`] as an SEC1-encoded
/// [`AffinePoint`].
///
/// # Returns
///
/// `None` value if `encoded_point` is not on the secp384r1 curve.
fn from_encoded_point(encoded_point: &EncodedPoint<C>) -> CtOption<Self> {
match encoded_point.coordinates() {
sec1::Coordinates::Identity => CtOption::new(Self::IDENTITY, 1.into()),
sec1::Coordinates::Compact { x } => Self::decompact(x),
sec1::Coordinates::Compressed { x, y_is_odd } => {
Self::decompress(x, Choice::from(y_is_odd as u8))
}
sec1::Coordinates::Uncompressed { x, y } => {
C::FieldElement::from_repr(*y).and_then(|y| {
C::FieldElement::from_repr(*x).and_then(|x| {
let lhs = y * &y;
let rhs = x * &x * &x + &(C::EQUATION_A * &x) + &C::EQUATION_B;
CtOption::new(Self { x, y, infinity: 0 }, lhs.ct_eq(&rhs))
})
})
}
}
}
}
impl<C> From<ProjectivePoint<C>> for AffinePoint<C>
where
C: PrimeCurveParams,
{
fn from(p: ProjectivePoint<C>) -> AffinePoint<C> {
p.to_affine()
}
}
impl<C> From<&ProjectivePoint<C>> for AffinePoint<C>
where
C: PrimeCurveParams,
{
fn from(p: &ProjectivePoint<C>) -> AffinePoint<C> {
p.to_affine()
}
}
impl<C> From<PublicKey<C>> for AffinePoint<C>
where
C: PrimeCurveParams,
{
fn from(public_key: PublicKey<C>) -> AffinePoint<C> {
*public_key.as_affine()
}
}
impl<C> From<&PublicKey<C>> for AffinePoint<C>
where
C: PrimeCurveParams,
{
fn from(public_key: &PublicKey<C>) -> AffinePoint<C> {
AffinePoint::from(*public_key)
}
}
impl<C> From<AffinePoint<C>> for EncodedPoint<C>
where
C: PrimeCurveParams,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
<UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
{
fn from(affine: AffinePoint<C>) -> EncodedPoint<C> {
affine.to_encoded_point(false)
}
}
impl<C> GroupEncoding for AffinePoint<C>
where
C: PrimeCurveParams,
FieldBytes<C>: Copy,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
<UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
{
type Repr = CompressedPoint<C>;
/// NOTE: not constant-time with respect to identity point
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
EncodedPoint::<C>::from_bytes(bytes)
.map(|point| CtOption::new(point, Choice::from(1)))
.unwrap_or_else(|_| {
// SEC1 identity encoding is technically 1-byte 0x00, but the
// `GroupEncoding` API requires a fixed-width `Repr`
let is_identity = bytes.ct_eq(&Self::Repr::default());
CtOption::new(EncodedPoint::<C>::identity(), is_identity)
})
.and_then(|point| Self::from_encoded_point(&point))
}
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
// No unchecked conversion possible for compressed points
Self::from_bytes(bytes)
}
fn to_bytes(&self) -> Self::Repr {
let encoded = self.to_encoded_point(true);
let mut result = CompressedPoint::<C>::default();
result[..encoded.len()].copy_from_slice(encoded.as_bytes());
result
}
}
impl<C> PartialEq for AffinePoint<C>
where
C: PrimeCurveParams,
{
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
impl<C> PrimeCurveAffine for AffinePoint<C>
where
C: PrimeCurveParams,
FieldBytes<C>: Copy,
FieldBytesSize<C>: ModulusSize,
ProjectivePoint<C>: Double,
CompressedPoint<C>: Copy,
<UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
{
type Curve = ProjectivePoint<C>;
type Scalar = Scalar<C>;
fn identity() -> AffinePoint<C> {
Self::IDENTITY
}
fn generator() -> AffinePoint<C> {
Self::GENERATOR
}
fn is_identity(&self) -> Choice {
self.is_identity()
}
fn to_curve(&self) -> ProjectivePoint<C> {
ProjectivePoint::from(*self)
}
}
impl<C> ToCompactEncodedPoint<C> for AffinePoint<C>
where
C: PrimeCurveParams,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
<UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
{
/// Serialize this value as a SEC1 compact [`EncodedPoint`]
fn to_compact_encoded_point(&self) -> CtOption<EncodedPoint<C>> {
let point = self.to_compact();
let mut bytes = CompressedPoint::<C>::default();
bytes[0] = sec1::Tag::Compact.into();
bytes[1..].copy_from_slice(&point.x.to_repr());
let encoded = EncodedPoint::<C>::from_bytes(bytes);
let is_some = point.y.ct_eq(&self.y);
CtOption::new(encoded.unwrap_or_default(), is_some)
}
}
impl<C> ToEncodedPoint<C> for AffinePoint<C>
where
C: PrimeCurveParams,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
<UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
{
fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> {
EncodedPoint::<C>::conditional_select(
&EncodedPoint::<C>::from_affine_coordinates(
&self.x.to_repr(),
&self.y.to_repr(),
compress,
),
&EncodedPoint::<C>::identity(),
self.is_identity(),
)
}
}
impl<C> TryFrom<EncodedPoint<C>> for AffinePoint<C>
where
C: PrimeCurveParams,
FieldBytes<C>: Copy,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
{
type Error = Error;
fn try_from(point: EncodedPoint<C>) -> Result<AffinePoint<C>> {
AffinePoint::try_from(&point)
}
}
impl<C> TryFrom<&EncodedPoint<C>> for AffinePoint<C>
where
C: PrimeCurveParams,
FieldBytes<C>: Copy,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
{
type Error = Error;
fn try_from(point: &EncodedPoint<C>) -> Result<AffinePoint<C>> {
Option::from(AffinePoint::<C>::from_encoded_point(point)).ok_or(Error)
}
}
impl<C> TryFrom<AffinePoint<C>> for PublicKey<C>
where
C: PrimeCurveParams,
{
type Error = Error;
fn try_from(affine_point: AffinePoint<C>) -> Result<PublicKey<C>> {
PublicKey::from_affine(affine_point)
}
}
impl<C> TryFrom<&AffinePoint<C>> for PublicKey<C>
where
C: PrimeCurveParams,
{
type Error = Error;
fn try_from(affine_point: &AffinePoint<C>) -> Result<PublicKey<C>> {
PublicKey::<C>::try_from(*affine_point)
}
}
//
// Arithmetic trait impls
//
impl<C, S> Mul<S> for AffinePoint<C>
where
C: PrimeCurveParams,
S: Borrow<Scalar<C>>,
ProjectivePoint<C>: Double,
{
type Output = ProjectivePoint<C>;
fn mul(self, scalar: S) -> ProjectivePoint<C> {
ProjectivePoint::<C>::from(self) * scalar
}
}
impl<C> Neg for AffinePoint<C>
where
C: PrimeCurveParams,
{
type Output = Self;
fn neg(self) -> Self {
AffinePoint {
x: self.x,
y: -self.y,
infinity: self.infinity,
}
}
}
impl<C> Neg for &AffinePoint<C>
where
C: PrimeCurveParams,
{
type Output = AffinePoint<C>;
fn neg(self) -> AffinePoint<C> {
-(*self)
}
}
//
// serde support
//
#[cfg(feature = "serde")]
impl<C> Serialize for AffinePoint<C>
where
C: PrimeCurveParams,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
<UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
{
fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
self.to_encoded_point(true).serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, C> Deserialize<'de> for AffinePoint<C>
where
C: PrimeCurveParams,
FieldBytes<C>: Copy,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
{
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
EncodedPoint::<C>::deserialize(deserializer)?
.try_into()
.map_err(de::Error::custom)
}
}

157
vendor/primeorder/src/dev.rs vendored Normal file
View File

@@ -0,0 +1,157 @@
//! Development-related functionality.
// TODO(tarcieri): move all development-related macros into this module
/// Implement projective arithmetic tests.
#[macro_export]
macro_rules! impl_projective_arithmetic_tests {
(
$affine:tt,
$projective:tt,
$scalar:ty,
$add_vectors:expr,
$mul_vectors:expr
) => {
/// Assert that the provided projective point matches the given test vector.
// TODO(tarcieri): use coordinate APIs. See zkcrypto/group#30
macro_rules! assert_point_eq {
($actual:expr, $expected:expr) => {
let (expected_x, expected_y) = $expected;
let point = $actual.to_affine().to_encoded_point(false);
let (actual_x, actual_y) = match point.coordinates() {
sec1::Coordinates::Uncompressed { x, y } => (x, y),
_ => unreachable!(),
};
assert_eq!(&expected_x, actual_x.as_slice());
assert_eq!(&expected_y, actual_y.as_slice());
};
}
#[test]
fn affine_to_projective() {
let basepoint_affine = $affine::GENERATOR;
let basepoint_projective = $projective::GENERATOR;
assert_eq!($projective::from(basepoint_affine), basepoint_projective,);
assert_eq!(basepoint_projective.to_affine(), basepoint_affine);
assert!(!bool::from(basepoint_projective.to_affine().is_identity()));
assert!(bool::from($projective::IDENTITY.to_affine().is_identity()));
}
#[test]
fn projective_identity_addition() {
let identity = $projective::IDENTITY;
let generator = $projective::GENERATOR;
assert_eq!(identity + &generator, generator);
assert_eq!(generator + &identity, generator);
}
#[test]
fn projective_mixed_addition() {
let identity = $projective::IDENTITY;
let basepoint_affine = $affine::GENERATOR;
let basepoint_projective = $projective::GENERATOR;
assert_eq!(identity + &basepoint_affine, basepoint_projective);
assert_eq!(
basepoint_projective + &basepoint_affine,
basepoint_projective + &basepoint_projective
);
}
#[test]
fn test_vector_repeated_add() {
let generator = $projective::GENERATOR;
let mut p = generator;
for i in 0..$add_vectors.len() {
assert_point_eq!(p, $add_vectors[i]);
p += &generator;
}
}
#[test]
fn test_vector_repeated_add_mixed() {
let generator = $affine::GENERATOR;
let mut p = $projective::GENERATOR;
for i in 0..$add_vectors.len() {
assert_point_eq!(p, $add_vectors[i]);
p += &generator;
}
}
#[test]
fn test_vector_add_mixed_identity() {
let generator = $projective::GENERATOR;
let p0 = generator + $projective::IDENTITY;
let p1 = generator + $affine::IDENTITY;
assert_eq!(p0, p1);
}
#[test]
fn test_vector_double_generator() {
let generator = $projective::GENERATOR;
let mut p = generator;
for i in 0..2 {
assert_point_eq!(p, $add_vectors[i]);
p = p.double();
}
}
#[test]
fn projective_add_vs_double() {
let generator = $projective::GENERATOR;
assert_eq!(generator + &generator, generator.double());
}
#[test]
fn projective_add_and_sub() {
let basepoint_affine = $affine::GENERATOR;
let basepoint_projective = $projective::GENERATOR;
assert_eq!(
(basepoint_projective + &basepoint_projective) - &basepoint_projective,
basepoint_projective
);
assert_eq!(
(basepoint_projective + &basepoint_affine) - &basepoint_affine,
basepoint_projective
);
}
#[test]
fn projective_double_and_sub() {
let generator = $projective::GENERATOR;
assert_eq!(generator.double() - &generator, generator);
}
#[test]
fn test_vector_scalar_mult() {
let generator = $projective::GENERATOR;
for (k, coords) in $add_vectors
.iter()
.enumerate()
.map(|(k, coords)| (<$scalar>::from(k as u64 + 1), *coords))
.chain($mul_vectors.iter().cloned().map(|(k, x, y)| {
(
<$scalar>::from_repr(
$crate::generic_array::GenericArray::clone_from_slice(&k),
)
.unwrap(),
(x, y),
)
}))
{
let p = generator * &k;
assert_point_eq!(p, coords);
}
}
};
}

660
vendor/primeorder/src/field.rs vendored Normal file
View File

@@ -0,0 +1,660 @@
/// Implements a field element type whose internal representation is in
/// Montgomery form, providing a combination of trait impls and inherent impls
/// which are `const fn` where possible.
///
/// Accepts a set of `const fn` arithmetic operation functions as arguments.
///
/// # Inherent impls
/// - `const ZERO: Self`
/// - `const ONE: Self` (multiplicative identity)
/// - `pub fn from_bytes`
/// - `pub fn from_slice`
/// - `pub fn from_uint`
/// - `fn from_uint_unchecked`
/// - `pub fn to_bytes`
/// - `pub fn to_canonical`
/// - `pub fn is_odd`
/// - `pub fn is_zero`
/// - `pub fn double`
///
/// NOTE: field implementations must provide their own inherent impls of
/// the following methods in order for the code generated by this macro to
/// compile:
///
/// - `pub fn invert`
/// - `pub fn sqrt`
///
/// # Trait impls
/// - `AsRef<$arr>`
/// - `ConditionallySelectable`
/// - `ConstantTimeEq`
/// - `ConstantTimeGreater`
/// - `ConstantTimeLess`
/// - `Default`
/// - `DefaultIsZeroes`
/// - `Eq`
/// - `Field`
/// - `PartialEq`
///
/// ## Ops
/// - `Add`
/// - `AddAssign`
/// - `Sub`
/// - `SubAssign`
/// - `Mul`
/// - `MulAssign`
/// - `Neg`
#[macro_export]
macro_rules! impl_mont_field_element {
(
$curve:tt,
$fe:tt,
$bytes:ty,
$uint:ty,
$modulus:expr,
$arr:ty,
$from_mont:ident,
$to_mont:ident,
$add:ident,
$sub:ident,
$mul:ident,
$neg:ident,
$square:ident
) => {
impl $fe {
/// Zero element.
pub const ZERO: Self = Self(<$uint>::ZERO);
/// Multiplicative identity.
pub const ONE: Self = Self::from_uint_unchecked(<$uint>::ONE);
/// Create a [`
#[doc = stringify!($fe)]
/// `] from a canonical big-endian representation.
pub fn from_bytes(repr: &$bytes) -> $crate::elliptic_curve::subtle::CtOption<Self> {
use $crate::elliptic_curve::FieldBytesEncoding;
Self::from_uint(FieldBytesEncoding::<$curve>::decode_field_bytes(repr))
}
/// Decode [`
#[doc = stringify!($fe)]
/// `] from a big endian byte slice.
pub fn from_slice(slice: &[u8]) -> $crate::elliptic_curve::Result<Self> {
use $crate::elliptic_curve::generic_array::{typenum::Unsigned, GenericArray};
if slice.len() != <$curve as $crate::elliptic_curve::Curve>::FieldBytesSize::USIZE {
return Err($crate::elliptic_curve::Error);
}
Option::from(Self::from_bytes(GenericArray::from_slice(slice)))
.ok_or($crate::elliptic_curve::Error)
}
/// Decode [`
#[doc = stringify!($fe)]
/// `]
/// from [`
#[doc = stringify!($uint)]
/// `] converting it into Montgomery form:
///
/// ```text
/// w * R^2 * R^-1 mod p = wR mod p
/// ```
pub fn from_uint(uint: $uint) -> $crate::elliptic_curve::subtle::CtOption<Self> {
use $crate::elliptic_curve::subtle::ConstantTimeLess as _;
let is_some = uint.ct_lt(&$modulus);
$crate::elliptic_curve::subtle::CtOption::new(
Self::from_uint_unchecked(uint),
is_some,
)
}
/// Parse a [`
#[doc = stringify!($fe)]
/// `] from big endian hex-encoded bytes.
///
/// Does *not* perform a check that the field element does not overflow the order.
///
/// This method is primarily intended for defining internal constants.
#[allow(dead_code)]
pub(crate) const fn from_hex(hex: &str) -> Self {
Self::from_uint_unchecked(<$uint>::from_be_hex(hex))
}
/// Convert a `u64` into a [`
#[doc = stringify!($fe)]
/// `].
pub const fn from_u64(w: u64) -> Self {
Self::from_uint_unchecked(<$uint>::from_u64(w))
}
/// Decode [`
#[doc = stringify!($fe)]
/// `] from [`
#[doc = stringify!($uint)]
/// `] converting it into Montgomery form.
///
/// Does *not* perform a check that the field element does not overflow the order.
///
/// Used incorrectly this can lead to invalid results!
pub(crate) const fn from_uint_unchecked(w: $uint) -> Self {
Self(<$uint>::from_words($to_mont(w.as_words())))
}
/// Returns the big-endian encoding of this [`
#[doc = stringify!($fe)]
/// `].
pub fn to_bytes(self) -> $bytes {
use $crate::elliptic_curve::FieldBytesEncoding;
FieldBytesEncoding::<$curve>::encode_field_bytes(&self.to_canonical())
}
/// Translate [`
#[doc = stringify!($fe)]
/// `] out of the Montgomery domain, returning a [`
#[doc = stringify!($uint)]
/// `] in canonical form.
#[inline]
pub const fn to_canonical(self) -> $uint {
<$uint>::from_words($from_mont(self.0.as_words()))
}
/// Determine if this [`
#[doc = stringify!($fe)]
/// `] is odd in the SEC1 sense: `self mod 2 == 1`.
///
/// # Returns
///
/// If odd, return `Choice(1)`. Otherwise, return `Choice(0)`.
pub fn is_odd(&self) -> Choice {
use $crate::elliptic_curve::bigint::Integer;
self.to_canonical().is_odd()
}
/// Determine if this [`
#[doc = stringify!($fe)]
/// `] is even in the SEC1 sense: `self mod 2 == 0`.
///
/// # Returns
///
/// If even, return `Choice(1)`. Otherwise, return `Choice(0)`.
pub fn is_even(&self) -> Choice {
!self.is_odd()
}
/// Determine if this [`
#[doc = stringify!($fe)]
/// `] is zero.
///
/// # Returns
///
/// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`.
pub fn is_zero(&self) -> Choice {
self.ct_eq(&Self::ZERO)
}
/// Add elements.
pub const fn add(&self, rhs: &Self) -> Self {
Self(<$uint>::from_words($add(
self.0.as_words(),
rhs.0.as_words(),
)))
}
/// Double element (add it to itself).
#[must_use]
pub const fn double(&self) -> Self {
self.add(self)
}
/// Subtract elements.
pub const fn sub(&self, rhs: &Self) -> Self {
Self(<$uint>::from_words($sub(
self.0.as_words(),
rhs.0.as_words(),
)))
}
/// Multiply elements.
pub const fn multiply(&self, rhs: &Self) -> Self {
Self(<$uint>::from_words($mul(
self.0.as_words(),
rhs.0.as_words(),
)))
}
/// Negate element.
pub const fn neg(&self) -> Self {
Self(<$uint>::from_words($neg(self.0.as_words())))
}
/// Compute modular square.
#[must_use]
pub const fn square(&self) -> Self {
Self(<$uint>::from_words($square(self.0.as_words())))
}
/// Returns `self^exp`, where `exp` is a little-endian integer exponent.
///
/// **This operation is variable time with respect to the exponent.**
///
/// If the exponent is fixed, this operation is effectively constant time.
pub const fn pow_vartime(&self, exp: &[u64]) -> Self {
let mut res = Self::ONE;
let mut i = exp.len();
while i > 0 {
i -= 1;
let mut j = 64;
while j > 0 {
j -= 1;
res = res.square();
if ((exp[i] >> j) & 1) == 1 {
res = res.multiply(self);
}
}
}
res
}
}
$crate::impl_mont_field_element_arithmetic!(
$fe, $bytes, $uint, $arr, $add, $sub, $mul, $neg
);
};
}
/// Add arithmetic impls to the given field element.
#[macro_export]
macro_rules! impl_mont_field_element_arithmetic {
(
$fe:tt,
$bytes:ty,
$uint:ty,
$arr:ty,
$add:ident,
$sub:ident,
$mul:ident,
$neg:ident
) => {
impl AsRef<$arr> for $fe {
fn as_ref(&self) -> &$arr {
self.0.as_ref()
}
}
impl Default for $fe {
fn default() -> Self {
Self::ZERO
}
}
impl Eq for $fe {}
impl PartialEq for $fe {
fn eq(&self, rhs: &Self) -> bool {
self.0.ct_eq(&(rhs.0)).into()
}
}
impl From<u32> for $fe {
fn from(n: u32) -> $fe {
Self::from_uint_unchecked(<$uint>::from(n))
}
}
impl From<u64> for $fe {
fn from(n: u64) -> $fe {
Self::from_uint_unchecked(<$uint>::from(n))
}
}
impl From<u128> for $fe {
fn from(n: u128) -> $fe {
Self::from_uint_unchecked(<$uint>::from(n))
}
}
impl $crate::elliptic_curve::subtle::ConditionallySelectable for $fe {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self(<$uint>::conditional_select(&a.0, &b.0, choice))
}
}
impl $crate::elliptic_curve::subtle::ConstantTimeEq for $fe {
fn ct_eq(&self, other: &Self) -> $crate::elliptic_curve::subtle::Choice {
self.0.ct_eq(&other.0)
}
}
impl $crate::elliptic_curve::subtle::ConstantTimeGreater for $fe {
fn ct_gt(&self, other: &Self) -> $crate::elliptic_curve::subtle::Choice {
self.0.ct_gt(&other.0)
}
}
impl $crate::elliptic_curve::subtle::ConstantTimeLess for $fe {
fn ct_lt(&self, other: &Self) -> $crate::elliptic_curve::subtle::Choice {
self.0.ct_lt(&other.0)
}
}
impl $crate::elliptic_curve::zeroize::DefaultIsZeroes for $fe {}
impl $crate::elliptic_curve::ff::Field for $fe {
const ZERO: Self = Self::ZERO;
const ONE: Self = Self::ONE;
fn random(mut rng: impl $crate::elliptic_curve::rand_core::RngCore) -> Self {
// NOTE: can't use ScalarPrimitive::random due to CryptoRng bound
let mut bytes = <$bytes>::default();
loop {
rng.fill_bytes(&mut bytes);
if let Some(fe) = Self::from_bytes(&bytes).into() {
return fe;
}
}
}
fn is_zero(&self) -> Choice {
Self::ZERO.ct_eq(self)
}
#[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()
}
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
$crate::elliptic_curve::ff::helpers::sqrt_ratio_generic(num, div)
}
}
$crate::impl_field_op!($fe, Add, add, $add);
$crate::impl_field_op!($fe, Sub, sub, $sub);
$crate::impl_field_op!($fe, Mul, mul, $mul);
impl AddAssign<$fe> for $fe {
#[inline]
fn add_assign(&mut self, other: $fe) {
*self = *self + other;
}
}
impl AddAssign<&$fe> for $fe {
#[inline]
fn add_assign(&mut self, other: &$fe) {
*self = *self + other;
}
}
impl SubAssign<$fe> for $fe {
#[inline]
fn sub_assign(&mut self, other: $fe) {
*self = *self - other;
}
}
impl SubAssign<&$fe> for $fe {
#[inline]
fn sub_assign(&mut self, other: &$fe) {
*self = *self - other;
}
}
impl MulAssign<&$fe> for $fe {
#[inline]
fn mul_assign(&mut self, other: &$fe) {
*self = *self * other;
}
}
impl MulAssign for $fe {
#[inline]
fn mul_assign(&mut self, other: $fe) {
*self = *self * other;
}
}
impl Neg for $fe {
type Output = $fe;
#[inline]
fn neg(self) -> $fe {
Self($neg(self.as_ref()).into())
}
}
impl Sum for $fe {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.reduce(core::ops::Add::add).unwrap_or(Self::ZERO)
}
}
impl<'a> Sum<&'a $fe> for $fe {
fn sum<I: Iterator<Item = &'a $fe>>(iter: I) -> Self {
iter.copied().sum()
}
}
impl Product for $fe {
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.reduce(core::ops::Mul::mul).unwrap_or(Self::ONE)
}
}
impl<'a> Product<&'a $fe> for $fe {
fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
iter.copied().product()
}
}
};
}
/// Emit impls for a `core::ops` trait for all combinations of reference types,
/// which thunk to the given function.
#[macro_export]
macro_rules! impl_field_op {
($fe:tt, $op:tt, $op_fn:ident, $func:ident) => {
impl ::core::ops::$op for $fe {
type Output = $fe;
#[inline]
fn $op_fn(self, rhs: $fe) -> $fe {
$fe($func(self.as_ref(), rhs.as_ref()).into())
}
}
impl ::core::ops::$op<&$fe> for $fe {
type Output = $fe;
#[inline]
fn $op_fn(self, rhs: &$fe) -> $fe {
$fe($func(self.as_ref(), rhs.as_ref()).into())
}
}
impl ::core::ops::$op<&$fe> for &$fe {
type Output = $fe;
#[inline]
fn $op_fn(self, rhs: &$fe) -> $fe {
$fe($func(self.as_ref(), rhs.as_ref()).into())
}
}
};
}
/// Implement Bernstein-Yang field element inversion.
#[macro_export]
macro_rules! impl_bernstein_yang_invert {
(
$a:expr,
$one:expr,
$d:expr,
$nlimbs:expr,
$word:ty,
$from_mont:ident,
$mul:ident,
$neg:ident,
$divstep_precomp:ident,
$divstep:ident,
$msat:ident,
$selectznz:ident,
) => {{
// See Bernstein-Yang 2019 p.366
const ITERATIONS: usize = (49 * $d + 57) / 17;
let a = $from_mont($a);
let mut d = 1;
let mut f = $msat();
let mut g = [0; $nlimbs + 1];
let mut v = [0; $nlimbs];
let mut r = $one;
let mut i = 0;
let mut j = 0;
while j < $nlimbs {
g[j] = a[j];
j += 1;
}
while i < ITERATIONS - ITERATIONS % 2 {
let (out1, out2, out3, out4, out5) = $divstep(d, &f, &g, &v, &r);
let (out1, out2, out3, out4, out5) = $divstep(out1, &out2, &out3, &out4, &out5);
d = out1;
f = out2;
g = out3;
v = out4;
r = out5;
i += 2;
}
if ITERATIONS % 2 != 0 {
let (_out1, out2, _out3, out4, _out5) = $divstep(d, &f, &g, &v, &r);
v = out4;
f = out2;
}
let s = ((f[f.len() - 1] >> <$word>::BITS - 1) & 1) as u8;
let v = $selectznz(s, &v, &$neg(&v));
$mul(&v, &$divstep_precomp())
}};
}
/// Implement field element identity tests.
#[macro_export]
macro_rules! impl_field_identity_tests {
($fe:tt) => {
#[test]
fn zero_is_additive_identity() {
let zero = $fe::ZERO;
let one = $fe::ONE;
assert_eq!(zero.add(&zero), zero);
assert_eq!(one.add(&zero), one);
}
#[test]
fn one_is_multiplicative_identity() {
let one = $fe::ONE;
assert_eq!(one.multiply(&one), one);
}
};
}
/// Implement field element inversion tests.
#[macro_export]
macro_rules! impl_field_invert_tests {
($fe:tt) => {
#[test]
fn invert() {
let one = $fe::ONE;
assert_eq!(one.invert().unwrap(), one);
let three = one + &one + &one;
let inv_three = three.invert().unwrap();
assert_eq!(three * &inv_three, one);
let minus_three = -three;
let inv_minus_three = minus_three.invert().unwrap();
assert_eq!(inv_minus_three, -inv_three);
assert_eq!(three * &inv_minus_three, -one);
}
};
}
/// Implement field element square root tests.
#[macro_export]
macro_rules! impl_field_sqrt_tests {
($fe:tt) => {
#[test]
fn sqrt() {
for &n in &[1u64, 4, 9, 16, 25, 36, 49, 64] {
let fe = $fe::from(n);
let sqrt = fe.sqrt().unwrap();
assert_eq!(sqrt.square(), fe);
}
}
};
}
/// Implement tests for the `PrimeField` trait.
#[macro_export]
macro_rules! impl_primefield_tests {
($fe:tt, $t:expr) => {
#[test]
fn two_inv_constant() {
assert_eq!($fe::from(2u32) * $fe::TWO_INV, $fe::ONE);
}
#[test]
fn root_of_unity_constant() {
assert!($fe::S < 128);
let two_to_s = 1u128 << $fe::S;
// ROOT_OF_UNITY^{2^s} mod m == 1
assert_eq!(
$fe::ROOT_OF_UNITY.pow_vartime(&[
(two_to_s & 0xFFFFFFFFFFFFFFFF) as u64,
(two_to_s >> 64) as u64,
0,
0
]),
$fe::ONE
);
// MULTIPLICATIVE_GENERATOR^{t} mod m == ROOT_OF_UNITY
assert_eq!(
$fe::MULTIPLICATIVE_GENERATOR.pow_vartime(&$t),
$fe::ROOT_OF_UNITY
)
}
#[test]
fn root_of_unity_inv_constant() {
assert_eq!($fe::ROOT_OF_UNITY * $fe::ROOT_OF_UNITY_INV, $fe::ONE);
}
#[test]
fn delta_constant() {
// DELTA^{t} mod m == 1
assert_eq!($fe::DELTA.pow_vartime(&$t), $fe::ONE);
}
};
}

53
vendor/primeorder/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,53 @@
#![no_std]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
)]
#![forbid(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms, unused_qualifications)]
#![doc = include_str!("../README.md")]
#[cfg(feature = "alloc")]
#[macro_use]
extern crate alloc;
pub mod point_arithmetic;
mod affine;
#[cfg(feature = "dev")]
mod dev;
mod field;
mod projective;
pub use crate::{affine::AffinePoint, projective::ProjectivePoint};
pub use elliptic_curve::{
self, generic_array, point::Double, Field, FieldBytes, PrimeCurve, PrimeField,
};
use elliptic_curve::CurveArithmetic;
/// Parameters for elliptic curves of prime order which can be described by the
/// short Weierstrass equation.
pub trait PrimeCurveParams:
PrimeCurve
+ CurveArithmetic
+ CurveArithmetic<AffinePoint = AffinePoint<Self>>
+ CurveArithmetic<ProjectivePoint = ProjectivePoint<Self>>
{
/// Base field element type.
// TODO(tarcieri): add `Invert` bound
type FieldElement: PrimeField<Repr = FieldBytes<Self>>;
/// [Point arithmetic](point_arithmetic) implementation, might be optimized for this specific curve
type PointArithmetic: point_arithmetic::PointArithmetic<Self>;
/// Coefficient `a` in the curve equation.
const EQUATION_A: Self::FieldElement;
/// Coefficient `b` in the curve equation.
const EQUATION_B: Self::FieldElement;
/// Generator point's affine coordinates: (x, y).
const GENERATOR: (Self::FieldElement, Self::FieldElement);
}

View File

@@ -0,0 +1,318 @@
//! Point arithmetic implementation optimised for different curve equations
//!
//! Support for formulas specialized to the short Weierstrass equation's
//! 𝒂-coefficient.
use elliptic_curve::{subtle::ConditionallySelectable, Field};
use crate::{AffinePoint, PrimeCurveParams, ProjectivePoint};
mod sealed {
use crate::{AffinePoint, PrimeCurveParams, ProjectivePoint};
/// Elliptic point arithmetic implementation
///
/// Provides implementation of point arithmetic (point addition, point doubling) which
/// might be optimized for the curve.
pub trait PointArithmetic<C: PrimeCurveParams> {
/// Returns `lhs + rhs`
fn add(lhs: &ProjectivePoint<C>, rhs: &ProjectivePoint<C>) -> ProjectivePoint<C>;
/// Returns `lhs + rhs`
fn add_mixed(lhs: &ProjectivePoint<C>, rhs: &AffinePoint<C>) -> ProjectivePoint<C>;
/// Returns `point + point`
fn double(point: &ProjectivePoint<C>) -> ProjectivePoint<C>;
}
}
/// Allow crate-local visibility
pub(crate) use sealed::PointArithmetic;
/// The 𝒂-coefficient of the short Weierstrass equation does not have specific
/// properties which allow for an optimized implementation.
pub struct EquationAIsGeneric {}
impl<C: PrimeCurveParams> PointArithmetic<C> for EquationAIsGeneric {
/// Implements complete addition for any curve
///
/// Implements the complete addition formula from [Renes-Costello-Batina 2015]
/// (Algorithm 1). The comments after each line indicate which algorithm steps
/// are being performed.
///
/// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060
fn add(lhs: &ProjectivePoint<C>, rhs: &ProjectivePoint<C>) -> ProjectivePoint<C> {
let b3 = C::FieldElement::from(3) * C::EQUATION_B;
let t0 = lhs.x * rhs.x; // 1
let t1 = lhs.y * rhs.y; // 2
let t2 = lhs.z * rhs.z; // 3
let t3 = lhs.x + lhs.y; // 4
let t4 = rhs.x + rhs.y; // 5
let t3 = t3 * t4; // 6
let t4 = t0 + t1; // 7
let t3 = t3 - t4; // 8
let t4 = lhs.x + lhs.z; // 9
let t5 = rhs.x + rhs.z; // 10
let t4 = t4 * t5; // 11
let t5 = t0 + t2; // 12
let t4 = t4 - t5; // 13
let t5 = lhs.y + lhs.z; // 14
let x3 = rhs.y + rhs.z; // 15
let t5 = t5 * x3; // 16
let x3 = t1 + t2; // 17
let t5 = t5 - x3; // 18
let z3 = C::EQUATION_A * t4; // 19
let x3 = b3 * t2; // 20
let z3 = x3 + z3; // 21
let x3 = t1 - z3; // 22
let z3 = t1 + z3; // 23
let y3 = x3 * z3; // 24
let t1 = t0 + t0; // 25
let t1 = t1 + t0; // 26
let t2 = C::EQUATION_A * t2; // 27
let t4 = b3 * t4; // 28
let t1 = t1 + t2; // 29
let t2 = t0 - t2; // 30
let t2 = C::EQUATION_A * t2; // 31
let t4 = t4 + t2; // 32
let t0 = t1 * t4; // 33
let y3 = y3 + t0; // 34
let t0 = t5 * t4; // 35
let x3 = t3 * x3; // 36
let x3 = x3 - t0; // 37
let t0 = t3 * t1; // 38
let z3 = t5 * z3; // 39
let z3 = z3 + t0; // 40
ProjectivePoint {
x: x3,
y: y3,
z: z3,
}
}
/// Implements complete mixed addition for curves with any `a`
///
/// Implements the complete mixed addition formula from [Renes-Costello-Batina 2015]
/// (Algorithm 2). The comments after each line indicate which algorithm
/// steps are being performed.
///
/// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060
fn add_mixed(lhs: &ProjectivePoint<C>, rhs: &AffinePoint<C>) -> ProjectivePoint<C> {
let b3 = C::EQUATION_B * C::FieldElement::from(3);
let t0 = lhs.x * rhs.x; // 1
let t1 = lhs.y * rhs.y; // 2
let t3 = rhs.x + rhs.y; // 3
let t4 = lhs.x + lhs.y; // 4
let t3 = t3 * t4; // 5
let t4 = t0 + t1; // 6
let t3 = t3 - t4; // 7
let t4 = rhs.x * lhs.z; // 8
let t4 = t4 + lhs.x; // 9
let t5 = rhs.y * lhs.z; // 10
let t5 = t5 + lhs.y; // 11
let z3 = C::EQUATION_A * t4; // 12
let x3 = b3 * lhs.z; // 13
let z3 = x3 + z3; // 14
let x3 = t1 - z3; // 15
let z3 = t1 + z3; // 16
let y3 = x3 * z3; // 17
let t1 = t0 + t0; // 18
let t1 = t1 + t0; // 19
let t2 = C::EQUATION_A * lhs.z; // 20
let t4 = b3 * t4; // 21
let t1 = t1 + t2; // 22
let t2 = t0 - t2; // 23
let t2 = C::EQUATION_A * t2; // 24
let t4 = t4 + t2; // 25
let t0 = t1 * t4; // 26
let y3 = y3 + t0; // 27
let t0 = t5 * t4; // 28
let x3 = t3 * x3; // 29
let x3 = x3 - t0; // 30
let t0 = t3 * t1; // 31
let z3 = t5 * z3; // 32
let z3 = z3 + t0; // 33
let mut ret = ProjectivePoint {
x: x3,
y: y3,
z: z3,
};
ret.conditional_assign(lhs, rhs.is_identity());
ret
}
/// Implements point doubling for curves with any `a`
///
/// Implements the exception-free point doubling formula from [Renes-Costello-Batina 2015]
/// (Algorithm 3). The comments after each line indicate which algorithm
/// steps are being performed.
///
/// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060
fn double(point: &ProjectivePoint<C>) -> ProjectivePoint<C> {
let b3 = C::EQUATION_B * C::FieldElement::from(3);
let t0 = point.x * point.x; // 1
let t1 = point.y * point.y; // 2
let t2 = point.z * point.z; // 3
let t3 = point.x * point.y; // 4
let t3 = t3 + t3; // 5
let z3 = point.x * point.z; // 6
let z3 = z3 + z3; // 7
let x3 = C::EQUATION_A * z3; // 8
let y3 = b3 * t2; // 9
let y3 = x3 + y3; // 10
let x3 = t1 - y3; // 11
let y3 = t1 + y3; // 12
let y3 = x3 * y3; // 13
let x3 = t3 * x3; // 14
let z3 = b3 * z3; // 15
let t2 = C::EQUATION_A * t2; // 16
let t3 = t0 - t2; // 17
let t3 = C::EQUATION_A * t3; // 18
let t3 = t3 + z3; // 19
let z3 = t0 + t0; // 20
let t0 = z3 + t0; // 21
let t0 = t0 + t2; // 22
let t0 = t0 * t3; // 23
let y3 = y3 + t0; // 24
let t2 = point.y * point.z; // 25
let t2 = t2 + t2; // 26
let t0 = t2 * t3; // 27
let x3 = x3 - t0; // 28
let z3 = t2 * t1; // 29
let z3 = z3 + z3; // 30
let z3 = z3 + z3; // 31
ProjectivePoint {
x: x3,
y: y3,
z: z3,
}
}
}
/// The 𝒂-coefficient of the short Weierstrass equation is -3.
pub struct EquationAIsMinusThree {}
impl<C: PrimeCurveParams> PointArithmetic<C> for EquationAIsMinusThree {
/// Implements complete addition for curves with `a = -3`
///
/// Implements the complete addition formula from [Renes-Costello-Batina 2015]
/// (Algorithm 4). The comments after each line indicate which algorithm steps
/// are being performed.
///
/// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060
fn add(lhs: &ProjectivePoint<C>, rhs: &ProjectivePoint<C>) -> ProjectivePoint<C> {
debug_assert_eq!(
C::EQUATION_A,
-C::FieldElement::from(3),
"this implementation is only valid for C::EQUATION_A = -3"
);
let xx = lhs.x * rhs.x; // 1
let yy = lhs.y * rhs.y; // 2
let zz = lhs.z * rhs.z; // 3
let xy_pairs = ((lhs.x + lhs.y) * (rhs.x + rhs.y)) - (xx + yy); // 4, 5, 6, 7, 8
let yz_pairs = ((lhs.y + lhs.z) * (rhs.y + rhs.z)) - (yy + zz); // 9, 10, 11, 12, 13
let xz_pairs = ((lhs.x + lhs.z) * (rhs.x + rhs.z)) - (xx + zz); // 14, 15, 16, 17, 18
let bzz_part = xz_pairs - (C::EQUATION_B * zz); // 19, 20
let bzz3_part = bzz_part.double() + bzz_part; // 21, 22
let yy_m_bzz3 = yy - bzz3_part; // 23
let yy_p_bzz3 = yy + bzz3_part; // 24
let zz3 = zz.double() + zz; // 26, 27
let bxz_part = (C::EQUATION_B * xz_pairs) - (zz3 + xx); // 25, 28, 29
let bxz3_part = bxz_part.double() + bxz_part; // 30, 31
let xx3_m_zz3 = xx.double() + xx - zz3; // 32, 33, 34
ProjectivePoint {
x: (yy_p_bzz3 * xy_pairs) - (yz_pairs * bxz3_part), // 35, 39, 40
y: (yy_p_bzz3 * yy_m_bzz3) + (xx3_m_zz3 * bxz3_part), // 36, 37, 38
z: (yy_m_bzz3 * yz_pairs) + (xy_pairs * xx3_m_zz3), // 41, 42, 43
}
}
/// Implements complete mixed addition for curves with `a = -3`
///
/// Implements the complete mixed addition formula from [Renes-Costello-Batina 2015]
/// (Algorithm 5). The comments after each line indicate which algorithm
/// steps are being performed.
///
/// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060
fn add_mixed(lhs: &ProjectivePoint<C>, rhs: &AffinePoint<C>) -> ProjectivePoint<C> {
debug_assert_eq!(
C::EQUATION_A,
-C::FieldElement::from(3),
"this implementation is only valid for C::EQUATION_A = -3"
);
let xx = lhs.x * rhs.x; // 1
let yy = lhs.y * rhs.y; // 2
let xy_pairs = ((lhs.x + lhs.y) * (rhs.x + rhs.y)) - (xx + yy); // 3, 4, 5, 6, 7
let yz_pairs = (rhs.y * lhs.z) + lhs.y; // 8, 9 (t4)
let xz_pairs = (rhs.x * lhs.z) + lhs.x; // 10, 11 (y3)
let bz_part = xz_pairs - (C::EQUATION_B * lhs.z); // 12, 13
let bz3_part = bz_part.double() + bz_part; // 14, 15
let yy_m_bzz3 = yy - bz3_part; // 16
let yy_p_bzz3 = yy + bz3_part; // 17
let z3 = lhs.z.double() + lhs.z; // 19, 20
let bxz_part = (C::EQUATION_B * xz_pairs) - (z3 + xx); // 18, 21, 22
let bxz3_part = bxz_part.double() + bxz_part; // 23, 24
let xx3_m_zz3 = xx.double() + xx - z3; // 25, 26, 27
let mut ret = ProjectivePoint {
x: (yy_p_bzz3 * xy_pairs) - (yz_pairs * bxz3_part), // 28, 32, 33
y: (yy_p_bzz3 * yy_m_bzz3) + (xx3_m_zz3 * bxz3_part), // 29, 30, 31
z: (yy_m_bzz3 * yz_pairs) + (xy_pairs * xx3_m_zz3), // 34, 35, 36
};
ret.conditional_assign(lhs, rhs.is_identity());
ret
}
/// Implements point doubling for curves with `a = -3`
///
/// Implements the exception-free point doubling formula from [Renes-Costello-Batina 2015]
/// (Algorithm 6). The comments after each line indicate which algorithm
/// steps are being performed.
///
/// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060
fn double(point: &ProjectivePoint<C>) -> ProjectivePoint<C> {
debug_assert_eq!(
C::EQUATION_A,
-C::FieldElement::from(3),
"this implementation is only valid for C::EQUATION_A = -3"
);
let xx = point.x.square(); // 1
let yy = point.y.square(); // 2
let zz = point.z.square(); // 3
let xy2 = (point.x * point.y).double(); // 4, 5
let xz2 = (point.x * point.z).double(); // 6, 7
let bzz_part = (C::EQUATION_B * zz) - xz2; // 8, 9
let bzz3_part = bzz_part.double() + bzz_part; // 10, 11
let yy_m_bzz3 = yy - bzz3_part; // 12
let yy_p_bzz3 = yy + bzz3_part; // 13
let y_frag = yy_p_bzz3 * yy_m_bzz3; // 14
let x_frag = yy_m_bzz3 * xy2; // 15
let zz3 = zz.double() + zz; // 16, 17
let bxz2_part = (C::EQUATION_B * xz2) - (zz3 + xx); // 18, 19, 20
let bxz6_part = bxz2_part.double() + bxz2_part; // 21, 22
let xx3_m_zz3 = xx.double() + xx - zz3; // 23, 24, 25
let y = y_frag + (xx3_m_zz3 * bxz6_part); // 26, 27
let yz2 = (point.y * point.z).double(); // 28, 29
let x = x_frag - (bxz6_part * yz2); // 30, 31
let z = (yz2 * yy).double().double(); // 32, 33, 34
ProjectivePoint { x, y, z }
}
}

781
vendor/primeorder/src/projective.rs vendored Normal file
View File

@@ -0,0 +1,781 @@
//! Projective curve points.
#![allow(clippy::needless_range_loop, clippy::op_ref)]
use crate::{point_arithmetic::PointArithmetic, AffinePoint, Field, PrimeCurveParams};
use core::{
borrow::Borrow,
iter::Sum,
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use elliptic_curve::{
bigint::{ArrayEncoding, Integer},
generic_array::ArrayLength,
group::{
self,
cofactor::CofactorGroup,
prime::{PrimeCurve, PrimeGroup},
Group, GroupEncoding,
},
ops::{BatchInvert, Invert, LinearCombination, MulByGenerator},
point::Double,
rand_core::RngCore,
sec1::{
CompressedPoint, EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint,
UncompressedPointSize,
},
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
zeroize::DefaultIsZeroes,
BatchNormalize, Error, FieldBytes, FieldBytesSize, PublicKey, Result, Scalar,
};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
/// Point on a Weierstrass curve in projective coordinates.
#[derive(Clone, Copy, Debug)]
pub struct ProjectivePoint<C: PrimeCurveParams> {
pub(crate) x: C::FieldElement,
pub(crate) y: C::FieldElement,
pub(crate) z: C::FieldElement,
}
impl<C> ProjectivePoint<C>
where
C: PrimeCurveParams,
{
/// Additive identity of the group a.k.a. the point at infinity.
pub const IDENTITY: Self = Self {
x: C::FieldElement::ZERO,
y: C::FieldElement::ONE,
z: C::FieldElement::ZERO,
};
/// Base point of the curve.
pub const GENERATOR: Self = Self {
x: C::GENERATOR.0,
y: C::GENERATOR.1,
z: C::FieldElement::ONE,
};
/// Returns the affine representation of this point, or `None` if it is the identity.
pub fn to_affine(&self) -> AffinePoint<C> {
<C::FieldElement as Field>::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<C> {
AffinePoint {
x: self.x * &zinv,
y: self.y * &zinv,
infinity: 0,
}
}
/// Returns `-self`.
pub fn neg(&self) -> Self {
Self {
x: self.x,
y: -self.y,
z: self.z,
}
}
/// Returns `self + other`.
pub fn add(&self, other: &Self) -> Self {
C::PointArithmetic::add(self, other)
}
/// Returns `self + other`.
fn add_mixed(&self, other: &AffinePoint<C>) -> Self {
C::PointArithmetic::add_mixed(self, other)
}
/// Returns `self - other`.
pub fn sub(&self, other: &Self) -> Self {
self.add(&other.neg())
}
/// Returns `self - other`.
fn sub_mixed(&self, other: &AffinePoint<C>) -> Self {
self.add_mixed(&other.neg())
}
/// Returns `[k] self`.
fn mul(&self, k: &Scalar<C>) -> Self
where
Self: Double,
{
let k = Into::<C::Uint>::into(*k).to_le_byte_array();
let mut pc = [Self::default(); 16];
pc[0] = Self::IDENTITY;
pc[1] = *self;
for i in 2..16 {
pc[i] = if i % 2 == 0 {
Double::double(&pc[i / 2])
} else {
pc[i - 1].add(self)
};
}
let mut q = Self::IDENTITY;
let mut pos = C::Uint::BITS - 4;
loop {
let slot = (k[pos >> 3] >> (pos & 7)) & 0xf;
let mut t = ProjectivePoint::IDENTITY;
for i in 1..16 {
t.conditional_assign(
&pc[i],
Choice::from(((slot as usize ^ i).wrapping_sub(1) >> 8) as u8 & 1),
);
}
q = q.add(&t);
if pos == 0 {
break;
}
q = Double::double(&Double::double(&Double::double(&Double::double(&q))));
pos -= 4;
}
q
}
}
impl<C> CofactorGroup for ProjectivePoint<C>
where
Self: Double,
C: PrimeCurveParams,
FieldBytes<C>: Copy,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
<UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
{
type Subgroup = Self;
fn clear_cofactor(&self) -> Self::Subgroup {
*self
}
fn into_subgroup(self) -> CtOption<Self> {
CtOption::new(self, 1.into())
}
fn is_torsion_free(&self) -> Choice {
1.into()
}
}
impl<C> ConditionallySelectable for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
#[inline(always)]
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self {
x: C::FieldElement::conditional_select(&a.x, &b.x, choice),
y: C::FieldElement::conditional_select(&a.y, &b.y, choice),
z: C::FieldElement::conditional_select(&a.z, &b.z, choice),
}
}
}
impl<C> ConstantTimeEq for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn ct_eq(&self, other: &Self) -> Choice {
self.to_affine().ct_eq(&other.to_affine())
}
}
impl<C> Default for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn default() -> Self {
Self::IDENTITY
}
}
impl<C> DefaultIsZeroes for ProjectivePoint<C> where C: PrimeCurveParams {}
impl<C: PrimeCurveParams> Double for ProjectivePoint<C> {
fn double(&self) -> Self {
C::PointArithmetic::double(self)
}
}
impl<C> Eq for ProjectivePoint<C> where C: PrimeCurveParams {}
impl<C> From<AffinePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn from(p: AffinePoint<C>) -> Self {
let projective = ProjectivePoint {
x: p.x,
y: p.y,
z: C::FieldElement::ONE,
};
Self::conditional_select(&projective, &Self::IDENTITY, p.is_identity())
}
}
impl<C> From<&AffinePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn from(p: &AffinePoint<C>) -> Self {
Self::from(*p)
}
}
impl<C> From<PublicKey<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn from(public_key: PublicKey<C>) -> ProjectivePoint<C> {
AffinePoint::from(public_key).into()
}
}
impl<C> From<&PublicKey<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn from(public_key: &PublicKey<C>) -> ProjectivePoint<C> {
AffinePoint::<C>::from(public_key).into()
}
}
impl<C> FromEncodedPoint<C> for ProjectivePoint<C>
where
C: PrimeCurveParams,
FieldBytes<C>: Copy,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
{
fn from_encoded_point(p: &EncodedPoint<C>) -> CtOption<Self> {
AffinePoint::<C>::from_encoded_point(p).map(Self::from)
}
}
impl<C> Group for ProjectivePoint<C>
where
Self: Double,
C: PrimeCurveParams,
{
type Scalar = Scalar<C>;
fn random(mut rng: impl RngCore) -> Self {
Self::GENERATOR * <Scalar<C> as Field>::random(&mut rng)
}
fn identity() -> Self {
Self::IDENTITY
}
fn generator() -> Self {
Self::GENERATOR
}
fn is_identity(&self) -> Choice {
self.ct_eq(&Self::IDENTITY)
}
#[must_use]
fn double(&self) -> Self {
Double::double(self)
}
}
impl<C> GroupEncoding for ProjectivePoint<C>
where
C: PrimeCurveParams,
FieldBytes<C>: Copy,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
<UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
{
type Repr = CompressedPoint<C>;
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
<AffinePoint<C> as GroupEncoding>::from_bytes(bytes).map(Into::into)
}
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
// No unchecked conversion possible for compressed points
Self::from_bytes(bytes)
}
fn to_bytes(&self) -> Self::Repr {
self.to_affine().to_bytes()
}
}
impl<C> group::Curve for ProjectivePoint<C>
where
Self: Double,
C: PrimeCurveParams,
{
type AffineRepr = AffinePoint<C>;
fn to_affine(&self) -> AffinePoint<C> {
ProjectivePoint::to_affine(self)
}
// TODO(tarcieri): re-enable when we can add `Invert` bounds on `FieldElement`
// #[cfg(feature = "alloc")]
// #[inline]
// fn batch_normalize(projective: &[Self], affine: &mut [Self::AffineRepr]) {
// assert_eq!(projective.len(), affine.len());
// let mut zs = vec![C::FieldElement::ONE; projective.len()];
// batch_normalize_generic(projective, zs.as_mut_slice(), affine);
// }
}
impl<const N: usize, C> BatchNormalize<[ProjectivePoint<C>; N]> for ProjectivePoint<C>
where
Self: Double,
C: PrimeCurveParams,
C::FieldElement: Invert<Output = CtOption<C::FieldElement>>,
{
type Output = [Self::AffineRepr; N];
#[inline]
fn batch_normalize(points: &[Self; N]) -> [Self::AffineRepr; N] {
let mut zs = [C::FieldElement::ONE; N];
let mut affine_points = [C::AffinePoint::IDENTITY; N];
batch_normalize_generic(points, &mut zs, &mut affine_points);
affine_points
}
}
#[cfg(feature = "alloc")]
impl<C> BatchNormalize<[ProjectivePoint<C>]> for ProjectivePoint<C>
where
Self: Double,
C: PrimeCurveParams,
C::FieldElement: Invert<Output = CtOption<C::FieldElement>>,
{
type Output = Vec<Self::AffineRepr>;
#[inline]
fn batch_normalize(points: &[Self]) -> Vec<Self::AffineRepr> {
let mut zs = vec![C::FieldElement::ONE; points.len()];
let mut affine_points = vec![AffinePoint::IDENTITY; points.len()];
batch_normalize_generic(points, zs.as_mut_slice(), &mut affine_points);
affine_points
}
}
/// Generic implementation of batch normalization.
fn batch_normalize_generic<C, P, Z, O>(points: &P, zs: &mut Z, out: &mut O)
where
C: PrimeCurveParams,
C::FieldElement: BatchInvert<Z>,
C::ProjectivePoint: Double,
P: AsRef<[ProjectivePoint<C>]> + ?Sized,
Z: AsMut<[C::FieldElement]> + ?Sized,
O: AsMut<[AffinePoint<C>]> + ?Sized,
{
let points = points.as_ref();
let out = out.as_mut();
for i in 0..points.len() {
// 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.as_mut()[i].conditional_assign(&points[i].z, !points[i].z.ct_eq(&C::FieldElement::ZERO));
}
// This is safe to unwrap since we assured that all elements are non-zero
let zs_inverses = <C::FieldElement as BatchInvert<Z>>::batch_invert(zs).unwrap();
for i in 0..out.len() {
// If the `z` coordinate is non-zero, we can use it to invert;
// otherwise it defaults to the `IDENTITY` value.
out[i] = C::AffinePoint::conditional_select(
&points[i].to_affine_internal(zs_inverses.as_ref()[i]),
&C::AffinePoint::IDENTITY,
points[i].z.ct_eq(&C::FieldElement::ZERO),
);
}
}
impl<C> LinearCombination for ProjectivePoint<C>
where
Self: Double,
C: PrimeCurveParams,
{
}
impl<C> MulByGenerator for ProjectivePoint<C>
where
Self: Double,
C: PrimeCurveParams,
{
fn mul_by_generator(scalar: &Self::Scalar) -> Self {
// TODO(tarcieri): precomputed basepoint tables
Self::generator() * scalar
}
}
impl<C> PrimeGroup for ProjectivePoint<C>
where
Self: Double,
C: PrimeCurveParams,
FieldBytes<C>: Copy,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
<UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
{
}
impl<C> PrimeCurve for ProjectivePoint<C>
where
Self: Double,
C: PrimeCurveParams,
FieldBytes<C>: Copy,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
<UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
{
type Affine = AffinePoint<C>;
}
impl<C> PartialEq for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
impl<C> ToEncodedPoint<C> for ProjectivePoint<C>
where
C: PrimeCurveParams,
FieldBytesSize<C>: ModulusSize,
CompressedPoint<C>: Copy,
<UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
{
fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> {
self.to_affine().to_encoded_point(compress)
}
}
impl<C> TryFrom<ProjectivePoint<C>> for PublicKey<C>
where
C: PrimeCurveParams,
{
type Error = Error;
fn try_from(point: ProjectivePoint<C>) -> Result<PublicKey<C>> {
AffinePoint::<C>::from(point).try_into()
}
}
impl<C> TryFrom<&ProjectivePoint<C>> for PublicKey<C>
where
C: PrimeCurveParams,
{
type Error = Error;
fn try_from(point: &ProjectivePoint<C>) -> Result<PublicKey<C>> {
AffinePoint::<C>::from(point).try_into()
}
}
//
// Arithmetic trait impls
//
impl<C> Add<ProjectivePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
type Output = ProjectivePoint<C>;
fn add(self, other: ProjectivePoint<C>) -> ProjectivePoint<C> {
ProjectivePoint::add(&self, &other)
}
}
impl<C> Add<&ProjectivePoint<C>> for &ProjectivePoint<C>
where
C: PrimeCurveParams,
{
type Output = ProjectivePoint<C>;
fn add(self, other: &ProjectivePoint<C>) -> ProjectivePoint<C> {
ProjectivePoint::add(self, other)
}
}
impl<C> Add<&ProjectivePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
type Output = ProjectivePoint<C>;
fn add(self, other: &ProjectivePoint<C>) -> ProjectivePoint<C> {
ProjectivePoint::add(&self, other)
}
}
impl<C> AddAssign<ProjectivePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn add_assign(&mut self, rhs: ProjectivePoint<C>) {
*self = ProjectivePoint::add(self, &rhs);
}
}
impl<C> AddAssign<&ProjectivePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn add_assign(&mut self, rhs: &ProjectivePoint<C>) {
*self = ProjectivePoint::add(self, rhs);
}
}
impl<C> Add<AffinePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
type Output = ProjectivePoint<C>;
fn add(self, other: AffinePoint<C>) -> ProjectivePoint<C> {
ProjectivePoint::add_mixed(&self, &other)
}
}
impl<C> Add<&AffinePoint<C>> for &ProjectivePoint<C>
where
C: PrimeCurveParams,
{
type Output = ProjectivePoint<C>;
fn add(self, other: &AffinePoint<C>) -> ProjectivePoint<C> {
ProjectivePoint::add_mixed(self, other)
}
}
impl<C> Add<&AffinePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
type Output = ProjectivePoint<C>;
fn add(self, other: &AffinePoint<C>) -> ProjectivePoint<C> {
ProjectivePoint::add_mixed(&self, other)
}
}
impl<C> AddAssign<AffinePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn add_assign(&mut self, rhs: AffinePoint<C>) {
*self = ProjectivePoint::add_mixed(self, &rhs);
}
}
impl<C> AddAssign<&AffinePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn add_assign(&mut self, rhs: &AffinePoint<C>) {
*self = ProjectivePoint::add_mixed(self, rhs);
}
}
impl<C> Sum for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(ProjectivePoint::IDENTITY, |a, b| a + b)
}
}
impl<'a, C> Sum<&'a ProjectivePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn sum<I: Iterator<Item = &'a ProjectivePoint<C>>>(iter: I) -> Self {
iter.cloned().sum()
}
}
impl<C> Sub<ProjectivePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
type Output = ProjectivePoint<C>;
fn sub(self, other: ProjectivePoint<C>) -> ProjectivePoint<C> {
ProjectivePoint::sub(&self, &other)
}
}
impl<C> Sub<&ProjectivePoint<C>> for &ProjectivePoint<C>
where
C: PrimeCurveParams,
{
type Output = ProjectivePoint<C>;
fn sub(self, other: &ProjectivePoint<C>) -> ProjectivePoint<C> {
ProjectivePoint::sub(self, other)
}
}
impl<C> Sub<&ProjectivePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
type Output = ProjectivePoint<C>;
fn sub(self, other: &ProjectivePoint<C>) -> ProjectivePoint<C> {
ProjectivePoint::sub(&self, other)
}
}
impl<C> SubAssign<ProjectivePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn sub_assign(&mut self, rhs: ProjectivePoint<C>) {
*self = ProjectivePoint::sub(self, &rhs);
}
}
impl<C> SubAssign<&ProjectivePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn sub_assign(&mut self, rhs: &ProjectivePoint<C>) {
*self = ProjectivePoint::sub(self, rhs);
}
}
impl<C> Sub<AffinePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
type Output = ProjectivePoint<C>;
fn sub(self, other: AffinePoint<C>) -> ProjectivePoint<C> {
ProjectivePoint::sub_mixed(&self, &other)
}
}
impl<C> Sub<&AffinePoint<C>> for &ProjectivePoint<C>
where
C: PrimeCurveParams,
{
type Output = ProjectivePoint<C>;
fn sub(self, other: &AffinePoint<C>) -> ProjectivePoint<C> {
ProjectivePoint::sub_mixed(self, other)
}
}
impl<C> Sub<&AffinePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
type Output = ProjectivePoint<C>;
fn sub(self, other: &AffinePoint<C>) -> ProjectivePoint<C> {
ProjectivePoint::sub_mixed(&self, other)
}
}
impl<C> SubAssign<AffinePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn sub_assign(&mut self, rhs: AffinePoint<C>) {
*self = ProjectivePoint::sub_mixed(self, &rhs);
}
}
impl<C> SubAssign<&AffinePoint<C>> for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
fn sub_assign(&mut self, rhs: &AffinePoint<C>) {
*self = ProjectivePoint::sub_mixed(self, rhs);
}
}
impl<C, S> Mul<S> for ProjectivePoint<C>
where
Self: Double,
C: PrimeCurveParams,
S: Borrow<Scalar<C>>,
{
type Output = Self;
fn mul(self, scalar: S) -> Self {
ProjectivePoint::mul(&self, scalar.borrow())
}
}
impl<C> Mul<&Scalar<C>> for &ProjectivePoint<C>
where
C: PrimeCurveParams,
ProjectivePoint<C>: Double,
{
type Output = ProjectivePoint<C>;
fn mul(self, scalar: &Scalar<C>) -> ProjectivePoint<C> {
ProjectivePoint::mul(self, scalar)
}
}
impl<C, S> MulAssign<S> for ProjectivePoint<C>
where
Self: Double,
C: PrimeCurveParams,
S: Borrow<Scalar<C>>,
{
fn mul_assign(&mut self, scalar: S) {
*self = ProjectivePoint::mul(self, scalar.borrow());
}
}
impl<C> Neg for ProjectivePoint<C>
where
C: PrimeCurveParams,
{
type Output = ProjectivePoint<C>;
fn neg(self) -> ProjectivePoint<C> {
ProjectivePoint::neg(&self)
}
}
impl<'a, C> Neg for &'a ProjectivePoint<C>
where
C: PrimeCurveParams,
{
type Output = ProjectivePoint<C>;
fn neg(self) -> ProjectivePoint<C> {
ProjectivePoint::neg(self)
}
}