commit
dab44bc35e
|
@ -12,7 +12,7 @@
|
||||||
//! [Groth16]: https://eprint.iacr.org/2016/260
|
//! [Groth16]: https://eprint.iacr.org/2016/260
|
||||||
|
|
||||||
use ff::PrimeField;
|
use ff::PrimeField;
|
||||||
use group::CurveProjective;
|
use group::cofactor::CofactorCurve;
|
||||||
|
|
||||||
use super::SynthesisError;
|
use super::SynthesisError;
|
||||||
|
|
||||||
|
@ -196,23 +196,23 @@ pub trait Group<Scalar: PrimeField>: Sized + Copy + Clone + Send + Sync {
|
||||||
fn group_sub_assign(&mut self, other: &Self);
|
fn group_sub_assign(&mut self, other: &Self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Point<G: CurveProjective>(pub G);
|
pub struct Point<G: CofactorCurve>(pub G);
|
||||||
|
|
||||||
impl<G: CurveProjective> PartialEq for Point<G> {
|
impl<G: CofactorCurve> PartialEq for Point<G> {
|
||||||
fn eq(&self, other: &Point<G>) -> bool {
|
fn eq(&self, other: &Point<G>) -> bool {
|
||||||
self.0 == other.0
|
self.0 == other.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: CurveProjective> Copy for Point<G> {}
|
impl<G: CofactorCurve> Copy for Point<G> {}
|
||||||
|
|
||||||
impl<G: CurveProjective> Clone for Point<G> {
|
impl<G: CofactorCurve> Clone for Point<G> {
|
||||||
fn clone(&self) -> Point<G> {
|
fn clone(&self) -> Point<G> {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: CurveProjective> Group<G::Scalar> for Point<G> {
|
impl<G: CofactorCurve> Group<G::Scalar> for Point<G> {
|
||||||
fn group_zero() -> Self {
|
fn group_zero() -> Self {
|
||||||
Point(G::identity())
|
Point(G::identity())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::ops::{AddAssign, MulAssign};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ff::{Field, PrimeField};
|
use ff::{Field, PrimeField};
|
||||||
use group::{CurveAffine, CurveProjective, Group, Wnaf};
|
use group::{cofactor::CofactorCurveAffine, Curve, Group, Wnaf, WnafGroup};
|
||||||
use pairing::Engine;
|
use pairing::Engine;
|
||||||
|
|
||||||
use super::{Parameters, VerifyingKey};
|
use super::{Parameters, VerifyingKey};
|
||||||
|
@ -22,6 +22,8 @@ pub fn generate_random_parameters<E, C, R>(
|
||||||
) -> Result<Parameters<E>, SynthesisError>
|
) -> Result<Parameters<E>, SynthesisError>
|
||||||
where
|
where
|
||||||
E: Engine,
|
E: Engine,
|
||||||
|
E::G1: WnafGroup,
|
||||||
|
E::G2: WnafGroup,
|
||||||
C: Circuit<E::Fr>,
|
C: Circuit<E::Fr>,
|
||||||
R: RngCore,
|
R: RngCore,
|
||||||
{
|
{
|
||||||
|
@ -165,6 +167,8 @@ pub fn generate_parameters<E, C>(
|
||||||
) -> Result<Parameters<E>, SynthesisError>
|
) -> Result<Parameters<E>, SynthesisError>
|
||||||
where
|
where
|
||||||
E: Engine,
|
E: Engine,
|
||||||
|
E::G1: WnafGroup,
|
||||||
|
E::G2: WnafGroup,
|
||||||
C: Circuit<E::Fr>,
|
C: Circuit<E::Fr>,
|
||||||
{
|
{
|
||||||
let mut assembly = KeypairAssembly {
|
let mut assembly = KeypairAssembly {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//!
|
//!
|
||||||
//! [Groth16]: https://eprint.iacr.org/2016/260
|
//! [Groth16]: https://eprint.iacr.org/2016/260
|
||||||
|
|
||||||
use group::CurveAffine;
|
use group::{cofactor::CofactorCurveAffine, GroupEncoding, UncompressedEncoding};
|
||||||
use pairing::{Engine, MultiMillerLoop};
|
use pairing::{Engine, MultiMillerLoop};
|
||||||
|
|
||||||
use crate::SynthesisError;
|
use crate::SynthesisError;
|
||||||
|
@ -38,19 +38,19 @@ impl<E: Engine> PartialEq for Proof<E> {
|
||||||
|
|
||||||
impl<E: Engine> Proof<E> {
|
impl<E: Engine> Proof<E> {
|
||||||
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
writer.write_all(self.a.to_compressed().as_ref())?;
|
writer.write_all(self.a.to_bytes().as_ref())?;
|
||||||
writer.write_all(self.b.to_compressed().as_ref())?;
|
writer.write_all(self.b.to_bytes().as_ref())?;
|
||||||
writer.write_all(self.c.to_compressed().as_ref())?;
|
writer.write_all(self.c.to_bytes().as_ref())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||||
let read_g1 = |reader: &mut R| -> io::Result<E::G1Affine> {
|
let read_g1 = |reader: &mut R| -> io::Result<E::G1Affine> {
|
||||||
let mut g1_repr = <E::G1Affine as CurveAffine>::Compressed::default();
|
let mut g1_repr = <E::G1Affine as GroupEncoding>::Repr::default();
|
||||||
reader.read_exact(g1_repr.as_mut())?;
|
reader.read_exact(g1_repr.as_mut())?;
|
||||||
|
|
||||||
let affine = E::G1Affine::from_compressed(&g1_repr);
|
let affine = E::G1Affine::from_bytes(&g1_repr);
|
||||||
let affine = if affine.is_some().into() {
|
let affine = if affine.is_some().into() {
|
||||||
Ok(affine.unwrap())
|
Ok(affine.unwrap())
|
||||||
} else {
|
} else {
|
||||||
|
@ -70,10 +70,10 @@ impl<E: Engine> Proof<E> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let read_g2 = |reader: &mut R| -> io::Result<E::G2Affine> {
|
let read_g2 = |reader: &mut R| -> io::Result<E::G2Affine> {
|
||||||
let mut g2_repr = <E::G2Affine as CurveAffine>::Compressed::default();
|
let mut g2_repr = <E::G2Affine as GroupEncoding>::Repr::default();
|
||||||
reader.read_exact(g2_repr.as_mut())?;
|
reader.read_exact(g2_repr.as_mut())?;
|
||||||
|
|
||||||
let affine = E::G2Affine::from_compressed(&g2_repr);
|
let affine = E::G2Affine::from_bytes(&g2_repr);
|
||||||
let affine = if affine.is_some().into() {
|
let affine = if affine.is_some().into() {
|
||||||
Ok(affine.unwrap())
|
Ok(affine.unwrap())
|
||||||
} else {
|
} else {
|
||||||
|
@ -158,7 +158,7 @@ impl<E: Engine> VerifyingKey<E> {
|
||||||
|
|
||||||
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||||
let read_g1 = |reader: &mut R| -> io::Result<E::G1Affine> {
|
let read_g1 = |reader: &mut R| -> io::Result<E::G1Affine> {
|
||||||
let mut g1_repr = <E::G1Affine as CurveAffine>::Uncompressed::default();
|
let mut g1_repr = <E::G1Affine as UncompressedEncoding>::Uncompressed::default();
|
||||||
reader.read_exact(g1_repr.as_mut())?;
|
reader.read_exact(g1_repr.as_mut())?;
|
||||||
|
|
||||||
let affine = E::G1Affine::from_uncompressed(&g1_repr);
|
let affine = E::G1Affine::from_uncompressed(&g1_repr);
|
||||||
|
@ -170,7 +170,7 @@ impl<E: Engine> VerifyingKey<E> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let read_g2 = |reader: &mut R| -> io::Result<E::G2Affine> {
|
let read_g2 = |reader: &mut R| -> io::Result<E::G2Affine> {
|
||||||
let mut g2_repr = <E::G2Affine as CurveAffine>::Uncompressed::default();
|
let mut g2_repr = <E::G2Affine as UncompressedEncoding>::Uncompressed::default();
|
||||||
reader.read_exact(g2_repr.as_mut())?;
|
reader.read_exact(g2_repr.as_mut())?;
|
||||||
|
|
||||||
let affine = E::G2Affine::from_uncompressed(&g2_repr);
|
let affine = E::G2Affine::from_uncompressed(&g2_repr);
|
||||||
|
@ -289,7 +289,7 @@ impl<E: Engine> Parameters<E> {
|
||||||
|
|
||||||
pub fn read<R: Read>(mut reader: R, checked: bool) -> io::Result<Self> {
|
pub fn read<R: Read>(mut reader: R, checked: bool) -> io::Result<Self> {
|
||||||
let read_g1 = |reader: &mut R| -> io::Result<E::G1Affine> {
|
let read_g1 = |reader: &mut R| -> io::Result<E::G1Affine> {
|
||||||
let mut repr = <E::G1Affine as CurveAffine>::Uncompressed::default();
|
let mut repr = <E::G1Affine as UncompressedEncoding>::Uncompressed::default();
|
||||||
reader.read_exact(repr.as_mut())?;
|
reader.read_exact(repr.as_mut())?;
|
||||||
|
|
||||||
let affine = if checked {
|
let affine = if checked {
|
||||||
|
@ -317,7 +317,7 @@ impl<E: Engine> Parameters<E> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let read_g2 = |reader: &mut R| -> io::Result<E::G2Affine> {
|
let read_g2 = |reader: &mut R| -> io::Result<E::G2Affine> {
|
||||||
let mut repr = <E::G2Affine as CurveAffine>::Uncompressed::default();
|
let mut repr = <E::G2Affine as UncompressedEncoding>::Uncompressed::default();
|
||||||
reader.read_exact(repr.as_mut())?;
|
reader.read_exact(repr.as_mut())?;
|
||||||
|
|
||||||
let affine = if checked {
|
let affine = if checked {
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::sync::Arc;
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
|
|
||||||
use ff::{Field, PrimeField};
|
use ff::{Field, PrimeField};
|
||||||
use group::{CurveAffine, CurveProjective};
|
use group::{cofactor::CofactorCurveAffine, Curve};
|
||||||
use pairing::Engine;
|
use pairing::Engine;
|
||||||
|
|
||||||
use super::{ParameterSource, Proof};
|
use super::{ParameterSource, Proof};
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
use ff::{Field, PrimeField};
|
use ff::{Field, PrimeField};
|
||||||
use group::{CurveAffine, CurveProjective, Group, PrimeGroup};
|
use group::{
|
||||||
|
cofactor::{CofactorCurve, CofactorCurveAffine, CofactorGroup},
|
||||||
|
prime::PrimeGroup,
|
||||||
|
Curve, Group, GroupEncoding, UncompressedEncoding, WnafGroup,
|
||||||
|
};
|
||||||
use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
|
use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
|
||||||
|
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
|
@ -367,7 +371,6 @@ impl MillerLoopResult for Fr {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Group for Fr {
|
impl Group for Fr {
|
||||||
type Subgroup = Fr;
|
|
||||||
type Scalar = Fr;
|
type Scalar = Fr;
|
||||||
|
|
||||||
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
|
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
|
||||||
|
@ -393,21 +396,27 @@ impl Group for Fr {
|
||||||
|
|
||||||
impl PrimeGroup for Fr {}
|
impl PrimeGroup for Fr {}
|
||||||
|
|
||||||
impl CurveProjective for Fr {
|
impl CofactorGroup for Fr {
|
||||||
type Affine = Fr;
|
type Subgroup = Fr;
|
||||||
|
|
||||||
fn batch_normalize(p: &[Self], q: &mut [Self::Affine]) {
|
fn mul_by_cofactor(&self) -> Self::Subgroup {
|
||||||
assert_eq!(p.len(), q.len());
|
*self
|
||||||
|
}
|
||||||
|
|
||||||
for (p, q) in p.iter().zip(q.iter_mut()) {
|
fn into_subgroup(self) -> CtOption<Self::Subgroup> {
|
||||||
*q = p.to_affine();
|
CtOption::new(self, Choice::from(1))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Curve for Fr {
|
||||||
|
type AffineRepr = Fr;
|
||||||
|
|
||||||
fn to_affine(&self) -> Fr {
|
fn to_affine(&self) -> Fr {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WnafGroup for Fr {
|
||||||
fn recommended_wnaf_for_scalar(_: &Self::Scalar) -> usize {
|
fn recommended_wnaf_for_scalar(_: &Self::Scalar) -> usize {
|
||||||
3
|
3
|
||||||
}
|
}
|
||||||
|
@ -417,6 +426,10 @@ impl CurveProjective for Fr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CofactorCurve for Fr {
|
||||||
|
type Affine = Fr;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default)]
|
#[derive(Copy, Clone, Default)]
|
||||||
pub struct FakePoint;
|
pub struct FakePoint;
|
||||||
|
|
||||||
|
@ -432,10 +445,8 @@ impl AsRef<[u8]> for FakePoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CurveAffine for Fr {
|
impl CofactorCurveAffine for Fr {
|
||||||
type Compressed = FakePoint;
|
type Curve = Fr;
|
||||||
type Uncompressed = FakePoint;
|
|
||||||
type Projective = Fr;
|
|
||||||
type Scalar = Fr;
|
type Scalar = Fr;
|
||||||
|
|
||||||
fn identity() -> Self {
|
fn identity() -> Self {
|
||||||
|
@ -450,21 +461,29 @@ impl CurveAffine for Fr {
|
||||||
Choice::from(if <Fr as Field>::is_zero(self) { 1 } else { 0 })
|
Choice::from(if <Fr as Field>::is_zero(self) { 1 } else { 0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_projective(&self) -> Self::Projective {
|
fn to_curve(&self) -> Self::Curve {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn from_compressed(_bytes: &Self::Compressed) -> CtOption<Self> {
|
impl GroupEncoding for Fr {
|
||||||
|
type Repr = FakePoint;
|
||||||
|
|
||||||
|
fn from_bytes(_bytes: &Self::Repr) -> CtOption<Self> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_compressed_unchecked(_bytes: &Self::Compressed) -> CtOption<Self> {
|
fn from_bytes_unchecked(_bytes: &Self::Repr) -> CtOption<Self> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_compressed(&self) -> Self::Compressed {
|
fn to_bytes(&self) -> Self::Repr {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UncompressedEncoding for Fr {
|
||||||
|
type Uncompressed = FakePoint;
|
||||||
|
|
||||||
fn from_uncompressed(_bytes: &Self::Uncompressed) -> CtOption<Self> {
|
fn from_uncompressed(_bytes: &Self::Uncompressed) -> CtOption<Self> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use group::{CurveAffine, CurveProjective};
|
use group::{cofactor::CofactorCurveAffine, Curve};
|
||||||
use pairing::{MillerLoopResult, MultiMillerLoop};
|
use pairing::{MillerLoopResult, MultiMillerLoop};
|
||||||
use std::ops::{AddAssign, Neg};
|
use std::ops::{AddAssign, Neg};
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ pub fn verify_proof<'a, E: MultiMillerLoop>(
|
||||||
return Err(SynthesisError::MalformedVerifyingKey);
|
return Err(SynthesisError::MalformedVerifyingKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut acc = pvk.ic[0].to_projective();
|
let mut acc = pvk.ic[0].to_curve();
|
||||||
|
|
||||||
for (i, b) in public_inputs.iter().zip(pvk.ic.iter().skip(1)) {
|
for (i, b) in public_inputs.iter().zip(pvk.ic.iter().skip(1)) {
|
||||||
AddAssign::<&E::G1>::add_assign(&mut acc, &(*b * i));
|
AddAssign::<&E::G1>::add_assign(&mut acc, &(*b * i));
|
||||||
|
|
|
@ -2,7 +2,7 @@ use super::multicore::Worker;
|
||||||
use bit_vec::{self, BitVec};
|
use bit_vec::{self, BitVec};
|
||||||
use ff::{Endianness, Field, PrimeField};
|
use ff::{Endianness, Field, PrimeField};
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use group::{CurveAffine, CurveProjective};
|
use group::cofactor::{CofactorCurve, CofactorCurveAffine};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::AddAssign;
|
use std::ops::AddAssign;
|
||||||
|
@ -11,33 +11,33 @@ use std::sync::Arc;
|
||||||
use super::SynthesisError;
|
use super::SynthesisError;
|
||||||
|
|
||||||
/// An object that builds a source of bases.
|
/// An object that builds a source of bases.
|
||||||
pub trait SourceBuilder<G: CurveAffine>: Send + Sync + 'static + Clone {
|
pub trait SourceBuilder<G: CofactorCurveAffine>: Send + Sync + 'static + Clone {
|
||||||
type Source: Source<G>;
|
type Source: Source<G>;
|
||||||
|
|
||||||
fn new(self) -> Self::Source;
|
fn new(self) -> Self::Source;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A source of bases, like an iterator.
|
/// A source of bases, like an iterator.
|
||||||
pub trait Source<G: CurveAffine> {
|
pub trait Source<G: CofactorCurveAffine> {
|
||||||
fn next(&mut self) -> Result<&G, SynthesisError>;
|
fn next(&mut self) -> Result<&G, SynthesisError>;
|
||||||
|
|
||||||
/// Skips `amt` elements from the source, avoiding deserialization.
|
/// Skips `amt` elements from the source, avoiding deserialization.
|
||||||
fn skip(&mut self, amt: usize) -> Result<(), SynthesisError>;
|
fn skip(&mut self, amt: usize) -> Result<(), SynthesisError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AddAssignFromSource: CurveProjective {
|
pub trait AddAssignFromSource: CofactorCurve {
|
||||||
/// Parses the element from the source. Fails if the point is at infinity.
|
/// Parses the element from the source. Fails if the point is at infinity.
|
||||||
fn add_assign_from_source<S: Source<<Self as CurveProjective>::Affine>>(
|
fn add_assign_from_source<S: Source<<Self as CofactorCurve>::Affine>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
source: &mut S,
|
source: &mut S,
|
||||||
) -> Result<(), SynthesisError> {
|
) -> Result<(), SynthesisError> {
|
||||||
AddAssign::<&<Self as CurveProjective>::Affine>::add_assign(self, source.next()?);
|
AddAssign::<&<Self as CofactorCurve>::Affine>::add_assign(self, source.next()?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<G> AddAssignFromSource for G where G: CurveProjective {}
|
impl<G> AddAssignFromSource for G where G: CofactorCurve {}
|
||||||
|
|
||||||
impl<G: CurveAffine> SourceBuilder<G> for (Arc<Vec<G>>, usize) {
|
impl<G: CofactorCurveAffine> SourceBuilder<G> for (Arc<Vec<G>>, usize) {
|
||||||
type Source = (Arc<Vec<G>>, usize);
|
type Source = (Arc<Vec<G>>, usize);
|
||||||
|
|
||||||
fn new(self) -> (Arc<Vec<G>>, usize) {
|
fn new(self) -> (Arc<Vec<G>>, usize) {
|
||||||
|
@ -45,7 +45,7 @@ impl<G: CurveAffine> SourceBuilder<G> for (Arc<Vec<G>>, usize) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: CurveAffine> Source<G> for (Arc<Vec<G>>, usize) {
|
impl<G: CofactorCurveAffine> Source<G> for (Arc<Vec<G>>, usize) {
|
||||||
fn next(&mut self) -> Result<&G, SynthesisError> {
|
fn next(&mut self) -> Result<&G, SynthesisError> {
|
||||||
if self.0.len() <= self.1 {
|
if self.0.len() <= self.1 {
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
|
@ -162,8 +162,8 @@ fn multiexp_inner<Q, D, G, S>(
|
||||||
where
|
where
|
||||||
for<'a> &'a Q: QueryDensity,
|
for<'a> &'a Q: QueryDensity,
|
||||||
D: Send + Sync + 'static + Clone + AsRef<Q>,
|
D: Send + Sync + 'static + Clone + AsRef<Q>,
|
||||||
G: CurveProjective,
|
G: CofactorCurve,
|
||||||
S: SourceBuilder<<G as CurveProjective>::Affine>,
|
S: SourceBuilder<<G as CofactorCurve>::Affine>,
|
||||||
{
|
{
|
||||||
// Perform this region of the multiexp
|
// Perform this region of the multiexp
|
||||||
let this = {
|
let this = {
|
||||||
|
@ -274,8 +274,8 @@ pub fn multiexp<Q, D, G, S>(
|
||||||
where
|
where
|
||||||
for<'a> &'a Q: QueryDensity,
|
for<'a> &'a Q: QueryDensity,
|
||||||
D: Send + Sync + 'static + Clone + AsRef<Q>,
|
D: Send + Sync + 'static + Clone + AsRef<Q>,
|
||||||
G: CurveProjective,
|
G: CofactorCurve,
|
||||||
S: SourceBuilder<<G as CurveProjective>::Affine>,
|
S: SourceBuilder<<G as CofactorCurve>::Affine>,
|
||||||
{
|
{
|
||||||
let c = if exponents.len() < 32 {
|
let c = if exponents.len() < 32 {
|
||||||
3u32
|
3u32
|
||||||
|
@ -296,8 +296,8 @@ where
|
||||||
#[cfg(feature = "pairing")]
|
#[cfg(feature = "pairing")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_with_bls12() {
|
fn test_with_bls12() {
|
||||||
fn naive_multiexp<G: CurveProjective>(
|
fn naive_multiexp<G: CofactorCurve>(
|
||||||
bases: Arc<Vec<<G as CurveProjective>::Affine>>,
|
bases: Arc<Vec<<G as CofactorCurve>::Affine>>,
|
||||||
exponents: Arc<Vec<G::Scalar>>,
|
exponents: Arc<Vec<G::Scalar>>,
|
||||||
) -> G {
|
) -> G {
|
||||||
assert_eq!(bases.len(), exponents.len());
|
assert_eq!(bases.len(), exponents.len());
|
||||||
|
@ -311,7 +311,7 @@ fn test_with_bls12() {
|
||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
|
|
||||||
use group::Group;
|
use group::{Curve, Group};
|
||||||
use pairing::{
|
use pairing::{
|
||||||
bls12_381::{Bls12, Fr},
|
bls12_381::{Bls12, Fr},
|
||||||
Engine,
|
Engine,
|
||||||
|
|
|
@ -213,6 +213,8 @@ pub trait PrimeField: Field + From<u64> {
|
||||||
fn root_of_unity() -> Self;
|
fn root_of_unity() -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Takes a little-endian representation of some value, and returns its bits in big-endian
|
||||||
|
/// order.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BitIterator<T, E: AsRef<[T]>> {
|
pub struct BitIterator<T, E: AsRef<[T]>> {
|
||||||
t: E,
|
t: E,
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
use core::fmt;
|
||||||
|
use core::ops::{Mul, Neg};
|
||||||
|
use ff::{BitIterator, Endianness, PrimeField};
|
||||||
|
use subtle::{Choice, CtOption};
|
||||||
|
|
||||||
|
use crate::{prime::PrimeGroup, Curve, Group, GroupEncoding, GroupOps, GroupOpsOwned};
|
||||||
|
|
||||||
|
/// This trait represents an element of a cryptographic group with a large prime-order
|
||||||
|
/// subgroup and a comparatively-small cofactor.
|
||||||
|
pub trait CofactorGroup:
|
||||||
|
Group
|
||||||
|
+ GroupEncoding
|
||||||
|
+ GroupOps<<Self as CofactorGroup>::Subgroup>
|
||||||
|
+ GroupOpsOwned<<Self as CofactorGroup>::Subgroup>
|
||||||
|
{
|
||||||
|
/// The large prime-order subgroup in which cryptographic operations are performed.
|
||||||
|
/// If `Self` implements `PrimeGroup`, then `Self::Subgroup` may be `Self`.
|
||||||
|
type Subgroup: PrimeGroup<Scalar = Self::Scalar> + Into<Self>;
|
||||||
|
|
||||||
|
/// Returns `[h] self`, where `h` is the cofactor of the group.
|
||||||
|
///
|
||||||
|
/// If `Self` implements [`PrimeGroup`], this returns `self`.
|
||||||
|
fn mul_by_cofactor(&self) -> Self::Subgroup;
|
||||||
|
|
||||||
|
/// Returns `self` if it is contained in the prime-order subgroup.
|
||||||
|
///
|
||||||
|
/// If `Self` implements [`PrimeGroup`], this returns `Some(self)`.
|
||||||
|
fn into_subgroup(self) -> CtOption<Self::Subgroup>;
|
||||||
|
|
||||||
|
/// Determines if this element is of small order.
|
||||||
|
///
|
||||||
|
/// Returns:
|
||||||
|
/// - `true` if `self` is in the torsion subgroup.
|
||||||
|
/// - `false` if `self` is not in the torsion subgroup.
|
||||||
|
fn is_small_order(&self) -> Choice {
|
||||||
|
self.mul_by_cofactor().is_identity()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if this element is "torsion free", i.e., is contained in the
|
||||||
|
/// prime-order subgroup.
|
||||||
|
///
|
||||||
|
/// Returns:
|
||||||
|
/// - `true` if `self` has zero torsion component and is in the prime-order subgroup.
|
||||||
|
/// - `false` if `self` has non-zero torsion component and is not in the prime-order
|
||||||
|
/// subgroup.
|
||||||
|
fn is_torsion_free(&self) -> Choice {
|
||||||
|
// Obtain the scalar field characteristic in little endian.
|
||||||
|
let mut char = Self::Scalar::char();
|
||||||
|
<Self::Scalar as PrimeField>::ReprEndianness::toggle_little_endian(&mut char);
|
||||||
|
|
||||||
|
// Multiply self by the characteristic to eliminate any prime-order subgroup
|
||||||
|
// component.
|
||||||
|
let bits = BitIterator::<u8, _>::new(char);
|
||||||
|
let mut res = Self::identity();
|
||||||
|
for i in bits {
|
||||||
|
res = res.double();
|
||||||
|
if i {
|
||||||
|
res.add_assign(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the result is the identity, there was zero torsion component!
|
||||||
|
res.is_identity()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Efficient representation of an elliptic curve point guaranteed to be
|
||||||
|
/// in the correct prime order subgroup.
|
||||||
|
pub trait CofactorCurve:
|
||||||
|
Curve<AffineRepr = <Self as CofactorCurve>::Affine> + CofactorGroup
|
||||||
|
{
|
||||||
|
type Affine: CofactorCurveAffine<Curve = Self, Scalar = Self::Scalar>
|
||||||
|
+ Mul<Self::Scalar, Output = Self>
|
||||||
|
+ for<'r> Mul<Self::Scalar, Output = Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Affine representation of an elliptic curve point guaranteed to be
|
||||||
|
/// in the correct prime order subgroup.
|
||||||
|
pub trait CofactorCurveAffine:
|
||||||
|
GroupEncoding
|
||||||
|
+ Copy
|
||||||
|
+ Clone
|
||||||
|
+ Sized
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ fmt::Debug
|
||||||
|
+ fmt::Display
|
||||||
|
+ PartialEq
|
||||||
|
+ Eq
|
||||||
|
+ 'static
|
||||||
|
+ Neg<Output = Self>
|
||||||
|
+ Mul<<Self as CofactorCurveAffine>::Scalar, Output = <Self as CofactorCurveAffine>::Curve>
|
||||||
|
+ for<'r> Mul<
|
||||||
|
<Self as CofactorCurveAffine>::Scalar,
|
||||||
|
Output = <Self as CofactorCurveAffine>::Curve,
|
||||||
|
>
|
||||||
|
{
|
||||||
|
type Scalar: PrimeField;
|
||||||
|
type Curve: CofactorCurve<Affine = Self, Scalar = Self::Scalar>;
|
||||||
|
|
||||||
|
/// Returns the additive identity.
|
||||||
|
fn identity() -> Self;
|
||||||
|
|
||||||
|
/// Returns a fixed generator of unknown exponent.
|
||||||
|
fn generator() -> Self;
|
||||||
|
|
||||||
|
/// Determines if this point represents the point at infinity; the
|
||||||
|
/// additive identity.
|
||||||
|
fn is_identity(&self) -> Choice;
|
||||||
|
|
||||||
|
/// Converts this element to its curve representation.
|
||||||
|
fn to_curve(&self) -> Self::Curve;
|
||||||
|
}
|
112
group/src/lib.rs
112
group/src/lib.rs
|
@ -8,10 +8,12 @@ use std::iter::Sum;
|
||||||
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||||
use subtle::{Choice, CtOption};
|
use subtle::{Choice, CtOption};
|
||||||
|
|
||||||
|
pub mod cofactor;
|
||||||
|
pub mod prime;
|
||||||
pub mod tests;
|
pub mod tests;
|
||||||
|
|
||||||
mod wnaf;
|
mod wnaf;
|
||||||
pub use self::wnaf::Wnaf;
|
pub use self::wnaf::{Wnaf, WnafGroup};
|
||||||
|
|
||||||
/// A helper trait for types with a group operation.
|
/// A helper trait for types with a group operation.
|
||||||
pub trait GroupOps<Rhs = Self, Output = Self>:
|
pub trait GroupOps<Rhs = Self, Output = Self>:
|
||||||
|
@ -54,16 +56,10 @@ pub trait Group:
|
||||||
+ Neg<Output = Self>
|
+ Neg<Output = Self>
|
||||||
+ GroupOps
|
+ GroupOps
|
||||||
+ GroupOpsOwned
|
+ GroupOpsOwned
|
||||||
+ GroupOps<<Self as Group>::Subgroup>
|
|
||||||
+ GroupOpsOwned<<Self as Group>::Subgroup>
|
|
||||||
+ ScalarMul<<Self as Group>::Scalar>
|
+ ScalarMul<<Self as Group>::Scalar>
|
||||||
+ ScalarMulOwned<<Self as Group>::Scalar>
|
+ ScalarMulOwned<<Self as Group>::Scalar>
|
||||||
{
|
{
|
||||||
/// The large prime-order subgroup in which cryptographic operations are performed.
|
/// Scalars modulo the order of this group's scalar field.
|
||||||
/// If `Self` implements `PrimeGroup`, then `Self::Subgroup` may be `Self`.
|
|
||||||
type Subgroup: PrimeGroup;
|
|
||||||
|
|
||||||
/// Scalars modulo the order of [`Group::Subgroup`].
|
|
||||||
type Scalar: PrimeField;
|
type Scalar: PrimeField;
|
||||||
|
|
||||||
/// Returns an element chosen uniformly at random using a user-provided RNG.
|
/// Returns an element chosen uniformly at random using a user-provided RNG.
|
||||||
|
@ -73,7 +69,7 @@ pub trait Group:
|
||||||
fn identity() -> Self;
|
fn identity() -> Self;
|
||||||
|
|
||||||
/// Returns a fixed generator of the prime-order subgroup.
|
/// Returns a fixed generator of the prime-order subgroup.
|
||||||
fn generator() -> Self::Subgroup;
|
fn generator() -> Self;
|
||||||
|
|
||||||
/// Determines if this point is the identity.
|
/// Determines if this point is the identity.
|
||||||
fn is_identity(&self) -> Choice;
|
fn is_identity(&self) -> Choice;
|
||||||
|
@ -83,85 +79,51 @@ pub trait Group:
|
||||||
fn double(&self) -> Self;
|
fn double(&self) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This trait represents an element of a prime-order cryptographic group.
|
/// Efficient representation of an elliptic curve point guaranteed.
|
||||||
pub trait PrimeGroup: Group {}
|
pub trait Curve:
|
||||||
|
Group + GroupOps<<Self as Curve>::AffineRepr> + GroupOpsOwned<<Self as Curve>::AffineRepr>
|
||||||
/// Projective representation of an elliptic curve point guaranteed to be
|
|
||||||
/// in the correct prime order subgroup.
|
|
||||||
pub trait CurveProjective:
|
|
||||||
Group
|
|
||||||
+ GroupOps<<Self as CurveProjective>::Affine>
|
|
||||||
+ GroupOpsOwned<<Self as CurveProjective>::Affine>
|
|
||||||
{
|
{
|
||||||
type Affine: CurveAffine<Projective = Self, Scalar = Self::Scalar>
|
/// The affine representation for this elliptic curve.
|
||||||
+ Mul<Self::Scalar, Output = Self>
|
type AffineRepr;
|
||||||
+ for<'r> Mul<Self::Scalar, Output = Self>;
|
|
||||||
|
|
||||||
/// Converts a batch of projective elements into affine elements. This function will
|
/// Converts a batch of projective elements into affine elements. This function will
|
||||||
/// panic if `p.len() != q.len()`.
|
/// panic if `p.len() != q.len()`.
|
||||||
fn batch_normalize(p: &[Self], q: &mut [Self::Affine]);
|
fn batch_normalize(p: &[Self], q: &mut [Self::AffineRepr]) {
|
||||||
|
assert_eq!(p.len(), q.len());
|
||||||
|
|
||||||
|
for (p, q) in p.iter().zip(q.iter_mut()) {
|
||||||
|
*q = p.to_affine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts this element into its affine representation.
|
/// Converts this element into its affine representation.
|
||||||
fn to_affine(&self) -> Self::Affine;
|
fn to_affine(&self) -> Self::AffineRepr;
|
||||||
|
|
||||||
/// Recommends a wNAF window table size given a scalar. Always returns a number
|
|
||||||
/// between 2 and 22, inclusive.
|
|
||||||
fn recommended_wnaf_for_scalar(scalar: &Self::Scalar) -> usize;
|
|
||||||
|
|
||||||
/// Recommends a wNAF window size given the number of scalars you intend to multiply
|
|
||||||
/// a base by. Always returns a number between 2 and 22, inclusive.
|
|
||||||
fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Affine representation of an elliptic curve point guaranteed to be
|
pub trait GroupEncoding: Sized {
|
||||||
/// in the correct prime order subgroup.
|
/// The encoding of group elements.
|
||||||
pub trait CurveAffine:
|
type Repr: Default + AsRef<[u8]> + AsMut<[u8]>;
|
||||||
Copy
|
|
||||||
+ Clone
|
|
||||||
+ Sized
|
|
||||||
+ Send
|
|
||||||
+ Sync
|
|
||||||
+ fmt::Debug
|
|
||||||
+ fmt::Display
|
|
||||||
+ PartialEq
|
|
||||||
+ Eq
|
|
||||||
+ 'static
|
|
||||||
+ Neg<Output = Self>
|
|
||||||
+ Mul<<Self as CurveAffine>::Scalar, Output = <Self as CurveAffine>::Projective>
|
|
||||||
+ for<'r> Mul<<Self as CurveAffine>::Scalar, Output = <Self as CurveAffine>::Projective>
|
|
||||||
{
|
|
||||||
type Scalar: PrimeField;
|
|
||||||
type Projective: CurveProjective<Affine = Self, Scalar = Self::Scalar>;
|
|
||||||
type Uncompressed: Default + AsRef<[u8]> + AsMut<[u8]>;
|
|
||||||
type Compressed: Default + AsRef<[u8]> + AsMut<[u8]>;
|
|
||||||
|
|
||||||
/// Returns the additive identity.
|
/// Attempts to deserialize a group element from its encoding.
|
||||||
fn identity() -> Self;
|
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self>;
|
||||||
|
|
||||||
/// Returns a fixed generator of unknown exponent.
|
/// Attempts to deserialize a group element, not checking if the element is valid.
|
||||||
fn generator() -> Self;
|
|
||||||
|
|
||||||
/// Determines if this point represents the point at infinity; the
|
|
||||||
/// additive identity.
|
|
||||||
fn is_identity(&self) -> Choice;
|
|
||||||
|
|
||||||
/// Converts this element into its affine representation.
|
|
||||||
fn to_projective(&self) -> Self::Projective;
|
|
||||||
|
|
||||||
/// Attempts to deserialize an element from its compressed encoding.
|
|
||||||
fn from_compressed(bytes: &Self::Compressed) -> CtOption<Self>;
|
|
||||||
|
|
||||||
/// Attempts to deserialize a compressed element, not checking if the element is in
|
|
||||||
/// the correct subgroup.
|
|
||||||
///
|
///
|
||||||
/// **This is dangerous to call unless you trust the bytes you are reading; otherwise,
|
/// **This is dangerous to call unless you trust the bytes you are reading; otherwise,
|
||||||
/// API invariants may be broken.** Please consider using
|
/// API invariants may be broken.** Please consider using
|
||||||
/// [`CurveAffine::from_compressed`] instead.
|
/// [`GroupEncoding::from_bytes`] instead.
|
||||||
fn from_compressed_unchecked(bytes: &Self::Compressed) -> CtOption<Self>;
|
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self>;
|
||||||
|
|
||||||
/// Converts this element into its compressed encoding, so long as it's not
|
/// Converts this element into its byte encoding. This may or may not support
|
||||||
/// the point at infinity.
|
/// encoding the identity.
|
||||||
fn to_compressed(&self) -> Self::Compressed;
|
// TODO: Figure out how to handle identity encoding generically.
|
||||||
|
fn to_bytes(&self) -> Self::Repr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Affine representation of a point on an elliptic curve that has a defined uncompressed
|
||||||
|
/// encoding.
|
||||||
|
pub trait UncompressedEncoding: Sized {
|
||||||
|
type Uncompressed: Default + AsRef<[u8]> + AsMut<[u8]>;
|
||||||
|
|
||||||
/// Attempts to deserialize an element from its uncompressed encoding.
|
/// Attempts to deserialize an element from its uncompressed encoding.
|
||||||
fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption<Self>;
|
fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption<Self>;
|
||||||
|
@ -171,7 +133,7 @@ pub trait CurveAffine:
|
||||||
///
|
///
|
||||||
/// **This is dangerous to call unless you trust the bytes you are reading; otherwise,
|
/// **This is dangerous to call unless you trust the bytes you are reading; otherwise,
|
||||||
/// API invariants may be broken.** Please consider using
|
/// API invariants may be broken.** Please consider using
|
||||||
/// [`CurveAffine::from_uncompressed`] instead.
|
/// [`UncompressedEncoding::from_uncompressed`] instead.
|
||||||
fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption<Self>;
|
fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption<Self>;
|
||||||
|
|
||||||
/// Converts this element into its uncompressed encoding, so long as it's not
|
/// Converts this element into its uncompressed encoding, so long as it's not
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
use core::fmt;
|
||||||
|
use core::ops::{Mul, Neg};
|
||||||
|
use ff::PrimeField;
|
||||||
|
use subtle::Choice;
|
||||||
|
|
||||||
|
use crate::{Curve, Group, GroupEncoding};
|
||||||
|
|
||||||
|
/// This trait represents an element of a prime-order cryptographic group.
|
||||||
|
pub trait PrimeGroup: Group + GroupEncoding {}
|
||||||
|
|
||||||
|
/// Efficient representation of an elliptic curve point guaranteed to be
|
||||||
|
/// in the correct prime order subgroup.
|
||||||
|
pub trait PrimeCurve: Curve<AffineRepr = <Self as PrimeCurve>::Affine> + PrimeGroup {
|
||||||
|
type Affine: PrimeCurveAffine<Curve = Self, Scalar = Self::Scalar>
|
||||||
|
+ Mul<Self::Scalar, Output = Self>
|
||||||
|
+ for<'r> Mul<Self::Scalar, Output = Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Affine representation of an elliptic curve point guaranteed to be
|
||||||
|
/// in the correct prime order subgroup.
|
||||||
|
pub trait PrimeCurveAffine:
|
||||||
|
GroupEncoding
|
||||||
|
+ Copy
|
||||||
|
+ Clone
|
||||||
|
+ Sized
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ fmt::Debug
|
||||||
|
+ fmt::Display
|
||||||
|
+ PartialEq
|
||||||
|
+ Eq
|
||||||
|
+ 'static
|
||||||
|
+ Neg<Output = Self>
|
||||||
|
+ Mul<<Self as PrimeCurveAffine>::Scalar, Output = <Self as PrimeCurveAffine>::Curve>
|
||||||
|
+ for<'r> Mul<<Self as PrimeCurveAffine>::Scalar, Output = <Self as PrimeCurveAffine>::Curve>
|
||||||
|
{
|
||||||
|
type Scalar: PrimeField;
|
||||||
|
type Curve: PrimeCurve<Affine = Self, Scalar = Self::Scalar>;
|
||||||
|
|
||||||
|
/// Returns the additive identity.
|
||||||
|
fn identity() -> Self;
|
||||||
|
|
||||||
|
/// Returns a fixed generator of unknown exponent.
|
||||||
|
fn generator() -> Self;
|
||||||
|
|
||||||
|
/// Determines if this point represents the point at infinity; the
|
||||||
|
/// additive identity.
|
||||||
|
fn is_identity(&self) -> Choice;
|
||||||
|
|
||||||
|
/// Converts this element to its curve representation.
|
||||||
|
fn to_curve(&self) -> Self::Curve;
|
||||||
|
}
|
|
@ -3,9 +3,13 @@ use rand::SeedableRng;
|
||||||
use rand_xorshift::XorShiftRng;
|
use rand_xorshift::XorShiftRng;
|
||||||
use std::ops::{Mul, Neg};
|
use std::ops::{Mul, Neg};
|
||||||
|
|
||||||
use crate::{CurveAffine, CurveProjective};
|
use crate::{
|
||||||
|
cofactor::{CofactorCurve, CofactorCurveAffine},
|
||||||
|
wnaf::WnafGroup,
|
||||||
|
GroupEncoding, UncompressedEncoding,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn curve_tests<G: CurveProjective>() {
|
pub fn curve_tests<G: CofactorCurve>() {
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||||
0xe5,
|
0xe5,
|
||||||
|
@ -50,8 +54,8 @@ pub fn curve_tests<G: CurveProjective>() {
|
||||||
// Transformations
|
// Transformations
|
||||||
{
|
{
|
||||||
let a = G::random(&mut rng);
|
let a = G::random(&mut rng);
|
||||||
let b = a.to_affine().to_projective();
|
let b = a.to_affine().to_curve();
|
||||||
let c = a.to_affine().to_projective().to_affine().to_projective();
|
let c = a.to_affine().to_curve().to_affine().to_curve();
|
||||||
assert_eq!(a, b);
|
assert_eq!(a, b);
|
||||||
assert_eq!(b, c);
|
assert_eq!(b, c);
|
||||||
}
|
}
|
||||||
|
@ -61,11 +65,10 @@ pub fn curve_tests<G: CurveProjective>() {
|
||||||
random_doubling_tests::<G>();
|
random_doubling_tests::<G>();
|
||||||
random_negation_tests::<G>();
|
random_negation_tests::<G>();
|
||||||
random_transformation_tests::<G>();
|
random_transformation_tests::<G>();
|
||||||
random_wnaf_tests::<G>();
|
random_compressed_encoding_tests::<G>();
|
||||||
random_encoding_tests::<G>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_wnaf_tests<G: CurveProjective>() {
|
pub fn random_wnaf_tests<G: WnafGroup>() {
|
||||||
use crate::wnaf::*;
|
use crate::wnaf::*;
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
|
@ -184,7 +187,7 @@ fn random_wnaf_tests<G: CurveProjective>() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_negation_tests<G: CurveProjective>() {
|
fn random_negation_tests<G: CofactorCurve>() {
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||||
0xe5,
|
0xe5,
|
||||||
|
@ -214,7 +217,7 @@ fn random_negation_tests<G: CurveProjective>() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_doubling_tests<G: CurveProjective>() {
|
fn random_doubling_tests<G: CofactorCurve>() {
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||||
0xe5,
|
0xe5,
|
||||||
|
@ -242,7 +245,7 @@ fn random_doubling_tests<G: CurveProjective>() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_multiplication_tests<G: CurveProjective>() {
|
fn random_multiplication_tests<G: CofactorCurve>() {
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||||
0xe5,
|
0xe5,
|
||||||
|
@ -277,7 +280,7 @@ fn random_multiplication_tests<G: CurveProjective>() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_addition_tests<G: CurveProjective>() {
|
fn random_addition_tests<G: CofactorCurve>() {
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||||
0xe5,
|
0xe5,
|
||||||
|
@ -325,17 +328,17 @@ fn random_addition_tests<G: CurveProjective>() {
|
||||||
// Mixed addition
|
// Mixed addition
|
||||||
|
|
||||||
// (a + b) + c
|
// (a + b) + c
|
||||||
tmp[3] = a_affine.to_projective();
|
tmp[3] = a_affine.to_curve();
|
||||||
tmp[3].add_assign(&b_affine);
|
tmp[3].add_assign(&b_affine);
|
||||||
tmp[3].add_assign(&c_affine);
|
tmp[3].add_assign(&c_affine);
|
||||||
|
|
||||||
// a + (b + c)
|
// a + (b + c)
|
||||||
tmp[4] = b_affine.to_projective();
|
tmp[4] = b_affine.to_curve();
|
||||||
tmp[4].add_assign(&c_affine);
|
tmp[4].add_assign(&c_affine);
|
||||||
tmp[4].add_assign(&a_affine);
|
tmp[4].add_assign(&a_affine);
|
||||||
|
|
||||||
// (a + c) + b
|
// (a + c) + b
|
||||||
tmp[5] = a_affine.to_projective();
|
tmp[5] = a_affine.to_curve();
|
||||||
tmp[5].add_assign(&c_affine);
|
tmp[5].add_assign(&c_affine);
|
||||||
tmp[5].add_assign(&b_affine);
|
tmp[5].add_assign(&b_affine);
|
||||||
|
|
||||||
|
@ -357,7 +360,7 @@ fn random_addition_tests<G: CurveProjective>() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_transformation_tests<G: CurveProjective>() {
|
fn random_transformation_tests<G: CofactorCurve>() {
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||||
0xe5,
|
0xe5,
|
||||||
|
@ -366,7 +369,7 @@ fn random_transformation_tests<G: CurveProjective>() {
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
let g = G::random(&mut rng);
|
let g = G::random(&mut rng);
|
||||||
let g_affine = g.to_affine();
|
let g_affine = g.to_affine();
|
||||||
let g_projective = g_affine.to_projective();
|
let g_projective = g_affine.to_curve();
|
||||||
assert_eq!(g, g_projective);
|
assert_eq!(g, g_projective);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,7 +385,7 @@ fn random_transformation_tests<G: CurveProjective>() {
|
||||||
}
|
}
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
let s = between.sample(&mut rng);
|
let s = between.sample(&mut rng);
|
||||||
v[s] = v[s].to_affine().to_projective();
|
v[s] = v[s].to_affine().to_curve();
|
||||||
}
|
}
|
||||||
|
|
||||||
let expected_v = v.iter().map(|v| v.to_affine()).collect::<Vec<_>>();
|
let expected_v = v.iter().map(|v| v.to_affine()).collect::<Vec<_>>();
|
||||||
|
@ -394,7 +397,36 @@ fn random_transformation_tests<G: CurveProjective>() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_encoding_tests<G: CurveProjective>() {
|
fn random_compressed_encoding_tests<G: CofactorCurve>() {
|
||||||
|
let mut rng = XorShiftRng::from_seed([
|
||||||
|
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||||
|
0xe5,
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
G::Affine::from_bytes(&G::Affine::identity().to_bytes()).unwrap(),
|
||||||
|
G::Affine::identity()
|
||||||
|
);
|
||||||
|
|
||||||
|
for _ in 0..1000 {
|
||||||
|
let mut r = G::random(&mut rng).to_affine();
|
||||||
|
|
||||||
|
let compressed = r.to_bytes();
|
||||||
|
let de_compressed = G::Affine::from_bytes(&compressed).unwrap();
|
||||||
|
assert_eq!(de_compressed, r);
|
||||||
|
|
||||||
|
r = r.neg();
|
||||||
|
|
||||||
|
let compressed = r.to_bytes();
|
||||||
|
let de_compressed = G::Affine::from_bytes(&compressed).unwrap();
|
||||||
|
assert_eq!(de_compressed, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn random_uncompressed_encoding_tests<G: CofactorCurve>()
|
||||||
|
where
|
||||||
|
<G as CofactorCurve>::Affine: UncompressedEncoding,
|
||||||
|
{
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||||
0xe5,
|
0xe5,
|
||||||
|
@ -405,26 +437,11 @@ fn random_encoding_tests<G: CurveProjective>() {
|
||||||
G::Affine::identity()
|
G::Affine::identity()
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
G::Affine::from_compressed(&G::Affine::identity().to_compressed()).unwrap(),
|
|
||||||
G::Affine::identity()
|
|
||||||
);
|
|
||||||
|
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
let mut r = G::random(&mut rng).to_affine();
|
let r = G::random(&mut rng).to_affine();
|
||||||
|
|
||||||
let uncompressed = r.to_uncompressed();
|
let uncompressed = r.to_uncompressed();
|
||||||
let de_uncompressed = G::Affine::from_uncompressed(&uncompressed).unwrap();
|
let de_uncompressed = G::Affine::from_uncompressed(&uncompressed).unwrap();
|
||||||
assert_eq!(de_uncompressed, r);
|
assert_eq!(de_uncompressed, r);
|
||||||
|
|
||||||
let compressed = r.to_compressed();
|
|
||||||
let de_compressed = G::Affine::from_compressed(&compressed).unwrap();
|
|
||||||
assert_eq!(de_compressed, r);
|
|
||||||
|
|
||||||
r = r.neg();
|
|
||||||
|
|
||||||
let compressed = r.to_compressed();
|
|
||||||
let de_compressed = G::Affine::from_compressed(&compressed).unwrap();
|
|
||||||
assert_eq!(de_compressed, r);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,21 @@ use byteorder::{ByteOrder, LittleEndian};
|
||||||
use ff::PrimeField;
|
use ff::PrimeField;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use super::{CurveProjective, Group};
|
use super::Group;
|
||||||
|
|
||||||
|
/// Extension trait on a [`Group`] that provides helpers used by [`Wnaf`].
|
||||||
|
pub trait WnafGroup: Group {
|
||||||
|
/// Recommends a wNAF window table size given a scalar. Always returns a number
|
||||||
|
/// between 2 and 22, inclusive.
|
||||||
|
fn recommended_wnaf_for_scalar(scalar: &Self::Scalar) -> usize;
|
||||||
|
|
||||||
|
/// Recommends a wNAF window size given the number of scalars you intend to multiply
|
||||||
|
/// a base by. Always returns a number between 2 and 22, inclusive.
|
||||||
|
fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
/// Replaces the contents of `table` with a w-NAF window table for the given window size.
|
/// Replaces the contents of `table` with a w-NAF window table for the given window size.
|
||||||
pub(crate) fn wnaf_table<G: CurveProjective>(table: &mut Vec<G>, mut base: G, window: usize) {
|
pub(crate) fn wnaf_table<G: Group>(table: &mut Vec<G>, mut base: G, window: usize) {
|
||||||
table.truncate(0);
|
table.truncate(0);
|
||||||
table.reserve(1 << (window - 1));
|
table.reserve(1 << (window - 1));
|
||||||
|
|
||||||
|
@ -78,7 +89,7 @@ pub(crate) fn wnaf_form<S: AsRef<[u8]>>(wnaf: &mut Vec<i64>, c: S, window: usize
|
||||||
///
|
///
|
||||||
/// This function must be provided a `table` and `wnaf` that were constructed with
|
/// This function must be provided a `table` and `wnaf` that were constructed with
|
||||||
/// the same window size; otherwise, it may panic or produce invalid results.
|
/// the same window size; otherwise, it may panic or produce invalid results.
|
||||||
pub(crate) fn wnaf_exp<G: CurveProjective>(table: &[G], wnaf: &[i64]) -> G {
|
pub(crate) fn wnaf_exp<G: Group>(table: &[G], wnaf: &[i64]) -> G {
|
||||||
let mut result = G::identity();
|
let mut result = G::identity();
|
||||||
|
|
||||||
let mut found_one = false;
|
let mut found_one = false;
|
||||||
|
@ -92,9 +103,9 @@ pub(crate) fn wnaf_exp<G: CurveProjective>(table: &[G], wnaf: &[i64]) -> G {
|
||||||
found_one = true;
|
found_one = true;
|
||||||
|
|
||||||
if *n > 0 {
|
if *n > 0 {
|
||||||
result.add_assign(&table[(n / 2) as usize]);
|
result += &table[(n / 2) as usize];
|
||||||
} else {
|
} else {
|
||||||
result.sub_assign(&table[((-n) / 2) as usize]);
|
result -= &table[((-n) / 2) as usize];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,7 +121,7 @@ pub struct Wnaf<W, B, S> {
|
||||||
window_size: W,
|
window_size: W,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: CurveProjective> Wnaf<(), Vec<G>, Vec<i64>> {
|
impl<G: Group> Wnaf<(), Vec<G>, Vec<i64>> {
|
||||||
/// Construct a new wNAF context without allocating.
|
/// Construct a new wNAF context without allocating.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Wnaf {
|
Wnaf {
|
||||||
|
@ -119,7 +130,9 @@ impl<G: CurveProjective> Wnaf<(), Vec<G>, Vec<i64>> {
|
||||||
window_size: (),
|
window_size: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G: WnafGroup> Wnaf<(), Vec<G>, Vec<i64>> {
|
||||||
/// Given a base and a number of scalars, compute a window table and return a `Wnaf` object that
|
/// Given a base and a number of scalars, compute a window table and return a `Wnaf` object that
|
||||||
/// can perform exponentiations with `.scalar(..)`.
|
/// can perform exponentiations with `.scalar(..)`.
|
||||||
pub fn base(&mut self, base: G, num_scalars: usize) -> Wnaf<usize, &[G], &mut Vec<i64>> {
|
pub fn base(&mut self, base: G, num_scalars: usize) -> Wnaf<usize, &[G], &mut Vec<i64>> {
|
||||||
|
@ -157,7 +170,7 @@ impl<G: CurveProjective> Wnaf<(), Vec<G>, Vec<i64>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, G: CurveProjective> Wnaf<usize, &'a [G], &'a mut Vec<i64>> {
|
impl<'a, G: Group> Wnaf<usize, &'a [G], &'a mut Vec<i64>> {
|
||||||
/// Constructs new space for the scalar representation while borrowing
|
/// Constructs new space for the scalar representation while borrowing
|
||||||
/// the computed window table, for sending the window table across threads.
|
/// the computed window table, for sending the window table across threads.
|
||||||
pub fn shared(&self) -> Wnaf<usize, &'a [G], Vec<i64>> {
|
pub fn shared(&self) -> Wnaf<usize, &'a [G], Vec<i64>> {
|
||||||
|
@ -169,7 +182,7 @@ impl<'a, G: CurveProjective> Wnaf<usize, &'a [G], &'a mut Vec<i64>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, G: CurveProjective> Wnaf<usize, &'a mut Vec<G>, &'a [i64]> {
|
impl<'a, G: Group> Wnaf<usize, &'a mut Vec<G>, &'a [i64]> {
|
||||||
/// Constructs new space for the window table while borrowing
|
/// Constructs new space for the window table while borrowing
|
||||||
/// the computed scalar representation, for sending the scalar representation
|
/// the computed scalar representation, for sending the scalar representation
|
||||||
/// across threads.
|
/// across threads.
|
||||||
|
@ -184,7 +197,7 @@ impl<'a, G: CurveProjective> Wnaf<usize, &'a mut Vec<G>, &'a [i64]> {
|
||||||
|
|
||||||
impl<B, S: AsRef<[i64]>> Wnaf<usize, B, S> {
|
impl<B, S: AsRef<[i64]>> Wnaf<usize, B, S> {
|
||||||
/// Performs exponentiation given a base.
|
/// Performs exponentiation given a base.
|
||||||
pub fn base<G: CurveProjective>(&mut self, base: G) -> G
|
pub fn base<G: Group>(&mut self, base: G) -> G
|
||||||
where
|
where
|
||||||
B: AsMut<Vec<G>>,
|
B: AsMut<Vec<G>>,
|
||||||
{
|
{
|
||||||
|
@ -195,7 +208,7 @@ impl<B, S: AsRef<[i64]>> Wnaf<usize, B, S> {
|
||||||
|
|
||||||
impl<B, S: AsMut<Vec<i64>>> Wnaf<usize, B, S> {
|
impl<B, S: AsMut<Vec<i64>>> Wnaf<usize, B, S> {
|
||||||
/// Performs exponentiation given a scalar.
|
/// Performs exponentiation given a scalar.
|
||||||
pub fn scalar<G: CurveProjective>(&mut self, scalar: &<G as Group>::Scalar) -> G
|
pub fn scalar<G: Group>(&mut self, scalar: &<G as Group>::Scalar) -> G
|
||||||
where
|
where
|
||||||
B: AsRef<[G]>,
|
B: AsRef<[G]>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@ macro_rules! curve_impl {
|
||||||
(
|
(
|
||||||
$name:expr,
|
$name:expr,
|
||||||
$projective:ident,
|
$projective:ident,
|
||||||
|
$subgroup:ident,
|
||||||
$affine:ident,
|
$affine:ident,
|
||||||
$basefield:ident,
|
$basefield:ident,
|
||||||
$scalarfield:ident,
|
$scalarfield:ident,
|
||||||
|
@ -100,6 +101,21 @@ macro_rules! curve_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub struct $subgroup($projective);
|
||||||
|
|
||||||
|
impl ::std::fmt::Display for $subgroup {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$subgroup> for $projective {
|
||||||
|
fn from(val: $subgroup) -> $projective {
|
||||||
|
val.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl $affine {
|
impl $affine {
|
||||||
fn mul_bits_u64<S: AsRef<[u64]>>(&self, bits: BitIterator<u64, S>) -> $projective {
|
fn mul_bits_u64<S: AsRef<[u64]>>(&self, bits: BitIterator<u64, S>) -> $projective {
|
||||||
let mut res = $projective::identity();
|
let mut res = $projective::identity();
|
||||||
|
@ -197,11 +213,9 @@ macro_rules! curve_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CurveAffine for $affine {
|
impl CofactorCurveAffine for $affine {
|
||||||
type Scalar = $scalarfield;
|
type Scalar = $scalarfield;
|
||||||
type Projective = $projective;
|
type Curve = $projective;
|
||||||
type Uncompressed = $uncompressed;
|
|
||||||
type Compressed = $compressed;
|
|
||||||
|
|
||||||
fn identity() -> Self {
|
fn identity() -> Self {
|
||||||
$affine {
|
$affine {
|
||||||
|
@ -219,12 +233,80 @@ macro_rules! curve_impl {
|
||||||
Choice::from(if self.infinity { 1 } else { 0 })
|
Choice::from(if self.infinity { 1 } else { 0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_projective(&self) -> $projective {
|
fn to_curve(&self) -> $projective {
|
||||||
(*self).into()
|
(*self).into()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn from_compressed(bytes: &Self::Compressed) -> CtOption<Self> {
|
impl GroupEncoding for $projective {
|
||||||
Self::from_compressed_unchecked(bytes).and_then(|affine| {
|
type Repr = $compressed;
|
||||||
|
|
||||||
|
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
|
||||||
|
if let Ok(affine) = bytes.into_affine_unchecked() {
|
||||||
|
// NB: Decompression guarantees that it is on the curve already.
|
||||||
|
CtOption::new(
|
||||||
|
affine.into(),
|
||||||
|
Choice::from(if affine.is_in_correct_subgroup_assuming_on_curve() {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
CtOption::new(Self::identity(), Choice::from(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
|
||||||
|
if let Ok(p) = bytes.into_affine_unchecked() {
|
||||||
|
CtOption::new(p.into(), Choice::from(1))
|
||||||
|
} else {
|
||||||
|
CtOption::new(Self::identity(), Choice::from(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bytes(&self) -> Self::Repr {
|
||||||
|
self.to_affine().to_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GroupEncoding for $subgroup {
|
||||||
|
type Repr = $compressed;
|
||||||
|
|
||||||
|
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
|
||||||
|
if let Ok(affine) = bytes.into_affine_unchecked() {
|
||||||
|
// NB: Decompression guarantees that it is on the curve already.
|
||||||
|
CtOption::new(
|
||||||
|
$subgroup(affine.into()),
|
||||||
|
Choice::from(if affine.is_in_correct_subgroup_assuming_on_curve() {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
CtOption::new(Self::identity(), Choice::from(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
|
||||||
|
if let Ok(p) = bytes.into_affine_unchecked() {
|
||||||
|
CtOption::new($subgroup(p.into()), Choice::from(1))
|
||||||
|
} else {
|
||||||
|
CtOption::new(Self::identity(), Choice::from(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bytes(&self) -> Self::Repr {
|
||||||
|
self.0.to_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GroupEncoding for $affine {
|
||||||
|
type Repr = $compressed;
|
||||||
|
|
||||||
|
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
|
||||||
|
Self::from_bytes_unchecked(bytes).and_then(|affine| {
|
||||||
// NB: Decompression guarantees that it is on the curve already.
|
// NB: Decompression guarantees that it is on the curve already.
|
||||||
CtOption::new(
|
CtOption::new(
|
||||||
affine,
|
affine,
|
||||||
|
@ -237,7 +319,7 @@ macro_rules! curve_impl {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_compressed_unchecked(bytes: &Self::Compressed) -> CtOption<Self> {
|
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
|
||||||
if let Ok(p) = bytes.into_affine_unchecked() {
|
if let Ok(p) = bytes.into_affine_unchecked() {
|
||||||
CtOption::new(p, Choice::from(1))
|
CtOption::new(p, Choice::from(1))
|
||||||
} else {
|
} else {
|
||||||
|
@ -245,9 +327,13 @@ macro_rules! curve_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_compressed(&self) -> Self::Compressed {
|
fn to_bytes(&self) -> Self::Repr {
|
||||||
$compressed::from_affine(*self)
|
$compressed::from_affine(*self)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UncompressedEncoding for $affine {
|
||||||
|
type Uncompressed = $uncompressed;
|
||||||
|
|
||||||
fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption<Self> {
|
fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption<Self> {
|
||||||
Self::from_uncompressed_unchecked(bytes).and_then(|affine| {
|
Self::from_uncompressed_unchecked(bytes).and_then(|affine| {
|
||||||
|
@ -460,30 +546,28 @@ macro_rules! curve_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> ::std::ops::Add<&'r <$projective as CurveProjective>::Affine> for $projective {
|
impl<'r> ::std::ops::Add<&'r $affine> for $projective {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add(self, other: &<$projective as CurveProjective>::Affine) -> Self {
|
fn add(self, other: &$affine) -> Self {
|
||||||
let mut ret = self;
|
let mut ret = self;
|
||||||
ret.add_assign(other);
|
ret.add_assign(other);
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::ops::Add<<$projective as CurveProjective>::Affine> for $projective {
|
impl ::std::ops::Add<$affine> for $projective {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add(self, other: <$projective as CurveProjective>::Affine) -> Self {
|
fn add(self, other: $affine) -> Self {
|
||||||
self + &other
|
self + &other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> ::std::ops::AddAssign<&'r <$projective as CurveProjective>::Affine>
|
impl<'r> ::std::ops::AddAssign<&'r $affine> for $projective {
|
||||||
for $projective
|
fn add_assign(&mut self, other: &$affine) {
|
||||||
{
|
|
||||||
fn add_assign(&mut self, other: &<$projective as CurveProjective>::Affine) {
|
|
||||||
if other.is_identity().into() {
|
if other.is_identity().into() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -561,44 +645,42 @@ macro_rules! curve_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::ops::AddAssign<<$projective as CurveProjective>::Affine> for $projective {
|
impl ::std::ops::AddAssign<$affine> for $projective {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add_assign(&mut self, other: <$projective as CurveProjective>::Affine) {
|
fn add_assign(&mut self, other: $affine) {
|
||||||
self.add_assign(&other);
|
self.add_assign(&other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> ::std::ops::Sub<&'r <$projective as CurveProjective>::Affine> for $projective {
|
impl<'r> ::std::ops::Sub<&'r $affine> for $projective {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn sub(self, other: &<$projective as CurveProjective>::Affine) -> Self {
|
fn sub(self, other: &$affine) -> Self {
|
||||||
let mut ret = self;
|
let mut ret = self;
|
||||||
ret.sub_assign(other);
|
ret.sub_assign(other);
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::ops::Sub<<$projective as CurveProjective>::Affine> for $projective {
|
impl ::std::ops::Sub<$affine> for $projective {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn sub(self, other: <$projective as CurveProjective>::Affine) -> Self {
|
fn sub(self, other: $affine) -> Self {
|
||||||
self - &other
|
self - &other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> ::std::ops::SubAssign<&'r <$projective as CurveProjective>::Affine>
|
impl<'r> ::std::ops::SubAssign<&'r $affine> for $projective {
|
||||||
for $projective
|
fn sub_assign(&mut self, other: &$affine) {
|
||||||
{
|
|
||||||
fn sub_assign(&mut self, other: &<$projective as CurveProjective>::Affine) {
|
|
||||||
self.add_assign(&other.neg());
|
self.add_assign(&other.neg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::ops::SubAssign<<$projective as CurveProjective>::Affine> for $projective {
|
impl ::std::ops::SubAssign<$affine> for $projective {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn sub_assign(&mut self, other: <$projective as CurveProjective>::Affine) {
|
fn sub_assign(&mut self, other: $affine) {
|
||||||
self.sub_assign(&other);
|
self.sub_assign(&other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -649,8 +731,182 @@ macro_rules! curve_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ::std::iter::Sum for $subgroup {
|
||||||
|
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
||||||
|
iter.fold(Self::identity(), ::std::ops::Add::add)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> ::std::iter::Sum<&'r $subgroup> for $subgroup {
|
||||||
|
fn sum<I: Iterator<Item = &'r Self>>(iter: I) -> Self {
|
||||||
|
iter.fold(Self::identity(), ::std::ops::Add::add)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::ops::Neg for $subgroup {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn neg(self) -> Self {
|
||||||
|
$subgroup(self.0.neg())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> ::std::ops::Add<&'r $subgroup> for $projective {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: &$subgroup) -> Self {
|
||||||
|
self + &other.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::ops::Add<$subgroup> for $projective {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: $subgroup) -> Self {
|
||||||
|
self + &other.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> ::std::ops::AddAssign<&'r $subgroup> for $projective {
|
||||||
|
fn add_assign(&mut self, other: &$subgroup) {
|
||||||
|
self.add_assign(&other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::ops::AddAssign<$subgroup> for $projective {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, other: $subgroup) {
|
||||||
|
self.add_assign(&other.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> ::std::ops::Sub<&'r $subgroup> for $projective {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, other: &$subgroup) -> Self {
|
||||||
|
self - &other.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::ops::Sub<$subgroup> for $projective {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, other: $subgroup) -> Self {
|
||||||
|
self - &other.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> ::std::ops::SubAssign<&'r $subgroup> for $projective {
|
||||||
|
fn sub_assign(&mut self, other: &$subgroup) {
|
||||||
|
self.sub_assign(&other.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::ops::SubAssign<$subgroup> for $projective {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, other: $subgroup) {
|
||||||
|
self.sub_assign(&other.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> ::std::ops::Add<&'r $subgroup> for $subgroup {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: &$subgroup) -> Self {
|
||||||
|
$subgroup(self.0 + &other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::ops::Add<$subgroup> for $subgroup {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: $subgroup) -> Self {
|
||||||
|
$subgroup(self.0 + &other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> ::std::ops::AddAssign<&'r $subgroup> for $subgroup {
|
||||||
|
fn add_assign(&mut self, other: &$subgroup) {
|
||||||
|
self.0.add_assign(&other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::ops::AddAssign<$subgroup> for $subgroup {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, other: $subgroup) {
|
||||||
|
self.0.add_assign(&other.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> ::std::ops::Sub<&'r $subgroup> for $subgroup {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, other: &$subgroup) -> Self {
|
||||||
|
$subgroup(self.0 - &other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::ops::Sub<$subgroup> for $subgroup {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, other: $subgroup) -> Self {
|
||||||
|
$subgroup(self.0 - &other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> ::std::ops::SubAssign<&'r $subgroup> for $subgroup {
|
||||||
|
fn sub_assign(&mut self, other: &$subgroup) {
|
||||||
|
self.0.sub_assign(&other.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::ops::SubAssign<$subgroup> for $subgroup {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, other: $subgroup) {
|
||||||
|
self.0.sub_assign(&other.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::ops::Mul<<$projective as Group>::Scalar> for $subgroup {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(mut self, other: <$projective as Group>::Scalar) -> Self {
|
||||||
|
self.0.mul_assign(&other);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> ::std::ops::Mul<&'r <$projective as Group>::Scalar> for $subgroup {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(mut self, other: &'r <$projective as Group>::Scalar) -> Self {
|
||||||
|
self.0.mul_assign(other);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::ops::MulAssign<<$projective as Group>::Scalar> for $subgroup {
|
||||||
|
fn mul_assign(&mut self, other: <$projective as Group>::Scalar) {
|
||||||
|
self.0.mul_assign(&other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> ::std::ops::MulAssign<&'r <$projective as Group>::Scalar> for $subgroup {
|
||||||
|
fn mul_assign(&mut self, other: &'r <$projective as Group>::Scalar) {
|
||||||
|
self.0.mul_assign(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Group for $projective {
|
impl Group for $projective {
|
||||||
type Subgroup = Self;
|
|
||||||
type Scalar = $scalarfield;
|
type Scalar = $scalarfield;
|
||||||
|
|
||||||
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
|
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
|
||||||
|
@ -738,10 +994,56 @@ macro_rules! curve_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrimeGroup for $projective {}
|
impl Group for $subgroup {
|
||||||
|
type Scalar = $scalarfield;
|
||||||
|
|
||||||
impl CurveProjective for $projective {
|
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
|
||||||
type Affine = $affine;
|
$subgroup($projective::random(rng))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn identity() -> Self {
|
||||||
|
$subgroup($projective::identity())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generator() -> Self {
|
||||||
|
$subgroup($projective::generator())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_identity(&self) -> Choice {
|
||||||
|
self.0.is_identity()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn double(&self) -> Self {
|
||||||
|
$subgroup(self.0.double())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrimeGroup for $subgroup {}
|
||||||
|
|
||||||
|
impl CofactorGroup for $projective {
|
||||||
|
type Subgroup = $subgroup;
|
||||||
|
|
||||||
|
fn mul_by_cofactor(&self) -> Self::Subgroup {
|
||||||
|
$subgroup($affine::from(*self).scale_by_cofactor().into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_subgroup(self) -> CtOption<Self::Subgroup> {
|
||||||
|
CtOption::new(
|
||||||
|
$subgroup(self),
|
||||||
|
Choice::from(
|
||||||
|
if $affine::from(self).is_in_correct_subgroup_assuming_on_curve() {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Curve for $projective {
|
||||||
|
type AffineRepr = $affine;
|
||||||
|
|
||||||
fn batch_normalize(p: &[Self], q: &mut [$affine]) {
|
fn batch_normalize(p: &[Self], q: &mut [$affine]) {
|
||||||
assert_eq!(p.len(), q.len());
|
assert_eq!(p.len(), q.len());
|
||||||
|
@ -790,7 +1092,9 @@ macro_rules! curve_impl {
|
||||||
fn to_affine(&self) -> $affine {
|
fn to_affine(&self) -> $affine {
|
||||||
(*self).into()
|
(*self).into()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WnafGroup for $projective {
|
||||||
fn recommended_wnaf_for_scalar(_: &Self::Scalar) -> usize {
|
fn recommended_wnaf_for_scalar(_: &Self::Scalar) -> usize {
|
||||||
Self::empirical_recommended_wnaf_for_scalar(
|
Self::empirical_recommended_wnaf_for_scalar(
|
||||||
<Self::Scalar as PrimeField>::NUM_BITS as usize,
|
<Self::Scalar as PrimeField>::NUM_BITS as usize,
|
||||||
|
@ -802,6 +1106,10 @@ macro_rules! curve_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CofactorCurve for $projective {
|
||||||
|
type Affine = $affine;
|
||||||
|
}
|
||||||
|
|
||||||
// The affine point X, Y is represented in the jacobian
|
// The affine point X, Y is represented in the jacobian
|
||||||
// coordinates with Z = 1.
|
// coordinates with Z = 1.
|
||||||
impl From<$affine> for $projective {
|
impl From<$affine> for $projective {
|
||||||
|
@ -901,7 +1209,11 @@ pub mod g1 {
|
||||||
use super::{g2::G2Affine, GroupDecodingError};
|
use super::{g2::G2Affine, GroupDecodingError};
|
||||||
use crate::{Engine, PairingCurveAffine};
|
use crate::{Engine, PairingCurveAffine};
|
||||||
use ff::{BitIterator, Field, PrimeField};
|
use ff::{BitIterator, Field, PrimeField};
|
||||||
use group::{CurveAffine, CurveProjective, Group, PrimeGroup};
|
use group::{
|
||||||
|
cofactor::{CofactorCurve, CofactorCurveAffine, CofactorGroup},
|
||||||
|
prime::PrimeGroup,
|
||||||
|
Curve, Group, GroupEncoding, UncompressedEncoding, WnafGroup,
|
||||||
|
};
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
||||||
|
@ -910,6 +1222,7 @@ pub mod g1 {
|
||||||
curve_impl!(
|
curve_impl!(
|
||||||
"G1",
|
"G1",
|
||||||
G1,
|
G1,
|
||||||
|
G1Subgroup,
|
||||||
G1Affine,
|
G1Affine,
|
||||||
Fq,
|
Fq,
|
||||||
Fr,
|
Fr,
|
||||||
|
@ -1454,21 +1767,23 @@ pub mod g1 {
|
||||||
assert!(b.is_on_curve() && b.is_in_correct_subgroup_assuming_on_curve());
|
assert!(b.is_on_curve() && b.is_in_correct_subgroup_assuming_on_curve());
|
||||||
assert!(c.is_on_curve() && c.is_in_correct_subgroup_assuming_on_curve());
|
assert!(c.is_on_curve() && c.is_in_correct_subgroup_assuming_on_curve());
|
||||||
|
|
||||||
let mut tmp1 = a.to_projective();
|
let mut tmp1 = a.to_curve();
|
||||||
tmp1.add_assign(&b.to_projective());
|
tmp1.add_assign(&b.to_curve());
|
||||||
assert_eq!(tmp1.to_affine(), c);
|
assert_eq!(tmp1.to_affine(), c);
|
||||||
assert_eq!(tmp1, c.to_projective());
|
assert_eq!(tmp1, c.to_curve());
|
||||||
|
|
||||||
let mut tmp2 = a.to_projective();
|
let mut tmp2 = a.to_curve();
|
||||||
tmp2.add_assign(&b);
|
tmp2.add_assign(&b);
|
||||||
assert_eq!(tmp2.to_affine(), c);
|
assert_eq!(tmp2.to_affine(), c);
|
||||||
assert_eq!(tmp2, c.to_projective());
|
assert_eq!(tmp2, c.to_curve());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn g1_curve_tests() {
|
fn g1_curve_tests() {
|
||||||
use group::tests::curve_tests;
|
use group::tests::{curve_tests, random_uncompressed_encoding_tests, random_wnaf_tests};
|
||||||
curve_tests::<G1>();
|
curve_tests::<G1>();
|
||||||
|
random_wnaf_tests::<G1>();
|
||||||
|
random_uncompressed_encoding_tests::<G1>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1477,7 +1792,11 @@ pub mod g2 {
|
||||||
use super::{g1::G1Affine, GroupDecodingError};
|
use super::{g1::G1Affine, GroupDecodingError};
|
||||||
use crate::{Engine, PairingCurveAffine};
|
use crate::{Engine, PairingCurveAffine};
|
||||||
use ff::{BitIterator, Field, PrimeField};
|
use ff::{BitIterator, Field, PrimeField};
|
||||||
use group::{CurveAffine, CurveProjective, Group, PrimeGroup};
|
use group::{
|
||||||
|
cofactor::{CofactorCurve, CofactorCurveAffine, CofactorGroup},
|
||||||
|
prime::PrimeGroup,
|
||||||
|
Curve, Group, GroupEncoding, UncompressedEncoding, WnafGroup,
|
||||||
|
};
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
||||||
|
@ -1486,6 +1805,7 @@ pub mod g2 {
|
||||||
curve_impl!(
|
curve_impl!(
|
||||||
"G2",
|
"G2",
|
||||||
G2,
|
G2,
|
||||||
|
G2Subgroup,
|
||||||
G2Affine,
|
G2Affine,
|
||||||
Fq2,
|
Fq2,
|
||||||
Fr,
|
Fr,
|
||||||
|
@ -2167,8 +2487,10 @@ pub mod g2 {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn g2_curve_tests() {
|
fn g2_curve_tests() {
|
||||||
use group::tests::curve_tests;
|
use group::tests::{curve_tests, random_uncompressed_encoding_tests, random_wnaf_tests};
|
||||||
curve_tests::<G2>();
|
curve_tests::<G2>();
|
||||||
|
random_wnaf_tests::<G2>();
|
||||||
|
random_uncompressed_encoding_tests::<G2>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub use self::fr::{Fr, FrRepr};
|
||||||
use super::{Engine, MillerLoopResult, MultiMillerLoop};
|
use super::{Engine, MillerLoopResult, MultiMillerLoop};
|
||||||
|
|
||||||
use ff::{BitIterator, Field};
|
use ff::{BitIterator, Field};
|
||||||
use group::CurveAffine;
|
use group::cofactor::CofactorCurveAffine;
|
||||||
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
||||||
|
|
||||||
// The BLS parameter x for BLS12-381 is -0xd201000000010000
|
// The BLS parameter x for BLS12-381 is -0xd201000000010000
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use ff::PrimeField;
|
use ff::PrimeField;
|
||||||
use group::{CurveAffine, CurveProjective};
|
use group::{
|
||||||
|
cofactor::{CofactorCurve, CofactorCurveAffine},
|
||||||
|
GroupEncoding, UncompressedEncoding,
|
||||||
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
@ -55,9 +58,12 @@ fn test_pairing_result_against_relic() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uncompressed_test_vectors<G: CurveProjective>(expected: &[u8]) {
|
fn uncompressed_test_vectors<G: CofactorCurve>(expected: &[u8])
|
||||||
|
where
|
||||||
|
G::Affine: UncompressedEncoding,
|
||||||
|
{
|
||||||
let mut e = G::identity();
|
let mut e = G::identity();
|
||||||
let encoded_len = <G::Affine as CurveAffine>::Uncompressed::default()
|
let encoded_len = <G::Affine as UncompressedEncoding>::Uncompressed::default()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.len();
|
.len();
|
||||||
|
|
||||||
|
@ -69,7 +75,7 @@ fn uncompressed_test_vectors<G: CurveProjective>(expected: &[u8]) {
|
||||||
let encoded = e_affine.to_uncompressed();
|
let encoded = e_affine.to_uncompressed();
|
||||||
v.extend_from_slice(encoded.as_ref());
|
v.extend_from_slice(encoded.as_ref());
|
||||||
|
|
||||||
let mut decoded = <G::Affine as CurveAffine>::Uncompressed::default();
|
let mut decoded = <G::Affine as UncompressedEncoding>::Uncompressed::default();
|
||||||
decoded.as_mut().copy_from_slice(&expected[0..encoded_len]);
|
decoded.as_mut().copy_from_slice(&expected[0..encoded_len]);
|
||||||
expected = &expected[encoded_len..];
|
expected = &expected[encoded_len..];
|
||||||
let decoded = G::Affine::from_uncompressed(&decoded).unwrap();
|
let decoded = G::Affine::from_uncompressed(&decoded).unwrap();
|
||||||
|
@ -82,24 +88,22 @@ fn uncompressed_test_vectors<G: CurveProjective>(expected: &[u8]) {
|
||||||
assert_eq!(&v[..], expected);
|
assert_eq!(&v[..], expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compressed_test_vectors<G: CurveProjective>(expected: &[u8]) {
|
fn compressed_test_vectors<G: CofactorCurve>(expected: &[u8]) {
|
||||||
let mut e = G::identity();
|
let mut e = G::identity();
|
||||||
let encoded_len = <G::Affine as CurveAffine>::Compressed::default()
|
let encoded_len = <G::Affine as GroupEncoding>::Repr::default().as_ref().len();
|
||||||
.as_ref()
|
|
||||||
.len();
|
|
||||||
|
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
{
|
{
|
||||||
let mut expected = expected;
|
let mut expected = expected;
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
let e_affine = e.to_affine();
|
let e_affine = e.to_affine();
|
||||||
let encoded = e_affine.to_compressed();
|
let encoded = e_affine.to_bytes();
|
||||||
v.extend_from_slice(encoded.as_ref());
|
v.extend_from_slice(encoded.as_ref());
|
||||||
|
|
||||||
let mut decoded = <G::Affine as CurveAffine>::Compressed::default();
|
let mut decoded = <G::Affine as GroupEncoding>::Repr::default();
|
||||||
decoded.as_mut().copy_from_slice(&expected[0..encoded_len]);
|
decoded.as_mut().copy_from_slice(&expected[0..encoded_len]);
|
||||||
expected = &expected[encoded_len..];
|
expected = &expected[encoded_len..];
|
||||||
let decoded = G::Affine::from_compressed(&decoded).unwrap();
|
let decoded = G::Affine::from_bytes(&decoded).unwrap();
|
||||||
assert_eq!(e_affine, decoded);
|
assert_eq!(e_affine, decoded);
|
||||||
|
|
||||||
e.add_assign(&G::generator());
|
e.add_assign(&G::generator());
|
||||||
|
@ -392,12 +396,12 @@ fn test_g2_uncompressed_invalid_vectors() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_g1_compressed_invalid_vectors() {
|
fn test_g1_compressed_invalid_vectors() {
|
||||||
{
|
{
|
||||||
let z = G1Affine::identity().to_compressed();
|
let z = G1Affine::identity().to_bytes();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut z = z;
|
let mut z = z;
|
||||||
z.as_mut()[0] &= 0b0111_1111;
|
z.as_mut()[0] &= 0b0111_1111;
|
||||||
if G1Affine::from_compressed(&z).is_none().into() {
|
if G1Affine::from_bytes(&z).is_none().into() {
|
||||||
// :)
|
// :)
|
||||||
} else {
|
} else {
|
||||||
panic!("should have rejected the point because we expected a compressed point");
|
panic!("should have rejected the point because we expected a compressed point");
|
||||||
|
@ -407,7 +411,7 @@ fn test_g1_compressed_invalid_vectors() {
|
||||||
{
|
{
|
||||||
let mut z = z;
|
let mut z = z;
|
||||||
z.as_mut()[0] |= 0b0010_0000;
|
z.as_mut()[0] |= 0b0010_0000;
|
||||||
if G1Affine::from_compressed(&z).is_none().into() {
|
if G1Affine::from_bytes(&z).is_none().into() {
|
||||||
// :)
|
// :)
|
||||||
} else {
|
} else {
|
||||||
panic!("should have rejected the point because the parity bit should not be set if the point is at infinity");
|
panic!("should have rejected the point because the parity bit should not be set if the point is at infinity");
|
||||||
|
@ -417,7 +421,7 @@ fn test_g1_compressed_invalid_vectors() {
|
||||||
for i in 0..G1Compressed::size() {
|
for i in 0..G1Compressed::size() {
|
||||||
let mut z = z;
|
let mut z = z;
|
||||||
z.as_mut()[i] |= 0b0000_0001;
|
z.as_mut()[i] |= 0b0000_0001;
|
||||||
if G1Affine::from_compressed(&z).is_none().into() {
|
if G1Affine::from_bytes(&z).is_none().into() {
|
||||||
// :)
|
// :)
|
||||||
} else {
|
} else {
|
||||||
panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity");
|
panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity");
|
||||||
|
@ -425,12 +429,12 @@ fn test_g1_compressed_invalid_vectors() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let o = G1Affine::generator().to_compressed();
|
let o = G1Affine::generator().to_bytes();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut o = o;
|
let mut o = o;
|
||||||
o.as_mut()[0] &= 0b0111_1111;
|
o.as_mut()[0] &= 0b0111_1111;
|
||||||
if G1Affine::from_compressed(&o).is_none().into() {
|
if G1Affine::from_bytes(&o).is_none().into() {
|
||||||
// :)
|
// :)
|
||||||
} else {
|
} else {
|
||||||
panic!("should have rejected the point because we expected a compressed point");
|
panic!("should have rejected the point because we expected a compressed point");
|
||||||
|
@ -444,7 +448,7 @@ fn test_g1_compressed_invalid_vectors() {
|
||||||
o.as_mut()[..48].copy_from_slice(m.as_ref());
|
o.as_mut()[..48].copy_from_slice(m.as_ref());
|
||||||
o.as_mut()[0] |= 0b1000_0000;
|
o.as_mut()[0] |= 0b1000_0000;
|
||||||
|
|
||||||
if G1Affine::from_compressed(&o).is_none().into() {
|
if G1Affine::from_bytes(&o).is_none().into() {
|
||||||
// x coordinate
|
// x coordinate
|
||||||
} else {
|
} else {
|
||||||
panic!("should have rejected the point")
|
panic!("should have rejected the point")
|
||||||
|
@ -466,7 +470,7 @@ fn test_g1_compressed_invalid_vectors() {
|
||||||
o.as_mut().copy_from_slice(x.to_repr().as_ref());
|
o.as_mut().copy_from_slice(x.to_repr().as_ref());
|
||||||
o.as_mut()[0] |= 0b1000_0000;
|
o.as_mut()[0] |= 0b1000_0000;
|
||||||
|
|
||||||
if G1Affine::from_compressed(&o).is_none().into() {
|
if G1Affine::from_bytes(&o).is_none().into() {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
panic!("should have rejected the point because it isn't on the curve")
|
panic!("should have rejected the point because it isn't on the curve")
|
||||||
|
@ -489,7 +493,7 @@ fn test_g1_compressed_invalid_vectors() {
|
||||||
o.as_mut().copy_from_slice(x.to_repr().as_ref());
|
o.as_mut().copy_from_slice(x.to_repr().as_ref());
|
||||||
o.as_mut()[0] |= 0b1000_0000;
|
o.as_mut()[0] |= 0b1000_0000;
|
||||||
|
|
||||||
if G1Affine::from_compressed(&o).is_none().into() {
|
if G1Affine::from_bytes(&o).is_none().into() {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
panic!(
|
panic!(
|
||||||
|
@ -506,12 +510,12 @@ fn test_g1_compressed_invalid_vectors() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_g2_compressed_invalid_vectors() {
|
fn test_g2_compressed_invalid_vectors() {
|
||||||
{
|
{
|
||||||
let z = G2Affine::identity().to_compressed();
|
let z = G2Affine::identity().to_bytes();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut z = z;
|
let mut z = z;
|
||||||
z.as_mut()[0] &= 0b0111_1111;
|
z.as_mut()[0] &= 0b0111_1111;
|
||||||
if G2Affine::from_compressed(&z).is_none().into() {
|
if G2Affine::from_bytes(&z).is_none().into() {
|
||||||
// :)
|
// :)
|
||||||
} else {
|
} else {
|
||||||
panic!("should have rejected the point because we expected a compressed point");
|
panic!("should have rejected the point because we expected a compressed point");
|
||||||
|
@ -521,7 +525,7 @@ fn test_g2_compressed_invalid_vectors() {
|
||||||
{
|
{
|
||||||
let mut z = z;
|
let mut z = z;
|
||||||
z.as_mut()[0] |= 0b0010_0000;
|
z.as_mut()[0] |= 0b0010_0000;
|
||||||
if G2Affine::from_compressed(&z).is_none().into() {
|
if G2Affine::from_bytes(&z).is_none().into() {
|
||||||
// :)
|
// :)
|
||||||
} else {
|
} else {
|
||||||
panic!("should have rejected the point because the parity bit should not be set if the point is at infinity");
|
panic!("should have rejected the point because the parity bit should not be set if the point is at infinity");
|
||||||
|
@ -531,7 +535,7 @@ fn test_g2_compressed_invalid_vectors() {
|
||||||
for i in 0..G2Compressed::size() {
|
for i in 0..G2Compressed::size() {
|
||||||
let mut z = z;
|
let mut z = z;
|
||||||
z.as_mut()[i] |= 0b0000_0001;
|
z.as_mut()[i] |= 0b0000_0001;
|
||||||
if G2Affine::from_compressed(&z).is_none().into() {
|
if G2Affine::from_bytes(&z).is_none().into() {
|
||||||
// :)
|
// :)
|
||||||
} else {
|
} else {
|
||||||
panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity");
|
panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity");
|
||||||
|
@ -539,12 +543,12 @@ fn test_g2_compressed_invalid_vectors() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let o = G2Affine::generator().to_compressed();
|
let o = G2Affine::generator().to_bytes();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut o = o;
|
let mut o = o;
|
||||||
o.as_mut()[0] &= 0b0111_1111;
|
o.as_mut()[0] &= 0b0111_1111;
|
||||||
if G2Affine::from_compressed(&o).is_none().into() {
|
if G2Affine::from_bytes(&o).is_none().into() {
|
||||||
// :)
|
// :)
|
||||||
} else {
|
} else {
|
||||||
panic!("should have rejected the point because we expected a compressed point");
|
panic!("should have rejected the point because we expected a compressed point");
|
||||||
|
@ -558,7 +562,7 @@ fn test_g2_compressed_invalid_vectors() {
|
||||||
o.as_mut()[..48].copy_from_slice(m.as_ref());
|
o.as_mut()[..48].copy_from_slice(m.as_ref());
|
||||||
o.as_mut()[0] |= 0b1000_0000;
|
o.as_mut()[0] |= 0b1000_0000;
|
||||||
|
|
||||||
if G2Affine::from_compressed(&o).is_none().into() {
|
if G2Affine::from_bytes(&o).is_none().into() {
|
||||||
// x coordinate (c1)
|
// x coordinate (c1)
|
||||||
} else {
|
} else {
|
||||||
panic!("should have rejected the point")
|
panic!("should have rejected the point")
|
||||||
|
@ -570,7 +574,7 @@ fn test_g2_compressed_invalid_vectors() {
|
||||||
o.as_mut()[48..96].copy_from_slice(m.as_ref());
|
o.as_mut()[48..96].copy_from_slice(m.as_ref());
|
||||||
o.as_mut()[0] |= 0b1000_0000;
|
o.as_mut()[0] |= 0b1000_0000;
|
||||||
|
|
||||||
if G2Affine::from_compressed(&o).is_none().into() {
|
if G2Affine::from_bytes(&o).is_none().into() {
|
||||||
// x coordinate (c0)
|
// x coordinate (c0)
|
||||||
} else {
|
} else {
|
||||||
panic!("should have rejected the point")
|
panic!("should have rejected the point")
|
||||||
|
@ -599,7 +603,7 @@ fn test_g2_compressed_invalid_vectors() {
|
||||||
o.as_mut()[48..].copy_from_slice(x.c0.to_repr().as_ref());
|
o.as_mut()[48..].copy_from_slice(x.c0.to_repr().as_ref());
|
||||||
o.as_mut()[0] |= 0b1000_0000;
|
o.as_mut()[0] |= 0b1000_0000;
|
||||||
|
|
||||||
if G2Affine::from_compressed(&o).is_none().into() {
|
if G2Affine::from_bytes(&o).is_none().into() {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
panic!("should have rejected the point because it isn't on the curve")
|
panic!("should have rejected the point because it isn't on the curve")
|
||||||
|
@ -629,7 +633,7 @@ fn test_g2_compressed_invalid_vectors() {
|
||||||
o.as_mut()[48..].copy_from_slice(x.c0.to_repr().as_ref());
|
o.as_mut()[48..].copy_from_slice(x.c0.to_repr().as_ref());
|
||||||
o.as_mut()[0] |= 0b1000_0000;
|
o.as_mut()[0] |= 0b1000_0000;
|
||||||
|
|
||||||
if G2Affine::from_compressed(&o).is_none().into() {
|
if G2Affine::from_bytes(&o).is_none().into() {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
panic!(
|
panic!(
|
||||||
|
|
|
@ -22,7 +22,10 @@ pub mod bls12_381;
|
||||||
|
|
||||||
use core::ops::Mul;
|
use core::ops::Mul;
|
||||||
use ff::{Field, PrimeField};
|
use ff::{Field, PrimeField};
|
||||||
use group::{CurveAffine, CurveProjective, GroupOps, GroupOpsOwned, ScalarMul, ScalarMulOwned};
|
use group::{
|
||||||
|
cofactor::{CofactorCurve, CofactorCurveAffine},
|
||||||
|
GroupOps, GroupOpsOwned, ScalarMul, ScalarMulOwned, UncompressedEncoding,
|
||||||
|
};
|
||||||
|
|
||||||
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
|
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
|
||||||
/// with well-defined relationships. In particular, the G1/G2 curve groups are
|
/// with well-defined relationships. In particular, the G1/G2 curve groups are
|
||||||
|
@ -32,7 +35,7 @@ pub trait Engine: Sized + 'static + Clone {
|
||||||
type Fr: PrimeField;
|
type Fr: PrimeField;
|
||||||
|
|
||||||
/// The projective representation of an element in G1.
|
/// The projective representation of an element in G1.
|
||||||
type G1: CurveProjective<Scalar = Self::Fr, Affine = Self::G1Affine>
|
type G1: CofactorCurve<Scalar = Self::Fr, Affine = Self::G1Affine>
|
||||||
+ From<Self::G1Affine>
|
+ From<Self::G1Affine>
|
||||||
+ GroupOps<Self::G1Affine>
|
+ GroupOps<Self::G1Affine>
|
||||||
+ GroupOpsOwned<Self::G1Affine>
|
+ GroupOpsOwned<Self::G1Affine>
|
||||||
|
@ -42,7 +45,7 @@ pub trait Engine: Sized + 'static + Clone {
|
||||||
/// The affine representation of an element in G1.
|
/// The affine representation of an element in G1.
|
||||||
type G1Affine: PairingCurveAffine<
|
type G1Affine: PairingCurveAffine<
|
||||||
Scalar = Self::Fr,
|
Scalar = Self::Fr,
|
||||||
Projective = Self::G1,
|
Curve = Self::G1,
|
||||||
Pair = Self::G2Affine,
|
Pair = Self::G2Affine,
|
||||||
PairingResult = Self::Gt,
|
PairingResult = Self::Gt,
|
||||||
> + From<Self::G1>
|
> + From<Self::G1>
|
||||||
|
@ -50,7 +53,7 @@ pub trait Engine: Sized + 'static + Clone {
|
||||||
+ for<'a> Mul<&'a Self::Fr, Output = Self::G1>;
|
+ for<'a> Mul<&'a Self::Fr, Output = Self::G1>;
|
||||||
|
|
||||||
/// The projective representation of an element in G2.
|
/// The projective representation of an element in G2.
|
||||||
type G2: CurveProjective<Scalar = Self::Fr, Affine = Self::G2Affine>
|
type G2: CofactorCurve<Scalar = Self::Fr, Affine = Self::G2Affine>
|
||||||
+ From<Self::G2Affine>
|
+ From<Self::G2Affine>
|
||||||
+ GroupOps<Self::G2Affine>
|
+ GroupOps<Self::G2Affine>
|
||||||
+ GroupOpsOwned<Self::G2Affine>
|
+ GroupOpsOwned<Self::G2Affine>
|
||||||
|
@ -60,7 +63,7 @@ pub trait Engine: Sized + 'static + Clone {
|
||||||
/// The affine representation of an element in G2.
|
/// The affine representation of an element in G2.
|
||||||
type G2Affine: PairingCurveAffine<
|
type G2Affine: PairingCurveAffine<
|
||||||
Scalar = Self::Fr,
|
Scalar = Self::Fr,
|
||||||
Projective = Self::G2,
|
Curve = Self::G2,
|
||||||
Pair = Self::G1Affine,
|
Pair = Self::G1Affine,
|
||||||
PairingResult = Self::Gt,
|
PairingResult = Self::Gt,
|
||||||
> + From<Self::G2>
|
> + From<Self::G2>
|
||||||
|
@ -77,7 +80,7 @@ pub trait Engine: Sized + 'static + Clone {
|
||||||
|
|
||||||
/// Affine representation of an elliptic curve point that can be used
|
/// Affine representation of an elliptic curve point that can be used
|
||||||
/// to perform pairings.
|
/// to perform pairings.
|
||||||
pub trait PairingCurveAffine: CurveAffine {
|
pub trait PairingCurveAffine: CofactorCurveAffine + UncompressedEncoding {
|
||||||
type Pair: PairingCurveAffine<Pair = Self>;
|
type Pair: PairingCurveAffine<Pair = Self>;
|
||||||
type PairingResult: Field;
|
type PairingResult: Field;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use ff::{Endianness, Field, PrimeField};
|
use ff::{Endianness, Field, PrimeField};
|
||||||
use group::{CurveAffine, CurveProjective, Group};
|
use group::{cofactor::CofactorCurveAffine, Curve, Group};
|
||||||
use rand_core::SeedableRng;
|
use rand_core::SeedableRng;
|
||||||
use rand_xorshift::XorShiftRng;
|
use rand_xorshift::XorShiftRng;
|
||||||
use std::ops::MulAssign;
|
use std::ops::MulAssign;
|
||||||
|
|
Loading…
Reference in New Issue