franklin_crypto/generic_twisted_edwards/
edwards.rsuse bellman::pairing::bn256::Bn256;
use bellman::pairing::ff::BitIterator;
use bellman::{Engine, Field, PrimeField, PrimeFieldRepr, ScalarEngine, SqrtField};
use rand::{Rand, Rng};
use std::marker::PhantomData;
struct LookupTable<E: Engine>(Vec<TwistedEdwardsPoint<E>>);
impl<E: Engine> LookupTable<E> {
fn from_point<C: TwistedEdwardsCurveParams<E>>(p: &TwistedEdwardsPoint<E>, curve: &TwistedEdwardsCurveImplementor<E, C>) -> Self {
let mut table = vec![p.clone(); 8];
for i in 0..7 {
table[i + 1] = curve.add(&p, &table[i]);
}
Self(table)
}
fn select<C: TwistedEdwardsCurveParams<E>>(&self, x: i8, curve: &TwistedEdwardsCurveImplementor<E, C>) -> TwistedEdwardsPoint<E> {
if x == 0 {
return TwistedEdwardsPoint::identity();
}
let xmask = x >> 7;
let abs = (xmask + x) ^ xmask;
let mut p = TwistedEdwardsPoint::identity();
for i in 1..9 {
p = TwistedEdwardsPoint::conditional_select(
(i == abs) as u8, &self.0[(i - 1) as usize].clone(),
&p,
);
}
let x_is_neg = (xmask & 1) as u8;
let p_neg = curve.negate(&p);
let result = TwistedEdwardsPoint::conditional_select(x_is_neg, &p_neg, &p);
result
}
}
impl<E: Engine> PartialEq for TwistedEdwardsPoint<E> {
fn eq(&self, other: &TwistedEdwardsPoint<E>) -> bool {
let mut x1 = self.x;
x1.mul_assign(&other.z);
let mut y1 = self.y;
y1.mul_assign(&other.z);
let mut x2 = other.x;
x2.mul_assign(&self.z);
let mut y2 = other.y;
y2.mul_assign(&self.z);
x1 == x2 && y1 == y2
}
}
impl<E: Engine> Eq for TwistedEdwardsPoint<E> {}
impl<E: Engine, C: TwistedEdwardsCurveParams<E>> TwistedEdwardsCurveImplementor<E, C> {
pub fn add(&self, p: &TwistedEdwardsPoint<E>, q: &TwistedEdwardsPoint<E>) -> TwistedEdwardsPoint<E> {
let mut a = p.x;
a.mul_assign(&q.x);
let mut b = p.y;
b.mul_assign(&q.y);
let mut c = self.curve_params.param_d().clone();
c.mul_assign(&p.t);
c.mul_assign(&q.t);
let mut d = p.z;
d.mul_assign(&q.z);
let h = if self.curve_params.is_param_a_equals_minus_one() {
let mut h = b;
h.add_assign(&a);
h
} else {
let mut h = a.clone();
h.mul_assign(&self.curve_params.param_a());
h.negate();
h.add_assign(&b);
h
};
let mut e = p.x;
e.add_assign(&p.y);
{
let mut tmp = q.x;
tmp.add_assign(&q.y);
e.mul_assign(&tmp);
}
e.sub_assign(&a);
e.sub_assign(&b);
let mut f = d;
f.sub_assign(&c);
let mut g = d;
g.add_assign(&c);
let mut x3 = e;
x3.mul_assign(&f);
let mut y3 = g;
y3.mul_assign(&h);
let mut t3 = e;
t3.mul_assign(&h);
let mut z3 = f;
z3.mul_assign(&g);
TwistedEdwardsPoint { x: x3, y: y3, t: t3, z: z3 }
}
pub fn double(&self, p: &TwistedEdwardsPoint<E>) -> TwistedEdwardsPoint<E> {
let mut a = p.x;
a.square();
let mut b = p.y;
b.square();
let mut c = p.z;
c.square();
c.double();
let d = if self.curve_params.is_param_a_equals_minus_one() {
let mut d = a;
d.negate();
d
} else {
let mut d = a;
d.mul_assign(&self.curve_params.param_a());
d
};
let mut e = p.x;
e.add_assign(&p.y);
e.square();
e.sub_assign(&a);
e.sub_assign(&b);
let mut g = d;
g.add_assign(&b);
let mut f = g;
f.sub_assign(&c);
let mut h = d;
h.sub_assign(&b);
let mut x3 = e;
x3.mul_assign(&f);
let mut y3 = g;
y3.mul_assign(&h);
let mut t3 = e;
t3.mul_assign(&h);
let mut z3 = f;
z3.mul_assign(&g);
TwistedEdwardsPoint { x: x3, y: y3, t: t3, z: z3 }
}
pub fn mul<S: Into<<C::Fs as PrimeField>::Repr>>(&self, p: &TwistedEdwardsPoint<E>, scalar: S) -> TwistedEdwardsPoint<E> {
let mut res = TwistedEdwardsPoint::identity();
for b in BitIterator::new(scalar.into()) {
res = self.double(&res);
if b {
res = self.add(&p, &res);
}
}
res
}
pub fn mul_by_bits(&self, p: &TwistedEdwardsPoint<E>, scalar_bits: &[bool]) -> TwistedEdwardsPoint<E> {
let mut res = TwistedEdwardsPoint::identity();
for b in scalar_bits.iter() {
res = self.double(&res);
if *b {
res = self.add(&p, &res);
}
}
res
}
pub fn ct_mul(&self, p: &TwistedEdwardsPoint<E>, scalar: C::Fs) -> TwistedEdwardsPoint<E> {
let table = LookupTable::from_point(&p, self);
let scalar_in_base_16 = super::util::scalar_to_radix_16::<_, C>(&scalar);
let mut q = TwistedEdwardsPoint::identity();
for i in (0..scalar_in_base_16.len()).rev() {
let s_i = scalar_in_base_16[i];
let t = table.select(s_i, self);
for _i in 0..4 {
q = self.double(&q);
}
q = self.add(&q, &t)
}
q
}
pub fn negate(&self, p: &TwistedEdwardsPoint<E>) -> TwistedEdwardsPoint<E> {
let mut q = p.clone();
q.x.negate();
q.t.negate();
q
}
pub fn mul_by_generator<S: Into<<C::Fs as PrimeField>::Repr>>(&self, scalar: S) -> TwistedEdwardsPoint<E> {
self.mul(&self.curve_params.generator(), scalar)
}
pub fn is_in_main_subgroup(&self, p: &TwistedEdwardsPoint<E>) -> bool {
use crate::plonk::circuit::utils::words_to_msb_first_bits;
let mut tmp = p.clone();
let msb_bits = words_to_msb_first_bits(C::Fs::char().as_ref());
for b in msb_bits.into_iter().skip(1) {
tmp = self.double(&tmp);
if b {
tmp = self.add(&tmp, p);
}
}
tmp.eq(&TwistedEdwardsPoint::identity())
}
}
pub trait TwistedEdwardsCurveParams<E: Engine>: Clone {
type Fs: PrimeField;
fn is_param_a_equals_minus_one(&self) -> bool;
fn param_d(&self) -> E::Fr;
fn param_a(&self) -> E::Fr;
fn generator(&self) -> TwistedEdwardsPoint<E>;
fn log_2_cofactor(&self) -> usize;
}
pub struct TwistedEdwardsCurveImplementor<E: Engine, C: TwistedEdwardsCurveParams<E>> {
pub curve_params: C,
_marker: std::marker::PhantomData<E>,
}
impl<E: Engine, C: TwistedEdwardsCurveParams<E>> TwistedEdwardsCurveImplementor<E, C> {
pub fn new_from_params(params: C) -> Self {
Self {
curve_params: params,
_marker: std::marker::PhantomData,
}
}
pub fn get_params(&self) -> &C {
&self.curve_params
}
pub fn get_for_y(&self, y: E::Fr, sign: bool) -> Option<TwistedEdwardsPoint<E>> {
let one = <E as ScalarEngine>::Fr::one();
let mut tmp1 = y;
tmp1.square();
let mut tmp2 = tmp1;
tmp2.mul_assign(&self.curve_params.param_d());
tmp2.add_assign(&one);
tmp1.sub_assign(&one);
if !self.curve_params.is_param_a_equals_minus_one() {
tmp1.mul_assign(&self.curve_params.param_a());
tmp1.negate();
}
match tmp2.inverse() {
Some(tmp2) => {
tmp1.mul_assign(&tmp2);
match tmp1.sqrt() {
Some(mut x) => {
if x.into_repr().is_odd() != sign {
x.negate();
}
let mut t = x;
t.mul_assign(&y);
Some(TwistedEdwardsPoint { x: x, y: y, t: t, z: one })
}
None => None,
}
}
None => None,
}
}
pub fn rand<R: Rng>(&self, rng: &mut R) -> TwistedEdwardsPoint<E> {
loop {
let y = rng.gen();
if let Some(p) = self.get_for_y(y, rng.gen()) {
return p;
}
}
}
}
pub(crate) trait ConditionalSelect<T> {
fn conditional_select(flag: u8, first: T, second: T) -> T;
}
impl ConditionalSelect<u64> for u64 {
fn conditional_select(flag: u8, first: u64, second: u64) -> u64 {
let bit = flag as u64;
bit * first + (1 - bit) * second }
}
#[derive(Clone, Debug)]
pub struct TwistedEdwardsPoint<E: Engine> {
pub(crate) x: E::Fr,
pub(crate) y: E::Fr,
pub(crate) z: E::Fr,
pub(crate) t: E::Fr,
}
impl<E: Engine> Copy for TwistedEdwardsPoint<E> {}
impl<E: Engine> Default for TwistedEdwardsPoint<E> {
fn default() -> Self {
Self::identity()
}
}
impl<E: Engine> TwistedEdwardsPoint<E> {
pub fn from_xy(x: E::Fr, y: E::Fr) -> Self {
let mut t = x;
t.mul_assign(&y);
Self { x, y, z: E::Fr::one(), t }
}
pub fn into_xy(&self) -> (E::Fr, E::Fr) {
let zinv = self.z.inverse().unwrap();
let mut x = self.x;
x.mul_assign(&zinv);
let mut y = self.y;
y.mul_assign(&zinv);
(x, y)
}
pub fn identity() -> TwistedEdwardsPoint<E> {
let zero = E::Fr::zero();
let one = E::Fr::one();
TwistedEdwardsPoint { x: zero, y: one, t: zero, z: one }
}
pub fn conditional_select(flag: u8, first: &Self, second: &Self) -> Self {
fn conditional_select_fe<E: Engine>(flag: u8, first: &E::Fr, second: &E::Fr) -> E::Fr {
let first_repr = first.into_raw_repr();
let second_repr = second.into_raw_repr();
let mut result_repr = <E::Fr as PrimeField>::Repr::default();
result_repr.as_mut()[0] = u64::conditional_select(flag, first_repr.as_ref()[0], second_repr.as_ref()[0]);
result_repr.as_mut()[1] = u64::conditional_select(flag, first_repr.as_ref()[1], second_repr.as_ref()[1]);
result_repr.as_mut()[2] = u64::conditional_select(flag, first_repr.as_ref()[2], second_repr.as_ref()[2]);
result_repr.as_mut()[3] = u64::conditional_select(flag, first_repr.as_ref()[3], second_repr.as_ref()[3]);
let result = E::Fr::from_raw_repr(result_repr).unwrap();
result
}
let mut result = Self::identity();
result.x = conditional_select_fe::<E>(flag, &first.x, &second.x);
result.y = conditional_select_fe::<E>(flag, &first.y, &second.y);
result.t = conditional_select_fe::<E>(flag, &first.t, &second.t);
result.z = conditional_select_fe::<E>(flag, &first.z, &second.z);
result
}
}
#[derive(Clone, Debug)]
pub struct GenericTwistedEdwardsCurveParams<E: Engine> {
pub is_param_a_equals_minus_one: bool,
pub param_d: E::Fr,
pub param_a: E::Fr,
pub generator: TwistedEdwardsPoint<E>,
pub log_2_cofactor: usize,
}
impl<E: Engine> Copy for GenericTwistedEdwardsCurveParams<E> {}
impl<E: Engine> GenericTwistedEdwardsCurveParams<E> {
pub fn new(d: E::Fr, a: E::Fr, generator: TwistedEdwardsPoint<E>, log_2_cofactor: usize) -> Self {
let mut minus_one = E::Fr::one();
minus_one.negate();
let is_param_a_equals_minus_one = a == minus_one;
Self {
param_d: d,
param_a: a,
is_param_a_equals_minus_one,
generator,
log_2_cofactor,
}
}
}