mirror of https://github.com/zcash/halo2.git
Merge pull request #60 from zcash/tweedle-refactor
Move curves and fields into tweedle module
This commit is contained in:
commit
1e8769b738
|
@ -2,9 +2,10 @@
|
||||||
extern crate criterion;
|
extern crate criterion;
|
||||||
|
|
||||||
extern crate halo2;
|
extern crate halo2;
|
||||||
use crate::arithmetic::{small_multiexp, EqAffine, Field, Fp, Fq};
|
use crate::arithmetic::{small_multiexp, Field};
|
||||||
use crate::poly::commitment::Params;
|
use crate::poly::commitment::Params;
|
||||||
use crate::transcript::DummyHash;
|
use crate::transcript::DummyHash;
|
||||||
|
use crate::tweedle::{EqAffine, Fp, Fq};
|
||||||
use halo2::*;
|
use halo2::*;
|
||||||
|
|
||||||
use criterion::{black_box, Criterion};
|
use criterion::{black_box, Criterion};
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
use crossbeam_utils::thread;
|
use crossbeam_utils::thread;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
mod macros;
|
|
||||||
mod curves;
|
mod curves;
|
||||||
mod fields;
|
mod fields;
|
||||||
|
|
||||||
|
@ -489,6 +487,9 @@ pub fn lagrange_interpolate<F: Field>(points: &[F], evals: &[F]) -> Vec<F> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use crate::tweedle::Fp;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lagrange_interpolate() {
|
fn test_lagrange_interpolate() {
|
||||||
let points = (0..5).map(|_| Fp::random()).collect::<Vec<_>>();
|
let points = (0..5).map(|_| Fp::random()).collect::<Vec<_>>();
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
//! This module contains implementations for the Tweedledum and Tweedledee
|
//! This module contains the `Curve`/`CurveAffine` abstractions that allow us to
|
||||||
//! elliptic curve groups. The `Curve`/`CurveAffine` abstractions allow us to
|
//! write code that generalizes over a pair of groups.
|
||||||
//! write code that generalizes over these two groups.
|
|
||||||
|
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
||||||
|
|
||||||
use super::{Field, Fp, Fq, Group};
|
use super::{Field, Group};
|
||||||
|
|
||||||
/// This trait is a common interface for dealing with elements of an elliptic
|
/// This trait is a common interface for dealing with elements of an elliptic
|
||||||
/// curve group in the "projective" form, where that arithmetic is usually more
|
/// curve group in the "projective" form, where that arithmetic is usually more
|
||||||
|
@ -165,696 +164,3 @@ pub trait CurveAffine:
|
||||||
/// Returns the curve constant $b$
|
/// Returns the curve constant $b$
|
||||||
fn b() -> Self::Base;
|
fn b() -> Self::Base;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! new_curve_impl {
|
|
||||||
($name:ident, $name_affine:ident, $base:ident, $scalar:ident) => {
|
|
||||||
/// Represents a point in the projective coordinate space.
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub struct $name {
|
|
||||||
x: $base,
|
|
||||||
y: $base,
|
|
||||||
z: $base,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl $name {
|
|
||||||
const fn curve_constant_b() -> $base {
|
|
||||||
// NOTE: this is specific to b = 5
|
|
||||||
$base::from_raw([5, 0, 0, 0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents a point in the affine coordinate space (or the point at
|
|
||||||
/// infinity).
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub struct $name_affine {
|
|
||||||
x: $base,
|
|
||||||
y: $base,
|
|
||||||
infinity: Choice,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Curve for $name {
|
|
||||||
type Affine = $name_affine;
|
|
||||||
type Scalar = $scalar;
|
|
||||||
type Base = $base;
|
|
||||||
|
|
||||||
fn zero() -> Self {
|
|
||||||
Self {
|
|
||||||
x: $base::zero(),
|
|
||||||
y: $base::zero(),
|
|
||||||
z: $base::zero(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn one() -> Self {
|
|
||||||
// NOTE: This is specific to b = 5
|
|
||||||
|
|
||||||
const NEGATIVE_ONE: $base = $base::neg(&$base::one());
|
|
||||||
const TWO: $base = $base::from_raw([2, 0, 0, 0]);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
x: NEGATIVE_ONE,
|
|
||||||
y: TWO,
|
|
||||||
z: $base::one(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_zero(&self) -> Choice {
|
|
||||||
self.z.is_zero()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_affine(&self) -> Self::Affine {
|
|
||||||
let zinv = self.z.invert().unwrap_or($base::zero());
|
|
||||||
let zinv2 = zinv.square();
|
|
||||||
let x = self.x * zinv2;
|
|
||||||
let zinv3 = zinv2 * zinv;
|
|
||||||
let y = self.y * zinv3;
|
|
||||||
|
|
||||||
let tmp = $name_affine {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
infinity: Choice::from(0u8),
|
|
||||||
};
|
|
||||||
|
|
||||||
$name_affine::conditional_select(&tmp, &$name_affine::zero(), zinv.is_zero())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn double(&self) -> Self {
|
|
||||||
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
|
|
||||||
//
|
|
||||||
// There are no points of order 2.
|
|
||||||
|
|
||||||
let a = self.x.square();
|
|
||||||
let b = self.y.square();
|
|
||||||
let c = b.square();
|
|
||||||
let d = self.x + b;
|
|
||||||
let d = d.square();
|
|
||||||
let d = d - a - c;
|
|
||||||
let d = d + d;
|
|
||||||
let e = a + a + a;
|
|
||||||
let f = e.square();
|
|
||||||
let z3 = self.z * self.y;
|
|
||||||
let z3 = z3 + z3;
|
|
||||||
let x3 = f - (d + d);
|
|
||||||
let c = c + c;
|
|
||||||
let c = c + c;
|
|
||||||
let c = c + c;
|
|
||||||
let y3 = e * (d - x3) - c;
|
|
||||||
|
|
||||||
let tmp = $name {
|
|
||||||
x: x3,
|
|
||||||
y: y3,
|
|
||||||
z: z3,
|
|
||||||
};
|
|
||||||
|
|
||||||
$name::conditional_select(&tmp, &$name::zero(), self.is_zero())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Apply the curve endomorphism by multiplying the x-coordinate
|
|
||||||
/// by an element of multiplicative order 3.
|
|
||||||
fn endo(&self) -> Self {
|
|
||||||
$name {
|
|
||||||
x: self.x * $base::ZETA,
|
|
||||||
y: self.y,
|
|
||||||
z: self.z,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn b() -> Self::Base {
|
|
||||||
$name::curve_constant_b()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_on_curve(&self) -> Choice {
|
|
||||||
// Y^2 - X^3 = 5(Z^6)
|
|
||||||
|
|
||||||
(self.y.square() - (self.x.square() * self.x))
|
|
||||||
.ct_eq(&((self.z.square() * self.z).square() * $name::curve_constant_b()))
|
|
||||||
| self.z.is_zero()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn batch_to_affine(p: &[Self], q: &mut [Self::Affine]) {
|
|
||||||
assert_eq!(p.len(), q.len());
|
|
||||||
|
|
||||||
let mut acc = $base::one();
|
|
||||||
for (p, q) in p.iter().zip(q.iter_mut()) {
|
|
||||||
// We use the `x` field of $name_affine to store the product
|
|
||||||
// of previous z-coordinates seen.
|
|
||||||
q.x = acc;
|
|
||||||
|
|
||||||
// We will end up skipping all identities in p
|
|
||||||
acc = $base::conditional_select(&(acc * p.z), &acc, p.is_zero());
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is the inverse, as all z-coordinates are nonzero and the ones
|
|
||||||
// that are not are skipped.
|
|
||||||
acc = acc.invert().unwrap();
|
|
||||||
|
|
||||||
for (p, q) in p.iter().rev().zip(q.iter_mut().rev()) {
|
|
||||||
let skip = p.is_zero();
|
|
||||||
|
|
||||||
// Compute tmp = 1/z
|
|
||||||
let tmp = q.x * acc;
|
|
||||||
|
|
||||||
// Cancel out z-coordinate in denominator of `acc`
|
|
||||||
acc = $base::conditional_select(&(acc * p.z), &acc, skip);
|
|
||||||
|
|
||||||
// Set the coordinates to the correct value
|
|
||||||
let tmp2 = tmp.square();
|
|
||||||
let tmp3 = tmp2 * tmp;
|
|
||||||
|
|
||||||
q.x = p.x * tmp2;
|
|
||||||
q.y = p.y * tmp3;
|
|
||||||
q.infinity = Choice::from(0u8);
|
|
||||||
|
|
||||||
*q = $name_affine::conditional_select(&q, &$name_affine::zero(), skip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a $name_affine> for $name {
|
|
||||||
fn from(p: &'a $name_affine) -> $name {
|
|
||||||
p.to_projective()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<$name_affine> for $name {
|
|
||||||
fn from(p: $name_affine) -> $name {
|
|
||||||
p.to_projective()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for $name {
|
|
||||||
fn default() -> $name {
|
|
||||||
$name::zero()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ConstantTimeEq for $name {
|
|
||||||
fn ct_eq(&self, other: &Self) -> Choice {
|
|
||||||
// Is (xz^2, yz^3, z) equal to (x'z'^2, yz'^3, z') when converted to affine?
|
|
||||||
|
|
||||||
let z = other.z.square();
|
|
||||||
let x1 = self.x * z;
|
|
||||||
let z = z * other.z;
|
|
||||||
let y1 = self.y * z;
|
|
||||||
let z = self.z.square();
|
|
||||||
let x2 = other.x * z;
|
|
||||||
let z = z * self.z;
|
|
||||||
let y2 = other.y * z;
|
|
||||||
|
|
||||||
let self_is_zero = self.is_zero();
|
|
||||||
let other_is_zero = other.is_zero();
|
|
||||||
|
|
||||||
(self_is_zero & other_is_zero) // Both point at infinity
|
|
||||||
| ((!self_is_zero) & (!other_is_zero) & x1.ct_eq(&x2) & y1.ct_eq(&y2))
|
|
||||||
// Neither point at infinity, coordinates are the same
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for $name {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.ct_eq(other).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl cmp::Eq for $name {}
|
|
||||||
|
|
||||||
impl ConditionallySelectable for $name {
|
|
||||||
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
|
||||||
$name {
|
|
||||||
x: $base::conditional_select(&a.x, &b.x, choice),
|
|
||||||
y: $base::conditional_select(&a.y, &b.y, choice),
|
|
||||||
z: $base::conditional_select(&a.z, &b.z, choice),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Neg for &'a $name {
|
|
||||||
type Output = $name;
|
|
||||||
|
|
||||||
fn neg(self) -> $name {
|
|
||||||
$name {
|
|
||||||
x: self.x,
|
|
||||||
y: -self.y,
|
|
||||||
z: self.z,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Neg for $name {
|
|
||||||
type Output = $name;
|
|
||||||
|
|
||||||
fn neg(self) -> $name {
|
|
||||||
-&self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> Add<&'a $name> for &'b $name {
|
|
||||||
type Output = $name;
|
|
||||||
|
|
||||||
fn add(self, rhs: &'a $name) -> $name {
|
|
||||||
if bool::from(self.is_zero()) {
|
|
||||||
*rhs
|
|
||||||
} else if bool::from(rhs.is_zero()) {
|
|
||||||
*self
|
|
||||||
} else {
|
|
||||||
let z1z1 = self.z.square();
|
|
||||||
let z2z2 = rhs.z.square();
|
|
||||||
let u1 = self.x * z2z2;
|
|
||||||
let u2 = rhs.x * z1z1;
|
|
||||||
let s1 = self.y * z2z2 * rhs.z;
|
|
||||||
let s2 = rhs.y * z1z1 * self.z;
|
|
||||||
|
|
||||||
if u1 == u2 {
|
|
||||||
if s1 == s2 {
|
|
||||||
self.double()
|
|
||||||
} else {
|
|
||||||
$name::zero()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let h = u2 - u1;
|
|
||||||
let i = (h + h).square();
|
|
||||||
let j = h * i;
|
|
||||||
let r = s2 - s1;
|
|
||||||
let r = r + r;
|
|
||||||
let v = u1 * i;
|
|
||||||
let x3 = r.square() - j - v - v;
|
|
||||||
let s1 = s1 * j;
|
|
||||||
let s1 = s1 + s1;
|
|
||||||
let y3 = r * (v - x3) - s1;
|
|
||||||
let z3 = (self.z + rhs.z).square() - z1z1 - z2z2;
|
|
||||||
let z3 = z3 * h;
|
|
||||||
|
|
||||||
$name {
|
|
||||||
x: x3, y: y3, z: z3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> Add<&'a $name_affine> for &'b $name {
|
|
||||||
type Output = $name;
|
|
||||||
|
|
||||||
fn add(self, rhs: &'a $name_affine) -> $name {
|
|
||||||
if bool::from(self.is_zero()) {
|
|
||||||
rhs.to_projective()
|
|
||||||
} else if bool::from(rhs.is_zero()) {
|
|
||||||
*self
|
|
||||||
} else {
|
|
||||||
let z1z1 = self.z.square();
|
|
||||||
let u2 = rhs.x * z1z1;
|
|
||||||
let s2 = rhs.y * z1z1 * self.z;
|
|
||||||
|
|
||||||
if self.x == u2 {
|
|
||||||
if self.y == s2 {
|
|
||||||
self.double()
|
|
||||||
} else {
|
|
||||||
$name::zero()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let h = u2 - self.x;
|
|
||||||
let hh = h.square();
|
|
||||||
let i = hh + hh;
|
|
||||||
let i = i + i;
|
|
||||||
let j = h * i;
|
|
||||||
let r = s2 - self.y;
|
|
||||||
let r = r + r;
|
|
||||||
let v = self.x * i;
|
|
||||||
let x3 = r.square() - j - v - v;
|
|
||||||
let j = self.y * j;
|
|
||||||
let j = j + j;
|
|
||||||
let y3 = r * (v - x3) - j;
|
|
||||||
let z3 = (self.z + h).square() - z1z1 - hh;
|
|
||||||
|
|
||||||
$name {
|
|
||||||
x: x3, y: y3, z: z3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> Sub<&'a $name> for &'b $name {
|
|
||||||
type Output = $name;
|
|
||||||
|
|
||||||
fn sub(self, other: &'a $name) -> $name {
|
|
||||||
self + (-other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> Sub<&'a $name_affine> for &'b $name {
|
|
||||||
type Output = $name;
|
|
||||||
|
|
||||||
fn sub(self, other: &'a $name_affine) -> $name {
|
|
||||||
self + (-other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> Mul<&'b $scalar> for &'a $name {
|
|
||||||
type Output = $name;
|
|
||||||
|
|
||||||
fn mul(self, other: &'b $scalar) -> Self::Output {
|
|
||||||
// TODO: make this faster
|
|
||||||
|
|
||||||
let mut acc = $name::zero();
|
|
||||||
|
|
||||||
// This is a simple double-and-add implementation of point
|
|
||||||
// multiplication, moving from most significant to least
|
|
||||||
// significant bit of the scalar.
|
|
||||||
//
|
|
||||||
// NOTE: We skip the leading bit because it's always unset.
|
|
||||||
for bit in other
|
|
||||||
.to_bytes()
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
|
|
||||||
.skip(1)
|
|
||||||
{
|
|
||||||
acc = acc.double();
|
|
||||||
acc = $name::conditional_select(&acc, &(acc + self), bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
acc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Neg for &'a $name_affine {
|
|
||||||
type Output = $name_affine;
|
|
||||||
|
|
||||||
fn neg(self) -> $name_affine {
|
|
||||||
$name_affine {
|
|
||||||
x: self.x,
|
|
||||||
y: -self.y,
|
|
||||||
infinity: self.infinity,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Neg for $name_affine {
|
|
||||||
type Output = $name_affine;
|
|
||||||
|
|
||||||
fn neg(self) -> $name_affine {
|
|
||||||
-&self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> Add<&'a $name> for &'b $name_affine {
|
|
||||||
type Output = $name;
|
|
||||||
|
|
||||||
fn add(self, rhs: &'a $name) -> $name {
|
|
||||||
rhs + self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> Add<&'a $name_affine> for &'b $name_affine {
|
|
||||||
type Output = $name;
|
|
||||||
|
|
||||||
fn add(self, rhs: &'a $name_affine) -> $name {
|
|
||||||
if bool::from(self.is_zero()) {
|
|
||||||
rhs.to_projective()
|
|
||||||
} else if bool::from(rhs.is_zero()) {
|
|
||||||
self.to_projective()
|
|
||||||
} else {
|
|
||||||
if self.x == rhs.x {
|
|
||||||
if self.y == rhs.y {
|
|
||||||
self.to_projective().double()
|
|
||||||
} else {
|
|
||||||
$name::zero()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let h = rhs.x - self.x;
|
|
||||||
let hh = h.square();
|
|
||||||
let i = hh + hh;
|
|
||||||
let i = i + i;
|
|
||||||
let j = h * i;
|
|
||||||
let r = rhs.y - self.y;
|
|
||||||
let r = r + r;
|
|
||||||
let v = self.x * i;
|
|
||||||
let x3 = r.square() - j - v - v;
|
|
||||||
let j = self.y * j;
|
|
||||||
let j = j + j;
|
|
||||||
let y3 = r * (v - x3) - j;
|
|
||||||
let z3 = h + h;
|
|
||||||
|
|
||||||
$name {
|
|
||||||
x: x3, y: y3, z: z3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> Sub<&'a $name_affine> for &'b $name_affine {
|
|
||||||
type Output = $name;
|
|
||||||
|
|
||||||
fn sub(self, other: &'a $name_affine) -> $name {
|
|
||||||
self + (-other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> Sub<&'a $name> for &'b $name_affine {
|
|
||||||
type Output = $name;
|
|
||||||
|
|
||||||
fn sub(self, other: &'a $name) -> $name {
|
|
||||||
self + (-other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> Mul<&'b $scalar> for &'a $name_affine {
|
|
||||||
type Output = $name;
|
|
||||||
|
|
||||||
fn mul(self, other: &'b $scalar) -> Self::Output {
|
|
||||||
// TODO: make this faster
|
|
||||||
|
|
||||||
let mut acc = $name::zero();
|
|
||||||
|
|
||||||
// This is a simple double-and-add implementation of point
|
|
||||||
// multiplication, moving from most significant to least
|
|
||||||
// significant bit of the scalar.
|
|
||||||
//
|
|
||||||
// NOTE: We skip the leading bit because it's always unset.
|
|
||||||
for bit in other
|
|
||||||
.to_bytes()
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
|
|
||||||
.skip(1)
|
|
||||||
{
|
|
||||||
acc = acc.double();
|
|
||||||
acc = $name::conditional_select(&acc, &(acc + self), bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
acc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CurveAffine for $name_affine {
|
|
||||||
type Projective = $name;
|
|
||||||
type Scalar = $scalar;
|
|
||||||
type Base = $base;
|
|
||||||
|
|
||||||
fn zero() -> Self {
|
|
||||||
Self {
|
|
||||||
x: $base::zero(),
|
|
||||||
y: $base::zero(),
|
|
||||||
infinity: Choice::from(1u8),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn one() -> Self {
|
|
||||||
// NOTE: This is specific to b = 5
|
|
||||||
|
|
||||||
const NEGATIVE_ONE: $base = $base::neg(&$base::from_raw([1, 0, 0, 0]));
|
|
||||||
const TWO: $base = $base::from_raw([2, 0, 0, 0]);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
x: NEGATIVE_ONE,
|
|
||||||
y: TWO,
|
|
||||||
infinity: Choice::from(0u8),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_zero(&self) -> Choice {
|
|
||||||
self.infinity
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_on_curve(&self) -> Choice {
|
|
||||||
// y^2 - x^3 ?= b
|
|
||||||
(self.y.square() - (self.x.square() * self.x)).ct_eq(&$name::curve_constant_b())
|
|
||||||
| self.infinity
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_projective(&self) -> Self::Projective {
|
|
||||||
$name {
|
|
||||||
x: self.x,
|
|
||||||
y: self.y,
|
|
||||||
z: $base::conditional_select(&$base::one(), &$base::zero(), self.infinity),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_xy(&self) -> CtOption<(Self::Base, Self::Base)> {
|
|
||||||
CtOption::new((self.x, self.y), !self.is_zero())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_xy(x: Self::Base, y: Self::Base) -> CtOption<Self> {
|
|
||||||
let p = $name_affine {
|
|
||||||
x, y, infinity: 0u8.into()
|
|
||||||
};
|
|
||||||
CtOption::new(p, p.is_on_curve())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_bytes(bytes: &[u8; 32]) -> CtOption<Self> {
|
|
||||||
let mut tmp = *bytes;
|
|
||||||
let ysign = Choice::from(tmp[31] >> 7);
|
|
||||||
tmp[31] &= 0b0111_1111;
|
|
||||||
|
|
||||||
$base::from_bytes(&tmp).and_then(|x| {
|
|
||||||
CtOption::new(Self::zero(), x.is_zero() & (!ysign)).or_else(|| {
|
|
||||||
let x3 = x.square() * x;
|
|
||||||
(x3 + $name::curve_constant_b()).sqrt().and_then(|y| {
|
|
||||||
let sign = Choice::from(y.to_bytes()[0] & 1);
|
|
||||||
|
|
||||||
let y = $base::conditional_select(&y, &-y, ysign ^ sign);
|
|
||||||
|
|
||||||
CtOption::new(
|
|
||||||
$name_affine {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
infinity: Choice::from(0u8),
|
|
||||||
},
|
|
||||||
Choice::from(1u8),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_bytes(&self) -> [u8; 32] {
|
|
||||||
// TODO: not constant time
|
|
||||||
if bool::from(self.is_zero()) {
|
|
||||||
[0; 32]
|
|
||||||
} else {
|
|
||||||
let (x, y) = (self.x, self.y);
|
|
||||||
let sign = (y.to_bytes()[0] & 1) << 7;
|
|
||||||
let mut xbytes = x.to_bytes();
|
|
||||||
xbytes[31] |= sign;
|
|
||||||
xbytes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_bytes_wide(bytes: &[u8; 64]) -> CtOption<Self> {
|
|
||||||
let mut xbytes = [0u8; 32];
|
|
||||||
let mut ybytes = [0u8; 32];
|
|
||||||
xbytes.copy_from_slice(&bytes[0..32]);
|
|
||||||
ybytes.copy_from_slice(&bytes[32..64]);
|
|
||||||
|
|
||||||
$base::from_bytes(&xbytes).and_then(|x| {
|
|
||||||
$base::from_bytes(&ybytes).and_then(|y| {
|
|
||||||
CtOption::new(Self::zero(), x.is_zero() & y.is_zero()).or_else(|| {
|
|
||||||
let on_curve =
|
|
||||||
(x * x.square() + $name::curve_constant_b()).ct_eq(&y.square());
|
|
||||||
|
|
||||||
CtOption::new(
|
|
||||||
$name_affine {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
infinity: Choice::from(0u8),
|
|
||||||
},
|
|
||||||
Choice::from(on_curve),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_bytes_wide(&self) -> [u8; 64] {
|
|
||||||
// TODO: not constant time
|
|
||||||
if bool::from(self.is_zero()) {
|
|
||||||
[0; 64]
|
|
||||||
} else {
|
|
||||||
let mut out = [0u8; 64];
|
|
||||||
(&mut out[0..32]).copy_from_slice(&self.x.to_bytes());
|
|
||||||
(&mut out[32..64]).copy_from_slice(&self.y.to_bytes());
|
|
||||||
|
|
||||||
out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn b() -> Self::Base {
|
|
||||||
$name::curve_constant_b()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for $name_affine {
|
|
||||||
fn default() -> $name_affine {
|
|
||||||
$name_affine::zero()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a $name> for $name_affine {
|
|
||||||
fn from(p: &'a $name) -> $name_affine {
|
|
||||||
p.to_affine()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<$name> for $name_affine {
|
|
||||||
fn from(p: $name) -> $name_affine {
|
|
||||||
p.to_affine()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ConstantTimeEq for $name_affine {
|
|
||||||
fn ct_eq(&self, other: &Self) -> Choice {
|
|
||||||
let z1 = self.infinity;
|
|
||||||
let z2 = other.infinity;
|
|
||||||
|
|
||||||
(z1 & z2) | ((!z1) & (!z2) & (self.x.ct_eq(&other.x)) & (self.y.ct_eq(&other.y)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for $name_affine {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.ct_eq(other).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl cmp::Eq for $name_affine {}
|
|
||||||
|
|
||||||
impl ConditionallySelectable for $name_affine {
|
|
||||||
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
|
||||||
$name_affine {
|
|
||||||
x: $base::conditional_select(&a.x, &b.x, choice),
|
|
||||||
y: $base::conditional_select(&a.y, &b.y, choice),
|
|
||||||
infinity: Choice::conditional_select(&a.infinity, &b.infinity, choice),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_binops_additive!($name, $name);
|
|
||||||
impl_binops_additive!($name, $name_affine);
|
|
||||||
impl_binops_additive_specify_output!($name_affine, $name_affine, $name);
|
|
||||||
impl_binops_additive_specify_output!($name_affine, $name, $name);
|
|
||||||
impl_binops_multiplicative!($name, $scalar);
|
|
||||||
impl_binops_multiplicative_mixed!($name_affine, $scalar, $name);
|
|
||||||
|
|
||||||
impl Group for $name {
|
|
||||||
type Scalar = $scalar;
|
|
||||||
|
|
||||||
fn group_zero() -> Self {
|
|
||||||
Self::zero()
|
|
||||||
}
|
|
||||||
fn group_add(&mut self, rhs: &Self) {
|
|
||||||
*self = *self + *rhs;
|
|
||||||
}
|
|
||||||
fn group_sub(&mut self, rhs: &Self) {
|
|
||||||
*self = *self - *rhs;
|
|
||||||
}
|
|
||||||
fn group_scale(&mut self, by: &Self::Scalar) {
|
|
||||||
*self = *self * (*by);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
new_curve_impl!(Ep, EpAffine, Fp, Fq);
|
|
||||||
new_curve_impl!(Eq, EqAffine, Fq, Fp);
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
//! This module contains implementations for the two finite fields of the
|
//! This module contains the `Field` abstraction that allows us to write
|
||||||
//! Tweedledum and Tweedledee curves. The `Field` abstraction allows us to write
|
//! code that generalizes over a pair of fields.
|
||||||
//! code that generalizes over these two fields.
|
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||||
|
@ -261,41 +260,23 @@ pub trait Field:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod fp;
|
|
||||||
mod fq;
|
|
||||||
|
|
||||||
/// Compute a + b + carry, returning the result and the new carry over.
|
/// Compute a + b + carry, returning the result and the new carry over.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
const fn adc(a: u64, b: u64, carry: u64) -> (u64, u64) {
|
pub(crate) const fn adc(a: u64, b: u64, carry: u64) -> (u64, u64) {
|
||||||
let ret = (a as u128) + (b as u128) + (carry as u128);
|
let ret = (a as u128) + (b as u128) + (carry as u128);
|
||||||
(ret as u64, (ret >> 64) as u64)
|
(ret as u64, (ret >> 64) as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute a - (b + borrow), returning the result and the new borrow.
|
/// Compute a - (b + borrow), returning the result and the new borrow.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
const fn sbb(a: u64, b: u64, borrow: u64) -> (u64, u64) {
|
pub(crate) const fn sbb(a: u64, b: u64, borrow: u64) -> (u64, u64) {
|
||||||
let ret = (a as u128).wrapping_sub((b as u128) + ((borrow >> 63) as u128));
|
let ret = (a as u128).wrapping_sub((b as u128) + ((borrow >> 63) as u128));
|
||||||
(ret as u64, (ret >> 64) as u64)
|
(ret as u64, (ret >> 64) as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute a + (b * c) + carry, returning the result and the new carry over.
|
/// Compute a + (b * c) + carry, returning the result and the new carry over.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
const fn mac(a: u64, b: u64, c: u64, carry: u64) -> (u64, u64) {
|
pub(crate) const fn mac(a: u64, b: u64, c: u64, carry: u64) -> (u64, u64) {
|
||||||
let ret = (a as u128) + ((b as u128) * (c as u128)) + (carry as u128);
|
let ret = (a as u128) + ((b as u128) * (c as u128)) + (carry as u128);
|
||||||
(ret as u64, (ret >> 64) as u64)
|
(ret as u64, (ret >> 64) as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use fp::*;
|
|
||||||
pub use fq::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extract() {
|
|
||||||
let a = Fq::random();
|
|
||||||
let a = a.square();
|
|
||||||
let (t, s) = a.extract_radix2_vartime().unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
t.pow_vartime(&[1 << Fq::S, 0, 0, 0]) * Fq::ROOT_OF_UNITY.pow_vartime(&[s, 0, 0, 0]),
|
|
||||||
a
|
|
||||||
);
|
|
||||||
assert_eq!(a.deterministic_sqrt().unwrap().square(), a);
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,3 +17,4 @@ pub mod arithmetic;
|
||||||
pub mod plonk;
|
pub mod plonk;
|
||||||
pub mod poly;
|
pub mod poly;
|
||||||
pub mod transcript;
|
pub mod transcript;
|
||||||
|
pub mod tweedle;
|
||||||
|
|
|
@ -111,9 +111,10 @@ pub fn hash_point<C: CurveAffine, H: Hasher<C::Base>>(
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_proving() {
|
fn test_proving() {
|
||||||
use crate::arithmetic::{Curve, EqAffine, Field, Fp, Fq};
|
use crate::arithmetic::{Curve, Field};
|
||||||
use crate::poly::commitment::{Blind, Params};
|
use crate::poly::commitment::{Blind, Params};
|
||||||
use crate::transcript::DummyHash;
|
use crate::transcript::DummyHash;
|
||||||
|
use crate::tweedle::{EqAffine, Fp, Fq};
|
||||||
use circuit::{Advice, Column, Fixed};
|
use circuit::{Advice, Column, Fixed};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
const K: u32 = 5;
|
const K: u32 = 5;
|
||||||
|
|
|
@ -222,8 +222,8 @@ impl<F: Field> MulAssign<F> for Blind<F> {
|
||||||
fn test_commit_lagrange() {
|
fn test_commit_lagrange() {
|
||||||
const K: u32 = 6;
|
const K: u32 = 6;
|
||||||
|
|
||||||
use crate::arithmetic::{EpAffine, Fp, Fq};
|
|
||||||
use crate::transcript::DummyHash;
|
use crate::transcript::DummyHash;
|
||||||
|
use crate::tweedle::{EpAffine, Fp, Fq};
|
||||||
let params = Params::<EpAffine>::new::<DummyHash<Fp>>(K);
|
let params = Params::<EpAffine>::new::<DummyHash<Fp>>(K);
|
||||||
let domain = super::EvaluationDomain::new(1, K);
|
let domain = super::EvaluationDomain::new(1, K);
|
||||||
|
|
||||||
|
@ -248,10 +248,9 @@ fn test_opening_proof() {
|
||||||
commitment::{Blind, Params},
|
commitment::{Blind, Params},
|
||||||
EvaluationDomain,
|
EvaluationDomain,
|
||||||
};
|
};
|
||||||
use crate::arithmetic::{
|
use crate::arithmetic::{eval_polynomial, get_challenge_scalar, Challenge, Curve, Field};
|
||||||
eval_polynomial, get_challenge_scalar, Challenge, Curve, EpAffine, Field, Fp, Fq,
|
|
||||||
};
|
|
||||||
use crate::transcript::{DummyHash, Hasher};
|
use crate::transcript::{DummyHash, Hasher};
|
||||||
|
use crate::tweedle::{EpAffine, Fp, Fq};
|
||||||
|
|
||||||
let params = Params::<EpAffine>::new::<DummyHash<Fp>>(K);
|
let params = Params::<EpAffine>::new::<DummyHash<Fp>>(K);
|
||||||
let domain = EvaluationDomain::new(1, K);
|
let domain = EvaluationDomain::new(1, K);
|
||||||
|
|
|
@ -191,7 +191,8 @@ where
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{construct_intermediate_sets, Query};
|
use super::{construct_intermediate_sets, Query};
|
||||||
use crate::arithmetic::{Field, Fp};
|
use crate::arithmetic::Field;
|
||||||
|
use crate::tweedle::Fp;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct MyQuery<F> {
|
struct MyQuery<F> {
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
//! This module contains implementations for the Tweedledum and Tweedledee
|
||||||
|
//! elliptic curve groups.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
mod curves;
|
||||||
|
mod fields;
|
||||||
|
|
||||||
|
pub mod dee;
|
||||||
|
pub mod dum;
|
||||||
|
|
||||||
|
pub use curves::*;
|
||||||
|
pub use fields::*;
|
|
@ -0,0 +1,703 @@
|
||||||
|
//! This module contains implementations for the Tweedledum and Tweedledee
|
||||||
|
//! elliptic curve groups.
|
||||||
|
|
||||||
|
use core::cmp;
|
||||||
|
use core::fmt::Debug;
|
||||||
|
use core::ops::{Add, Mul, Neg, Sub};
|
||||||
|
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
||||||
|
|
||||||
|
use super::{Fp, Fq};
|
||||||
|
use crate::arithmetic::{Curve, CurveAffine, Field, Group};
|
||||||
|
|
||||||
|
macro_rules! new_curve_impl {
|
||||||
|
($name:ident, $name_affine:ident, $base:ident, $scalar:ident) => {
|
||||||
|
/// Represents a point in the projective coordinate space.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct $name {
|
||||||
|
x: $base,
|
||||||
|
y: $base,
|
||||||
|
z: $base,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $name {
|
||||||
|
const fn curve_constant_b() -> $base {
|
||||||
|
// NOTE: this is specific to b = 5
|
||||||
|
$base::from_raw([5, 0, 0, 0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a point in the affine coordinate space (or the point at
|
||||||
|
/// infinity).
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct $name_affine {
|
||||||
|
x: $base,
|
||||||
|
y: $base,
|
||||||
|
infinity: Choice,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Curve for $name {
|
||||||
|
type Affine = $name_affine;
|
||||||
|
type Scalar = $scalar;
|
||||||
|
type Base = $base;
|
||||||
|
|
||||||
|
fn zero() -> Self {
|
||||||
|
Self {
|
||||||
|
x: $base::zero(),
|
||||||
|
y: $base::zero(),
|
||||||
|
z: $base::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn one() -> Self {
|
||||||
|
// NOTE: This is specific to b = 5
|
||||||
|
|
||||||
|
const NEGATIVE_ONE: $base = $base::neg(&$base::one());
|
||||||
|
const TWO: $base = $base::from_raw([2, 0, 0, 0]);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
x: NEGATIVE_ONE,
|
||||||
|
y: TWO,
|
||||||
|
z: $base::one(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_zero(&self) -> Choice {
|
||||||
|
self.z.is_zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_affine(&self) -> Self::Affine {
|
||||||
|
let zinv = self.z.invert().unwrap_or($base::zero());
|
||||||
|
let zinv2 = zinv.square();
|
||||||
|
let x = self.x * zinv2;
|
||||||
|
let zinv3 = zinv2 * zinv;
|
||||||
|
let y = self.y * zinv3;
|
||||||
|
|
||||||
|
let tmp = $name_affine {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
infinity: Choice::from(0u8),
|
||||||
|
};
|
||||||
|
|
||||||
|
$name_affine::conditional_select(&tmp, &$name_affine::zero(), zinv.is_zero())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn double(&self) -> Self {
|
||||||
|
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
|
||||||
|
//
|
||||||
|
// There are no points of order 2.
|
||||||
|
|
||||||
|
let a = self.x.square();
|
||||||
|
let b = self.y.square();
|
||||||
|
let c = b.square();
|
||||||
|
let d = self.x + b;
|
||||||
|
let d = d.square();
|
||||||
|
let d = d - a - c;
|
||||||
|
let d = d + d;
|
||||||
|
let e = a + a + a;
|
||||||
|
let f = e.square();
|
||||||
|
let z3 = self.z * self.y;
|
||||||
|
let z3 = z3 + z3;
|
||||||
|
let x3 = f - (d + d);
|
||||||
|
let c = c + c;
|
||||||
|
let c = c + c;
|
||||||
|
let c = c + c;
|
||||||
|
let y3 = e * (d - x3) - c;
|
||||||
|
|
||||||
|
let tmp = $name {
|
||||||
|
x: x3,
|
||||||
|
y: y3,
|
||||||
|
z: z3,
|
||||||
|
};
|
||||||
|
|
||||||
|
$name::conditional_select(&tmp, &$name::zero(), self.is_zero())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply the curve endomorphism by multiplying the x-coordinate
|
||||||
|
/// by an element of multiplicative order 3.
|
||||||
|
fn endo(&self) -> Self {
|
||||||
|
$name {
|
||||||
|
x: self.x * $base::ZETA,
|
||||||
|
y: self.y,
|
||||||
|
z: self.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() -> Self::Base {
|
||||||
|
$name::curve_constant_b()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_on_curve(&self) -> Choice {
|
||||||
|
// Y^2 - X^3 = 5(Z^6)
|
||||||
|
|
||||||
|
(self.y.square() - (self.x.square() * self.x))
|
||||||
|
.ct_eq(&((self.z.square() * self.z).square() * $name::curve_constant_b()))
|
||||||
|
| self.z.is_zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn batch_to_affine(p: &[Self], q: &mut [Self::Affine]) {
|
||||||
|
assert_eq!(p.len(), q.len());
|
||||||
|
|
||||||
|
let mut acc = $base::one();
|
||||||
|
for (p, q) in p.iter().zip(q.iter_mut()) {
|
||||||
|
// We use the `x` field of $name_affine to store the product
|
||||||
|
// of previous z-coordinates seen.
|
||||||
|
q.x = acc;
|
||||||
|
|
||||||
|
// We will end up skipping all identities in p
|
||||||
|
acc = $base::conditional_select(&(acc * p.z), &acc, p.is_zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the inverse, as all z-coordinates are nonzero and the ones
|
||||||
|
// that are not are skipped.
|
||||||
|
acc = acc.invert().unwrap();
|
||||||
|
|
||||||
|
for (p, q) in p.iter().rev().zip(q.iter_mut().rev()) {
|
||||||
|
let skip = p.is_zero();
|
||||||
|
|
||||||
|
// Compute tmp = 1/z
|
||||||
|
let tmp = q.x * acc;
|
||||||
|
|
||||||
|
// Cancel out z-coordinate in denominator of `acc`
|
||||||
|
acc = $base::conditional_select(&(acc * p.z), &acc, skip);
|
||||||
|
|
||||||
|
// Set the coordinates to the correct value
|
||||||
|
let tmp2 = tmp.square();
|
||||||
|
let tmp3 = tmp2 * tmp;
|
||||||
|
|
||||||
|
q.x = p.x * tmp2;
|
||||||
|
q.y = p.y * tmp3;
|
||||||
|
q.infinity = Choice::from(0u8);
|
||||||
|
|
||||||
|
*q = $name_affine::conditional_select(&q, &$name_affine::zero(), skip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a $name_affine> for $name {
|
||||||
|
fn from(p: &'a $name_affine) -> $name {
|
||||||
|
p.to_projective()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$name_affine> for $name {
|
||||||
|
fn from(p: $name_affine) -> $name {
|
||||||
|
p.to_projective()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for $name {
|
||||||
|
fn default() -> $name {
|
||||||
|
$name::zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConstantTimeEq for $name {
|
||||||
|
fn ct_eq(&self, other: &Self) -> Choice {
|
||||||
|
// Is (xz^2, yz^3, z) equal to (x'z'^2, yz'^3, z') when converted to affine?
|
||||||
|
|
||||||
|
let z = other.z.square();
|
||||||
|
let x1 = self.x * z;
|
||||||
|
let z = z * other.z;
|
||||||
|
let y1 = self.y * z;
|
||||||
|
let z = self.z.square();
|
||||||
|
let x2 = other.x * z;
|
||||||
|
let z = z * self.z;
|
||||||
|
let y2 = other.y * z;
|
||||||
|
|
||||||
|
let self_is_zero = self.is_zero();
|
||||||
|
let other_is_zero = other.is_zero();
|
||||||
|
|
||||||
|
(self_is_zero & other_is_zero) // Both point at infinity
|
||||||
|
| ((!self_is_zero) & (!other_is_zero) & x1.ct_eq(&x2) & y1.ct_eq(&y2))
|
||||||
|
// Neither point at infinity, coordinates are the same
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for $name {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.ct_eq(other).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl cmp::Eq for $name {}
|
||||||
|
|
||||||
|
impl ConditionallySelectable for $name {
|
||||||
|
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
||||||
|
$name {
|
||||||
|
x: $base::conditional_select(&a.x, &b.x, choice),
|
||||||
|
y: $base::conditional_select(&a.y, &b.y, choice),
|
||||||
|
z: $base::conditional_select(&a.z, &b.z, choice),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Neg for &'a $name {
|
||||||
|
type Output = $name;
|
||||||
|
|
||||||
|
fn neg(self) -> $name {
|
||||||
|
$name {
|
||||||
|
x: self.x,
|
||||||
|
y: -self.y,
|
||||||
|
z: self.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for $name {
|
||||||
|
type Output = $name;
|
||||||
|
|
||||||
|
fn neg(self) -> $name {
|
||||||
|
-&self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Add<&'a $name> for &'b $name {
|
||||||
|
type Output = $name;
|
||||||
|
|
||||||
|
fn add(self, rhs: &'a $name) -> $name {
|
||||||
|
if bool::from(self.is_zero()) {
|
||||||
|
*rhs
|
||||||
|
} else if bool::from(rhs.is_zero()) {
|
||||||
|
*self
|
||||||
|
} else {
|
||||||
|
let z1z1 = self.z.square();
|
||||||
|
let z2z2 = rhs.z.square();
|
||||||
|
let u1 = self.x * z2z2;
|
||||||
|
let u2 = rhs.x * z1z1;
|
||||||
|
let s1 = self.y * z2z2 * rhs.z;
|
||||||
|
let s2 = rhs.y * z1z1 * self.z;
|
||||||
|
|
||||||
|
if u1 == u2 {
|
||||||
|
if s1 == s2 {
|
||||||
|
self.double()
|
||||||
|
} else {
|
||||||
|
$name::zero()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let h = u2 - u1;
|
||||||
|
let i = (h + h).square();
|
||||||
|
let j = h * i;
|
||||||
|
let r = s2 - s1;
|
||||||
|
let r = r + r;
|
||||||
|
let v = u1 * i;
|
||||||
|
let x3 = r.square() - j - v - v;
|
||||||
|
let s1 = s1 * j;
|
||||||
|
let s1 = s1 + s1;
|
||||||
|
let y3 = r * (v - x3) - s1;
|
||||||
|
let z3 = (self.z + rhs.z).square() - z1z1 - z2z2;
|
||||||
|
let z3 = z3 * h;
|
||||||
|
|
||||||
|
$name {
|
||||||
|
x: x3, y: y3, z: z3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Add<&'a $name_affine> for &'b $name {
|
||||||
|
type Output = $name;
|
||||||
|
|
||||||
|
fn add(self, rhs: &'a $name_affine) -> $name {
|
||||||
|
if bool::from(self.is_zero()) {
|
||||||
|
rhs.to_projective()
|
||||||
|
} else if bool::from(rhs.is_zero()) {
|
||||||
|
*self
|
||||||
|
} else {
|
||||||
|
let z1z1 = self.z.square();
|
||||||
|
let u2 = rhs.x * z1z1;
|
||||||
|
let s2 = rhs.y * z1z1 * self.z;
|
||||||
|
|
||||||
|
if self.x == u2 {
|
||||||
|
if self.y == s2 {
|
||||||
|
self.double()
|
||||||
|
} else {
|
||||||
|
$name::zero()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let h = u2 - self.x;
|
||||||
|
let hh = h.square();
|
||||||
|
let i = hh + hh;
|
||||||
|
let i = i + i;
|
||||||
|
let j = h * i;
|
||||||
|
let r = s2 - self.y;
|
||||||
|
let r = r + r;
|
||||||
|
let v = self.x * i;
|
||||||
|
let x3 = r.square() - j - v - v;
|
||||||
|
let j = self.y * j;
|
||||||
|
let j = j + j;
|
||||||
|
let y3 = r * (v - x3) - j;
|
||||||
|
let z3 = (self.z + h).square() - z1z1 - hh;
|
||||||
|
|
||||||
|
$name {
|
||||||
|
x: x3, y: y3, z: z3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Sub<&'a $name> for &'b $name {
|
||||||
|
type Output = $name;
|
||||||
|
|
||||||
|
fn sub(self, other: &'a $name) -> $name {
|
||||||
|
self + (-other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Sub<&'a $name_affine> for &'b $name {
|
||||||
|
type Output = $name;
|
||||||
|
|
||||||
|
fn sub(self, other: &'a $name_affine) -> $name {
|
||||||
|
self + (-other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Mul<&'b $scalar> for &'a $name {
|
||||||
|
type Output = $name;
|
||||||
|
|
||||||
|
fn mul(self, other: &'b $scalar) -> Self::Output {
|
||||||
|
// TODO: make this faster
|
||||||
|
|
||||||
|
let mut acc = $name::zero();
|
||||||
|
|
||||||
|
// This is a simple double-and-add implementation of point
|
||||||
|
// multiplication, moving from most significant to least
|
||||||
|
// significant bit of the scalar.
|
||||||
|
//
|
||||||
|
// NOTE: We skip the leading bit because it's always unset.
|
||||||
|
for bit in other
|
||||||
|
.to_bytes()
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
|
||||||
|
.skip(1)
|
||||||
|
{
|
||||||
|
acc = acc.double();
|
||||||
|
acc = $name::conditional_select(&acc, &(acc + self), bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Neg for &'a $name_affine {
|
||||||
|
type Output = $name_affine;
|
||||||
|
|
||||||
|
fn neg(self) -> $name_affine {
|
||||||
|
$name_affine {
|
||||||
|
x: self.x,
|
||||||
|
y: -self.y,
|
||||||
|
infinity: self.infinity,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for $name_affine {
|
||||||
|
type Output = $name_affine;
|
||||||
|
|
||||||
|
fn neg(self) -> $name_affine {
|
||||||
|
-&self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Add<&'a $name> for &'b $name_affine {
|
||||||
|
type Output = $name;
|
||||||
|
|
||||||
|
fn add(self, rhs: &'a $name) -> $name {
|
||||||
|
rhs + self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Add<&'a $name_affine> for &'b $name_affine {
|
||||||
|
type Output = $name;
|
||||||
|
|
||||||
|
fn add(self, rhs: &'a $name_affine) -> $name {
|
||||||
|
if bool::from(self.is_zero()) {
|
||||||
|
rhs.to_projective()
|
||||||
|
} else if bool::from(rhs.is_zero()) {
|
||||||
|
self.to_projective()
|
||||||
|
} else {
|
||||||
|
if self.x == rhs.x {
|
||||||
|
if self.y == rhs.y {
|
||||||
|
self.to_projective().double()
|
||||||
|
} else {
|
||||||
|
$name::zero()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let h = rhs.x - self.x;
|
||||||
|
let hh = h.square();
|
||||||
|
let i = hh + hh;
|
||||||
|
let i = i + i;
|
||||||
|
let j = h * i;
|
||||||
|
let r = rhs.y - self.y;
|
||||||
|
let r = r + r;
|
||||||
|
let v = self.x * i;
|
||||||
|
let x3 = r.square() - j - v - v;
|
||||||
|
let j = self.y * j;
|
||||||
|
let j = j + j;
|
||||||
|
let y3 = r * (v - x3) - j;
|
||||||
|
let z3 = h + h;
|
||||||
|
|
||||||
|
$name {
|
||||||
|
x: x3, y: y3, z: z3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Sub<&'a $name_affine> for &'b $name_affine {
|
||||||
|
type Output = $name;
|
||||||
|
|
||||||
|
fn sub(self, other: &'a $name_affine) -> $name {
|
||||||
|
self + (-other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Sub<&'a $name> for &'b $name_affine {
|
||||||
|
type Output = $name;
|
||||||
|
|
||||||
|
fn sub(self, other: &'a $name) -> $name {
|
||||||
|
self + (-other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Mul<&'b $scalar> for &'a $name_affine {
|
||||||
|
type Output = $name;
|
||||||
|
|
||||||
|
fn mul(self, other: &'b $scalar) -> Self::Output {
|
||||||
|
// TODO: make this faster
|
||||||
|
|
||||||
|
let mut acc = $name::zero();
|
||||||
|
|
||||||
|
// This is a simple double-and-add implementation of point
|
||||||
|
// multiplication, moving from most significant to least
|
||||||
|
// significant bit of the scalar.
|
||||||
|
//
|
||||||
|
// NOTE: We skip the leading bit because it's always unset.
|
||||||
|
for bit in other
|
||||||
|
.to_bytes()
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
|
||||||
|
.skip(1)
|
||||||
|
{
|
||||||
|
acc = acc.double();
|
||||||
|
acc = $name::conditional_select(&acc, &(acc + self), bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CurveAffine for $name_affine {
|
||||||
|
type Projective = $name;
|
||||||
|
type Scalar = $scalar;
|
||||||
|
type Base = $base;
|
||||||
|
|
||||||
|
fn zero() -> Self {
|
||||||
|
Self {
|
||||||
|
x: $base::zero(),
|
||||||
|
y: $base::zero(),
|
||||||
|
infinity: Choice::from(1u8),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn one() -> Self {
|
||||||
|
// NOTE: This is specific to b = 5
|
||||||
|
|
||||||
|
const NEGATIVE_ONE: $base = $base::neg(&$base::from_raw([1, 0, 0, 0]));
|
||||||
|
const TWO: $base = $base::from_raw([2, 0, 0, 0]);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
x: NEGATIVE_ONE,
|
||||||
|
y: TWO,
|
||||||
|
infinity: Choice::from(0u8),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_zero(&self) -> Choice {
|
||||||
|
self.infinity
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_on_curve(&self) -> Choice {
|
||||||
|
// y^2 - x^3 ?= b
|
||||||
|
(self.y.square() - (self.x.square() * self.x)).ct_eq(&$name::curve_constant_b())
|
||||||
|
| self.infinity
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_projective(&self) -> Self::Projective {
|
||||||
|
$name {
|
||||||
|
x: self.x,
|
||||||
|
y: self.y,
|
||||||
|
z: $base::conditional_select(&$base::one(), &$base::zero(), self.infinity),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_xy(&self) -> CtOption<(Self::Base, Self::Base)> {
|
||||||
|
CtOption::new((self.x, self.y), !self.is_zero())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_xy(x: Self::Base, y: Self::Base) -> CtOption<Self> {
|
||||||
|
let p = $name_affine {
|
||||||
|
x, y, infinity: 0u8.into()
|
||||||
|
};
|
||||||
|
CtOption::new(p, p.is_on_curve())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_bytes(bytes: &[u8; 32]) -> CtOption<Self> {
|
||||||
|
let mut tmp = *bytes;
|
||||||
|
let ysign = Choice::from(tmp[31] >> 7);
|
||||||
|
tmp[31] &= 0b0111_1111;
|
||||||
|
|
||||||
|
$base::from_bytes(&tmp).and_then(|x| {
|
||||||
|
CtOption::new(Self::zero(), x.is_zero() & (!ysign)).or_else(|| {
|
||||||
|
let x3 = x.square() * x;
|
||||||
|
(x3 + $name::curve_constant_b()).sqrt().and_then(|y| {
|
||||||
|
let sign = Choice::from(y.to_bytes()[0] & 1);
|
||||||
|
|
||||||
|
let y = $base::conditional_select(&y, &-y, ysign ^ sign);
|
||||||
|
|
||||||
|
CtOption::new(
|
||||||
|
$name_affine {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
infinity: Choice::from(0u8),
|
||||||
|
},
|
||||||
|
Choice::from(1u8),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bytes(&self) -> [u8; 32] {
|
||||||
|
// TODO: not constant time
|
||||||
|
if bool::from(self.is_zero()) {
|
||||||
|
[0; 32]
|
||||||
|
} else {
|
||||||
|
let (x, y) = (self.x, self.y);
|
||||||
|
let sign = (y.to_bytes()[0] & 1) << 7;
|
||||||
|
let mut xbytes = x.to_bytes();
|
||||||
|
xbytes[31] |= sign;
|
||||||
|
xbytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_bytes_wide(bytes: &[u8; 64]) -> CtOption<Self> {
|
||||||
|
let mut xbytes = [0u8; 32];
|
||||||
|
let mut ybytes = [0u8; 32];
|
||||||
|
xbytes.copy_from_slice(&bytes[0..32]);
|
||||||
|
ybytes.copy_from_slice(&bytes[32..64]);
|
||||||
|
|
||||||
|
$base::from_bytes(&xbytes).and_then(|x| {
|
||||||
|
$base::from_bytes(&ybytes).and_then(|y| {
|
||||||
|
CtOption::new(Self::zero(), x.is_zero() & y.is_zero()).or_else(|| {
|
||||||
|
let on_curve =
|
||||||
|
(x * x.square() + $name::curve_constant_b()).ct_eq(&y.square());
|
||||||
|
|
||||||
|
CtOption::new(
|
||||||
|
$name_affine {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
infinity: Choice::from(0u8),
|
||||||
|
},
|
||||||
|
Choice::from(on_curve),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bytes_wide(&self) -> [u8; 64] {
|
||||||
|
// TODO: not constant time
|
||||||
|
if bool::from(self.is_zero()) {
|
||||||
|
[0; 64]
|
||||||
|
} else {
|
||||||
|
let mut out = [0u8; 64];
|
||||||
|
(&mut out[0..32]).copy_from_slice(&self.x.to_bytes());
|
||||||
|
(&mut out[32..64]).copy_from_slice(&self.y.to_bytes());
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() -> Self::Base {
|
||||||
|
$name::curve_constant_b()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for $name_affine {
|
||||||
|
fn default() -> $name_affine {
|
||||||
|
$name_affine::zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a $name> for $name_affine {
|
||||||
|
fn from(p: &'a $name) -> $name_affine {
|
||||||
|
p.to_affine()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$name> for $name_affine {
|
||||||
|
fn from(p: $name) -> $name_affine {
|
||||||
|
p.to_affine()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConstantTimeEq for $name_affine {
|
||||||
|
fn ct_eq(&self, other: &Self) -> Choice {
|
||||||
|
let z1 = self.infinity;
|
||||||
|
let z2 = other.infinity;
|
||||||
|
|
||||||
|
(z1 & z2) | ((!z1) & (!z2) & (self.x.ct_eq(&other.x)) & (self.y.ct_eq(&other.y)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for $name_affine {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.ct_eq(other).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl cmp::Eq for $name_affine {}
|
||||||
|
|
||||||
|
impl ConditionallySelectable for $name_affine {
|
||||||
|
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
||||||
|
$name_affine {
|
||||||
|
x: $base::conditional_select(&a.x, &b.x, choice),
|
||||||
|
y: $base::conditional_select(&a.y, &b.y, choice),
|
||||||
|
infinity: Choice::conditional_select(&a.infinity, &b.infinity, choice),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_binops_additive!($name, $name);
|
||||||
|
impl_binops_additive!($name, $name_affine);
|
||||||
|
impl_binops_additive_specify_output!($name_affine, $name_affine, $name);
|
||||||
|
impl_binops_additive_specify_output!($name_affine, $name, $name);
|
||||||
|
impl_binops_multiplicative!($name, $scalar);
|
||||||
|
impl_binops_multiplicative_mixed!($name_affine, $scalar, $name);
|
||||||
|
|
||||||
|
impl Group for $name {
|
||||||
|
type Scalar = $scalar;
|
||||||
|
|
||||||
|
fn group_zero() -> Self {
|
||||||
|
Self::zero()
|
||||||
|
}
|
||||||
|
fn group_add(&mut self, rhs: &Self) {
|
||||||
|
*self = *self + *rhs;
|
||||||
|
}
|
||||||
|
fn group_sub(&mut self, rhs: &Self) {
|
||||||
|
*self = *self - *rhs;
|
||||||
|
}
|
||||||
|
fn group_scale(&mut self, by: &Self::Scalar) {
|
||||||
|
*self = *self * (*by);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
new_curve_impl!(Ep, EpAffine, Fp, Fq);
|
||||||
|
new_curve_impl!(Eq, EqAffine, Fq, Fp);
|
|
@ -0,0 +1,13 @@
|
||||||
|
//! The Tweedledee elliptic curve group.
|
||||||
|
|
||||||
|
/// A Tweedledee point in the projective coordinate space.
|
||||||
|
pub type Point = super::Eq;
|
||||||
|
|
||||||
|
/// A Tweedledee point in the affine coordinate space (or the point at infinity).
|
||||||
|
pub type Affine = super::EqAffine;
|
||||||
|
|
||||||
|
/// The base field of the Tweedledee group.
|
||||||
|
pub type Base = super::Fq;
|
||||||
|
|
||||||
|
/// The scalar field of the Tweedledee group.
|
||||||
|
pub type Scalar = super::Fp;
|
|
@ -0,0 +1,13 @@
|
||||||
|
//! The Tweedledum elliptic curve group.
|
||||||
|
|
||||||
|
/// A Tweedledum point in the projective coordinate space.
|
||||||
|
pub type Point = super::Ep;
|
||||||
|
|
||||||
|
/// A Tweedledum point in the affine coordinate space (or the point at infinity).
|
||||||
|
pub type Affine = super::EpAffine;
|
||||||
|
|
||||||
|
/// The base field of the Tweedledum group.
|
||||||
|
pub type Base = super::Fp;
|
||||||
|
|
||||||
|
/// The scalar field of the Tweedledum group.
|
||||||
|
pub type Scalar = super::Fq;
|
|
@ -0,0 +1,23 @@
|
||||||
|
//! This module contains implementations for the two finite fields of the
|
||||||
|
//! Tweedledum and Tweedledee curves.
|
||||||
|
|
||||||
|
mod fp;
|
||||||
|
mod fq;
|
||||||
|
|
||||||
|
pub use fp::*;
|
||||||
|
pub use fq::*;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use crate::arithmetic::Field;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_extract() {
|
||||||
|
let a = Fq::random();
|
||||||
|
let a = a.square();
|
||||||
|
let (t, s) = a.extract_radix2_vartime().unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
t.pow_vartime(&[1 << Fq::S, 0, 0, 0]) * Fq::ROOT_OF_UNITY.pow_vartime(&[s, 0, 0, 0]),
|
||||||
|
a
|
||||||
|
);
|
||||||
|
assert_eq!(a.deterministic_sqrt().unwrap().square(), a);
|
||||||
|
}
|
|
@ -1,12 +1,10 @@
|
||||||
use super::{Field, Group};
|
|
||||||
|
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
use core::ops::{Add, Mul, Neg, Sub};
|
||||||
|
|
||||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
||||||
|
|
||||||
use super::{adc, mac, sbb};
|
use crate::arithmetic::{adc, mac, sbb, Field, Group};
|
||||||
|
|
||||||
/// This represents an element of $\mathbb{F}_p$ where
|
/// This represents an element of $\mathbb{F}_p$ where
|
||||||
///
|
///
|
|
@ -1,12 +1,10 @@
|
||||||
use super::{Field, Group};
|
|
||||||
|
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
use core::ops::{Add, Mul, Neg, Sub};
|
||||||
|
|
||||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
||||||
|
|
||||||
use super::{adc, mac, sbb};
|
use crate::arithmetic::{adc, mac, sbb, Field, Group};
|
||||||
|
|
||||||
/// This represents an element of $\mathbb{F}_q$ where
|
/// This represents an element of $\mathbb{F}_q$ where
|
||||||
///
|
///
|
|
@ -1,6 +1,6 @@
|
||||||
macro_rules! impl_add_binop_specify_output {
|
macro_rules! impl_add_binop_specify_output {
|
||||||
($lhs:ident, $rhs:ident, $output:ident) => {
|
($lhs:ident, $rhs:ident, $output:ident) => {
|
||||||
impl<'b> Add<&'b $rhs> for $lhs {
|
impl<'b> ::core::ops::Add<&'b $rhs> for $lhs {
|
||||||
type Output = $output;
|
type Output = $output;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -9,7 +9,7 @@ macro_rules! impl_add_binop_specify_output {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Add<$rhs> for &'a $lhs {
|
impl<'a> ::core::ops::Add<$rhs> for &'a $lhs {
|
||||||
type Output = $output;
|
type Output = $output;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -18,7 +18,7 @@ macro_rules! impl_add_binop_specify_output {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add<$rhs> for $lhs {
|
impl ::core::ops::Add<$rhs> for $lhs {
|
||||||
type Output = $output;
|
type Output = $output;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -31,7 +31,7 @@ macro_rules! impl_add_binop_specify_output {
|
||||||
|
|
||||||
macro_rules! impl_sub_binop_specify_output {
|
macro_rules! impl_sub_binop_specify_output {
|
||||||
($lhs:ident, $rhs:ident, $output:ident) => {
|
($lhs:ident, $rhs:ident, $output:ident) => {
|
||||||
impl<'b> Sub<&'b $rhs> for $lhs {
|
impl<'b> ::core::ops::Sub<&'b $rhs> for $lhs {
|
||||||
type Output = $output;
|
type Output = $output;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -40,7 +40,7 @@ macro_rules! impl_sub_binop_specify_output {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Sub<$rhs> for &'a $lhs {
|
impl<'a> ::core::ops::Sub<$rhs> for &'a $lhs {
|
||||||
type Output = $output;
|
type Output = $output;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -49,7 +49,7 @@ macro_rules! impl_sub_binop_specify_output {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sub<$rhs> for $lhs {
|
impl ::core::ops::Sub<$rhs> for $lhs {
|
||||||
type Output = $output;
|
type Output = $output;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -69,7 +69,7 @@ macro_rules! impl_binops_additive_specify_output {
|
||||||
|
|
||||||
macro_rules! impl_binops_multiplicative_mixed {
|
macro_rules! impl_binops_multiplicative_mixed {
|
||||||
($lhs:ident, $rhs:ident, $output:ident) => {
|
($lhs:ident, $rhs:ident, $output:ident) => {
|
||||||
impl<'b> Mul<&'b $rhs> for $lhs {
|
impl<'b> ::core::ops::Mul<&'b $rhs> for $lhs {
|
||||||
type Output = $output;
|
type Output = $output;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -78,7 +78,7 @@ macro_rules! impl_binops_multiplicative_mixed {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Mul<$rhs> for &'a $lhs {
|
impl<'a> ::core::ops::Mul<$rhs> for &'a $lhs {
|
||||||
type Output = $output;
|
type Output = $output;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -87,7 +87,7 @@ macro_rules! impl_binops_multiplicative_mixed {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mul<$rhs> for $lhs {
|
impl ::core::ops::Mul<$rhs> for $lhs {
|
||||||
type Output = $output;
|
type Output = $output;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -102,28 +102,28 @@ macro_rules! impl_binops_additive {
|
||||||
($lhs:ident, $rhs:ident) => {
|
($lhs:ident, $rhs:ident) => {
|
||||||
impl_binops_additive_specify_output!($lhs, $rhs, $lhs);
|
impl_binops_additive_specify_output!($lhs, $rhs, $lhs);
|
||||||
|
|
||||||
impl SubAssign<$rhs> for $lhs {
|
impl ::core::ops::SubAssign<$rhs> for $lhs {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn sub_assign(&mut self, rhs: $rhs) {
|
fn sub_assign(&mut self, rhs: $rhs) {
|
||||||
*self = &*self - &rhs;
|
*self = &*self - &rhs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddAssign<$rhs> for $lhs {
|
impl ::core::ops::AddAssign<$rhs> for $lhs {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add_assign(&mut self, rhs: $rhs) {
|
fn add_assign(&mut self, rhs: $rhs) {
|
||||||
*self = &*self + &rhs;
|
*self = &*self + &rhs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> SubAssign<&'b $rhs> for $lhs {
|
impl<'b> ::core::ops::SubAssign<&'b $rhs> for $lhs {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn sub_assign(&mut self, rhs: &'b $rhs) {
|
fn sub_assign(&mut self, rhs: &'b $rhs) {
|
||||||
*self = &*self - rhs;
|
*self = &*self - rhs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> AddAssign<&'b $rhs> for $lhs {
|
impl<'b> ::core::ops::AddAssign<&'b $rhs> for $lhs {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add_assign(&mut self, rhs: &'b $rhs) {
|
fn add_assign(&mut self, rhs: &'b $rhs) {
|
||||||
*self = &*self + rhs;
|
*self = &*self + rhs;
|
||||||
|
@ -136,14 +136,14 @@ macro_rules! impl_binops_multiplicative {
|
||||||
($lhs:ident, $rhs:ident) => {
|
($lhs:ident, $rhs:ident) => {
|
||||||
impl_binops_multiplicative_mixed!($lhs, $rhs, $lhs);
|
impl_binops_multiplicative_mixed!($lhs, $rhs, $lhs);
|
||||||
|
|
||||||
impl MulAssign<$rhs> for $lhs {
|
impl ::core::ops::MulAssign<$rhs> for $lhs {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul_assign(&mut self, rhs: $rhs) {
|
fn mul_assign(&mut self, rhs: $rhs) {
|
||||||
*self = &*self * &rhs;
|
*self = &*self * &rhs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> MulAssign<&'b $rhs> for $lhs {
|
impl<'b> ::core::ops::MulAssign<&'b $rhs> for $lhs {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul_assign(&mut self, rhs: &'b $rhs) {
|
fn mul_assign(&mut self, rhs: &'b $rhs) {
|
||||||
*self = &*self * rhs;
|
*self = &*self * rhs;
|
Loading…
Reference in New Issue