mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Add crate for working with short Weierstrass elliptic curves
This commit is contained in:
1
.github/workflows/crypto-tests.yml
vendored
1
.github/workflows/crypto-tests.yml
vendored
@@ -36,6 +36,7 @@ jobs:
|
||||
-p multiexp \
|
||||
-p schnorr-signatures \
|
||||
-p prime-field \
|
||||
-p short-weierstrass \
|
||||
-p secq256k1 \
|
||||
-p embedwards25519 \
|
||||
-p dkg \
|
||||
|
||||
27
Cargo.lock
generated
27
Cargo.lock
generated
@@ -474,7 +474,7 @@ dependencies = [
|
||||
"alloy-rlp",
|
||||
"alloy-serde",
|
||||
"alloy-sol-types",
|
||||
"itertools 0.13.0",
|
||||
"itertools 0.14.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
@@ -2517,7 +2517,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976"
|
||||
dependencies = [
|
||||
"data-encoding",
|
||||
"syn 2.0.106",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2988,6 +2988,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"blake2",
|
||||
"ciphersuite 0.4.2",
|
||||
"curve25519-dalek",
|
||||
"dalek-ff-group",
|
||||
"ec-divisors",
|
||||
"ff-group-tests",
|
||||
@@ -2997,6 +2998,7 @@ dependencies = [
|
||||
"hex-literal",
|
||||
"prime-field",
|
||||
"rand_core 0.6.4",
|
||||
"short-weierstrass",
|
||||
"std-shims",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -4559,6 +4561,15 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.15"
|
||||
@@ -10180,6 +10191,7 @@ dependencies = [
|
||||
"prime-field",
|
||||
"schnorr-signatures",
|
||||
"secq256k1",
|
||||
"short-weierstrass",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10911,6 +10923,17 @@ version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "short-weierstrass"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ff",
|
||||
"group",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.6"
|
||||
|
||||
@@ -40,6 +40,7 @@ members = [
|
||||
"crypto/schnorr",
|
||||
|
||||
"crypto/prime-field",
|
||||
"crypto/short-weierstrass",
|
||||
"crypto/evrf/secq256k1",
|
||||
"crypto/evrf/embedwards25519",
|
||||
|
||||
|
||||
@@ -83,6 +83,15 @@ pub mod __prime_field_private {
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a odd-prime field.
|
||||
///
|
||||
/// The length of the `modulus_as_be_hex` string will effect the size of the underlying
|
||||
/// representation and the encoding. It MAY have a "0x" prefix, if preferred.
|
||||
///
|
||||
/// `multiplicative_generator_as_be_hex` MAY have a "0x" prefix. It MAY be short and of a length
|
||||
/// less than `modulus_as_be_hex`.
|
||||
///
|
||||
/// `big_endian` controls if the encoded representation will be big-endian or not.
|
||||
#[macro_export]
|
||||
macro_rules! odd_prime_field {
|
||||
(
|
||||
|
||||
27
crypto/short-weierstrass/Cargo.toml
Normal file
27
crypto/short-weierstrass/Cargo.toml
Normal file
@@ -0,0 +1,27 @@
|
||||
[package]
|
||||
name = "short-weierstrass"
|
||||
version = "0.1.0"
|
||||
description = "A library for working with curves in a short Weierstrass form"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/short-weierstrass"
|
||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||
keywords = ["ff", "group", "elliptic-curve", "weierstrass"]
|
||||
edition = "2021"
|
||||
rust-version = "1.79"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[dependencies]
|
||||
zeroize = { version = "^1.5", default-features = false }
|
||||
subtle = { version = "^2.4", default-features = false }
|
||||
rand_core = { version = "0.6", default-features = false }
|
||||
|
||||
ff = { version = "0.13", default-features = false, features = ["bits"] }
|
||||
group = { version = "0.13", default-features = false }
|
||||
|
||||
[features]
|
||||
alloc = ["zeroize/alloc", "rand_core/alloc", "ff/alloc", "group/alloc"]
|
||||
std = ["zeroize/std", "subtle/std", "rand_core/std", "ff/std"]
|
||||
default = ["std"]
|
||||
21
crypto/short-weierstrass/LICENSE
Normal file
21
crypto/short-weierstrass/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022-2025 Luke Parker
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
3
crypto/short-weierstrass/README.md
Normal file
3
crypto/short-weierstrass/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Short Weierstrass
|
||||
|
||||
A library for working with elliptic curves represented in short Weierstrass form.
|
||||
96
crypto/short-weierstrass/src/affine.rs
Normal file
96
crypto/short-weierstrass/src/affine.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use core::ops::*;
|
||||
|
||||
use subtle::{Choice, CtOption, ConstantTimeEq, ConditionallySelectable, ConditionallyNegatable};
|
||||
use zeroize::DefaultIsZeroes;
|
||||
|
||||
use rand_core::RngCore;
|
||||
|
||||
use group::ff::Field;
|
||||
|
||||
use crate::{ShortWeierstrass, Projective};
|
||||
|
||||
/// A point represented with affine coordinates.
|
||||
#[derive(Debug)]
|
||||
pub struct Affine<C: ShortWeierstrass> {
|
||||
pub(crate) x: C::FieldElement,
|
||||
pub(crate) y: C::FieldElement,
|
||||
}
|
||||
impl<C: ShortWeierstrass> Clone for Affine<C> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> Copy for Affine<C> {}
|
||||
|
||||
impl<C: ShortWeierstrass> Affine<C> {
|
||||
pub fn try_from(projective: Projective<C>) -> CtOption<Self> {
|
||||
projective.z.invert().map(|z_inv| Self { x: projective.x * z_inv, y: projective.y * z_inv })
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: ShortWeierstrass> Default for Affine<C> {
|
||||
fn default() -> Self {
|
||||
C::GENERATOR
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> DefaultIsZeroes for Affine<C> {}
|
||||
|
||||
impl<C: ShortWeierstrass> ConstantTimeEq for Affine<C> {
|
||||
fn ct_eq(&self, other: &Self) -> Choice {
|
||||
self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y)
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> PartialEq for Affine<C> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.ct_eq(other).into()
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> Eq for Affine<C> {}
|
||||
|
||||
impl<C: ShortWeierstrass> ConditionallySelectable for Affine<C> {
|
||||
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
||||
let x = C::FieldElement::conditional_select(&a.x, &b.x, choice);
|
||||
let y = C::FieldElement::conditional_select(&a.y, &b.y, choice);
|
||||
Affine { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: ShortWeierstrass> Neg for Affine<C> {
|
||||
type Output = Self;
|
||||
fn neg(mut self) -> Self::Output {
|
||||
self.y = -self.y;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: ShortWeierstrass> ConditionallyNegatable for Affine<C> {
|
||||
fn conditional_negate(&mut self, negate: Choice) {
|
||||
self.y = <_>::conditional_select(&self.y, &-self.y, negate);
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: ShortWeierstrass> Affine<C> {
|
||||
/// Create an affine point from `x, y` coordinates, without performing any checks.
|
||||
///
|
||||
/// This should NOT be used. It is solely intended for trusted data at compile-time. It MUST NOT
|
||||
/// be used with any untrusted/unvalidated data.
|
||||
pub const fn from_xy_unchecked(x: C::FieldElement, y: C::FieldElement) -> Self { Self { x, y } }
|
||||
|
||||
/// The `x, y` coordinates of this point.
|
||||
pub fn coordinates(self) -> (C::FieldElement, C::FieldElement) {
|
||||
(self.x, self.y)
|
||||
}
|
||||
|
||||
/// Sample a random on-curve point with an unknown discrete logarithm w.r.t. any other points.
|
||||
pub fn random(mut rng: impl RngCore) -> Self {
|
||||
loop {
|
||||
let x = C::FieldElement::random(&mut rng);
|
||||
let y_square = ((x.square() + C::A) * x) + C::B;
|
||||
let Some(mut y) = Option::<C::FieldElement>::from(y_square.sqrt()) else { continue };
|
||||
if (rng.next_u64() % 2) == 1 {
|
||||
y = -y;
|
||||
}
|
||||
return Self { x, y };
|
||||
}
|
||||
}
|
||||
}
|
||||
30
crypto/short-weierstrass/src/lib.rs
Normal file
30
crypto/short-weierstrass/src/lib.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![no_std]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use core::fmt::Debug;
|
||||
|
||||
use zeroize::Zeroize;
|
||||
use group::ff::PrimeField;
|
||||
|
||||
mod affine;
|
||||
pub use affine::Affine;
|
||||
mod projective;
|
||||
pub use projective::Projective;
|
||||
|
||||
/// An elliptic curve represented in short Weierstrass form, with equation `y^2 = x^3 + A x + B`.
|
||||
pub trait ShortWeierstrass: 'static + Sized + Debug {
|
||||
/// The field the elliptic curve is defined over.
|
||||
type FieldElement: Zeroize + PrimeField;
|
||||
/// The constant `A` from the curve equation.
|
||||
const A: Self::FieldElement;
|
||||
/// The constant `B` from the curve equation.
|
||||
const B: Self::FieldElement;
|
||||
/// A generator of this elliptic curve.
|
||||
const GENERATOR: Affine<Self>;
|
||||
/// The scalar type.
|
||||
///
|
||||
/// This may be omitted by specifying `()`.
|
||||
type Scalar;
|
||||
}
|
||||
313
crypto/short-weierstrass/src/projective.rs
Normal file
313
crypto/short-weierstrass/src/projective.rs
Normal file
@@ -0,0 +1,313 @@
|
||||
use core::{hint::black_box, borrow::Borrow, ops::*, iter::Sum};
|
||||
|
||||
use subtle::{Choice, ConstantTimeEq, ConditionallySelectable, ConditionallyNegatable};
|
||||
use zeroize::{Zeroize, DefaultIsZeroes};
|
||||
|
||||
use rand_core::RngCore;
|
||||
|
||||
use group::{
|
||||
ff::{Field, PrimeFieldBits},
|
||||
Group,
|
||||
};
|
||||
|
||||
use crate::{ShortWeierstrass, Affine};
|
||||
|
||||
/// A point represented with projective coordinates.
|
||||
#[derive(Debug)]
|
||||
pub struct Projective<C: ShortWeierstrass> {
|
||||
pub(crate) x: C::FieldElement,
|
||||
pub(crate) y: C::FieldElement,
|
||||
pub(crate) z: C::FieldElement,
|
||||
}
|
||||
impl<C: ShortWeierstrass> Clone for Projective<C> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> Copy for Projective<C> {}
|
||||
|
||||
impl<C: ShortWeierstrass> From<Affine<C>> for Projective<C> {
|
||||
fn from(affine: Affine<C>) -> Self {
|
||||
Self { x: affine.x, y: affine.y, z: C::FieldElement::ONE }
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: ShortWeierstrass> Default for Projective<C> {
|
||||
fn default() -> Self {
|
||||
Self::IDENTITY
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> DefaultIsZeroes for Projective<C> {}
|
||||
|
||||
impl<C: ShortWeierstrass> ConstantTimeEq for Projective<C> {
|
||||
fn ct_eq(&self, other: &Self) -> Choice {
|
||||
let c1 = (self.x * other.z).ct_eq(&(other.x * self.z));
|
||||
let c2 = (self.y * other.z).ct_eq(&(other.y * self.z));
|
||||
c1 & c2
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> PartialEq for Projective<C> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.ct_eq(other).into()
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> Eq for Projective<C> {}
|
||||
|
||||
impl<C: ShortWeierstrass> ConditionallySelectable for Projective<C> {
|
||||
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
||||
let x = C::FieldElement::conditional_select(&a.x, &b.x, choice);
|
||||
let y = C::FieldElement::conditional_select(&a.y, &b.y, choice);
|
||||
let z = C::FieldElement::conditional_select(&a.z, &b.z, choice);
|
||||
Projective { x, y, z }
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: ShortWeierstrass> Neg for Projective<C> {
|
||||
type Output = Self;
|
||||
fn neg(mut self) -> Self::Output {
|
||||
self.y = -self.y;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: ShortWeierstrass> ConditionallyNegatable for Projective<C> {
|
||||
fn conditional_negate(&mut self, negate: Choice) {
|
||||
self.y = <_>::conditional_select(&self.y, &-self.y, negate);
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: ShortWeierstrass> Add for Projective<C> {
|
||||
type Output = Self;
|
||||
// add-1998-cmo-2
|
||||
/*
|
||||
We don't use the complete formulas from 2015 as they require the curve is prime order, when we
|
||||
do not.
|
||||
*/
|
||||
fn add(self, p2: Self) -> Self {
|
||||
let Self { x: X1, y: Y1, z: Z1 } = self;
|
||||
let Self { x: X2, y: Y2, z: Z2 } = p2;
|
||||
|
||||
let Y1Z2 = Y1 * Z2;
|
||||
let X1Z2 = X1 * Z2;
|
||||
let Z1Z2 = Z1 * Z2;
|
||||
let u = (Y2 * Z1) - Y1Z2;
|
||||
let uu = u.square();
|
||||
let v = (X2 * Z1) - X1Z2;
|
||||
let vv = v.square();
|
||||
let vvv = v * vv;
|
||||
let R = vv * X1Z2;
|
||||
let A = (uu * Z1Z2) - vvv - R.double();
|
||||
let X3 = v * A;
|
||||
let Y3 = (u * (R - A)) - (vvv * Y1Z2);
|
||||
let Z3 = vvv * Z1Z2;
|
||||
|
||||
let res = Self { x: X3, y: Y3, z: Z3 };
|
||||
|
||||
let same_x_coordinate = (self.x * p2.z).ct_eq(&(p2.x * self.z));
|
||||
let same_y_coordinate = (self.y * p2.z).ct_eq(&(p2.y * self.z));
|
||||
let res = <_>::conditional_select(
|
||||
&res,
|
||||
&Self::IDENTITY,
|
||||
(self.is_identity_internal() & p2.is_identity_internal()) |
|
||||
(same_x_coordinate & (!same_y_coordinate)),
|
||||
);
|
||||
let res =
|
||||
<_>::conditional_select(&res, &self.double_internal(), same_x_coordinate & same_y_coordinate);
|
||||
let res = <_>::conditional_select(&res, &p2, self.is_identity_internal());
|
||||
<_>::conditional_select(&res, &self, p2.is_identity_internal())
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> Sub for Projective<C> {
|
||||
type Output = Self;
|
||||
fn sub(self, p2: Self) -> Self {
|
||||
self + -p2
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> AddAssign for Projective<C> {
|
||||
fn add_assign(&mut self, p2: Self) {
|
||||
*self = *self + p2;
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> SubAssign for Projective<C> {
|
||||
fn sub_assign(&mut self, p2: Self) {
|
||||
*self = *self - p2;
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> Add<&Self> for Projective<C> {
|
||||
type Output = Self;
|
||||
fn add(self, p2: &Self) -> Self {
|
||||
self + *p2
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> Sub<&Self> for Projective<C> {
|
||||
type Output = Self;
|
||||
fn sub(self, p2: &Self) -> Self {
|
||||
self - *p2
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> AddAssign<&Self> for Projective<C> {
|
||||
fn add_assign(&mut self, p2: &Self) {
|
||||
*self = *self + p2;
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass> SubAssign<&Self> for Projective<C> {
|
||||
fn sub_assign(&mut self, p2: &Self) {
|
||||
*self = *self - p2;
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: ShortWeierstrass> Projective<C> {
|
||||
/// The additive identity, or point at infinity.
|
||||
pub const IDENTITY: Self =
|
||||
Projective { x: C::FieldElement::ZERO, y: C::FieldElement::ONE, z: C::FieldElement::ZERO };
|
||||
/// A generator of this elliptic curve.
|
||||
pub const GENERATOR: Self =
|
||||
Projective { x: C::GENERATOR.x, y: C::GENERATOR.y, z: C::FieldElement::ONE };
|
||||
|
||||
fn is_identity_internal(&self) -> Choice {
|
||||
self.z.ct_eq(&C::FieldElement::ZERO)
|
||||
}
|
||||
|
||||
// dbl-1998-cmo-2
|
||||
fn double_internal(&self) -> Self {
|
||||
let Self { x: X1, y: Y1, z: Z1 } = *self;
|
||||
|
||||
let X1X1 = X1.square();
|
||||
let w = (C::A * Z1.square()) + X1X1.double() + X1X1;
|
||||
let s = Y1 * Z1;
|
||||
let ss = s.square();
|
||||
let sss = s * ss;
|
||||
let R = Y1 * s;
|
||||
let B = X1 * R;
|
||||
let B4 = B.double().double();
|
||||
let h = w.square() - B4.double();
|
||||
let X3 = (h * s).double();
|
||||
let Y3 = w * (B4 - h) - R.square().double().double().double();
|
||||
let Z3 = sss.double().double().double();
|
||||
|
||||
let res = Self { x: X3, y: Y3, z: Z3 };
|
||||
<_>::conditional_select(&res, &Self::IDENTITY, self.is_identity_internal())
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: ShortWeierstrass> Sum for Projective<C> {
|
||||
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
||||
let mut res = Self::IDENTITY;
|
||||
for item in iter {
|
||||
res += item;
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, C: ShortWeierstrass> Sum<&'a Self> for Projective<C> {
|
||||
fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
|
||||
let mut res = Self::IDENTITY;
|
||||
for item in iter {
|
||||
res += item;
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: ShortWeierstrass<Scalar = ()>> Projective<C> {
|
||||
/// Sample a random on-curve point with an unknown discrete logarithm w.r.t. any other points.
|
||||
pub fn random(rng: impl RngCore) -> Self {
|
||||
Self::from(Affine::random(rng))
|
||||
}
|
||||
/// If this point is the additive identity.
|
||||
pub fn is_identity(&self) -> Choice {
|
||||
self.is_identity_internal()
|
||||
}
|
||||
/// The sum of this point with itself.
|
||||
pub fn double(&self) -> Self {
|
||||
self.double_internal()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: ShortWeierstrass<Scalar: PrimeFieldBits>, S: Borrow<C::Scalar>> Mul<S> for Projective<C> {
|
||||
type Output = Self;
|
||||
fn mul(self, scalar: S) -> Self {
|
||||
let mut table = [Self::IDENTITY; 16];
|
||||
table[1] = self;
|
||||
for i in 2 .. 16 {
|
||||
table[i] = table[i - 1] + self;
|
||||
}
|
||||
|
||||
let mut res = Self::identity();
|
||||
let mut bits = 0;
|
||||
for (i, mut bit) in scalar.borrow().to_le_bits().iter_mut().rev().enumerate() {
|
||||
fn u8_from_bool(bit_ref: &mut bool) -> u8 {
|
||||
let bit_ref = black_box(bit_ref);
|
||||
|
||||
let mut bit = black_box(*bit_ref);
|
||||
let res = black_box(u8::from(bit));
|
||||
bit.zeroize();
|
||||
debug_assert!((res | 1) == 1);
|
||||
|
||||
bit_ref.zeroize();
|
||||
res
|
||||
}
|
||||
|
||||
bits <<= 1;
|
||||
let mut bit = u8_from_bool(bit.deref_mut());
|
||||
bits |= bit;
|
||||
bit.zeroize();
|
||||
|
||||
if ((i + 1) % 4) == 0 {
|
||||
if i != 3 {
|
||||
for _ in 0 .. 4 {
|
||||
res = res.double();
|
||||
}
|
||||
}
|
||||
|
||||
let mut term = table[0];
|
||||
for (j, candidate) in table[1 ..].iter().enumerate() {
|
||||
let j = j + 1;
|
||||
term = Self::conditional_select(&term, candidate, usize::from(bits).ct_eq(&j));
|
||||
}
|
||||
res += term;
|
||||
bits = 0;
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass<Scalar: PrimeFieldBits>, S: Borrow<C::Scalar>> MulAssign<S>
|
||||
for Projective<C>
|
||||
{
|
||||
fn mul_assign(&mut self, scalar: S) {
|
||||
*self = *self * scalar.borrow();
|
||||
}
|
||||
}
|
||||
/*
|
||||
impl<C: ShortWeierstrass<Scalar: PrimeFieldBits>> Mul<&C::Scalar> for Projective<C> {
|
||||
type Output = Self;
|
||||
fn mul(self, scalar: &C::Scalar) -> Self {
|
||||
self * *scalar
|
||||
}
|
||||
}
|
||||
impl<C: ShortWeierstrass<Scalar: PrimeFieldBits>> MulAssign<&C::Scalar> for Projective<C> {
|
||||
fn mul_assign(&mut self, scalar: &C::Scalar) {
|
||||
*self *= *scalar;
|
||||
}
|
||||
}
|
||||
*/
|
||||
impl<C: ShortWeierstrass<Scalar: PrimeFieldBits>> Group for Projective<C> {
|
||||
type Scalar = C::Scalar;
|
||||
fn random(rng: impl RngCore) -> Self {
|
||||
Self::from(Affine::<C>::random(rng))
|
||||
}
|
||||
fn identity() -> Self {
|
||||
Self::IDENTITY
|
||||
}
|
||||
fn generator() -> Self {
|
||||
C::GENERATOR.into()
|
||||
}
|
||||
fn is_identity(&self) -> Choice {
|
||||
self.is_identity_internal()
|
||||
}
|
||||
fn double(&self) -> Self {
|
||||
self.double_internal()
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ multiexp = { path = "../../crypto/multiexp", default-features = false, features
|
||||
schnorr-signatures = { path = "../../crypto/schnorr", default-features = false }
|
||||
|
||||
prime-field = { path = "../../crypto/prime-field", default-features = false, features = ["alloc"] }
|
||||
short-weierstrass = { path = "../../crypto/short-weierstrass", default-features = false, features = ["alloc"] }
|
||||
secq256k1 = { path = "../../crypto/evrf/secq256k1", default-features = false }
|
||||
embedwards25519 = { path = "../../crypto/evrf/embedwards25519", default-features = false }
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ pub use multiexp;
|
||||
pub use schnorr_signatures;
|
||||
|
||||
pub use prime_field;
|
||||
pub use short_weierstrass;
|
||||
pub use secq256k1;
|
||||
pub use embedwards25519;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user