pub mod arkworks_instances;
mod bls12_381_arkworks;
mod ed25519_instance;
mod field_adapters;
pub mod secret_value;
pub use secret_value::{Secret, Value};
use crate::common::{Serial, Serialize};
use rand::*;
use std::{borrow::Borrow, fmt, fmt::Debug};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum CurveDecodingError {
#[error("Not a point on the curve.")]
NotOnCurve,
#[error("{0} is not a field element.")]
NotInField(String),
}
pub trait Field: Sized + Eq + Copy + Clone + Send + Sync + fmt::Debug {
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self;
fn zero() -> Self;
fn one() -> Self;
fn is_zero(&self) -> bool;
fn square(&mut self);
fn double(&mut self);
fn negate(&mut self);
fn add_assign(&mut self, other: &Self);
fn sub_assign(&mut self, other: &Self);
fn mul_assign(&mut self, other: &Self);
fn inverse(&self) -> Option<Self>;
fn pow<S: AsRef<[u64]>>(&self, exp: S) -> Self {
let mut res = Self::one();
for e in exp.as_ref().iter().rev() {
for i in (0..64).rev() {
res.square();
if ((*e >> i) & 1) == 1 {
res.mul_assign(self);
}
}
}
res
}
}
pub trait PrimeField: Field {
const NUM_BITS: u32;
const CAPACITY: u32;
fn into_repr(self) -> Vec<u64>;
fn from_repr(_: &[u64]) -> Result<Self, CurveDecodingError>;
}
pub trait Curve:
Serialize + Copy + Clone + Sized + Send + Sync + Debug + PartialEq + Eq + 'static
{
type Scalar: PrimeField + Serialize;
type MultiExpType: MultiExp<CurvePoint = Self>;
const SCALAR_LENGTH: usize;
const GROUP_ELEMENT_LENGTH: usize;
fn new_multiexp<X: Borrow<Self>>(gs: &[X]) -> Self::MultiExpType {
Self::MultiExpType::new(gs)
}
fn zero_point() -> Self;
fn one_point() -> Self;
fn is_zero_point(&self) -> bool;
#[must_use]
fn inverse_point(&self) -> Self;
#[must_use]
fn double_point(&self) -> Self;
#[must_use]
fn plus_point(&self, other: &Self) -> Self;
#[must_use]
fn minus_point(&self, other: &Self) -> Self;
#[must_use]
fn mul_by_scalar(&self, scalar: &Self::Scalar) -> Self;
fn generate<R: Rng>(rng: &mut R) -> Self;
fn generate_scalar<R: Rng>(rng: &mut R) -> Self::Scalar;
fn generate_non_zero_scalar<R: Rng>(rng: &mut R) -> Self::Scalar {
loop {
let s = Self::generate_scalar(rng);
if !s.is_zero() {
return s;
}
}
}
fn scalar_from_u64(n: u64) -> Self::Scalar;
fn scalar_from_bytes<A: AsRef<[u8]>>(bs: A) -> Self::Scalar;
fn hash_to_group(m: &[u8]) -> Result<Self, CurveDecodingError>;
}
pub trait MultiExp {
type CurvePoint: Curve;
fn new<X: Borrow<Self::CurvePoint>>(gs: &[X]) -> Self;
fn multiexp<X: Borrow<<Self::CurvePoint as Curve>::Scalar>>(
&self,
exps: &[X],
) -> Self::CurvePoint;
}
pub struct GenericMultiExp<C> {
table: Vec<Vec<C>>,
window_size: usize,
}
impl<C: Curve> GenericMultiExp<C> {
const DEFAULT_WINDOW_SIZE: usize = 4;
pub fn new<X: Borrow<C>>(gs: &[X], window_size: usize) -> Self {
let k = gs.len();
let mut table = Vec::with_capacity(k);
for g in gs.iter() {
let sq = g.borrow().plus_point(g.borrow());
let mut tmp = *g.borrow();
let num_exponents = 1 << (window_size - 1);
let mut exps = Vec::with_capacity(num_exponents);
exps.push(tmp);
for _ in 1..num_exponents {
tmp = tmp.plus_point(&sq);
exps.push(tmp);
}
table.push(exps);
}
Self { table, window_size }
}
}
impl<C: Curve> MultiExp for GenericMultiExp<C> {
type CurvePoint = C;
fn new<X: Borrow<C>>(gs: &[X]) -> Self {
Self::new(gs, Self::DEFAULT_WINDOW_SIZE)
}
fn multiexp<X: Borrow<<Self::CurvePoint as Curve>::Scalar>>(
&self,
exps: &[X],
) -> Self::CurvePoint {
let window_size_plus1 = self.window_size + 1;
let k = exps.len();
assert!(window_size_plus1 >= 2);
assert!(window_size_plus1 < 63);
let mut wnaf = Vec::with_capacity(k);
let width = 1u64 << window_size_plus1;
let window_mask = width - 1;
for c in exps.iter() {
let mut pos = 0;
let mut carry = 0;
let repr_limbs = c.borrow().into_repr();
let mut v = Vec::new();
let num_bits = repr_limbs.len() * 64;
while pos < num_bits {
let u64_idx = pos / 64;
let bit_idx = pos % 64;
let cur_u64 = repr_limbs[u64_idx];
let bit_buf = if bit_idx + window_size_plus1 < 64 {
cur_u64 >> bit_idx
} else {
let next_u64 = repr_limbs.get(u64_idx + 1).copied().unwrap_or(0);
(cur_u64 >> bit_idx) | (next_u64 << (64 - bit_idx))
};
let window_val = carry + (bit_buf & window_mask);
if window_val & 1 == 0 {
v.push(0);
pos += 1;
} else {
v.push(if window_val < width / 2 {
carry = 0;
window_val as i64
} else {
carry = 1;
(window_val as i64).wrapping_sub(width as i64)
});
v.extend(std::iter::repeat(0).take(window_size_plus1 - 1));
pos += window_size_plus1;
}
}
wnaf.push(v);
}
let mut a = C::zero_point();
for j in (0..=C::Scalar::NUM_BITS as usize).rev() {
a = a.double_point();
for (wnaf_i, table_i) in wnaf.iter().zip(self.table.iter()) {
match wnaf_i.get(j) {
Some(&ge) if ge > 0 => {
a = a.plus_point(&table_i[(ge / 2) as usize]);
}
Some(&ge) if ge < 0 => {
a = a.minus_point(&table_i[((-ge) / 2) as usize]);
}
_ => (),
}
}
}
a
}
}
pub trait Pairing: Sized + 'static + Clone {
type ScalarField: PrimeField + Serialize;
type G1: Curve<Scalar = Self::ScalarField>;
type G2: Curve<Scalar = Self::ScalarField>;
type G1Prepared;
type G2Prepared;
type TargetField: Field + Serial;
fn miller_loop<'a, I>(i: I) -> Self::TargetField
where
I: IntoIterator<Item = &'a (&'a Self::G1Prepared, &'a Self::G2Prepared)>;
fn check_pairing_eq(g1x: &Self::G1, g2x: &Self::G2, g1y: &Self::G1, g2y: &Self::G2) -> bool {
let pairs = [
(&Self::g1_prepare(g1x), &Self::g2_prepare(g2x)),
(
&Self::g1_prepare(&g1y.inverse_point()),
&Self::g2_prepare(g2y),
),
];
let res = Self::miller_loop(pairs.iter());
if let Some(mut y) = Self::final_exponentiation(&res) {
y.sub_assign(&Self::TargetField::one());
y.is_zero()
} else {
false
}
}
fn pairing_product(
g1x: &Self::G1,
g2x: &Self::G2,
g1y: &Self::G1,
g2y: &Self::G2,
) -> Option<Self::TargetField> {
let pairs = [
(&Self::g1_prepare(g1x), &Self::g2_prepare(g2x)),
(&Self::g1_prepare(g1y), &Self::g2_prepare(g2y)),
];
let res = Self::miller_loop(pairs.iter());
Self::final_exponentiation(&res)
}
fn final_exponentiation(_: &Self::TargetField) -> Option<Self::TargetField>;
fn g1_prepare(_: &Self::G1) -> Self::G1Prepared;
fn g2_prepare(_: &Self::G2) -> Self::G2Prepared;
fn pair(p: &Self::G1, q: &Self::G2) -> Self::TargetField {
let g1p = Self::g1_prepare(p);
let g2p = Self::g2_prepare(q);
let x = Self::miller_loop([(&g1p, &g2p)].iter());
if x.is_zero() {
panic!("Cannot perform final exponentiation on 0.")
} else {
Self::final_exponentiation(&x).unwrap()
}
}
fn generate_scalar<R: Rng>(rng: &mut R) -> Self::ScalarField;
fn generate_non_zero_scalar<R: Rng>(rng: &mut R) -> Self::ScalarField {
loop {
let s = Self::generate_scalar(rng);
if !s.is_zero() {
return s;
}
}
}
}
#[inline(always)]
pub fn multiexp<C, X>(gs: &[X], exps: &[C::Scalar]) -> C
where
C: Curve,
X: Borrow<C>,
{
C::new_multiexp(gs).multiexp(exps)
}
#[cfg(test)]
mod tests {
use super::{arkworks_instances::ArkGroup, *};
use ark_bls12_381::G1Projective;
type SomeCurve = ArkGroup<G1Projective>;
#[test]
pub fn test_multiscalar() {
let mut csprng = thread_rng();
for l in 1..100 {
let mut gs = Vec::with_capacity(l);
let mut es = Vec::with_capacity(l);
for _ in 0..l {
gs.push(SomeCurve::generate(&mut csprng));
es.push(SomeCurve::generate_scalar(&mut csprng));
}
let mut goal = SomeCurve::zero_point();
for (g, e) in gs.iter().zip(es.iter()) {
goal = goal.plus_point(&g.mul_by_scalar(e))
}
let g = multiexp(&gs, &es);
assert!(
goal.minus_point(&g).is_zero_point(),
"Multiexponentiation produces a different answer than the naive method."
)
}
}
}