-
Notifications
You must be signed in to change notification settings - Fork 254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve ec
traits.
#294
Improve ec
traits.
#294
Conversation
CyclotomicField
to represent cyclotomic operationsec
traits.
ff/src/fields/mod.rs
Outdated
/// Fields that have a cyclotomic subgroup, and which can leverage efficient inversion | ||
/// and squaring operations for elements in this subgroup. | ||
pub trait CyclotomicField: Field { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New field that should be implemented for fields that have more efficient operations for their cyclotomic subgroup, such as faster inverses or squaring.
@@ -50,88 +50,19 @@ impl<P: Fp12Parameters> QuadExtParameters for Fp12ParamsWrapper<P> { | |||
fn mul_base_field_by_frob_coeff(fe: &mut Self::BaseField, power: usize) { | |||
fe.mul_assign_by_fp2(Self::FROBENIUS_COEFF_C1[power % Self::DEGREE_OVER_BASE_PRIME_FIELD]); | |||
} | |||
|
|||
fn cyclotomic_exp(fe: &Fp12<P>, exponent: impl AsRef<[u64]>) -> Fp12<P> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to the CyclotomicField
trait.
} | ||
} | ||
|
||
// TODO: make `const fn` in 1.46. | ||
pub fn characteristic_square_mod_6_is_one(characteristic: &[u64]) -> bool { | ||
pub const fn characteristic_square_mod_6_is_one(characteristic: &[u64]) -> bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can now be a const fn
.
@@ -49,6 +50,15 @@ impl<P: Fp4Parameters> QuadExtParameters for Fp4ParamsWrapper<P> { | |||
|
|||
pub type Fp4<P> = QuadExtField<Fp4ParamsWrapper<P>>; | |||
|
|||
impl<P: Fp4Parameters> CyclotomicField for Fp4<P> { | |||
fn cyclotomic_inverse_in_place(&mut self) -> Option<&mut Self> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same for Fp4.
@@ -23,6 +23,15 @@ pub trait Fp6Parameters: 'static + Send + Sync { | |||
} | |||
} | |||
|
|||
impl<P: Fp6Parameters> CyclotomicField for Fp6<P> { | |||
fn cyclotomic_inverse_in_place(&mut self) -> Option<&mut Self> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think technically we can also have cyclotomic squaring ala Fp12, but I didn't want to implement that in this PR.
|
||
/// A specializable method for exponentiating that is to be used | ||
/// *only* when `fe` is known to be in the cyclotommic subgroup. | ||
fn cyclotomic_exp(fe: &QuadExtField<Self>, exponent: impl AsRef<[u64]>) -> QuadExtField<Self> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no need for this to be in the QuadExtParameters
trait anymore, which simplifies things slightly.
/// This is only to be used when the element is *known* to be in the cyclotomic subgroup. | ||
pub fn cyclotomic_exp(&self, exponent: impl AsRef<[u64]>) -> Self { | ||
P::cyclotomic_exp(self, exponent) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to the CyclotomicField
trait.
@@ -52,7 +52,7 @@ pub(crate) fn mac_discard(a: u64, b: u64, c: u64, carry: &mut u64) { | |||
*carry = (tmp >> 64) as u64; | |||
} | |||
|
|||
pub fn find_wnaf(num: &[u64]) -> Vec<i64> { | |||
pub fn find_wnaf(num: &[u64]) -> Vec<i8> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drive-by improvement to memory consumption of find_wnaf
.
ec/src/models/mod.rs
Outdated
// pub mod bls12; | ||
// pub mod bn; | ||
// pub mod bw6; | ||
// pub mod mnt4; | ||
// pub mod mnt6; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: revert this once things compile.
}; | ||
|
||
use ark_ff::{ | ||
bytes::{FromBytes, ToBytes}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We no longer implement FromBytes
and ToBytes
, as part of a move towards #5.
self.into_projective() == *other | ||
impl<P: Parameters> PartialEq<Projective<P>> for Affine<P> { | ||
fn eq(&self, other: &Projective<P>) -> bool { | ||
Projective::from(*self) == *other |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: specialize this to take advantage of the fact that self.z == 1.
#[inline] | ||
fn default() -> Self { | ||
Self::zero() | ||
} | ||
} | ||
|
||
impl<P: Parameters> GroupProjective<P> { | ||
impl<P: Parameters> Projective<P> { | ||
/// Construct a [`Self`] *without* validating that the coordinates form a valid point. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// [`Explanation of usage`] | ||
/// | ||
/// [`Explanation of usage`]: https://github.com/scipr-lab/zexe/issues/79#issue-556220473 | ||
/// The result of this function is only approximately `ln(a)`. See [here](https://github.com/arkworks-rs/snark/79#issue-556220473) for details. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
drive-by fix
use ark_std::rand::{Rng, distributions::{Distribution, Standard}}; | ||
use crate::*; | ||
|
||
pub trait Pairing: Sized + 'static + Copy + Debug + Sync + Send + Eq { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revampled Pairing
trait.
ec/src/pairing.rs
Outdated
/// An element of G1. | ||
type G1: CurveGroup<ScalarField = Self::ScalarField> | ||
+ MulAssign<Self::ScalarField>; // needed due to https://github.com/rust-lang/rust/issues/69640 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that there is no longer a separate G1Affine
and G1Projective
.
// Sample a random G1 element | ||
let g1 = P::G1::rand(rng); | ||
// Sample a random G2 element | ||
let g2 = P::G2::rand(rng); | ||
P::pairing(g1, g2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sampling a random GT element requires sampling random g1 and g2 elements, and then pairing them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this impacts anything..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it not suffice to sample a random GT element, and then take the final exponentiation on it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good idea, it should work. That can also provide us with a generator, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd only provide generators independent of pairing outputs, which maybe useful sometimes, but most protocols need a generator e(G_1,G_2) if they need a G_t generator at all.
// Sample a random G1 element | ||
let g1 = P::G1::generator(); | ||
// Sample a random G2 element | ||
let g2 = P::G2::generator(); | ||
P::pairing(g1.into(), g2.into()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To obtain the GT generator, we just pair the G1 and G2 generators. Since this value is fixed, we can technically hardcode it, but that requires work, and is also unlikely to really be used anywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ooh I wonder if we should use that for other constants too now...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Atomic laziness incurs a performance hit of like 2ns I hear, but afaik most protocols access their generator only rarely, so whatever. It's more likely recomputation once per thread or once per exec causes pain in WASM or unix CLI binaries, so then the fastest would be pre-computed or if const generics work then
const GENERATOR: Self::UniqueRepr = {
let g1 = P::G1::generator();
let g2 = P::G2::generator();
P::pairing(g1.into(), g2.into())
};
I'd expect const generics to be better by the time anyone cases, so maybe lazycell now with a performance TODO for the future.
As an aside, we've layers of tables that depend upon tables in https://github.com/w3f/rs-ec-perf/ so I used https://gitlab.com/okannen/static_init to avoid the 2ns performance hit, but it brings portability issues so likely unsuitable here. As a further aside, rand had a long discussion around mutable thread locals in rust-random/rand#968
|
||
pub mod msm; | ||
|
||
pub mod wnaf; | ||
|
||
pub trait PairingEngine: Sized + 'static + Copy + Debug + Sync + Send + Eq + PartialEq { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PairingEngine
trait is renamed to Pairing
and the implementation now lives in the pairing
module.
Cyclotomic field work LGTM, I suggest we move that to a standalone PR to avoid a massive PR at the end of the refactor that will be super hard to review |
Co-authored-by: Dev Ojha <[email protected]>
* [*Short Weierstrass*](https://github.com/arkworks-rs/algebra/blob/master/ec/src/models/short_weierstrass_jacobian.rs) curves. The `AffineCurve` in this case is in typical Short Weierstrass point representation, and the `ProjectiveCurve` is using points in [Jacobian Coordinates](https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates). | ||
* [*Twisted Edwards*](https://github.com/arkworks-rs/algebra/blob/master/ec/src/models/twisted_edwards_extended.rs) curves. The `AffineCurve` in this case is in standard Twisted Edwards curve representation, whereas the `ProjectiveCurve` uses points in [Extended Twisted Edwards Coordinates](https://eprint.iacr.org/2008/522.pdf). | ||
* [*Short Weierstrass*](https://github.com/arkworks-rs/algebra/blob/master/ec/src/models/short_weierstrass.rs) curves. The underlying canonical representation uses standard short Weierstrass coordinates, while arithmetic relies on formulae over [Jacobian Coordinates](https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates). | ||
* [*Twisted Edwards*](https://github.com/arkworks-rs/algebra/blob/master/ec/src/models/twisted_edwards.rs) curves. The underlying canonical representation uses standard twisted Edwards coordinates, while arithmetic relies on formulae over [Extended Twisted Edwards Coordinates](https://eprint.iacr.org/2008/522.pdf). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* [*Twisted Edwards*](https://github.com/arkworks-rs/algebra/blob/master/ec/src/models/twisted_edwards.rs) curves. The underlying canonical representation uses standard twisted Edwards coordinates, while arithmetic relies on formulae over [Extended Twisted Edwards Coordinates](https://eprint.iacr.org/2008/522.pdf). | |
* [*Twisted Edwards*](https://github.com/arkworks-rs/algebra/blob/master/ec/src/models/twisted_edwards.rs) curves. The underlying canonical representation uses standard Twisted Edwards coordinates, while arithmetic relies on formulae over [Extended Twisted Edwards Coordinates](https://eprint.iacr.org/2008/522.pdf). |
/// Perform a miller loop with some number of (G1, G2) pairs. | ||
#[must_use] | ||
fn miller_loop<'a>( | ||
i: impl IntoIterator<Item = &'a (Self::G1Prepared, Self::G2Prepared)>, | ||
) -> MillerLoopOutput<Self>; | ||
|
||
/// Perform final exponentiation of the result of a miller loop. | ||
#[must_use] | ||
fn final_exponentiation(mlo: MillerLoopOutput<Self>) -> Option<PairingOutput<Self>>; | ||
|
||
/// Computes a product of pairings. | ||
#[must_use] | ||
fn product_of_pairings<'a>( | ||
i: impl IntoIterator<Item = &'a (Self::G1Prepared, Self::G2Prepared)>, | ||
) -> PairingOutput<Self> { | ||
Self::final_exponentiation(Self::miller_loop(i)).unwrap() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we please use a pair of references instead of a reference to a pair?
impl IntoIterator<Item = (&'a Self::G1Prepared, &'a Self::G2Prepared)>
It's almost impossible to compose this API with others that involve calling the pairing algorithm more than once or using custom data structures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's a good suggestion.
Description
closes: #41.
The aim is to also address #27 and #268.
Before we can merge this PR, please make sure that all the following items have been
checked off. If any of the checklist items are not applicable, please leave them but
write a little note why.
Pending
section inCHANGELOG.md
Files changed
in the Github PR explorer