diff --git a/CHANGELOG.md b/CHANGELOG.md index a632aa4a0..86d2ac9fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,69 +4,78 @@ ### Breaking changes -- [\#300](https://github.com/arkworks-rs/algebra/pull/300) (ark-ec) Change the implementation of `Hash` trait of `GroupProjective` to use the affine coordinates. -- [\#310](https://github.com/arkworks-rs/algebra/pull/310) (ark-ec, ark-ff) Remove unnecessary internal `PhantomData`. -- [\#333](https://github.com/arkworks-rs/algebra/pull/333) (ark-poly) Expose more properties of `EvaluationDomain`s. -- [\#338](https://github.com/arkworks-rs/algebra/pull/338) (ark-ec) Add missing `UniformRand` trait bound to `GroupAffine`. +- [\#300](https://github.com/arkworks-rs/algebra/pull/300) (`ark-ec`) Change the implementation of `Hash` trait of `GroupProjective` to use the affine co-ordinates. +- [\#310](https://github.com/arkworks-rs/algebra/pull/310) (`ark-ec`, `ark-ff`) Remove unnecessary internal `PhantomData`. +- [\#333](https://github.com/arkworks-rs/algebra/pull/333) (`ark-poly`) Expose more properties of `EvaluationDomain`s. +- [\#338](https://github.com/arkworks-rs/algebra/pull/338) (`ark-ec`) Add missing `UniformRand` trait bound to `GroupAffine`. - [\#338](https://github.com/arkworks-rs/algebra/pull/338) (workspace) Change to Rust 2021 edition. -- [\#345](https://github.com/arkworks-rs/algebra/pull/345) (arc-ec, ark-serialize) Change the serialization format for Twisted Edwards Curves. We now encode the Y coordinate and take the sign bit of the X co-ordinate, the default flag is also now the Positive X value. The old methods for backwards compatibility are located [here](https://github.com/arkworks-rs/algebra/pull/345/files#diff-3621a48bb33f469144044d8d5fc663f767e103132a764812cda6be6c25877494R860) -- [\#348](https://github.com/arkworks-rs/algebra/pull/348) (arc-ec) Rename `msm:{Fixed,Variable}BaseMSM:multi_scalar_mul` to `msm:{Fixed,Variable}:msm` to avoid redundancy. +- [\#345](https://github.com/arkworks-rs/algebra/pull/345) (`ark-ec`, `ark-serialize`) Change the serialization format for Twisted Edwards Curves. We now encode the Y co-ordinate and take the sign bit of the X co-ordinate, the default flag is also now the Positive X value. The old methods for backwards compatibility are located [here](https://github.com/arkworks-rs/algebra/pull/345/files#diff-3621a48bb33f469144044d8d5fc663f767e103132a764812cda6be6c25877494R860) +- [\#348](https://github.com/arkworks-rs/algebra/pull/348) (`ark-ec`) Rename `msm:{Fixed,Variable}BaseMSM:multi_scalar_mul` to `msm:{Fixed,Variable}:msm` to avoid redundancy. - [\#359](https://github.com/arkworks-rs/algebra/pull/359) (ark-test-templates) Simplify the field and curve test macros. -- [\#365](https://github.com/arkworks-rs/algebra/pull/365) (arc-ec) +- [\#365](https://github.com/arkworks-rs/algebra/pull/365) (`ark-ec`) - Move `COFACTOR`, `COFACTOR_INV`, and `is_in_correct_subgroup_assuming_on_curve()` from `{SW,TE}ModelParameters` to `ModelParameters`. - Add `mul_bits()` to `AffineCurve` and provide a default implementation of `mul()` using this. - Remove duplicate function `scale_by_cofactor()` from `short_weierstrass_jacobian::GroupAffine` and `twisted_edwards_extended::GroupAffine` - [\#370](https://github.com/arkworks-rs/algebra/pull/370) (all) Set the minimum `rust-version = 1.56` in the manifests of all crates. +- [\#379](https://github.com/arkworks-rs/algebra/pull/379) (`ark-ff`) Refactor `Field` implementation and `PrimeField` trait: + - Switch from hardcoded `FpXYZ` to `Fp` based on `const` generics. + - Move Montgomery arithmetic to an optional backend. + - Rename `field_new` macros to `MontFp`, `QuadExt` and `CubicExt` macros. + - Introduce `const fn`s for generating many constants. + - Add default associated constants to reduce boilerplate. + - Rename `Fp*Parameters` to `Fp*Config`. + - Add `From`, `From`, and `From` `impl`s for `BigInt`. + - Remove `FftConfig`; move its contents to `FftField`. ### Features -- [\#321](https://github.com/arkworks-rs/algebra/pull/321) (ark-ff) Change bigint conversions to impl `From` instead of `Into`. -- [\#301](https://github.com/arkworks-rs/algebra/pull/301) (ark-ec) Add `GLVParameters` trait definition. -- [\#312](https://github.com/arkworks-rs/algebra/pull/312) (ark-ec) Add `is_in_correct_subgroup_assuming_on_curve` for all `SWModelParameters`. -- [\#348](https://github.com/arkworks-rs/algebra/pull/348) (ark-ec) Add `msm:{Fixed,Variable}Base:msm_checked_len`. -- [\#364](https://github.com/arkworks-rs/algebra/pull/364) (ark-ec) Add `ChunkedPippenger` to variable-base MSM. -- [\#371](https://github.com/arkworks-rs/algebra/pull/371) (ark-serialize) Add serialization impls for arrays +- [\#321](https://github.com/arkworks-rs/algebra/pull/321) (`ark-ff`) Change bigint conversions to impl `From` instead of `Into`. +- [\#301](https://github.com/arkworks-rs/algebra/pull/301) (`ark-ec`) Add `GLVParameters` trait definition. +- [\#312](https://github.com/arkworks-rs/algebra/pull/312) (`ark-ec`) Add `is_in_correct_subgroup_assuming_on_curve` for all `SWModelParameters`. +- [\#348](https://github.com/arkworks-rs/algebra/pull/348) (`ark-ec`) Add `msm:{Fixed,Variable}Base:msm_checked_len`. +- [\#364](https://github.com/arkworks-rs/algebra/pull/364) (`ark-ec`) Add `ChunkedPippenger` to variable-base MSM. +- [\#371](https://github.com/arkworks-rs/algebra/pull/371) (`ark-serialize`) Add serialization impls for arrays ### Improvements -- [\#339](https://github.com/arkworks-rs/algebra/pull/339) (ark-ff) Remove duplicated code from `test_field` module and replace its usage with `ark-test-curves` crate. -- [\#352](https://github.com/arkworks-rs/algebra/pull/352) (ark-ff) Update `QuadExtField::sqrt` for better performance. -- [\#357](https://github.com/arkworks-rs/algebra/pull/357) (ark-poly) Speedup division by vanishing polynomials for dense polynomials. +- [\#339](https://github.com/arkworks-rs/algebra/pull/339) (`ark-ff`) Remove duplicated code from `test_field` module and replace its usage with `ark-test-curves` crate. +- [\#352](https://github.com/arkworks-rs/algebra/pull/352) (`ark-ff`) Update `QuadExtField::sqrt` for better performance. +- [\#357](https://github.com/arkworks-rs/algebra/pull/357) (`ark-poly`) Speedup division by vanishing polynomials for dense polynomials. ### Bugfixes -- [\#350](https://github.com/arkworks-rs/algebra/pull/350) (ark-serialize) Fix issues with santiation whenever a non-standard `Result` type is in scope. -- [\#358](https://github.com/arkworks-rs/algebra/pull/358) (ark-ff) Fix the bug for `QuadExtField::sqrt` when `c1 = 0 && c0.legendre.is_qnr()` -- [\#366](https://github.com/arkworks-rs/algebra/pull/366) (ark-ff) Fix `norm()` for cubic extension field towers. +- [\#350](https://github.com/arkworks-rs/algebra/pull/350) (`ark-serialize`) Fix issues with hygiene whenever a non-standard `Result` type is in scope. +- [\#358](https://github.com/arkworks-rs/algebra/pull/358) (`ark-ff`) Fix the bug for `QuadExtField::sqrt` when `c1 = 0 && c0.legendre.is_qnr()` +- [\#366](https://github.com/arkworks-rs/algebra/pull/366) (`ark-ff`) Fix `norm()` for cubic extension field towers. ## v0.3.0 ### Breaking changes -- [\#285](https://github.com/arkworks-rs/algebra/pull/285) (ark-ec) Remove `ATE_LOOP_COUNT_IS_NEGATIVE` from BN curve parameter trait. -- [\#292](https://github.com/arkworks-rs/algebra/pull/292) (ark-ec) Remove `CycleEngine`. -- [\#293](https://github.com/arkworks-rs/algebra/pull/293) (ark-ff) Remove `ark_ff::test_rng`. +- [\#285](https://github.com/arkworks-rs/algebra/pull/285) (`ark-ec`) Remove `ATE_LOOP_COUNT_IS_NEGATIVE` from BN curve parameter trait. +- [\#292](https://github.com/arkworks-rs/algebra/pull/292) (`ark-ec`) Remove `CycleEngine`. +- [\#293](https://github.com/arkworks-rs/algebra/pull/293) (`ark-ff`) Remove `ark_ff::test_rng`. ### Features -- [\#230](https://github.com/arkworks-rs/algebra/pull/230) (ark-ec) Add `wnaf_mul` implementation for `ProjectiveCurve`. -- [\#245](https://github.com/arkworks-rs/algebra/pull/245) (ark-poly) Speedup the sequential and parallel radix-2 FFT and IFFT significantly by making the method in which it accesses roots more cache-friendly. -- [\#258](https://github.com/arkworks-rs/algebra/pull/258) (ark-poly) Add `Mul` implementation for `DensePolynomial`. -- [\#259](https://github.com/arkworks-rs/algebra/pull/259) (ark-poly) Add `Mul` implementation for `SparsePolynomial` and `Add>/Sub>` for `DensePolynomial`. -- [\#261](https://github.com/arkworks-rs/algebra/pull/261) (ark-ff) Add support for 448-bit integers and fields. -- [\#263](https://github.com/arkworks-rs/algebra/pull/263) (ark-ff) Add `From` implementations to fields. +- [\#230](https://github.com/arkworks-rs/algebra/pull/230) (`ark-ec`) Add `wnaf_mul` implementation for `ProjectiveCurve`. +- [\#245](https://github.com/arkworks-rs/algebra/pull/245) (`ark-poly`) Speedup the sequential and parallel radix-2 FFT and IFFT significantly by making the method in which it accesses roots more cache-friendly. +- [\#258](https://github.com/arkworks-rs/algebra/pull/258) (`ark-poly`) Add `Mul` implementation for `DensePolynomial`. +- [\#259](https://github.com/arkworks-rs/algebra/pull/259) (`ark-poly`) Add `Mul` implementation for `SparsePolynomial` and `Add>/Sub>` for `DensePolynomial`. +- [\#261](https://github.com/arkworks-rs/algebra/pull/261) (`ark-ff`) Add support for 448-bit integers and fields. +- [\#263](https://github.com/arkworks-rs/algebra/pull/263) (`ark-ff`) Add `From` implementations to fields. - [\#265](https://github.com/arkworks-rs/algebra/pull/265) (ark-serialize) Add hashing as an extension trait of `CanonicalSerialize`. -- [\#280](https://github.com/arkworks-rs/algebra/pull/280) (ark-ff) Add `Into` and `From` implementations to `BigInteger` and `PrimeField`. -- [\#289](https://github.com/arkworks-rs/algebra/pull/289) (ark-ec) Add `Sum` implementation for all `AffineCurve`. +- [\#280](https://github.com/arkworks-rs/algebra/pull/280) (`ark-ff`) Add `Into` and `From` implementations to `BigInteger` and `PrimeField`. +- [\#289](https://github.com/arkworks-rs/algebra/pull/289) (`ark-ec`) Add `Sum` implementation for all `AffineCurve`. ### Improvements -- [\#279](https://github.com/arkworks-rs/algebra/pull/279) (ark-ec) Parallelize miller loop operations for BLS12. +- [\#279](https://github.com/arkworks-rs/algebra/pull/279) (`ark-ec`) Parallelize miller loop operations for BLS12. ### Bugfixes -- [\#252](https://github.com/arkworks-rs/algebra/pull/252) (ark-ff) Fix prime field sampling when `REPR_SHIFT_BITS` is 64. -- [\#284](https://github.com/arkworks-rs/algebra/pull/284) (ark-poly-benches) Fix the panic `subgroup_fft_in_place` benchmark for MNT6-753's Fr. +- [\#252](https://github.com/arkworks-rs/algebra/pull/252) (`ark-ff`) Fix prime field sampling when `REPR_SHIFT_BITS` is 64. +- [\#284](https://github.com/arkworks-rs/algebra/pull/284) (`ark-poly-benches`) Fix the panic `subgroup_fft_in_place` benchmark for MNT6-753's Fr. ## v0.2.0 @@ -84,95 +93,95 @@ The main features of this release are: ### Breaking changes -- [\#20](https://github.com/arkworks-rs/algebra/pull/20) (ark-poly) Move univariate DensePolynomial and SparsePolynomial into a +- [\#20](https://github.com/arkworks-rs/algebra/pull/20) (`ark-poly`) Move univariate DensePolynomial and SparsePolynomial into a univariate sub-crate. Make this change by: find w/ regular expression `ark_poly::(Dense|Sparse)Polynomial`, and replace with `ark_poly::univariate::$1Polynomial`. -- [\#36](https://github.com/arkworks-rs/algebra/pull/36) (ark-ec) In Short-Weierstrass curves, include an infinity bit in `ToConstraintField`. -- [\#37](https://github.com/arkworks-rs/algebra/pull/37) (ark-poly) In the `Polynomial` trait, add `Hash` trait bound to `Point`. -- [\#38](https://github.com/arkworks-rs/algebra/pull/38) (ark-poly) Add `Add` and `Neg` trait bounds to `Polynomial`. -- [\#51](https://github.com/arkworks-rs/algebra/pull/51) (ark-ff) Removed `unitary_inverse` from `QuadExtField`. Make this change by +- [\#36](https://github.com/arkworks-rs/algebra/pull/36) (`ark-ec`) In Short-Weierstrass curves, include an infinity bit in `ToConstraintField`. +- [\#37](https://github.com/arkworks-rs/algebra/pull/37) (`ark-poly`) In the `Polynomial` trait, add `Hash` trait bound to `Point`. +- [\#38](https://github.com/arkworks-rs/algebra/pull/38) (`ark-poly`) Add `Add` and `Neg` trait bounds to `Polynomial`. +- [\#51](https://github.com/arkworks-rs/algebra/pull/51) (`ark-ff`) Removed `unitary_inverse` from `QuadExtField`. Make this change by replacing `x.unitary_inverse()` with `let mut tmp = x.clone(); tmp.conjugate()`. -- [\#53](https://github.com/arkworks-rs/algebra/pull/53) (ark-poly) Add `Zero` trait bound to `Polynomial`. -- [\#96](https://github.com/arkworks-rs/algebra/pull/96) (ark-ff) Make the `field_new` macro accept values in integer form, without requiring decomposition into limbs, and without requiring encoding in Montgomery form. -- [\#106](https://github.com/arkworks-rs/algebra/pull/106) (ark-ff, ark-ec) Add `Zeroize` trait bound to `Field, ProjectiveGroup, AffineGroup` traits. -- [\#108](https://github.com/arkworks-rs/algebra/pull/108) (ark-ff) Add `extension_degree()` method to `Field`. -- [\#110](https://github.com/arkworks-rs/algebra/pull/110) (ark-ec) Change the trait bound on the scalar for `mul`, from (essentially) `Into` to `AsRef<[u64]>`. -- [\#117](https://github.com/arkworks-rs/algebra/pull/117) (ark-poly) Make the univariate `SparsePolynomial` implement `Polynomial`. Make this change +- [\#53](https://github.com/arkworks-rs/algebra/pull/53) (`ark-poly`) Add `Zero` trait bound to `Polynomial`. +- [\#96](https://github.com/arkworks-rs/algebra/pull/96) (`ark-ff`) Make the `field_new` macro accept values in integer form, without requiring decomposition into limbs, and without requiring encoding in Montgomery form. +- [\#106](https://github.com/arkworks-rs/algebra/pull/106) (`ark-ff`, `ark-ec`) Add `Zeroize` trait bound to `Field, ProjectiveGroup, AffineGroup` traits. +- [\#108](https://github.com/arkworks-rs/algebra/pull/108) (`ark-ff`) Add `extension_degree()` method to `Field`. +- [\#110](https://github.com/arkworks-rs/algebra/pull/110) (`ark-ec`) Change the trait bound on the scalar for `mul`, from (essentially) `Into` to `AsRef<[u64]>`. +- [\#117](https://github.com/arkworks-rs/algebra/pull/117) (`ark-poly`) Make the univariate `SparsePolynomial` implement `Polynomial`. Make this change by replacing `sparse_poly.evaluate(pt)` to `sparse_poly.evaluate(&pt)`. -- [\#129](https://github.com/arkworks-rs/algebra/pull/129) (ark-ff) Move `ark_ff::{UniformRand, test_rng}` to `ark_std::{UniformRand, test_rng}`. +- [\#129](https://github.com/arkworks-rs/algebra/pull/129) (`ark-ff`) Move `ark_ff::{UniformRand, test_rng}` to `ark_std::{UniformRand, test_rng}`. Importing these from `ark-ff` is still possible, but is deprecated and will be removed in the following release. -- [\#144](https://github.com/arkworks-rs/algebra/pull/144) (ark-poly) Add `CanonicalSerialize` and `CanonicalDeserialize` trait bounds for `Polynomial`. -- [\#160](https://github.com/arkworks-rs/algebra/pull/160) (ark-serialize, ark-ff, ark-ec) +- [\#144](https://github.com/arkworks-rs/algebra/pull/144) (`ark-poly`) Add `CanonicalSerialize` and `CanonicalDeserialize` trait bounds for `Polynomial`. +- [\#160](https://github.com/arkworks-rs/algebra/pull/160) (`ark-serialize`, `ark-ff`, `ark-ec`) - Remove `ConstantSerializedSize`; users should use `serialized_size*` (see next). - Add `serialized_size_with_flags` method to `CanonicalSerializeWithFlags`. - Change `from_random_bytes_with_flags` to output `ark_serialize::Flags`. - Change signatures of `Flags::from_u8*` to output `Option`. - - Change `Flags::from_u8*` to be more strict about the inputs they accept: + - Change `Flags::from_u8*` to be more strict about the inputs it accepts: if the top bits of the `u8` value do *not* correspond to one of the possible outputs of `Flags::u8_bitmask`, then these methods output `None`, whereas before they output a default value. Downstream users other than `ark-curves` should not see breakage unless they rely on these methods/traits explicitly. -- [\#165](https://github.com/arkworks-rs/algebra/pull/165) (ark-ff) Add `from_base_field_elements` as a method to the `Field` trait. -- [\#166](https://github.com/arkworks-rs/algebra/pull/166) (ark-ff) Change `BigInt::{from_bytes, to_bits}` to `from_bytes_le, from_bytes_be, to_bits_le, to_bits_be`. +- [\#165](https://github.com/arkworks-rs/algebra/pull/165) (`ark-ff`) Add `from_base_field_elements` as a method to the `Field` trait. +- [\#166](https://github.com/arkworks-rs/algebra/pull/166) (`ark-ff`) Change `BigInt::{from_bytes, to_bits}` to `from_bytes_le, from_bytes_be, to_bits_le, to_bits_be`. ### Features -- [\#20](https://github.com/arkworks-rs/algebra/pull/20) (ark-poly) Add structs/traits for multivariate polynomials. -- [\#96](https://github.com/arkworks-rs/algebra/pull/96) (ark-ff) Make the `field_new` macro accept values in integer form, without requiring decomposition into limbs, and without requiring encoding in Montgomery form. -- [\#106](https://github.com/arkworks-rs/algebra/pull/106) (ark-ff, ark-ec) Add `Zeroize` trait bound to `Field, ProjectiveGroup, AffineGroup` traits. -- [\#117](https://github.com/arkworks-rs/algebra/pull/117) (ark-poly) Add operations to `SparsePolynomial`, so it implements `Polynomial`. -- [\#140](https://github.com/arkworks-rs/algebra/pull/140) (ark-poly) Add support for multilinear extensions in dense and sparse evaluation form. -- [\#164](https://github.com/arkworks-rs/algebra/pull/164) (ark-ff) Add methods `from_{be, le}_bytes_mod_order` to the `PrimeField` trait. -- [\#197](https://github.com/arkworks-rs/algebra/pull/197) (ark-test-curves) Add a BN384 curve with low two-arity for mixed-radix testing. +- [\#20](https://github.com/arkworks-rs/algebra/pull/20) (`ark-poly`) Add structs/traits for multivariate polynomials. +- [\#96](https://github.com/arkworks-rs/algebra/pull/96) (`ark-ff`) Make the `field_new` macro accept values in integer form, without requiring decomposition into limbs, and without requiring encoding in Montgomery form. +- [\#106](https://github.com/arkworks-rs/algebra/pull/106) (`ark-ff`, `ark-ec`) Add `Zeroize` trait bound to `Field, ProjectiveGroup, AffineGroup` traits. +- [\#117](https://github.com/arkworks-rs/algebra/pull/117) (`ark-poly`) Add operations to `SparsePolynomial`, so it implements `Polynomial`. +- [\#140](https://github.com/arkworks-rs/algebra/pull/140) (`ark-poly`) Add support for multilinear extensions in dense and sparse evaluation form. +- [\#164](https://github.com/arkworks-rs/algebra/pull/164) (`ark-ff`) Add methods `from_{be, le}_bytes_mod_order` to the `PrimeField` trait. +- [\#197](https://github.com/arkworks-rs/algebra/pull/197) (`ark-test-curves`) Add a BN384 curve with low two-adicity for mixed-radix testing. ### Improvements -- [\#22](https://github.com/arkworks-rs/algebra/pull/22) (ark-ec) Speedup fixed-base MSMs. -- [\#28](https://github.com/arkworks-rs/algebra/pull/28) (ark-poly) Add `domain()` method on the `evaluations` struct. -- [\#31](https://github.com/arkworks-rs/algebra/pull/31) (ark-ec) Speedup point doubling on twisted edwards curves. -- [\#35](https://github.com/arkworks-rs/algebra/pull/35) (ark-ff) Implement `ToConstraintField` for `bool`. -- [\#48](https://github.com/arkworks-rs/algebra/pull/48) (ark-ff) Speedup `sqrt` on `QuadExtField`. -- [\#94](https://github.com/arkworks-rs/algebra/pull/94) (ark-ff) Implement `ToBytes` and `FromBytes` for `u128`. -- [\#99](https://github.com/arkworks-rs/algebra/pull/99) (ark-poly) Speedup `evaluate_all_lagrange_coefficients`. -- [\#100](https://github.com/arkworks-rs/algebra/pull/100) (ark-ff) Implement `batch_inverse_and_mul`. -- [\#101](https://github.com/arkworks-rs/algebra/pull/101) (ark-ff) Add `element(i: usize)` on the `Domain` trait. -- [\#107](https://github.com/arkworks-rs/algebra/pull/107) (ark-serialize) Add an impl of `CanonicalSerialize/Deserialize` for `BTreeSet`. -- [\#114](https://github.com/arkworks-rs/algebra/pull/114) (ark-poly) Significantly speedup and reduce memory usage of `DensePolynomial.evaluate`. -- [\#114](https://github.com/arkworks-rs/algebra/pull/114), #119 (ark-poly) Add infrastructure for benchmarking `DensePolynomial` operations. -- [\#115](https://github.com/arkworks-rs/algebra/pull/115) (ark-poly) Add parallel implementation to operations on `Evaluations`. -- [\#115](https://github.com/arkworks-rs/algebra/pull/115) (ark-ff) Add parallel implementation of `batch_inversion`. -- [\#122](https://github.com/arkworks-rs/algebra/pull/122) (ark-poly) Add infrastructure for benchmarking `FFT`s. -- [\#125](https://github.com/arkworks-rs/algebra/pull/125) (ark-poly) Add parallelization to applying coset shifts within `coset_fft`. -- [\#126](https://github.com/arkworks-rs/algebra/pull/126) (ark-ec) Use `ark_ff::batch_inversion` for point normalization. -- [\#131](https://github.com/arkworks-rs/algebra/pull/131), #137 (ark-ff) Speedup `sqrt` on fields when a square root exists. (And slows it down when doesn't exist.) -- [\#141](https://github.com/arkworks-rs/algebra/pull/141) (ark-ff) Add `Fp64`. -- [\#144](https://github.com/arkworks-rs/algebra/pull/144) (ark-poly) Add serialization for polynomials and evaluations. -- [\#149](https://github.com/arkworks-rs/algebra/pull/149) (ark-serialize) Add an impl of `CanonicalSerialize/Deserialize` for `String`. -- [\#153](https://github.com/arkworks-rs/algebra/pull/153) (ark-serialize) Add an impl of `CanonicalSerialize/Deserialize` for `Rc`. -- [\#157](https://github.com/arkworks-rs/algebra/pull/157) (ark-ec) Speed up `variable_base_msm` by not relying on unnecessary normalization. -- [\#158](https://github.com/arkworks-rs/algebra/pull/158) (ark-serialize) Add an impl of `CanonicalSerialize/Deserialize` for `()`. -- [\#166](https://github.com/arkworks-rs/algebra/pull/166) (ark-ff) Add a `to_bytes_be()` and `to_bytes_le` methods to `BigInt`. -- [\#169](https://github.com/arkworks-rs/algebra/pull/169) (ark-poly) Improve radix-2 FFTs by moving to a faster algorithm by Riad S. Wahby. -- [\#171](https://github.com/arkworks-rs/algebra/pull/171), #173, #176 (ark-poly) Apply significant further speedups to the new radix-2 FFT. -- [\#188](https://github.com/arkworks-rs/algebra/pull/188) (ark-ec) Make Short Weierstrass random sampling result in an element with unknown discrete log. -- [\#190](https://github.com/arkworks-rs/algebra/pull/190) (ark-ec) Add curve cycle trait and extended pairing cycle trait for all types of ec cycles. -- [\#201](https://github.com/arkworks-rs/algebra/pull/201) (ark-ec, ark-ff, ark-test-curves, ark-test-templates) Remove the dependency on `rand_xorshift`. -- [\#205](https://github.com/arkworks-rs/algebra/pull/205) (ark-ec, ark-ff) Unroll loops and conditionally use intrinsics in `biginteger` arithmetic, and reduce copies in `ff` and `ec` arithmetic. -- [\#207](https://github.com/arkworks-rs/algebra/pull/207) (ark-ff) Improve performance of extension fields when the non-residue is negative. (Improves fq2, fq12, and g2 speed on bls12 and bn curves.) -- [\#211](https://github.com/arkworks-rs/algebra/pull/211) (ark-ec) Improve performance of BLS12 final exponentiation. -- [\#214](https://github.com/arkworks-rs/algebra/pull/214) (ark-poly) Utilise a more efficient way of evaluating a polynomial at a single point. -- [\#242](https://github.com/arkworks-rs/algebra/pull/242), [\#244][https://github.com/arkworks-rs/algebra/pull/244] (ark-poly) Speedup the sequential radix-2 FFT significantly by making the method in which it accesses roots more cache-friendly. +- [\#22](https://github.com/arkworks-rs/algebra/pull/22) (`ark-ec`) Speedup fixed-base MSMs. +- [\#28](https://github.com/arkworks-rs/algebra/pull/28) (`ark-poly`) Add `domain()` method on the `evaluations` struct. +- [\#31](https://github.com/arkworks-rs/algebra/pull/31) (`ark-ec`) Speedup point doubling on twisted edwards curves. +- [\#35](https://github.com/arkworks-rs/algebra/pull/35) (`ark-ff`) Implement `ToConstraintField` for `bool`. +- [\#48](https://github.com/arkworks-rs/algebra/pull/48) (`ark-ff`) Speedup `sqrt` on `QuadExtField`. +- [\#94](https://github.com/arkworks-rs/algebra/pull/94) (`ark-ff`) Implement `ToBytes` and `FromBytes` for `u128`. +- [\#99](https://github.com/arkworks-rs/algebra/pull/99) (`ark-poly`) Speedup `evaluate_all_lagrange_coefficients`. +- [\#100](https://github.com/arkworks-rs/algebra/pull/100) (`ark-ff`) Implement `batch_inverse_and_mul`. +- [\#101](https://github.com/arkworks-rs/algebra/pull/101) (`ark-ff`) Add `element(i: usize)` on the `Domain` trait. +- [\#107](https://github.com/arkworks-rs/algebra/pull/107) (`ark-serialize`) Add an impl of `CanonicalSerialize/Deserialize` for `BTreeSet`. +- [\#114](https://github.com/arkworks-rs/algebra/pull/114) (`ark-poly`) Significantly speedup and reduce memory usage of `DensePolynomial.evaluate`. +- [\#114](https://github.com/arkworks-rs/algebra/pull/114), #119 (`ark-poly`) Add infrastructure for benchmarking `DensePolynomial` operations. +- [\#115](https://github.com/arkworks-rs/algebra/pull/115) (`ark-poly`) Add parallel implementation to operations on `Evaluations`. +- [\#115](https://github.com/arkworks-rs/algebra/pull/115) (`ark-ff`) Add parallel implementation of `batch_inversion`. +- [\#122](https://github.com/arkworks-rs/algebra/pull/122) (`ark-poly`) Add infrastructure for benchmarking `FFT`s. +- [\#125](https://github.com/arkworks-rs/algebra/pull/125) (`ark-poly`) Add parallelization to applying coset shifts within `coset_fft`. +- [\#126](https://github.com/arkworks-rs/algebra/pull/126) (`ark-ec`) Use `ark_ff::batch_inversion` for point normalization. +- [\#131](https://github.com/arkworks-rs/algebra/pull/131), #137 (`ark-ff`) Speedup `sqrt` on fields when a square root exists. (And slows it down when doesn't exist.) +- [\#141](https://github.com/arkworks-rs/algebra/pull/141) (`ark-ff`) Add `Fp64`. +- [\#144](https://github.com/arkworks-rs/algebra/pull/144) (`ark-poly`) Add serialization for polynomials and evaluations. +- [\#149](https://github.com/arkworks-rs/algebra/pull/149) (`ark-serialize`) Add an impl of `CanonicalSerialize/Deserialize` for `String`. +- [\#153](https://github.com/arkworks-rs/algebra/pull/153) (`ark-serialize`) Add an impl of `CanonicalSerialize/Deserialize` for `Rc`. +- [\#157](https://github.com/arkworks-rs/algebra/pull/157) (`ark-ec`) Speed up `variable_base_msm` by not relying on unnecessary normalization. +- [\#158](https://github.com/arkworks-rs/algebra/pull/158) (`ark-serialize`) Add an impl of `CanonicalSerialize/Deserialize` for `()`. +- [\#166](https://github.com/arkworks-rs/algebra/pull/166) (`ark-ff`) Add a `to_bytes_be()` and `to_bytes_le` methods to `BigInt`. +- [\#169](https://github.com/arkworks-rs/algebra/pull/169) (`ark-poly`) Improve radix-2 FFTs by moving to a faster algorithm by Riad S. Wahby. +- [\#171](https://github.com/arkworks-rs/algebra/pull/171), #173, #176 (`ark-poly`) Apply significant further speedups to the new radix-2 FFT. +- [\#188](https://github.com/arkworks-rs/algebra/pull/188) (`ark-ec`) Make Short Weierstrass random sampling result in an element with unknown discrete log. +- [\#190](https://github.com/arkworks-rs/algebra/pull/190) (`ark-ec`) Add curve cycle trait and extended pairing cycle trait for all types of ec cycles. +- [\#201](https://github.com/arkworks-rs/algebra/pull/201) (`ark-ec`, `ark-ff`, `ark-test-curves`, `ark-test-templates`) Remove the dependency on `rand_xorshift`. +- [\#205](https://github.com/arkworks-rs/algebra/pull/205) (`ark-ec`, `ark-ff`) Unroll loops and conditionally use intrinsics in `biginteger` arithmetic, and reduce copies in `ff` and `ec` arithmetic. +- [\#207](https://github.com/arkworks-rs/algebra/pull/207) (`ark-ff`) Improve performance of extension fields when the non-residue is negative. (Improves fq2, fq12, and g2 speed on bls12 and bn curves.) +- [\#211](https://github.com/arkworks-rs/algebra/pull/211) (`ark-ec`) Improve performance of BLS12 final exponentiation. +- [\#214](https://github.com/arkworks-rs/algebra/pull/214) (`ark-poly`) Utilise a more efficient way of evaluating a polynomial at a single point. +- [\#242](https://github.com/arkworks-rs/algebra/pull/242), [\#244][https://github.com/arkworks-rs/algebra/pull/244] (`ark-poly`) Speedup the sequential radix-2 FFT significantly by making the method in which it accesses roots more cache-friendly. ### Bugfixes -- [\#36](https://github.com/arkworks-rs/algebra/pull/36) (ark-ec) In Short-Weierstrass curves, include an infinity bit in `ToConstraintField`. -- [\#107](https://github.com/arkworks-rs/algebra/pull/107) (ark-serialize) Fix handling of `(de)serialize_uncompressed/unchecked` in various impls of `CanonicalSerialize/Deserialize`. -- [\#112](https://github.com/arkworks-rs/algebra/pull/112) (ark-serialize) Make `bool`s checked serialization methods non-malleable. -- [\#119](https://github.com/arkworks-rs/algebra/pull/119) (ark-poly) Fix bugs in degree calculation if adding/subtracting same degree polynomials +- [\#36](https://github.com/arkworks-rs/algebra/pull/36) (`ark-ec`) In Short-Weierstrass curves, include an infinity bit in `ToConstraintField`. +- [\#107](https://github.com/arkworks-rs/algebra/pull/107) (`ark-serialize`) Fix handling of `(de)serialize_uncompressed/unchecked` in various impls of `CanonicalSerialize/Deserialize`. +- [\#112](https://github.com/arkworks-rs/algebra/pull/112) (`ark-serialize`) Make `bool`s checked serialization methods non-malleable. +- [\#119](https://github.com/arkworks-rs/algebra/pull/119) (`ark-poly`) Fix bugs in degree calculation if adding/subtracting same degree polynomials whose leading coefficients cancel. -- [\#160](https://github.com/arkworks-rs/algebra/pull/160) (ark-serialize, ark-ff, ark-ec) Support serializing when `MODULUS_BITS + FLAG_BITS` is greater than the multiple of 8 just greater than `MODULUS_BITS`, which is the case for the Pasta curves (fixes #47). -- [\#165](https://github.com/arkworks-rs/algebra/pull/165) (ark-ff) Enforce in the type system that an extension fields `BaseField` extends from the correct `BasePrimeField`. +- [\#160](https://github.com/arkworks-rs/algebra/pull/160) (`ark-serialize`, `ark-ff`, `ark-ec`) Support serializing when `MODULUS_BITS + FLAG_BITS` is greater than the multiple of 8 just greater than `MODULUS_BITS`, which is the case for the Pasta curves (fixes #47). +- [\#165](https://github.com/arkworks-rs/algebra/pull/165) (`ark-ff`) Enforce in the type system that an extension fields `BaseField` extends from the correct `BasePrimeField`. - [\#184](https://github.com/arkworks-rs/algebra/pull/184) Compile with `panic='abort'` in release mode, for safety of the library across FFI boundaries. - [\#192](https://github.com/arkworks-rs/algebra/pull/192) Fix a bug in the assembly backend for finite field arithmetic. -- [\#217](https://github.com/arkworks-rs/algebra/pull/217) (ark-ec) Fix the definition of `PairingFriendlyCycle` introduced in #190. +- [\#217](https://github.com/arkworks-rs/algebra/pull/217) (`ark-ec`) Fix the definition of `PairingFriendlyCycle` introduced in #190. ## v0.1.0 (Initial release of arkworks/algebra) diff --git a/ec/Cargo.toml b/ec/Cargo.toml index df329fee9..8cb1aded5 100644 --- a/ec/Cargo.toml +++ b/ec/Cargo.toml @@ -11,7 +11,7 @@ categories = ["cryptography"] include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] license = "MIT/Apache-2.0" edition = "2021" -rust-version = "1.56" +rust-version = "1.57" [dependencies] ark-std = { version = "^0.3.0", default-features = false } diff --git a/ec/src/models/bls12/mod.rs b/ec/src/models/bls12/mod.rs index e5b1c50e9..2918c0813 100644 --- a/ec/src/models/bls12/mod.rs +++ b/ec/src/models/bls12/mod.rs @@ -4,8 +4,8 @@ use crate::{ }; use ark_ff::fields::{ fp12_2over3over2::{Fp12, Fp12Parameters}, - fp2::Fp2Parameters, - fp6_3over2::Fp6Parameters, + fp2::Fp2Config, + fp6_3over2::Fp6Config, BitIteratorBE, Field, Fp2, PrimeField, SquareRootField, }; use core::marker::PhantomData; @@ -34,8 +34,8 @@ pub trait Bls12Parameters: 'static { const TWIST_TYPE: TwistType; type Fp: PrimeField + SquareRootField + Into<::BigInt>; - type Fp2Params: Fp2Parameters; - type Fp6Params: Fp6Parameters; + type Fp2Params: Fp2Config; + type Fp6Params: Fp6Config; type Fp12Params: Fp12Parameters; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< @@ -68,12 +68,12 @@ impl Bls12

{ c2.mul_assign_by_fp(&p.y); c1.mul_assign_by_fp(&p.x); f.mul_by_014(&c0, &c1, &c2); - } + }, TwistType::D => { c0.mul_assign_by_fp(&p.y); c1.mul_assign_by_fp(&p.x); f.mul_by_034(&c0, &c1, &c2); - } + }, } } diff --git a/ec/src/models/bn/g2.rs b/ec/src/models/bn/g2.rs index f8e8c91de..6087079de 100644 --- a/ec/src/models/bn/g2.rs +++ b/ec/src/models/bn/g2.rs @@ -92,10 +92,10 @@ impl From> for G2Prepared

{ match bit { 1 => { ell_coeffs.push(addition_step::

(&mut r, &q)); - } + }, -1 => { ell_coeffs.push(addition_step::

(&mut r, &negq)); - } + }, _ => continue, } } diff --git a/ec/src/models/bn/mod.rs b/ec/src/models/bn/mod.rs index 7e1751797..9c243ab3b 100644 --- a/ec/src/models/bn/mod.rs +++ b/ec/src/models/bn/mod.rs @@ -4,8 +4,8 @@ use crate::{ }; use ark_ff::fields::{ fp12_2over3over2::{Fp12, Fp12Parameters}, - fp2::Fp2Parameters, - fp6_3over2::Fp6Parameters, + fp2::Fp2Config, + fp6_3over2::Fp6Config, Field, Fp2, PrimeField, SquareRootField, }; use num_traits::One; @@ -32,8 +32,8 @@ pub trait BnParameters: 'static { const TWIST_MUL_BY_Q_X: Fp2; const TWIST_MUL_BY_Q_Y: Fp2; type Fp: PrimeField + SquareRootField + Into<::BigInt>; - type Fp2Params: Fp2Parameters; - type Fp6Params: Fp6Parameters; + type Fp2Params: Fp2Config; + type Fp6Params: Fp6Config; type Fp12Params: Fp12Parameters; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< @@ -66,12 +66,12 @@ impl Bn

{ c2.mul_assign_by_fp(&p.y); c1.mul_assign_by_fp(&p.x); f.mul_by_014(&c0, &c1, &c2); - } + }, TwistType::D => { c0.mul_assign_by_fp(&p.y); c1.mul_assign_by_fp(&p.x); f.mul_by_034(&c0, &c1, &c2); - } + }, } } @@ -124,12 +124,12 @@ impl PairingEngine for Bn

{ for &mut (p, ref mut coeffs) in &mut pairs { Self::ell(&mut f, coeffs.next().unwrap(), &p.0); } - } + }, -1 => { for &mut (p, ref mut coeffs) in &mut pairs { Self::ell(&mut f, coeffs.next().unwrap(), &p.0); } - } + }, _ => continue, } } diff --git a/ec/src/models/bw6/g2.rs b/ec/src/models/bw6/g2.rs index 68fbacfbc..ba240f477 100644 --- a/ec/src/models/bw6/g2.rs +++ b/ec/src/models/bw6/g2.rs @@ -112,10 +112,10 @@ impl From> for G2Prepared

{ match bit { 1 => { ell_coeffs_2.push(addition_step::

(&mut r, &q)); - } + }, -1 => { ell_coeffs_2.push(addition_step::

(&mut r, &negq)); - } + }, _ => continue, } } diff --git a/ec/src/models/bw6/mod.rs b/ec/src/models/bw6/mod.rs index ff2726e10..b4b6e8fa4 100644 --- a/ec/src/models/bw6/mod.rs +++ b/ec/src/models/bw6/mod.rs @@ -3,8 +3,8 @@ use crate::{ PairingEngine, }; use ark_ff::fields::{ - fp3::Fp3Parameters, - fp6_2over3::{Fp6, Fp6Parameters}, + fp3::Fp3Config, + fp6_2over3::{Fp6, Fp6Config}, BitIteratorBE, Field, PrimeField, SquareRootField, }; use num_traits::One; @@ -25,8 +25,8 @@ pub trait BW6Parameters: 'static + Eq + PartialEq { const ATE_LOOP_COUNT_2_IS_NEGATIVE: bool; const TWIST_TYPE: TwistType; type Fp: PrimeField + SquareRootField + Into<::BigInt>; - type Fp3Params: Fp3Parameters; - type Fp6Params: Fp6Parameters; + type Fp3Params: Fp3Config; + type Fp6Params: Fp6Config; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< BaseField = Self::Fp, @@ -58,12 +58,12 @@ impl BW6

{ c2 *= &p.y; c1 *= &p.x; f.mul_by_014(&c0, &c1, &c2); - } + }, TwistType::D => { c0 *= &p.y; c1 *= &p.x; f.mul_by_034(&c0, &c1, &c2); - } + }, } } @@ -274,12 +274,12 @@ impl PairingEngine for BW6

{ for &mut (p, ref mut coeffs) in &mut pairs_2 { Self::ell(&mut f_2, coeffs.next().unwrap(), &p.0); } - } + }, -1 => { for &mut (p, ref mut coeffs) in &mut pairs_2 { Self::ell(&mut f_2, coeffs.next().unwrap(), &p.0); } - } + }, _ => continue, } } diff --git a/ec/src/models/mnt4/mod.rs b/ec/src/models/mnt4/mod.rs index ea73fdcb2..1bce34496 100644 --- a/ec/src/models/mnt4/mod.rs +++ b/ec/src/models/mnt4/mod.rs @@ -3,8 +3,8 @@ use crate::{ PairingEngine, }; use ark_ff::{ - fp2::{Fp2, Fp2Parameters}, - fp4::{Fp4, Fp4Parameters}, + fp2::{Fp2, Fp2Config}, + fp4::{Fp4, Fp4Config}, BitIteratorBE, Field, PrimeField, SquareRootField, }; use num_traits::{One, Zero}; @@ -32,8 +32,8 @@ pub trait MNT4Parameters: 'static { const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: ::BigInt; type Fp: PrimeField + SquareRootField + Into<::BigInt>; type Fr: PrimeField + SquareRootField + Into<::BigInt>; - type Fp2Params: Fp2Parameters; - type Fp4Params: Fp4Parameters; + type Fp2Params: Fp2Config; + type Fp4Params: Fp4Config; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< BaseField = Fp2, diff --git a/ec/src/models/mnt6/mod.rs b/ec/src/models/mnt6/mod.rs index fe1efa8cb..d8afe31a6 100644 --- a/ec/src/models/mnt6/mod.rs +++ b/ec/src/models/mnt6/mod.rs @@ -3,8 +3,8 @@ use crate::{ PairingEngine, }; use ark_ff::{ - fp3::{Fp3, Fp3Parameters}, - fp6_2over3::{Fp6, Fp6Parameters}, + fp3::{Fp3, Fp3Config}, + fp6_2over3::{Fp6, Fp6Config}, BitIteratorBE, Field, PrimeField, SquareRootField, }; use num_traits::{One, Zero}; @@ -32,8 +32,8 @@ pub trait MNT6Parameters: 'static { const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: ::BigInt; type Fp: PrimeField + SquareRootField + Into<::BigInt>; type Fr: PrimeField + SquareRootField + Into<::BigInt>; - type Fp3Params: Fp3Parameters; - type Fp6Params: Fp6Parameters; + type Fp3Params: Fp3Config; + type Fp6Params: Fp6Config; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< BaseField = Fp3, diff --git a/ec/src/models/short_weierstrass_jacobian.rs b/ec/src/models/short_weierstrass_jacobian.rs index 0c1918bd6..677d6fc68 100644 --- a/ec/src/models/short_weierstrass_jacobian.rs +++ b/ec/src/models/short_weierstrass_jacobian.rs @@ -688,7 +688,7 @@ impl<'a, P: Parameters> SubAssign<&'a Self> for GroupProjective

{ impl MulAssign for GroupProjective

{ fn mul_assign(&mut self, other: P::ScalarField) { - *self = self.mul(other.into_repr()) + *self = self.mul(other.into_bigint()) } } diff --git a/ec/src/models/twisted_edwards_extended.rs b/ec/src/models/twisted_edwards_extended.rs index 8f42fe222..ef0aefea2 100644 --- a/ec/src/models/twisted_edwards_extended.rs +++ b/ec/src/models/twisted_edwards_extended.rs @@ -200,7 +200,7 @@ impl<'a, P: Parameters> SubAssign<&'a Self> for GroupAffine

{ impl MulAssign for GroupAffine

{ fn mul_assign(&mut self, other: P::ScalarField) { - *self = self.mul(other.into_repr()).into() + *self = self.mul(other.into_bigint()).into() } } @@ -583,7 +583,7 @@ impl<'a, P: Parameters> SubAssign<&'a Self> for GroupProjective

{ impl MulAssign for GroupProjective

{ fn mul_assign(&mut self, other: P::ScalarField) { - *self = self.mul(other.into_repr()) + *self = self.mul(other.into_bigint()) } } diff --git a/ec/src/msm/fixed_base.rs b/ec/src/msm/fixed_base.rs index 27360fe38..09d9f6189 100644 --- a/ec/src/msm/fixed_base.rs +++ b/ec/src/msm/fixed_base.rs @@ -1,5 +1,5 @@ use crate::{AffineCurve, ProjectiveCurve}; -use ark_ff::{BigInteger, FpParameters, PrimeField}; +use ark_ff::{BigInteger, PrimeField}; use ark_std::{cfg_iter, cfg_iter_mut, vec::Vec}; #[cfg(feature = "parallel")] @@ -63,8 +63,8 @@ impl FixedBase { multiples_of_g: &[Vec], scalar: &T::ScalarField, ) -> T { - let modulus_size = ::Params::MODULUS_BITS as usize; - let scalar_val = scalar.into_repr().to_bits_le(); + let modulus_size = T::ScalarField::MODULUS_BIT_SIZE as usize; + let scalar_val = scalar.into_bigint().to_bits_le(); let mut res = multiples_of_g[0][0].into_projective(); for outer in 0..outerc { diff --git a/ec/src/msm/variable_base/mod.rs b/ec/src/msm/variable_base/mod.rs index 59593f379..76ffcb9eb 100644 --- a/ec/src/msm/variable_base/mod.rs +++ b/ec/src/msm/variable_base/mod.rs @@ -47,8 +47,8 @@ impl VariableBase { super::ln_without_floats(size) + 2 }; - let num_bits = ::Params::MODULUS_BITS as usize; - let fr_one = G::ScalarField::one().into_repr(); + let num_bits = G::ScalarField::MODULUS_BIT_SIZE as usize; + let fr_one = G::ScalarField::one().into_bigint(); let zero = G::Projective::zero(); let window_starts: Vec<_> = (0..num_bits).step_by(c).collect(); diff --git a/ec/src/wnaf.rs b/ec/src/wnaf.rs index 1cfec156a..eda40a78e 100644 --- a/ec/src/wnaf.rs +++ b/ec/src/wnaf.rs @@ -52,7 +52,7 @@ impl WnafContext { if 1 << (self.window_size - 1) > base_table.len() { return None; } - let scalar_wnaf = scalar.into_repr().find_wnaf(self.window_size).unwrap(); + let scalar_wnaf = scalar.into_bigint().find_wnaf(self.window_size).unwrap(); let mut result = G::zero(); diff --git a/ff-asm/Cargo.toml b/ff-asm/Cargo.toml index 3cb833a2e..56b375a77 100644 --- a/ff-asm/Cargo.toml +++ b/ff-asm/Cargo.toml @@ -11,7 +11,7 @@ categories = ["cryptography"] include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] license = "MIT/Apache-2.0" edition = "2021" -rust-version = "1.56" +rust-version = "1.57" [dependencies] quote = "1.0.0" diff --git a/ff-asm/src/lib.rs b/ff-asm/src/lib.rs index 9a24909b6..30a9334af 100644 --- a/ff-asm/src/lib.rs +++ b/ff-asm/src/lib.rs @@ -298,9 +298,9 @@ fn generate_impl(num_limbs: usize, is_mul: bool) -> String { if is_mul { ctx.add_declaration("b", "r", "b"); } - ctx.add_declaration("modulus", "r", "&P::MODULUS.0"); + ctx.add_declaration("modulus", "r", "&Self::MODULUS.0"); ctx.add_declaration("0", "i", "0u64"); - ctx.add_declaration("mod_prime", "i", "P::INV"); + ctx.add_declaration("mod_prime", "i", "Self::INV"); if num_limbs > MAX_REGS { ctx.add_buffer(2 * num_limbs); diff --git a/ff/Cargo.toml b/ff/Cargo.toml index 0a3fcfd39..fe6f1e793 100644 --- a/ff/Cargo.toml +++ b/ff/Cargo.toml @@ -12,7 +12,7 @@ include = ["Cargo.toml", "build.rs", "src", "README.md", "LICENSE-APACHE", "LICE license = "MIT/Apache-2.0" edition = "2021" build = "build.rs" -rust-version = "1.56" +rust-version = "1.57" [dependencies] ark-ff-asm = { version = "^0.3.0", path = "../ff-asm" } diff --git a/ff/README.md b/ff/README.md index 28e4c16d0..3369e497a 100644 --- a/ff/README.md +++ b/ff/README.md @@ -7,28 +7,28 @@

This crate defines Finite Field traits and useful abstraction models that follow these traits. -Implementations of finite fields with concrete parameters can be found in [`arkworks-rs/curves`](https://github.com/arkworks-rs/curves/README.md) under `arkworks-rs/curves//src/fields/`, which are used for some of the popular curves, such as a specific [`Fq`](https://github.com/arkworks-rs/curves/blob/master/bls12_381/src/fields/fq.rs) used in BLS-381. +Implementations of concrete finite fields for some popular elliptic curves can be found in [`arkworks-rs/curves`](https://github.com/arkworks-rs/curves/README.md) under `arkworks-rs/curves//src/fields/`. This crate contains two types of traits: - `Field` traits: These define interfaces for manipulating field elements, such as addition, multiplication, inverses, square roots, and more. -- Field Parameters: holds the parameters defining the field in question. For extension fields, it also provides additional functionality required for the field, such as operations involving a (cubic or quadratic) non-residue used for constructing the field (`NONRESIDUE`). +- Field `Config`s: specifies the parameters defining the field in question. For extension fields, it also provides additional functionality required for the field, such as operations involving a (cubic or quadratic) non-residue used for constructing the field (`NONRESIDUE`). The available field traits are: -- [`Field`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L66) - Interface for the most generic finte field -- [`FftField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L275) - Exposes methods that allow for performing efficient FFTs on this field's elements -- [`PrimeField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L347) - Field with `p` (`p` prime) elements, later referred to as `Fp`. +- [`Field`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L66) - Interface for a generic finite field. +- [`FftField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L275) - Exposes methods that allow for performing efficient FFTs on field elements. +- [`PrimeField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L347) - Field with a prime `p` number of elements, also referred to as `Fp`. - [`SquareRootField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L431) - Interface for fields that support square-root operations The models implemented are: - [`Quadratic Extension`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs) -- [`QuadExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L140) - Struct representing a quadratic extension field, in this case holding two elements -- [`QuadExtParameters`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Quadratic Extension Field + - [`QuadExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L140) - Struct representing a quadratic extension field, in this case holding two base field elements + - [`QuadExtConfig`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Quadratic Extension Field - [`Cubic Extension`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs) -- [`CubicExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L72) - Struct representing a cubic extension field, holds three elements -- [`CubicExtParameters`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Cubic Extension Field + - [`CubicExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L72) - Struct representing a cubic extension field, holds three base field elements + - [`CubicExtConfig`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Cubic Extension Field The above two models serve as abstractions for constructing the extension fields `Fp^m` directly (i.e. `m` equal 2 or 3) or for creating extension towers to arrive at higher `m`. The latter is done by applying the extensions iteratively, e.g. cubic extension over a quadratic extension field. @@ -36,4 +36,4 @@ The above two models serve as abstractions for constructing the extension fields - [`Fp3`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp3.rs#L54) - Cubic extension directly on the prime field, i.e. `BaseField == BasePrimeField` - [`Fp6_2over3`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp6_2over3.rs#L48) - Extension tower: quadratic extension on a cubic extension field, i.e. `BaseField = Fp3`, but `BasePrimeField = Fp`. - [`Fp6_3over2`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp6_3over2.rs#L49) - Extension tower, similar to the above except that the towering order is reversed: it's a cubic extension on a quadratic extension field, i.e. `BaseField = Fp2`, but `BasePrimeField = Fp`. Only this latter one is exported by default as `Fp6`. -- [`Fp12_2over3over2`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp12_2over3over2.rs#L83) - Extension tower: quadratic extension of the `Fp6_3over2`, i.e. `BaseField = Fp6`. +- [`Fp12_2over3over2`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp12_2over3over2.rs#L83) - Extension tower: quadratic extension of `Fp6_3over2`, i.e. `BaseField = Fp6`. diff --git a/ff/src/biginteger/arithmetic.rs b/ff/src/biginteger/arithmetic.rs index 64ed704a1..a40e25310 100644 --- a/ff/src/biginteger/arithmetic.rs +++ b/ff/src/biginteger/arithmetic.rs @@ -1,41 +1,51 @@ use ark_std::vec::Vec; -/// Calculate a + b + carry, returning the sum and modifying the -/// carry value. macro_rules! adc { ($a:expr, $b:expr, &mut $carry:expr$(,)?) => {{ let tmp = ($a as u128) + ($b as u128) + ($carry as u128); - $carry = (tmp >> 64) as u64; - tmp as u64 }}; } -/// Calculate a + (b * c) + carry, returning the least significant digit -/// and setting carry to the most significant digit. +/// Calculate a + b + carry, returning the sum and modifying the +/// carry value. +#[inline(always)] +pub(crate) fn adc(a: u64, b: u64, carry: &mut u64) -> u64 { + adc!(a, b, &mut *carry) +} + macro_rules! mac_with_carry { ($a:expr, $b:expr, $c:expr, &mut $carry:expr$(,)?) => {{ let tmp = ($a as u128) + ($b as u128 * $c as u128) + ($carry as u128); - $carry = (tmp >> 64) as u64; - tmp as u64 }}; } -/// Calculate a - b - borrow, returning the result and modifying -/// the borrow value. +/// Calculate a + (b * c) + carry, returning the least significant digit +/// and setting carry to the most significant digit. +#[inline(always)] +pub(crate) fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 { + mac_with_carry!(a, b, c, &mut *carry) +} + +#[macro_export] macro_rules! sbb { ($a:expr, $b:expr, &mut $borrow:expr$(,)?) => {{ let tmp = (1u128 << 64) + ($a as u128) - ($b as u128) - ($borrow as u128); - $borrow = if tmp >> 64 == 0 { 1 } else { 0 }; - tmp as u64 }}; } +/// Calculate a - b - borrow, returning the result and modifying +/// the borrow value. +#[inline(always)] +pub(crate) fn sbb(a: u64, b: u64, borrow: &mut u64) -> u64 { + sbb!(a, b, &mut *borrow) +} + /// Calculate a + b * c, returning the lower 64 bits of the result and setting /// `carry` to the upper 64 bits. #[inline(always)] @@ -66,7 +76,7 @@ pub fn find_wnaf(num: &[u64]) -> Vec { let mut borrow = 0; for (a, b) in num.iter_mut().zip(other) { - *a = sbb!(*a, b, &mut borrow); + *a = sbb(*a, b, &mut borrow); } }; let add_nocarry = |num: &mut [u64], z: u64| { @@ -75,7 +85,7 @@ pub fn find_wnaf(num: &[u64]) -> Vec { let mut carry = 0; for (a, b) in num.iter_mut().zip(other) { - *a = adc!(*a, b, &mut carry); + *a = adc(*a, b, &mut carry); } }; let div2 = |num: &mut [u64]| { diff --git a/ff/src/biginteger/mod.rs b/ff/src/biginteger/mod.rs index fb293501d..369e8aa15 100644 --- a/ff/src/biginteger/mod.rs +++ b/ff/src/biginteger/mod.rs @@ -1,5 +1,6 @@ use crate::{ bytes::{FromBytes, ToBytes}, + const_for, fields::{BitIteratorBE, BitIteratorLE}, UniformRand, }; @@ -33,6 +34,200 @@ impl BigInt { pub const fn new(value: [u64; N]) -> Self { Self(value) } + + pub const fn zero() -> Self { + Self([0u64; N]) + } +} + +/// Construct a [`struct@BigInt`] element from a literal string. +/// +/// # Panics +/// +/// If the integer represented by the string cannot fit in the number +/// of limbs of the `BigInt`, this macro results in a +/// * compile-time error if used in a const context +/// * run-time error otherwise. +/// +/// # Usage +/// ```rust +/// # use ark_ff::BigInt; +/// const ONE: BigInt<6> = BigInt!("1"); +/// +/// fn check_correctness() { +/// assert_eq!(ONE, BigInt::from(1u8)); +/// } +/// ``` +#[macro_export] +macro_rules! BigInt { + ($c0:expr) => {{ + let (is_positive, limbs) = $crate::ark_ff_macros::to_sign_and_limbs!($c0); + assert!(is_positive); + let mut integer = $crate::BigInt::zero(); + assert!(integer.0.len() >= limbs.len()); + $crate::const_for!((i in 0..(limbs.len())) { + integer.0[i] = limbs[i]; + }); + integer + }}; +} + +#[doc(hidden)] +macro_rules! const_modulo { + ($a:ident, $divisor:ident) => {{ + // Stupid slow base-2 long division taken from + // https://en.wikipedia.org/wiki/Division_algorithm + assert!(!$divisor.const_is_zero()); + let mut remainder = Self::new([0u64; N]); + let end = $a.num_bits(); + let mut i = (end - 1) as isize; + while i >= 0 { + remainder = remainder.const_mul2(); + remainder.0[0] |= $a.get_bit(i as usize) as u64; + if remainder.const_geq($divisor) { + let (r, borrow) = remainder.const_sub_noborrow($divisor); + remainder = r; + assert!(!borrow); + } + i -= 1; + } + remainder + }}; +} +impl BigInt { + #[doc(hidden)] + pub const fn const_is_even(&self) -> bool { + self.0[0] % 2 == 0 + } + + #[doc(hidden)] + pub const fn const_is_odd(&self) -> bool { + self.0[0] % 2 == 1 + } + + /// Compute a right shift of `self` + /// This is equivalent to a (saturating) division by 2. + #[doc(hidden)] + pub const fn const_shr(&self) -> Self { + let mut result = *self; + let mut t = 0; + crate::const_for!((i in 0..N) { + let a = result.0[N - i - 1]; + let t2 = a << 63; + result.0[N - i - 1] >>= 1; + result.0[N - i - 1] |= t; + t = t2; + }); + result + } + + const fn const_geq(&self, other: &Self) -> bool { + const_for!((i in 0..N) { + let a = self.0[N - i - 1]; + let b = other.0[N - i - 1]; + if a < b { + return false; + } else if a > b { + return true; + } + }); + true + } + + /// Compute the largest integer `s` such that `self = 2**s * t` for odd `t`. + #[doc(hidden)] + pub const fn two_adic_valuation(mut self) -> u32 { + let mut two_adicity = 0; + assert!(self.const_is_odd()); + // Since `self` is odd, we can always subtract one + // without a borrow + self.0[0] -= 1; + while self.const_is_even() { + self = self.const_shr(); + two_adicity += 1; + } + two_adicity + } + + /// Compute the smallest odd integer `t` such that `self = 2**s * t` for some + /// integer `s = self.two_adic_valuation()`. + #[doc(hidden)] + pub const fn two_adic_coefficient(mut self) -> Self { + assert!(self.const_is_odd()); + // Since `self` is odd, we can always subtract one + // without a borrow + self.0[0] -= 1; + while self.const_is_even() { + self = self.const_shr(); + } + assert!(self.const_is_odd()); + self + } + + /// Divide `self` by 2, rounding down if necessary. + /// That is, if `self.is_odd()`, compute `(self - 1)/2`. + /// Else, compute `self/2`. + #[doc(hidden)] + pub const fn divide_by_2_round_down(mut self) -> Self { + if self.const_is_odd() { + self.0[0] -= 1; + } + self.const_shr() + } + + /// Find the number of bits in the binary decomposition of `self`. + #[doc(hidden)] + pub const fn const_num_bits(self) -> u32 { + ((N - 1) * 64) as u32 + (64 - self.0[N - 1].leading_zeros()) + } + + #[inline] + #[ark_ff_asm::unroll_for_loops] + pub(crate) const fn const_sub_noborrow(mut self, other: &Self) -> (Self, bool) { + let mut borrow = 0; + + const_for!((i in 0..N) { + self.0[i] = sbb!(self.0[i], other.0[i], &mut borrow); + }); + + (self, borrow != 0) + } + + const fn const_mul2(mut self) -> Self { + let mut last = 0; + crate::const_for!((i in 0..N) { + let a = self.0[i]; + let tmp = a >> 63; + self.0[i] <<= 1; + self.0[i] |= last; + last = tmp; + }); + self + } + + #[ark_ff_asm::unroll_for_loops] + pub(crate) const fn const_is_zero(&self) -> bool { + let mut is_zero = true; + crate::const_for!((i in 0..N) { + is_zero &= self.0[i] == 0; + }); + is_zero + } + + /// Computes the Montgomery R constant modulo `self`. + #[doc(hidden)] + pub const fn montgomery_r(&self) -> Self { + let two_pow_n_times_64 = crate::const_helpers::RBuffer::([0u64; N], 1); + const_modulo!(two_pow_n_times_64, self) + } + + /// Computes the Montgomery R2 constant modulo `self`. + #[doc(hidden)] + pub const fn montgomery_r2(&self) -> Self { + let two_pow_n_times_64_square = + crate::const_helpers::R2Buffer::([0u64; N], [0u64; N], 1); + const_modulo!(two_pow_n_times_64_square, self) + } } impl BigInteger for BigInt { @@ -53,12 +248,13 @@ impl BigInteger for BigInt { #[cfg(not(all(target_arch = "x86_64", feature = "asm")))] { - self.0[i] = adc!(self.0[i], other.0[i], &mut carry); + self.0[i] = arithmetic::adc(self.0[i], other.0[i], &mut carry); } } carry != 0 } + #[inline] #[ark_ff_asm::unroll_for_loops] fn sub_noborrow(&mut self, other: &Self) -> bool { @@ -74,7 +270,7 @@ impl BigInteger for BigInt { #[cfg(not(all(target_arch = "x86_64", feature = "asm")))] { - self.0[i] = sbb!(self.0[i], other.0[i], &mut borrow); + self.0[i] = arithmetic::sbb(self.0[i], other.0[i], &mut borrow); } } @@ -115,7 +311,7 @@ impl BigInteger for BigInt { #[ark_ff_asm::unroll_for_loops] fn muln(&mut self, mut n: u32) { if n >= (64 * N) as u32 { - *self = Self::from(0); + *self = Self::from(0u64); return; } @@ -158,7 +354,7 @@ impl BigInteger for BigInt { #[ark_ff_asm::unroll_for_loops] fn divn(&mut self, mut n: u32) { if n >= (64 * N) as u32 { - *self = Self::from(0); + *self = Self::from(0u64); return; } @@ -381,19 +577,44 @@ impl From for BigInt { repr } } + +impl From for BigInt { + #[inline] + fn from(val: u32) -> BigInt { + let mut repr = Self::default(); + repr.0[0] = u64::from(val); + repr + } +} + +impl From for BigInt { + #[inline] + fn from(val: u16) -> BigInt { + let mut repr = Self::default(); + repr.0[0] = u64::from(val); + repr + } +} + +impl From for BigInt { + #[inline] + fn from(val: u8) -> BigInt { + let mut repr = Self::default(); + repr.0[0] = u64::from(val); + repr + } +} + impl TryFrom for BigInt { - type Error = ark_std::string::String; + type Error = (); + /// Returns `Err(())` if the bit size of `val` is more than `N * 64`. #[inline] fn try_from(val: num_bigint::BigUint) -> Result, Self::Error> { let bytes = val.to_bytes_le(); if bytes.len() > N * 8 { - Err(format!( - "A BigUint of {} bytes cannot fit into {} limbs.", - bytes.len(), - N - )) + Err(()) } else { let mut limbs = [0u64; N]; @@ -418,6 +639,7 @@ impl From> for BigUint { BigUint::from_bytes_le(&val.to_bytes_le()) } } + /// Compute the signed modulo operation on a u64 representation, returning the result. /// If n % modulus > modulus / 2, return modulus - n /// # Example @@ -470,7 +692,10 @@ pub trait BigInteger: + AsMut<[u64]> + AsRef<[u64]> + From - + TryFrom + + From + + From + + From + + TryFrom + Into { /// Number of 64-bit limbs representing `Self`. diff --git a/ff/src/bytes.rs b/ff/src/bytes.rs index af2e8ef6a..f96ce997a 100644 --- a/ff/src/bytes.rs +++ b/ff/src/bytes.rs @@ -133,6 +133,7 @@ macro_rules! to_bytes { }); } +#[doc(hidden)] #[macro_export] macro_rules! push_to_vec { ($buf:expr, $y:expr, $($x:expr),*) => ({ diff --git a/ff/src/const_helpers.rs b/ff/src/const_helpers.rs new file mode 100644 index 000000000..9f2a98aa0 --- /dev/null +++ b/ff/src/const_helpers.rs @@ -0,0 +1,308 @@ +use ark_serialize::{Read, Write}; +use ark_std::ops::{Index, IndexMut}; + +use crate::BigInt; + +/// A helper macro for emulating `for` loops in a `const` context. +/// # Usage +/// ```rust +/// # use ark_ff::const_for; +/// const fn for_in_const() { +/// let mut array = [0usize; 4]; +/// const_for!((i in 0..(array.len())) { // We need to wrap the `array.len()` in parenthesis. +/// array[i] = i; +/// }); +/// assert!(array[0] == 0); +/// assert!(array[1] == 1); +/// assert!(array[2] == 2); +/// assert!(array[3] == 3); +/// } +/// ``` +#[macro_export] +macro_rules! const_for { + (($i:ident in $start:tt..$end:tt) $code:expr ) => {{ + let mut $i = $start; + while $i < $end { + $code + $i += 1; + } + }}; +} + +/// A buffer to hold values of size 2 * N. This is mostly +/// a hack that's necessary until `generic_const_exprs` is stable. +#[derive(Copy, Clone)] +#[repr(C, align(8))] +pub(super) struct MulBuffer { + pub(super) b0: [u64; N], + pub(super) b1: [u64; N], +} + +impl MulBuffer { + const fn new(b0: [u64; N], b1: [u64; N]) -> Self { + Self { b0, b1 } + } + + pub(super) const fn zeroed() -> Self { + let b = [0u64; N]; + Self::new(b, b) + } + + #[inline(always)] + pub(super) const fn get(&self, index: usize) -> &u64 { + if index < N { + &self.b0[index] + } else { + &self.b1[index - N] + } + } + + #[inline(always)] + pub(super) fn get_mut(&mut self, index: usize) -> &mut u64 { + if index < N { + &mut self.b0[index] + } else { + &mut self.b1[index - N] + } + } +} + +impl Index for MulBuffer { + type Output = u64; + #[inline(always)] + fn index(&self, index: usize) -> &Self::Output { + self.get(index) + } +} + +impl IndexMut for MulBuffer { + #[inline(always)] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.get_mut(index) + } +} + +/// A buffer to hold values of size 2 * N. This is mostly +/// a hack that's necessary until `generic_const_exprs` is stable. +#[derive(Copy, Clone)] +#[repr(C, align(1))] +pub(super) struct SerBuffer { + pub(super) buffers: [[u8; 8]; N], + pub(super) last: u8, +} + +impl SerBuffer { + pub(super) const fn zeroed() -> Self { + Self { + buffers: [[0u8; 8]; N], + last: 0u8, + } + } + + #[inline(always)] + pub(super) const fn get(&self, index: usize) -> &u8 { + if index == 8 * N { + &self.last + } else { + let part = index / 8; + let in_buffer_index = index % 8; + &self.buffers[part][in_buffer_index] + } + } + + #[inline(always)] + pub(super) fn get_mut(&mut self, index: usize) -> &mut u8 { + if index == 8 * N { + &mut self.last + } else { + let part = index / 8; + let in_buffer_index = index % 8; + &mut self.buffers[part][in_buffer_index] + } + } + + #[allow(unsafe_code)] + pub(super) fn as_slice(&self) -> &[u8] { + unsafe { ark_std::slice::from_raw_parts((self as *const Self) as *const u8, 8 * N + 1) } + } + + #[inline(always)] + pub(super) fn last_n_plus_1_bytes_mut(&mut self) -> impl Iterator { + self.buffers[N - 1] + .iter_mut() + .chain(ark_std::iter::once(&mut self.last)) + } + + #[inline(always)] + pub(super) fn copy_from_u8_slice(&mut self, other: &[u8]) { + other.chunks(8).enumerate().for_each(|(i, chunk)| { + if i < N { + for j in 0..chunk.len() { + self.buffers[i][j] = chunk[j] + } + } else { + self.last = chunk[0] + } + }); + } + + #[inline(always)] + pub(super) fn copy_from_u64_slice(&mut self, other: &[u64; N]) { + other + .iter() + .zip(&mut self.buffers) + .for_each(|(other, this)| *this = other.to_le_bytes()); + } + + #[inline(always)] + pub(super) fn to_bigint(&self) -> BigInt { + let mut self_integer = BigInt::from(0u64); + self_integer + .0 + .iter_mut() + .zip(self.buffers) + .for_each(|(other, this)| *other = u64::from_le_bytes(this)); + self_integer + } + + #[inline(always)] + /// Write up to `num_bytes` bytes from `self` to `other`. + /// `num_bytes` is allowed to range from `8 * (N - 1) + 1` to `8 * N + 1`. + pub(super) fn write_up_to( + &self, + mut other: impl Write, + num_bytes: usize, + ) -> ark_std::io::Result<()> { + debug_assert!(num_bytes <= 8 * N + 1, "index too large"); + debug_assert!(num_bytes > 8 * (N - 1), "index too small"); + // unconditionally write first `N - 1` limbs. + for i in 0..(N - 1) { + other.write_all(&self.buffers[i])?; + } + // for the `N`-th limb, depending on `index`, we can write anywhere from + // 1 to all bytes. + let remaining_bytes = num_bytes - (8 * (N - 1)); + let write_last_byte = remaining_bytes > 8; + let num_last_limb_bytes = ark_std::cmp::min(8, remaining_bytes); + other.write_all(&self.buffers[N - 1][..num_last_limb_bytes])?; + if write_last_byte { + other.write_all(&[self.last])?; + } + Ok(()) + } + + #[inline(always)] + /// Read up to `num_bytes` bytes from `other` to `self`. + /// `num_bytes` is allowed to range from `8 * (N - 1)` to `8 * N + 1`. + pub(super) fn read_exact_up_to( + &mut self, + mut other: impl Read, + num_bytes: usize, + ) -> ark_std::io::Result<()> { + debug_assert!(num_bytes <= 8 * N + 1, "index too large"); + debug_assert!(num_bytes > 8 * (N - 1), "index too small"); + // unconditionally write first `N - 1` limbs. + for i in 0..(N - 1) { + other.read_exact(&mut self.buffers[i])?; + } + // for the `N`-th limb, depending on `index`, we can write anywhere from + // 1 to all bytes. + let remaining_bytes = num_bytes - (8 * (N - 1)); + let write_last_byte = remaining_bytes > 8; + let num_last_limb_bytes = ark_std::cmp::min(8, remaining_bytes); + other.read_exact(&mut self.buffers[N - 1][..num_last_limb_bytes])?; + if write_last_byte { + other.read_exact(&mut [self.last])?; + } + Ok(()) + } +} + +impl Index for SerBuffer { + type Output = u8; + #[inline(always)] + fn index(&self, index: usize) -> &Self::Output { + self.get(index) + } +} + +impl IndexMut for SerBuffer { + #[inline(always)] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.get_mut(index) + } +} + +pub(super) struct RBuffer(pub [u64; N], pub u64); + +impl RBuffer { + /// Find the number of bits in the binary decomposition of `self`. + pub(super) const fn num_bits(&self) -> u32 { + (N * 64) as u32 + (64 - self.1.leading_zeros()) + } + + /// Returns the `i`-th bit where bit 0 is the least significant one. + /// In other words, the bit with weight `2^i`. + pub(super) const fn get_bit(&self, i: usize) -> bool { + let d = i / 64; + let b = i % 64; + if d == N { + (self.1 >> b) & 1 == 1 + } else { + (self.0[d] >> b) & 1 == 1 + } + } +} + +pub(super) struct R2Buffer(pub [u64; N], pub [u64; N], pub u64); + +impl R2Buffer { + /// Find the number of bits in the binary decomposition of `self`. + pub(super) const fn num_bits(&self) -> u32 { + ((2 * N) * 64) as u32 + (64 - self.2.leading_zeros()) + } + + /// Returns the `i`-th bit where bit 0 is the least significant one. + /// In other words, the bit with weight `2^i`. + pub(super) const fn get_bit(&self, i: usize) -> bool { + let d = i / 64; + let b = i % 64; + if d == 2 * N { + (self.2 >> b) & 1 == 1 + } else if d >= N { + (self.1[d - N] >> b) & 1 == 1 + } else { + (self.0[d] >> b) & 1 == 1 + } + } +} + +mod tests { + #[test] + fn test_mul_buffer_correctness() { + use super::*; + type Buf = MulBuffer<10>; + let temp = Buf::new([10u64; 10], [20u64; 10]); + + for i in 0..20 { + if i < 10 { + assert_eq!(temp[i], 10); + } else { + assert_eq!(temp[i], 20); + } + } + } + + #[test] + #[should_panic] + fn test_mul_buffer_soundness() { + use super::*; + type Buf = MulBuffer<10>; + let temp = Buf::new([10u64; 10], [10u64; 10]); + + for i in 20..21 { + // indexing `temp[20]` should panic + assert_eq!(temp[i], 10); + } + } +} diff --git a/ff/src/fields/arithmetic.rs b/ff/src/fields/arithmetic.rs index e324c940b..985322595 100644 --- a/ff/src/fields/arithmetic.rs +++ b/ff/src/fields/arithmetic.rs @@ -1,297 +1,3 @@ -/// This modular multiplication algorithm uses Montgomery -/// reduction for efficient implementation. It also additionally -/// uses the "no-carry optimization" outlined -/// [here](https://hackmd.io/@zkteam/modular_multiplication) if -/// `P::MODULUS` has (a) a non-zero MSB, and (b) at least one -/// zero bit in the rest of the modulus. -macro_rules! impl_field_mul_assign { - ($limbs:expr) => { - #[inline] - #[ark_ff_asm::unroll_for_loops] - fn mul_assign(&mut self, other: &Self) { - // Checking the modulus at compile time - let first_bit_set = P::MODULUS.0[$limbs - 1] >> 63 != 0; - // $limbs can be 1, hence we can run into a case with an unused mut. - #[allow(unused_mut)] - let mut all_bits_set = P::MODULUS.0[$limbs - 1] == !0 - (1 << 63); - for i in 1..$limbs { - all_bits_set &= P::MODULUS.0[$limbs - i - 1] == !0u64; - } - let _no_carry: bool = !(first_bit_set || all_bits_set); - - // No-carry optimisation applied to CIOS - if _no_carry { - #[cfg(use_asm)] - #[allow(unsafe_code, unused_mut)] - { - // Tentatively avoid using assembly for `$limbs == 1`. - if $limbs <= 6 && $limbs > 1 { - ark_ff_asm::x86_64_asm_mul!($limbs, (self.0).0, (other.0).0); - self.reduce(); - return; - } - } - let mut r = [0u64; $limbs]; - let mut carry1 = 0u64; - let mut carry2 = 0u64; - - for i in 0..$limbs { - r[0] = fa::mac(r[0], (self.0).0[0], (other.0).0[i], &mut carry1); - let k = r[0].wrapping_mul(P::INV); - fa::mac_discard(r[0], k, P::MODULUS.0[0], &mut carry2); - for j in 1..$limbs { - r[j] = mac_with_carry!(r[j], (self.0).0[j], (other.0).0[i], &mut carry1); - r[j - 1] = mac_with_carry!(r[j], k, P::MODULUS.0[j], &mut carry2); - } - r[$limbs - 1] = carry1 + carry2; - } - (self.0).0 = r; - self.reduce(); - // Alternative implementation - } else { - *self = self.mul_without_reduce(other, P::MODULUS, P::INV); - self.reduce(); - } - } - }; -} - -macro_rules! impl_field_into_repr { - ($limbs:expr, $BigIntegerType:ty) => { - #[inline] - #[ark_ff_asm::unroll_for_loops] - #[allow(clippy::modulo_one)] - fn into_repr(&self) -> $BigIntegerType { - let mut tmp = self.0; - let mut r = tmp.0; - // Montgomery Reduction - for i in 0..$limbs { - let k = r[i].wrapping_mul(P::INV); - let mut carry = 0; - - mac_with_carry!(r[i], k, P::MODULUS.0[0], &mut carry); - for j in 1..$limbs { - r[(j + i) % $limbs] = - mac_with_carry!(r[(j + i) % $limbs], k, P::MODULUS.0[j], &mut carry); - } - r[i % $limbs] = carry; - } - tmp.0 = r; - tmp - } - }; -} - -macro_rules! impl_field_square_in_place { - ($limbs: expr) => { - #[inline] - #[ark_ff_asm::unroll_for_loops] - #[allow(unused_braces, clippy::absurd_extreme_comparisons)] - fn square_in_place(&mut self) -> &mut Self { - if $limbs == 1 { - // We default to multiplying with `self` using the `Mul` impl - // for the 1 limb case - *self = *self * *self; - return self; - } - #[cfg(use_asm)] - #[allow(unsafe_code, unused_mut)] - { - // Checking the modulus at compile time - let first_bit_set = P::MODULUS.0[$limbs - 1] >> 63 != 0; - let mut all_bits_set = P::MODULUS.0[$limbs - 1] == !0 - (1 << 63); - for i in 1..$limbs { - all_bits_set &= P::MODULUS.0[$limbs - i - 1] == core::u64::MAX; - } - let _no_carry: bool = !(first_bit_set || all_bits_set); - - if $limbs <= 6 && _no_carry { - ark_ff_asm::x86_64_asm_square!($limbs, (self.0).0); - self.reduce(); - return self; - } - } - let mut r = [0u64; $limbs * 2]; - - let mut carry = 0; - for i in 0..$limbs { - if i < $limbs - 1 { - for j in 0..$limbs { - if j > i { - r[i + j] = - mac_with_carry!(r[i + j], (self.0).0[i], (self.0).0[j], &mut carry); - } - } - r[$limbs + i] = carry; - carry = 0; - } - } - r[$limbs * 2 - 1] = r[$limbs * 2 - 2] >> 63; - for i in 0..$limbs { - // This computes `r[2 * ($limbs - 1) - (i + 1)]`, but additionally - // handles the case where the index underflows. - // Note that we should never hit this case because it only occurs - // when `$limbs == 1`, but we handle that separately above. - let subtractor = (2 * ($limbs - 1usize)) - .checked_sub(i + 1) - .map(|index| r[index]) - .unwrap_or(0); - r[2 * ($limbs - 1) - i] = (r[2 * ($limbs - 1) - i] << 1) | (subtractor >> 63); - } - for i in 3..$limbs { - r[$limbs + 1 - i] = (r[$limbs + 1 - i] << 1) | (r[$limbs - i] >> 63); - } - r[1] <<= 1; - - for i in 0..$limbs { - r[2 * i] = mac_with_carry!(r[2 * i], (self.0).0[i], (self.0).0[i], &mut carry); - // need unused assignment because the last iteration of the loop produces an - // assignment to `carry` that is unused. - #[allow(unused_assignments)] - { - r[2 * i + 1] = adc!(r[2 * i + 1], 0, &mut carry); - } - } - // Montgomery reduction - let mut _carry2 = 0; - for i in 0..$limbs { - let k = r[i].wrapping_mul(P::INV); - let mut carry = 0; - mac_with_carry!(r[i], k, P::MODULUS.0[0], &mut carry); - for j in 1..$limbs { - r[j + i] = mac_with_carry!(r[j + i], k, P::MODULUS.0[j], &mut carry); - } - r[$limbs + i] = adc!(r[$limbs + i], _carry2, &mut carry); - _carry2 = carry; - } - (self.0).0.copy_from_slice(&r[$limbs..]); - self.reduce(); - self - } - }; -} - -macro_rules! impl_field_bigint_conv { - ($field: ident, $bigint: ident, $params: ident) => { - impl Into<$bigint> for $field

{ - fn into(self) -> $bigint { - self.into_repr() - } - } - - impl From<$bigint> for $field

{ - /// Converts `Self::BigInteger` into `Self` - /// - /// # Panics - /// This method panics if `int` is larger than `P::MODULUS`. - fn from(int: $bigint) -> Self { - Self::from_repr(int).unwrap() - } - } - }; -} - -macro_rules! impl_prime_field_standard_sample { - ($field: ident, $params: ident) => { - impl ark_std::rand::distributions::Distribution<$field

> - for ark_std::rand::distributions::Standard - { - #[inline] - fn sample(&self, rng: &mut R) -> $field

{ - loop { - let mut tmp = $field( - rng.sample(ark_std::rand::distributions::Standard), - PhantomData, - ); - - // Mask away the unused bits at the beginning. - assert!(P::REPR_SHAVE_BITS <= 64); - let mask = if P::REPR_SHAVE_BITS == 64 { - 0 - } else { - core::u64::MAX >> P::REPR_SHAVE_BITS - }; - tmp.0.as_mut().last_mut().map(|val| *val &= mask); - - if tmp.is_valid() { - return tmp; - } - } - } - } - }; -} - -macro_rules! impl_prime_field_from_int { - ($field: ident, 128, $params: ident, $limbs:expr) => { - impl From for $field

{ - fn from(other: u128) -> Self { - let mut default_int = P::BigInt::default(); - if $limbs == 1 { - default_int.0[0] = (other % u128::from(P::MODULUS.0[0])) as u64; - } else { - let upper = (other >> 64) as u64; - let lower = ((other << 64) >> 64) as u64; - // This is equivalent to the following, but satisfying the compiler: - // default_int.0[0] = lower; - // default_int.0[1] = upper; - let limbs = [lower, upper]; - for (cur, other) in default_int.0.iter_mut().zip(&limbs) { - *cur = *other; - } - } - Self::from_repr(default_int).unwrap() - } - } - - impl From for $field

{ - fn from(other: i128) -> Self { - let abs = Self::from(other.unsigned_abs()); - if other.is_positive() { - abs - } else { - -abs - } - } - } - }; - ($field: ident, bool, $params: ident, $limbs:expr) => { - impl From for $field

{ - fn from(other: bool) -> Self { - if $limbs == 1 { - Self::from_repr(P::BigInt::from(u64::from(other) % P::MODULUS.0[0])).unwrap() - } else { - Self::from_repr(P::BigInt::from(u64::from(other))).unwrap() - } - } - } - }; - ($field: ident, $int: expr, $params: ident, $limbs:expr) => { - paste::paste!{ - impl From<[]> for $field

{ - fn from(other: []) -> Self { - if $limbs == 1 { - Self::from_repr(P::BigInt::from(u64::from(other) % P::MODULUS.0[0])).unwrap() - } else { - Self::from_repr(P::BigInt::from(u64::from(other))).unwrap() - } - } - } - - impl From<[]> for $field

{ - fn from(other: []) -> Self { - let abs = Self::from(other.unsigned_abs()); - if other.is_positive() { - abs - } else { - -abs - } - } - } - } - }; -} - macro_rules! sqrt_impl { ($Self:ident, $P:tt, $self:expr) => {{ // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) @@ -305,7 +11,7 @@ macro_rules! sqrt_impl { // Check at the end of the algorithm if x was a square root // Begin Tonelli-Shanks let mut z = $Self::qnr_to_t(); - let mut w = $self.pow($P::T_MINUS_ONE_DIV_TWO); + let mut w = $self.pow($P::TRACE_MINUS_ONE_DIV_TWO); let mut x = w * $self; let mut b = x * &w; diff --git a/ff/src/fields/macros.rs b/ff/src/fields/macros.rs deleted file mode 100644 index 4245768f7..000000000 --- a/ff/src/fields/macros.rs +++ /dev/null @@ -1,746 +0,0 @@ -macro_rules! impl_prime_field_serializer { - ($field: ident, $params: ident, $byte_size: expr) => { - impl CanonicalSerializeWithFlags for $field

{ - fn serialize_with_flags( - &self, - mut writer: W, - flags: F, - ) -> Result<(), SerializationError> { - // All reasonable `Flags` should be less than 8 bits in size - // (256 values are enough for anyone!) - if F::BIT_SIZE > 8 { - return Err(SerializationError::NotEnoughSpace); - } - - // Calculate the number of bytes required to represent a field element - // serialized with `flags`. If `F::BIT_SIZE < 8`, - // this is at most `$byte_size + 1` - let output_byte_size = buffer_byte_size(P::MODULUS_BITS as usize + F::BIT_SIZE); - - // Write out `self` to a temporary buffer. - // The size of the buffer is $byte_size + 1 because `F::BIT_SIZE` - // is at most 8 bits. - let mut bytes = [0u8; $byte_size + 1]; - self.write(&mut bytes[..$byte_size])?; - - // Mask out the bits of the last byte that correspond to the flag. - bytes[output_byte_size - 1] |= flags.u8_bitmask(); - - writer.write_all(&bytes[..output_byte_size])?; - Ok(()) - } - - // Let `m = 8 * n` for some `n` be the smallest multiple of 8 greater - // than `P::MODULUS_BITS`. - // If `(m - P::MODULUS_BITS) >= F::BIT_SIZE` , then this method returns `n`; - // otherwise, it returns `n + 1`. - fn serialized_size_with_flags(&self) -> usize { - buffer_byte_size(P::MODULUS_BITS as usize + F::BIT_SIZE) - } - } - - impl CanonicalSerialize for $field

{ - #[inline] - fn serialize( - &self, - writer: W, - ) -> Result<(), SerializationError> { - self.serialize_with_flags(writer, EmptyFlags) - } - - #[inline] - fn serialized_size(&self) -> usize { - self.serialized_size_with_flags::() - } - } - - impl CanonicalDeserializeWithFlags for $field

{ - fn deserialize_with_flags( - mut reader: R, - ) -> Result<(Self, F), SerializationError> { - // All reasonable `Flags` should be less than 8 bits in size - // (256 values are enough for anyone!) - if F::BIT_SIZE > 8 { - return Err(SerializationError::NotEnoughSpace); - } - // Calculate the number of bytes required to represent a field element - // serialized with `flags`. If `F::BIT_SIZE < 8`, - // this is at most `$byte_size + 1` - let output_byte_size = buffer_byte_size(P::MODULUS_BITS as usize + F::BIT_SIZE); - - let mut masked_bytes = [0; $byte_size + 1]; - reader.read_exact(&mut masked_bytes[..output_byte_size])?; - - let flags = F::from_u8_remove_flags(&mut masked_bytes[output_byte_size - 1]) - .ok_or(SerializationError::UnexpectedFlags)?; - - Ok((Self::read(&masked_bytes[..])?, flags)) - } - } - - impl CanonicalDeserialize for $field

{ - fn deserialize(reader: R) -> Result { - Self::deserialize_with_flags::(reader).map(|(r, _)| r) - } - } - }; -} - -macro_rules! impl_Fp { - ($Fp:ident, $FpParameters:ident, $BigInteger:ident, $BigIntegerType:ty, $limbs:expr, $field_size:expr) => { - /// Trait for prime field parameters of size at most - #[doc = $field_size] - /// bits. - pub trait $FpParameters: FpParameters> {} - - /// Represents an element of the prime field F_p, where `p == P::MODULUS`. - /// This type can represent elements in any field of size at most - #[doc = $field_size] - /// bits. - #[derive(Derivative)] - #[derivative( - Default(bound = ""), - Hash(bound = ""), - Clone(bound = ""), - Copy(bound = ""), - PartialEq(bound = ""), - Eq(bound = "") - )] - pub struct $Fp

( - pub $BigIntegerType, - #[derivative(Debug = "ignore")] - #[doc(hidden)] - pub PhantomData

, - ); - - impl

$Fp

{ - /// Construct a new prime element directly from its underlying - /// `BigInteger` data type. The `BigInteger` should be in - /// Montgomery representation. If it is not, use `Self::from_repr`. - #[inline] - pub const fn new(element: $BigIntegerType) -> Self { - Self(element, PhantomData) - } - - #[ark_ff_asm::unroll_for_loops] - const fn const_is_zero(&self) -> bool { - let mut is_zero = true; - for i in 0..$limbs { - is_zero &= (self.0).0[i] == 0; - } - is_zero - } - - const fn const_neg(self, modulus: $BigIntegerType) -> Self { - if !self.const_is_zero() { - Self::new(Self::sub_noborrow(&modulus, &self.0)) - } else { - self - } - } - - /// Interpret a string of decimal numbers as a prime field element. - /// Does not accept unnecessary leading zeroes or a blank string. - /// For *internal* use only; please use the `field_new` macro instead - /// of this method - #[doc(hidden)] - pub const fn const_from_str(limbs: &[u64], is_positive: bool, r2: $BigIntegerType, modulus: $BigIntegerType, inv: u64) -> Self { - let mut repr = BigInt::<$limbs>([0; $limbs]); - let mut i = 0; - while i < limbs.len() { - repr.0[i] = limbs[i]; - i += 1; - } - let res = Self::const_from_repr(repr, r2, modulus, inv); - if is_positive { - res - } else { - res.const_neg(modulus) - } - } - - #[inline] - pub(crate) const fn const_from_repr(repr: $BigIntegerType, r2: $BigIntegerType, modulus: $BigIntegerType, inv: u64) -> Self { - let mut r = Self::new(repr); - if r.const_is_zero() { - r - } else { - r = r.const_mul(&$Fp(r2, PhantomData), modulus, inv); - r - } - } - - #[ark_ff_asm::unroll_for_loops] - const fn mul_without_reduce(mut self, other: &Self, modulus: $BigIntegerType, inv: u64) -> Self { - let mut r = [0u64; $limbs * 2]; - - for i in 0..$limbs { - let mut carry = 0; - for j in 0..$limbs { - r[j + i] = mac_with_carry!(r[j + i], (self.0).0[i], (other.0).0[j], &mut carry); - } - r[$limbs + i] = carry; - } - // Montgomery reduction - let mut _carry2 = 0; - for i in 0..$limbs { - let k = r[i].wrapping_mul(inv); - let mut carry = 0; - mac_with_carry!(r[i], k, modulus.0[0], &mut carry); - for j in 1..$limbs { - r[j + i] = mac_with_carry!(r[j + i], k, modulus.0[j], &mut carry); - } - r[$limbs + i] = adc!(r[$limbs + i], _carry2, &mut carry); - _carry2 = carry; - } - - for i in 0..$limbs { - (self.0).0[i] = r[$limbs + i]; - } - self - } - - #[ark_ff_asm::unroll_for_loops] - const fn const_mul(mut self, other: &Self, modulus: $BigIntegerType, inv: u64) -> Self { - self = self.mul_without_reduce(other, modulus, inv); - self.const_reduce(modulus) - } - - - #[ark_ff_asm::unroll_for_loops] - const fn const_is_valid(&self, modulus: $BigIntegerType) -> bool { - for i in 0..$limbs { - if (self.0).0[($limbs - i - 1)] < modulus.0[($limbs - i - 1)] { - return true - } else if (self.0).0[($limbs - i - 1)] > modulus.0[($limbs - i - 1)] { - return false - } - } - false - } - - #[inline] - const fn const_reduce(mut self, modulus: $BigIntegerType) -> Self { - if !self.const_is_valid(modulus) { - self.0 = Self::sub_noborrow(&self.0, &modulus); - } - self - } - - #[ark_ff_asm::unroll_for_loops] - // need unused assignment because the last iteration of the loop produces an assignment - // to `borrow` that is unused. - #[allow(unused_assignments)] - const fn sub_noborrow(a: &$BigIntegerType, b: &$BigIntegerType) -> $BigInteger { - let mut a = *a; - let mut borrow = 0; - for i in 0..$limbs { - a.0[i] = sbb!(a.0[i], b.0[i], &mut borrow); - } - a - } - } - - impl $Fp

{ - #[inline(always)] - pub(crate) fn is_valid(&self) -> bool { - self.0 < P::MODULUS - } - - #[inline] - fn reduce(&mut self) { - if !self.is_valid() { - self.0.sub_noborrow(&P::MODULUS); - } - } - } - - impl

ark_std::fmt::Debug for $Fp

{ - fn fmt(&self, f: &mut ark_std::fmt::Formatter<'_>) -> ark_std::fmt::Result { - ark_std::fmt::Debug::fmt(&self.0, f) - } - } - - impl Zero for $Fp

{ - #[inline] - fn zero() -> Self { - $Fp::

($BigInteger::from(0), PhantomData) - } - - #[inline] - fn is_zero(&self) -> bool { - self.0.is_zero() - } - } - - impl One for $Fp

{ - #[inline] - fn one() -> Self { - $Fp::

(P::R, PhantomData) - } - - #[inline] - fn is_one(&self) -> bool { - self.0 == P::R - } - } - - impl Field for $Fp

{ - type BasePrimeField = Self; - - fn extension_degree() -> u64 { - 1 - } - - fn from_base_prime_field_elems(elems: &[Self::BasePrimeField]) -> Option { - if elems.len() != (Self::extension_degree() as usize) { - return None; - } - Some(elems[0]) - } - - #[inline] - fn double(&self) -> Self { - let mut temp = *self; - temp.double_in_place(); - temp - } - - #[inline] - fn double_in_place(&mut self) -> &mut Self { - // This cannot exceed the backing capacity. - self.0.mul2(); - // However, it may need to be reduced. - self.reduce(); - self - } - - #[inline] - fn characteristic() -> &'static [u64] { - P::MODULUS.as_ref() - } - - #[inline] - fn from_random_bytes_with_flags(bytes: &[u8]) -> Option<(Self, F)> { - if F::BIT_SIZE > 8 { - return None - } else { - let mut result_bytes = [0u8; $limbs * 8 + 1]; - // Copy the input into a temporary buffer. - result_bytes.iter_mut().zip(bytes).for_each(|(result, input)| { - *result = *input; - }); - // This mask retains everything in the last limb - // that is below `P::MODULUS_BITS`. - let last_limb_mask = (u64::MAX >> P::REPR_SHAVE_BITS).to_le_bytes(); - let mut last_bytes_mask = [0u8; 9]; - last_bytes_mask[..8].copy_from_slice(&last_limb_mask); - - - // Length of the buffer containing the field element and the flag. - let output_byte_size = buffer_byte_size(P::MODULUS_BITS as usize + F::BIT_SIZE); - // Location of the flag is the last byte of the serialized - // form of the field element. - let flag_location = output_byte_size - 1; - - // At which byte is the flag located in the last limb? - let flag_location_in_last_limb = flag_location - (8 * ($limbs - 1)); - - // Take all but the last 9 bytes. - let last_bytes = &mut result_bytes[8 * ($limbs - 1)..]; - - // The mask only has the last `F::BIT_SIZE` bits set - let flags_mask = u8::MAX.checked_shl(8 - (F::BIT_SIZE as u32)).unwrap_or(0); - - // Mask away the remaining bytes, and try to reconstruct the - // flag - let mut flags: u8 = 0; - for (i, (b, m)) in last_bytes.iter_mut().zip(&last_bytes_mask).enumerate() { - if i == flag_location_in_last_limb { - flags = *b & flags_mask - } - *b &= m; - } - Self::deserialize(&result_bytes[..($limbs * 8)]) - .ok() - .and_then(|f| F::from_u8(flags).map(|flag| (f, flag))) - } - } - - #[inline] - fn square(&self) -> Self { - let mut temp = self.clone(); - temp.square_in_place(); - temp - } - - impl_field_square_in_place!($limbs); - - #[inline] - fn inverse(&self) -> Option { - if self.is_zero() { - None - } else { - // Guajardo Kumar Paar Pelzl - // Efficient Software-Implementation of Finite Fields with Applications to - // Cryptography - // Algorithm 16 (BEA for Inversion in Fp) - - let one = $BigInteger::from(1); - - let mut u = self.0; - let mut v = P::MODULUS; - let mut b = $Fp::

(P::R2, PhantomData); // Avoids unnecessary reduction step. - let mut c = Self::zero(); - - while u != one && v != one { - while u.is_even() { - u.div2(); - - if b.0.is_even() { - b.0.div2(); - } else { - b.0.add_nocarry(&P::MODULUS); - b.0.div2(); - } - } - - while v.is_even() { - v.div2(); - - if c.0.is_even() { - c.0.div2(); - } else { - c.0.add_nocarry(&P::MODULUS); - c.0.div2(); - } - } - - if v < u { - u.sub_noborrow(&v); - b.sub_assign(&c); - } else { - v.sub_noborrow(&u); - c.sub_assign(&b); - } - } - - if u == one { - Some(b) - } else { - Some(c) - } - } - } - - fn inverse_in_place(&mut self) -> Option<&mut Self> { - if let Some(inverse) = self.inverse() { - *self = inverse; - Some(self) - } else { - None - } - } - - /// The Frobenius map has no effect in a prime field. - #[inline] - fn frobenius_map(&mut self, _: usize) {} - } - - impl PrimeField for $Fp

{ - type Params = P; - type BigInt = $BigIntegerType; - - #[inline] - fn from_repr(r: $BigIntegerType) -> Option { - let mut r = $Fp(r, PhantomData); - if r.is_zero() { - Some(r) - } else if r.is_valid() { - r *= &$Fp(P::R2, PhantomData); - Some(r) - } else { - None - } - } - - impl_field_into_repr!($limbs, $BigIntegerType); - } - - impl FftField for $Fp

{ - type FftParams = P; - - #[inline] - fn two_adic_root_of_unity() -> Self { - $Fp::

(P::TWO_ADIC_ROOT_OF_UNITY, PhantomData) - } - - #[inline] - fn large_subgroup_root_of_unity() -> Option { - Some($Fp::

(P::LARGE_SUBGROUP_ROOT_OF_UNITY?, PhantomData)) - } - - #[inline] - fn multiplicative_generator() -> Self { - $Fp::

(P::GENERATOR, PhantomData) - } - } - - impl SquareRootField for $Fp

{ - #[inline] - fn legendre(&self) -> LegendreSymbol { - use crate::fields::LegendreSymbol::*; - - // s = self^((MODULUS - 1) // 2) - let s = self.pow(P::MODULUS_MINUS_ONE_DIV_TWO); - if s.is_zero() { - Zero - } else if s.is_one() { - QuadraticResidue - } else { - QuadraticNonResidue - } - } - - #[inline] - fn sqrt(&self) -> Option { - sqrt_impl!(Self, P, self) - } - - fn sqrt_in_place(&mut self) -> Option<&mut Self> { - (*self).sqrt().map(|sqrt| { - *self = sqrt; - self - }) - } - } - - /// Note that this implementation of `Ord` compares field elements viewing - /// them as integers in the range 0, 1, ..., P::MODULUS - 1. However, other - /// implementations of `PrimeField` might choose a different ordering, and - /// as such, users should use this `Ord` for applications where - /// any ordering suffices (like in a BTreeMap), and not in applications - /// where a particular ordering is required. - impl Ord for $Fp

{ - #[inline(always)] - fn cmp(&self, other: &Self) -> Ordering { - self.into_repr().cmp(&other.into_repr()) - } - } - - /// Note that this implementation of `PartialOrd` compares field elements viewing - /// them as integers in the range 0, 1, ..., `P::MODULUS` - 1. However, other - /// implementations of `PrimeField` might choose a different ordering, and - /// as such, users should use this `PartialOrd` for applications where - /// any ordering suffices (like in a BTreeMap), and not in applications - /// where a particular ordering is required. - impl PartialOrd for $Fp

{ - #[inline(always)] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } - - impl_prime_field_from_int!($Fp, 128, $FpParameters, $limbs); - impl_prime_field_from_int!($Fp, 64, $FpParameters, $limbs); - impl_prime_field_from_int!($Fp, 32, $FpParameters, $limbs); - impl_prime_field_from_int!($Fp, 16, $FpParameters, $limbs); - impl_prime_field_from_int!($Fp, 8, $FpParameters, $limbs); - impl_prime_field_from_int!($Fp, bool, $FpParameters, $limbs); - - impl_prime_field_standard_sample!($Fp, $FpParameters); - - impl_prime_field_serializer!($Fp, $FpParameters, $limbs * 8); - - impl ToBytes for $Fp

{ - #[inline] - fn write(&self, writer: W) -> IoResult<()> { - self.into_repr().write(writer) - } - } - - impl FromBytes for $Fp

{ - #[inline] - fn read(reader: R) -> IoResult { - $BigInteger::read(reader).and_then(|b| - match $Fp::from_repr(b) { - Some(f) => Ok(f), - None => Err(crate::error("FromBytes::read failed")), - }) - } - } - - impl FromStr for $Fp

{ - type Err = (); - - /// Interpret a string of numbers as a (congruent) prime field element. - /// Does not accept unnecessary leading zeroes or a blank string. - fn from_str(s: &str) -> Result { - if s.is_empty() { - return Err(()); - } - - if s == "0" { - return Ok(Self::zero()); - } - - let mut res = Self::zero(); - - let ten = Self::from(::BigInt::from(10)); - - let mut first_digit = true; - - for c in s.chars() { - match c.to_digit(10) { - Some(c) => { - if first_digit { - if c == 0 { - return Err(()); - } - - first_digit = false; - } - - res.mul_assign(&ten); - let digit = Self::from(u64::from(c)); - res.add_assign(&digit); - }, - None => { - return Err(()); - }, - } - } - if !res.is_valid() { - Err(()) - } else { - Ok(res) - } - } - } - - /// Outputs a string containing the value of `self`, chunked up into - /// 64-bit limbs. - impl Display for $Fp

{ - #[inline] - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, stringify!($Fp "({})"), self.into_repr()) - } - } - - impl Neg for $Fp

{ - type Output = Self; - #[inline] - #[must_use] - fn neg(self) -> Self { - if !self.is_zero() { - let mut tmp = P::MODULUS; - tmp.sub_noborrow(&self.0); - $Fp::

(tmp, PhantomData) - } else { - self - } - } - } - - impl<'a, P: $FpParameters> Add<&'a $Fp

> for $Fp

{ - type Output = Self; - - #[inline] - fn add(mut self, other: &Self) -> Self { - self.add_assign(other); - self - } - } - - impl<'a, P: $FpParameters> Sub<&'a $Fp

> for $Fp

{ - type Output = Self; - - #[inline] - fn sub(mut self, other: &Self) -> Self { - self.sub_assign(other); - self - } - } - - impl<'a, P: $FpParameters> Mul<&'a $Fp

> for $Fp

{ - type Output = Self; - - #[inline] - fn mul(mut self, other: &Self) -> Self { - self.mul_assign(other); - self - } - } - - impl<'a, P: $FpParameters> Div<&'a $Fp

> for $Fp

{ - type Output = Self; - - /// Returns `self * other.inverse()` if `other.inverse()` is `Some`, and - /// panics otherwise. - #[inline] - fn div(mut self, other: &Self) -> Self { - self.mul_assign(&other.inverse().unwrap()); - self - } - } - - impl_additive_ops_from_ref!($Fp, $FpParameters); - impl_multiplicative_ops_from_ref!($Fp, $FpParameters); - - impl<'a, P: $FpParameters> AddAssign<&'a Self> for $Fp

{ - #[inline] - fn add_assign(&mut self, other: &Self) { - // This cannot exceed the backing capacity. - self.0.add_nocarry(&other.0); - // However, it may need to be reduced - self.reduce(); - } - } - - impl<'a, P: $FpParameters> SubAssign<&'a Self> for $Fp

{ - #[inline] - fn sub_assign(&mut self, other: &Self) { - // If `other` is larger than `self`, add the modulus to self first. - if other.0 > self.0 { - self.0.add_nocarry(&P::MODULUS); - } - self.0.sub_noborrow(&other.0); - } - } - - impl<'a, P: $FpParameters> MulAssign<&'a Self> for $Fp

{ - impl_field_mul_assign!($limbs); - } - - /// Computes `self *= other.inverse()` if `other.inverse()` is `Some`, and - /// panics otherwise. - impl<'a, P: $FpParameters> DivAssign<&'a Self> for $Fp

{ - #[inline] - fn div_assign(&mut self, other: &Self) { - self.mul_assign(&other.inverse().unwrap()); - } - } - - impl zeroize::Zeroize for $Fp

{ - // The phantom data does not contain element-specific data - // and thus does not need to be zeroized. - fn zeroize(&mut self) { - self.0.zeroize(); - } - } - - impl From for $Fp

{ - #[inline] - fn from(val: num_bigint::BigUint) -> $Fp

{ - $Fp::

::from_le_bytes_mod_order(&val.to_bytes_le()) - } - } - - impl From<$Fp

> for num_bigint::BigUint { - #[inline] - fn from(other: $Fp

) -> Self { - other.into_repr().into() - } - } - } -} diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index bc6df82de..ff5b6f514 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -1,9 +1,4 @@ -use crate::{ - biginteger::BigInteger, - bytes::{FromBytes, ToBytes}, - fields::utils::k_adicity, - UniformRand, -}; +use crate::{biginteger::BigInteger, fields::utils::k_adicity, FromBytes, ToBytes, UniformRand}; use ark_serialize::{ CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize, CanonicalSerializeWithFlags, EmptyFlags, Flags, @@ -18,16 +13,16 @@ use ark_std::{ }; pub use ark_ff_macros; +use num_bigint::BigUint; use num_traits::{One, Zero}; use zeroize::Zeroize; -#[macro_use] -pub mod macros; pub mod utils; #[macro_use] pub mod arithmetic; +#[macro_use] pub mod models; pub use self::models::*; @@ -36,37 +31,9 @@ use ark_std::cmp::max; #[cfg(feature = "parallel")] use rayon::prelude::*; -#[macro_export] -macro_rules! field_new { - ($name:ident, $c0:expr) => {{ - use $crate::FpParameters; - type Params = <$name as $crate::PrimeField>::Params; - let (is_positive, limbs) = $crate::ark_ff_macros::to_sign_and_limbs!($c0); - $name::const_from_str( - &limbs, - is_positive, - Params::R2, - Params::MODULUS, - Params::INV, - ) - }}; - ($name:ident, $c0:expr, $c1:expr $(,)?) => { - $name { c0: $c0, c1: $c1 } - }; - ($name:ident, $c0:expr, $c1:expr, $c2:expr $(,)?) => { - $name { - c0: $c0, - c1: $c1, - c2: $c2, - } - }; -} - /// The interface for a generic field. pub trait Field: - ToBytes - + 'static - + FromBytes + 'static + Copy + Clone + Debug @@ -87,6 +54,8 @@ pub trait Field: + CanonicalSerializeWithFlags + CanonicalDeserialize + CanonicalDeserializeWithFlags + + ToBytes + + FromBytes + Add + Sub + Mul @@ -204,9 +173,10 @@ pub trait Field: } } -/// A trait that defines parameters for a field that can be used for FFTs. -pub trait FftParameters: 'static + Send + Sync + Sized { - type BigInt: BigInteger; +/// The interface for fields that are able to be used in FFTs. +pub trait FftField: Field { + /// The generator of the multiplicative group of the field + const GENERATOR: Self; /// Let `N` be the size of the multiplicative group defined by the field. /// Then `TWO_ADICITY` is the two-adicity of `N`, i.e. the integer `s` @@ -214,7 +184,7 @@ pub trait FftParameters: 'static + Send + Sync + Sized { const TWO_ADICITY: u32; /// 2^s root of unity computed by GENERATOR^t - const TWO_ADIC_ROOT_OF_UNITY: Self::BigInt; + const TWO_ADIC_ROOT_OF_UNITY: Self; /// An integer `b` such that there exists a multiplicative subgroup /// of size `b^k` for some integer `k`. @@ -227,89 +197,33 @@ pub trait FftParameters: 'static + Send + Sync + Sized { /// GENERATOR^((MODULUS-1) / (2^s * /// SMALL_SUBGROUP_BASE^SMALL_SUBGROUP_BASE_ADICITY)) Used for mixed-radix /// FFT. - const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = None; -} - -/// A trait that defines parameters for a prime field. -pub trait FpParameters: FftParameters { - /// The modulus of the field. - const MODULUS: Self::BigInt; - - /// The number of bits needed to represent the `Self::MODULUS`. - const MODULUS_BITS: u32; - - /// The number of bits that must be shaved from the beginning of - /// the representation when randomly sampling. - const REPR_SHAVE_BITS: u32; - - /// Let `M` be the power of 2^64 nearest to `Self::MODULUS_BITS`. Then - /// `R = M % Self::MODULUS`. - const R: Self::BigInt; - - /// R2 = R^2 % Self::MODULUS - const R2: Self::BigInt; - - /// INV = -MODULUS^{-1} mod 2^64 - const INV: u64; - - /// A multiplicative generator of the field. - /// `Self::GENERATOR` is an element having multiplicative order - /// `Self::MODULUS - 1`. - const GENERATOR: Self::BigInt; - - /// The number of bits that can be reliably stored. - /// (Should equal `SELF::MODULUS_BITS - 1`) - const CAPACITY: u32; - - /// t for 2^s * t = MODULUS - 1, and t coprime to 2. - const T: Self::BigInt; - - /// (t - 1) / 2 - const T_MINUS_ONE_DIV_TWO: Self::BigInt; - - /// (Self::MODULUS - 1) / 2 - const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt; -} - -/// The interface for fields that are able to be used in FFTs. -pub trait FftField: Field { - type FftParams: FftParameters; - - /// Returns the 2^s root of unity. - fn two_adic_root_of_unity() -> Self; - - /// Returns the 2^s * small_subgroup_base^small_subgroup_base_adicity root - /// of unity if a small subgroup is defined. - fn large_subgroup_root_of_unity() -> Option; - - /// Returns the multiplicative generator of `char()` - 1 order. - fn multiplicative_generator() -> Self; + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = None; /// Returns the root of unity of order n, if one exists. /// If no small multiplicative subgroup is defined, this is the 2-adic root /// of unity of order n (for n a power of 2). /// If a small multiplicative subgroup is defined, this is the root of unity /// of order n for the larger subgroup generated by - /// `FftParams::LARGE_SUBGROUP_ROOT_OF_UNITY` - /// (for n = 2^i * FftParams::SMALL_SUBGROUP_BASE^j for some i, j). - fn get_root_of_unity(n: usize) -> Option { + /// `FftConfig::LARGE_SUBGROUP_ROOT_OF_UNITY` + /// (for n = 2^i * FftConfig::SMALL_SUBGROUP_BASE^j for some i, j). + fn get_root_of_unity(n: u64) -> Option { let mut omega: Self; - if let Some(large_subgroup_root_of_unity) = Self::large_subgroup_root_of_unity() { - let q = Self::FftParams::SMALL_SUBGROUP_BASE.expect( + if let Some(large_subgroup_root_of_unity) = Self::LARGE_SUBGROUP_ROOT_OF_UNITY { + let q = Self::SMALL_SUBGROUP_BASE.expect( "LARGE_SUBGROUP_ROOT_OF_UNITY should only be set in conjunction with SMALL_SUBGROUP_BASE", - ) as usize; - let small_subgroup_base_adicity = Self::FftParams::SMALL_SUBGROUP_BASE_ADICITY.expect( + ) as u64; + let small_subgroup_base_adicity = Self::SMALL_SUBGROUP_BASE_ADICITY.expect( "LARGE_SUBGROUP_ROOT_OF_UNITY should only be set in conjunction with SMALL_SUBGROUP_BASE_ADICITY", ); let q_adicity = k_adicity(q, n); - let q_part = q.pow(q_adicity); + let q_part = q.checked_pow(q_adicity)?; let two_adicity = k_adicity(2, n); - let two_part = 1 << two_adicity; + let two_part = 2u64.checked_pow(two_adicity)?; if n != two_part * q_part - || (two_adicity > Self::FftParams::TWO_ADICITY) + || (two_adicity > Self::TWO_ADICITY) || (q_adicity > small_subgroup_base_adicity) { return None; @@ -320,7 +234,7 @@ pub trait FftField: Field { omega = omega.pow(&[q as u64]); } - for _ in two_adicity..Self::FftParams::TWO_ADICITY { + for _ in two_adicity..Self::TWO_ADICITY { omega.square_in_place(); } } else { @@ -328,14 +242,14 @@ pub trait FftField: Field { let size = n.next_power_of_two() as u64; let log_size_of_group = ark_std::log2(usize::try_from(size).expect("too large")); - if n != size as usize || log_size_of_group > Self::FftParams::TWO_ADICITY { + if n != size || log_size_of_group > Self::TWO_ADICITY { return None; } // Compute the generator for the multiplicative subgroup. // It should be 2^(log_size_of_group) root of unity. - omega = Self::two_adic_root_of_unity(); - for _ in log_size_of_group..Self::FftParams::TWO_ADICITY { + omega = Self::TWO_ADIC_ROOT_OF_UNITY; + for _ in log_size_of_group..Self::TWO_ADICITY { omega.square_in_place(); } } @@ -343,32 +257,46 @@ pub trait FftField: Field { } } -/// The interface for a prime field. +/// The interface for a prime field, i.e. the field of integers modulo a prime p. pub trait PrimeField: Field - + FftField::Params> + + FftField + FromStr + From<::BigInt> + Into<::BigInt> + From + Into { - /// Associated `FpParameters` that define this field. - type Params: FpParameters; - /// A `BigInteger` type that can represent elements of this field. type BigInt: BigInteger; - /// Returns a prime field element from its underlying representation. - fn from_repr(repr: Self::BigInt) -> Option; + /// The modulus `p`. + const MODULUS: Self::BigInt; + /// The value `(p - 1)/ 2`. + const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt; + /// The size of the modulus in bits. + const MODULUS_BIT_SIZE: u32; + + /// The multiplicative generator of this field. + const GENERATOR: Self; + + /// The trace of the field is defined as the smallest integer `t` such that by + /// `2^s * t = p - 1`, and `t` is coprime to 2. + const TRACE: Self::BigInt; + /// The value `(t - 1)/ 2`. + const TRACE_MINUS_ONE_DIV_TWO: Self::BigInt; - /// Returns the underlying representation of the prime field element. - fn into_repr(&self) -> Self::BigInt; + /// Construct a prime field element from an integer in the range 0..(p - 1). + fn from_bigint(repr: Self::BigInt) -> Option; + + /// Converts an element of the prime field into an integer in the range 0..(p - 1). + fn into_bigint(&self) -> Self::BigInt; /// Reads bytes in big-endian, and converts them to a field element. - /// If the bytes are larger than the modulus, it will reduce them. + /// If the integer represented by `bytes` is larger than the modulus `p`, this method + /// performs the appropriate reduction. fn from_be_bytes_mod_order(bytes: &[u8]) -> Self { - let num_modulus_bytes = ((Self::Params::MODULUS_BITS + 7) / 8) as usize; + let num_modulus_bytes = ((Self::MODULUS_BIT_SIZE + 7) / 8) as usize; let num_bytes_to_directly_convert = min(num_modulus_bytes - 1, bytes.len()); // Copy the leading big-endian bytes directly into a field element. // The number of bytes directly converted must be less than the @@ -393,51 +321,22 @@ pub trait PrimeField: } /// Reads bytes in little-endian, and converts them to a field element. - /// If the bytes are larger than the modulus, it will reduce them. + /// If the integer represented by `bytes` is larger than the modulus `p`, this method + /// performs the appropriate reduction. fn from_le_bytes_mod_order(bytes: &[u8]) -> Self { let mut bytes_copy = bytes.to_vec(); bytes_copy.reverse(); Self::from_be_bytes_mod_order(&bytes_copy) } - - /// Return the QNR^t, for t defined by - /// `2^s * t = MODULUS - 1`, and t coprime to 2. - fn qnr_to_t() -> Self { - Self::two_adic_root_of_unity() - } - - /// Returns the field size in bits. - fn size_in_bits() -> usize { - Self::Params::MODULUS_BITS as usize - } - - /// Returns the trace. - fn trace() -> Self::BigInt { - Self::Params::T - } - - /// Returns the trace minus one divided by two. - fn trace_minus_one_div_two() -> Self::BigInt { - Self::Params::T_MINUS_ONE_DIV_TWO - } - - /// Returns the modulus. - fn modulus() -> Self::BigInt { - Self::Params::MODULUS - } - - /// Returns the modulus minus one divided by two. - fn modulus_minus_one_div_two() -> Self::BigInt { - Self::Params::MODULUS_MINUS_ONE_DIV_TWO - } } /// The interface for a field that supports an efficient square-root operation. pub trait SquareRootField: Field { /// Returns a `LegendreSymbol`, which indicates whether this field element - /// is 1 : a quadratic residue - /// 0 : equal to 0 - /// -1 : a quadratic non-residue + /// is + /// - 1: a quadratic residue + /// - 0: equal to 0 + /// - -1: a quadratic non-residue fn legendre(&self) -> LegendreSymbol; /// Returns the square root of self, if it exists. @@ -453,9 +352,8 @@ pub trait SquareRootField: Field { /// # Examples /// ``` /// # use ark_std::test_rng; -/// # use ark_test_curves::bls12_381::Fq as Fp; /// # use ark_std::UniformRand; -/// # use ark_ff::{LegendreSymbol, Field, SquareRootField}; +/// # use ark_test_curves::{LegendreSymbol, Field, SquareRootField, bls12_381::Fq as Fp}; /// let a: Fp = Fp::rand(&mut test_rng()); /// let b = a.square(); /// assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); @@ -473,9 +371,8 @@ impl LegendreSymbol { /// # Examples /// ``` /// # use ark_std::test_rng; - /// # use ark_test_curves::bls12_381::Fq as Fp; /// # use ark_std::UniformRand; - /// # use ark_ff::{LegendreSymbol, Field, SquareRootField}; + /// # use ark_test_curves::{LegendreSymbol, Field, SquareRootField, bls12_381::Fq as Fp}; /// let a: Fp = Fp::rand(&mut test_rng()); /// let b: Fp = a.square(); /// assert!(!b.legendre().is_zero()); @@ -488,10 +385,8 @@ impl LegendreSymbol { /// /// # Examples /// ``` - /// # use ark_test_curves::bls12_381::{Fq, Fq2Parameters}; - /// # use ark_ff::{LegendreSymbol, SquareRootField}; - /// # use ark_ff::Fp2Parameters; - /// let a: Fq = Fq2Parameters::NONRESIDUE; + /// # use ark_test_curves::{Fp2Config, LegendreSymbol, SquareRootField, bls12_381::{Fq, Fq2Config}}; + /// let a: Fq = Fq2Config::NONRESIDUE; /// assert!(a.legendre().is_qnr()); /// ``` pub fn is_qnr(&self) -> bool { @@ -597,20 +492,6 @@ impl> Iterator for BitIteratorLE { } } -use crate::biginteger::{ - BigInteger256, BigInteger320, BigInteger384, BigInteger448, BigInteger64, BigInteger768, - BigInteger832, -}; -use num_bigint::BigUint; - -impl_field_bigint_conv!(Fp64, BigInteger64, Fp64Parameters); -impl_field_bigint_conv!(Fp256, BigInteger256, Fp256Parameters); -impl_field_bigint_conv!(Fp320, BigInteger320, Fp320Parameters); -impl_field_bigint_conv!(Fp384, BigInteger384, Fp384Parameters); -impl_field_bigint_conv!(Fp448, BigInteger448, Fp448Parameters); -impl_field_bigint_conv!(Fp768, BigInteger768, Fp768Parameters); -impl_field_bigint_conv!(Fp832, BigInteger832, Fp832Parameters); - // Given a vector of field elements {v_i}, compute the vector {v_i^(-1)} pub fn batch_inversion(v: &mut [F]) { batch_inversion_and_mul(v, &F::one()); @@ -699,14 +580,10 @@ mod std_tests { mod no_std_tests { use super::*; use ark_std::test_rng; - // TODO: only Fr & FrParameters should need to be imported. + // TODO: only Fr & FrConfig should need to be imported. // The rest of imports are caused by cargo not resolving the deps properly // from this crate and from ark_test_curves - use ark_test_curves::{ - batch_inversion, batch_inversion_and_mul, - bls12_381::{Fr, FrParameters}, - BigInteger, FpParameters, PrimeField, - }; + use ark_test_curves::{batch_inversion, batch_inversion_and_mul, bls12_381::Fr, PrimeField}; #[test] fn test_batch_inversion() { @@ -737,8 +614,8 @@ mod no_std_tests { fn test_from_into_biguint() { let mut rng = ark_std::test_rng(); - let modulus_bits = FrParameters::MODULUS_BITS; - let modulus: num_bigint::BigUint = FrParameters::MODULUS.into(); + let modulus_bits = Fr::MODULUS_BIT_SIZE; + let modulus: num_bigint::BigUint = Fr::MODULUS.into(); let mut rand_bytes = Vec::new(); for _ in 0..(2 * modulus_bits / 8) { @@ -761,10 +638,10 @@ mod no_std_tests { // TODO: Eventually generate all the test vector bytes via computation with the // modulus use ark_std::{rand::Rng, string::ToString}; + use ark_test_curves::BigInteger; use num_bigint::BigUint; - let ref_modulus = - BigUint::from_bytes_be(&::Params::MODULUS.to_bytes_be()); + let ref_modulus = BigUint::from_bytes_be(&Fr::MODULUS.to_bytes_be()); let mut test_vectors = vec![ // 0 diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index 970c5c3d5..247ae0b13 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -25,7 +25,7 @@ use crate::{ }; /// Defines a Cubic extension field from a cubic non-residue. -pub trait CubicExtParameters: 'static + Send + Sync { +pub trait CubicExtConfig: 'static + Send + Sync { /// The prime field that this cubic extension is eventually an extension of. type BasePrimeField: PrimeField; /// The base field that this field is a cubic extension of. @@ -68,21 +68,43 @@ pub trait CubicExtParameters: 'static + Send + Sync { /// represented as c0 + c1 * X + c2 * X^2, for c0, c1, c2 in `P::BaseField`. #[derive(Derivative)] #[derivative( - Default(bound = "P: CubicExtParameters"), - Hash(bound = "P: CubicExtParameters"), - Clone(bound = "P: CubicExtParameters"), - Copy(bound = "P: CubicExtParameters"), - Debug(bound = "P: CubicExtParameters"), - PartialEq(bound = "P: CubicExtParameters"), - Eq(bound = "P: CubicExtParameters") + Default(bound = "P: CubicExtConfig"), + Hash(bound = "P: CubicExtConfig"), + Clone(bound = "P: CubicExtConfig"), + Copy(bound = "P: CubicExtConfig"), + Debug(bound = "P: CubicExtConfig"), + PartialEq(bound = "P: CubicExtConfig"), + Eq(bound = "P: CubicExtConfig") )] -pub struct CubicExtField { +pub struct CubicExtField { pub c0: P::BaseField, pub c1: P::BaseField, pub c2: P::BaseField, } -impl CubicExtField

{ +/// Construct a [`CubicExtField`] element from elements of the base field. This should +/// be used primarily for constructing constant field elements; in a non-const +/// context, [`CubicExtField::new`] is preferable. +/// +/// # Usage +/// ```rust +/// # use ark_test_curves::CubicExt; +/// # use ark_test_curves::mnt6_753 as ark_mnt6_753; +/// use ark_mnt6_753::{FQ_ZERO, FQ_ONE, Fq3}; +/// const ONE: Fq3 = CubicExt!(FQ_ONE, FQ_ZERO, FQ_ZERO); +/// ``` +#[macro_export] +macro_rules! CubicExt { + ($c0:expr, $c1:expr, $c2:expr $(,)?) => { + $crate::CubicExtField { + c0: $c0, + c1: $c1, + c2: $c2, + } + }; +} + +impl CubicExtField

{ /// Create a new field element from coefficients `c0`, `c1` and `c2` /// so that the result is of the form `c0 + c1 * X + c2 * X^2`. /// @@ -91,7 +113,7 @@ impl CubicExtField

{ /// ``` /// # use ark_std::test_rng; /// # use ark_test_curves::bls12_381::{Fq2 as Fp2, Fq6 as Fp6}; - /// # use ark_test_curves::bls12_381::Fq6Parameters; + /// # use ark_test_curves::bls12_381::Fq6Config; /// # use ark_std::UniformRand; /// # use ark_ff::models::fp6_3over2::Fp6ParamsWrapper; /// use ark_ff::models::cubic_extension::CubicExtField; @@ -99,7 +121,7 @@ impl CubicExtField

{ /// let c0: Fp2 = Fp2::rand(&mut test_rng()); /// let c1: Fp2 = Fp2::rand(&mut test_rng()); /// let c2: Fp2 = Fp2::rand(&mut test_rng()); - /// # type Params = Fp6ParamsWrapper; + /// # type Params = Fp6ParamsWrapper; /// // `Fp6` a degree-3 extension over `Fp2`. /// let c: CubicExtField = Fp6::new(c0, c1, c2); /// ``` @@ -132,7 +154,7 @@ impl CubicExtField

{ } } -impl Zero for CubicExtField

{ +impl Zero for CubicExtField

{ fn zero() -> Self { Self::new( P::BaseField::zero(), @@ -146,7 +168,7 @@ impl Zero for CubicExtField

{ } } -impl One for CubicExtField

{ +impl One for CubicExtField

{ fn one() -> Self { Self::new( P::BaseField::one(), @@ -160,7 +182,7 @@ impl One for CubicExtField

{ } } -impl Field for CubicExtField

{ +impl Field for CubicExtField

{ type BasePrimeField = P::BasePrimeField; fn extension_degree() -> u64 { @@ -293,7 +315,7 @@ impl Field for CubicExtField

{ } /// `CubicExtField` elements are ordered lexicographically. -impl Ord for CubicExtField

{ +impl Ord for CubicExtField

{ #[inline(always)] fn cmp(&self, other: &Self) -> Ordering { let c2_cmp = self.c2.cmp(&other.c2); @@ -311,14 +333,14 @@ impl Ord for CubicExtField

{ } } -impl PartialOrd for CubicExtField

{ +impl PartialOrd for CubicExtField

{ #[inline(always)] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Zeroize for CubicExtField

{ +impl Zeroize for CubicExtField

{ // The phantom data does not contain element-specific data // and thus does not need to be zeroized. fn zeroize(&mut self) { @@ -328,14 +350,14 @@ impl Zeroize for CubicExtField

{ } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ fn from(other: u128) -> Self { let fe: P::BaseField = other.into(); Self::new(fe, P::BaseField::zero(), P::BaseField::zero()) } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ #[inline] fn from(val: i128) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -347,14 +369,14 @@ impl From for CubicExtField

{ } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ fn from(other: u64) -> Self { let fe: P::BaseField = other.into(); Self::new(fe, P::BaseField::zero(), P::BaseField::zero()) } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ #[inline] fn from(val: i64) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -366,14 +388,14 @@ impl From for CubicExtField

{ } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ fn from(other: u32) -> Self { let fe: P::BaseField = other.into(); Self::new(fe, P::BaseField::zero(), P::BaseField::zero()) } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ #[inline] fn from(val: i32) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -385,14 +407,14 @@ impl From for CubicExtField

{ } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ fn from(other: u16) -> Self { let fe: P::BaseField = other.into(); Self::new(fe, P::BaseField::zero(), P::BaseField::zero()) } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ #[inline] fn from(val: i16) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -404,14 +426,14 @@ impl From for CubicExtField

{ } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ fn from(other: u8) -> Self { let fe: P::BaseField = other.into(); Self::new(fe, P::BaseField::zero(), P::BaseField::zero()) } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ #[inline] fn from(val: i8) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -423,7 +445,7 @@ impl From for CubicExtField

{ } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ fn from(other: bool) -> Self { Self::new( u8::from(other).into(), @@ -433,26 +455,7 @@ impl From for CubicExtField

{ } } -impl ToBytes for CubicExtField

{ - #[inline] - fn write(&self, mut writer: W) -> IoResult<()> { - self.c0.write(&mut writer)?; - self.c1.write(&mut writer)?; - self.c2.write(writer) - } -} - -impl FromBytes for CubicExtField

{ - #[inline] - fn read(mut reader: R) -> IoResult { - let c0 = P::BaseField::read(&mut reader)?; - let c1 = P::BaseField::read(&mut reader)?; - let c2 = P::BaseField::read(reader)?; - Ok(CubicExtField::new(c0, c1, c2)) - } -} - -impl Neg for CubicExtField

{ +impl Neg for CubicExtField

{ type Output = Self; #[inline] fn neg(mut self) -> Self { @@ -463,7 +466,7 @@ impl Neg for CubicExtField

{ } } -impl Distribution> for Standard { +impl Distribution> for Standard { #[inline] fn sample(&self, rng: &mut R) -> CubicExtField

{ CubicExtField::new( @@ -474,7 +477,7 @@ impl Distribution> for Standard { } } -impl<'a, P: CubicExtParameters> Add<&'a CubicExtField

> for CubicExtField

{ +impl<'a, P: CubicExtConfig> Add<&'a CubicExtField

> for CubicExtField

{ type Output = Self; #[inline] @@ -484,7 +487,7 @@ impl<'a, P: CubicExtParameters> Add<&'a CubicExtField

> for CubicExtField

{ } } -impl<'a, P: CubicExtParameters> Sub<&'a CubicExtField

> for CubicExtField

{ +impl<'a, P: CubicExtConfig> Sub<&'a CubicExtField

> for CubicExtField

{ type Output = Self; #[inline] @@ -494,7 +497,7 @@ impl<'a, P: CubicExtParameters> Sub<&'a CubicExtField

> for CubicExtField

{ } } -impl<'a, P: CubicExtParameters> Mul<&'a CubicExtField

> for CubicExtField

{ +impl<'a, P: CubicExtConfig> Mul<&'a CubicExtField

> for CubicExtField

{ type Output = Self; #[inline] @@ -504,7 +507,7 @@ impl<'a, P: CubicExtParameters> Mul<&'a CubicExtField

> for CubicExtField

{ } } -impl<'a, P: CubicExtParameters> Div<&'a CubicExtField

> for CubicExtField

{ +impl<'a, P: CubicExtConfig> Div<&'a CubicExtField

> for CubicExtField

{ type Output = Self; #[inline] @@ -514,9 +517,9 @@ impl<'a, P: CubicExtParameters> Div<&'a CubicExtField

> for CubicExtField

{ } } -impl_additive_ops_from_ref!(CubicExtField, CubicExtParameters); -impl_multiplicative_ops_from_ref!(CubicExtField, CubicExtParameters); -impl<'a, P: CubicExtParameters> AddAssign<&'a Self> for CubicExtField

{ +impl_additive_ops_from_ref!(CubicExtField, CubicExtConfig); +impl_multiplicative_ops_from_ref!(CubicExtField, CubicExtConfig); +impl<'a, P: CubicExtConfig> AddAssign<&'a Self> for CubicExtField

{ #[inline] fn add_assign(&mut self, other: &Self) { self.c0.add_assign(&other.c0); @@ -525,7 +528,7 @@ impl<'a, P: CubicExtParameters> AddAssign<&'a Self> for CubicExtField

{ } } -impl<'a, P: CubicExtParameters> SubAssign<&'a Self> for CubicExtField

{ +impl<'a, P: CubicExtConfig> SubAssign<&'a Self> for CubicExtField

{ #[inline] fn sub_assign(&mut self, other: &Self) { self.c0.sub_assign(&other.c0); @@ -534,7 +537,7 @@ impl<'a, P: CubicExtParameters> SubAssign<&'a Self> for CubicExtField

{ } } -impl<'a, P: CubicExtParameters> MulAssign<&'a Self> for CubicExtField

{ +impl<'a, P: CubicExtConfig> MulAssign<&'a Self> for CubicExtField

{ #[inline] #[allow(clippy::many_single_char_names)] fn mul_assign(&mut self, other: &Self) { @@ -564,20 +567,20 @@ impl<'a, P: CubicExtParameters> MulAssign<&'a Self> for CubicExtField

{ } } -impl<'a, P: CubicExtParameters> DivAssign<&'a Self> for CubicExtField

{ +impl<'a, P: CubicExtConfig> DivAssign<&'a Self> for CubicExtField

{ #[inline] fn div_assign(&mut self, other: &Self) { self.mul_assign(&other.inverse().unwrap()); } } -impl fmt::Display for CubicExtField

{ +impl fmt::Display for CubicExtField

{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "CubicExtField({}, {}, {})", self.c0, self.c1, self.c2) } } -impl CanonicalSerializeWithFlags for CubicExtField

{ +impl CanonicalSerializeWithFlags for CubicExtField

{ #[inline] fn serialize_with_flags( &self, @@ -598,7 +601,7 @@ impl CanonicalSerializeWithFlags for CubicExtField

{ } } -impl CanonicalSerialize for CubicExtField

{ +impl CanonicalSerialize for CubicExtField

{ #[inline] fn serialize(&self, writer: W) -> Result<(), SerializationError> { self.serialize_with_flags(writer, EmptyFlags) @@ -610,7 +613,7 @@ impl CanonicalSerialize for CubicExtField

{ } } -impl CanonicalDeserializeWithFlags for CubicExtField

{ +impl CanonicalDeserializeWithFlags for CubicExtField

{ #[inline] fn deserialize_with_flags( mut reader: R, @@ -622,7 +625,7 @@ impl CanonicalDeserializeWithFlags for CubicExtField

{ } } -impl CanonicalDeserialize for CubicExtField

{ +impl CanonicalDeserialize for CubicExtField

{ #[inline] fn deserialize(mut reader: R) -> Result { let c0: P::BaseField = CanonicalDeserialize::deserialize(&mut reader)?; @@ -632,7 +635,7 @@ impl CanonicalDeserialize for CubicExtField

{ } } -impl ToConstraintField for CubicExtField

+impl ToConstraintField for CubicExtField

where P::BaseField: ToConstraintField, { @@ -650,6 +653,25 @@ where } } +impl ToBytes for CubicExtField

{ + #[inline] + fn write(&self, mut writer: W) -> IoResult<()> { + self.c0.write(&mut writer)?; + self.c1.write(&mut writer)?; + self.c2.write(writer) + } +} + +impl FromBytes for CubicExtField

{ + #[inline] + fn read(mut reader: R) -> IoResult { + let c0 = P::BaseField::read(&mut reader)?; + let c1 = P::BaseField::read(&mut reader)?; + let c2 = P::BaseField::read(reader)?; + Ok(CubicExtField::new(c0, c1, c2)) + } +} + #[cfg(test)] mod cube_ext_tests { use super::*; diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs new file mode 100644 index 000000000..6d080fae3 --- /dev/null +++ b/ff/src/fields/models/fp/mod.rs @@ -0,0 +1,1021 @@ +use ark_serialize::{ + buffer_byte_size, CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize, + CanonicalSerializeWithFlags, EmptyFlags, Flags, SerializationError, +}; +use ark_std::{ + cmp::{Ord, Ordering, PartialOrd}, + fmt::{Display, Formatter, Result as FmtResult}, + io::{Read, Result as IoResult, Write}, + marker::PhantomData, + ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, + str::FromStr, + One, Zero, +}; + +#[macro_use] +mod montgomery_backend; +pub use montgomery_backend::*; + +use crate::{ + BigInt, BigInteger, FftField, Field, FromBytes, LegendreSymbol, PrimeField, SquareRootField, + ToBytes, +}; +/// A trait that specifies the configuration of a prime field. +/// Also specifies how to perform arithmetic on field elements. +pub trait FpConfig: Send + Sync + 'static + Sized { + /// The modulus of the field. + const MODULUS: crate::BigInt; + + /// A multiplicative generator of the field. + /// `Self::GENERATOR` is an element having multiplicative order + /// `Self::MODULUS - 1`. + const GENERATOR: Fp; + + /// Additive identity of the field, i.e. the element `e` + /// such that, for all elements `f` of the field, `e + f = f`. + const ZERO: Fp; + + /// Multiplicative identity of the field, i.e. the element `e` + /// such that, for all elements `f` of the field, `e * f = f`. + const ONE: Fp; + + /// Let `N` be the size of the multiplicative group defined by the field. + /// Then `TWO_ADICITY` is the two-adicity of `N`, i.e. the integer `s` + /// such that `N = 2^s * t` for some odd integer `t`. + const TWO_ADICITY: u32; + + /// 2^s root of unity computed by GENERATOR^t + const TWO_ADIC_ROOT_OF_UNITY: Fp; + + /// An integer `b` such that there exists a multiplicative subgroup + /// of size `b^k` for some integer `k`. + const SMALL_SUBGROUP_BASE: Option = None; + + /// The integer `k` such that there exists a multiplicative subgroup + /// of size `Self::SMALL_SUBGROUP_BASE^k`. + const SMALL_SUBGROUP_BASE_ADICITY: Option = None; + + /// GENERATOR^((MODULUS-1) / (2^s * + /// SMALL_SUBGROUP_BASE^SMALL_SUBGROUP_BASE_ADICITY)) Used for mixed-radix + /// FFT. + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option> = None; + + /// Set a += b. + fn add_assign(a: &mut Fp, b: &Fp); + + /// Set a -= b. + fn sub_assign(a: &mut Fp, b: &Fp); + + /// Set a = a + a. + fn double_in_place(a: &mut Fp); + + /// Set a *= b. + fn mul_assign(a: &mut Fp, b: &Fp); + + /// Set a *= b. + fn square_in_place(a: &mut Fp); + + /// Compute a^{-1} if `a` is not zero. + fn inverse(a: &Fp) -> Option>; + + /// Compute the square root of a, if it exists. + fn square_root(a: &Fp) -> Option> { + // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) + // Actually this is just normal Tonelli-Shanks; since [`Self::GENERATOR`] + // is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t` + // is also a quadratic non-residue (since `t` is odd). + if a.is_zero() { + return Some(Fp::zero()); + } + // Try computing the square root (x at the end of the algorithm) + // Check at the end of the algorithm if x was a square root + // Begin Tonelli-Shanks + let mut z = Fp::TWO_ADIC_ROOT_OF_UNITY; + let mut w = a.pow(Fp::::TRACE_MINUS_ONE_DIV_TWO); + let mut x = w * a; + let mut b = x * &w; + + let mut v = Self::TWO_ADICITY as usize; + + while !b.is_one() { + let mut k = 0usize; + + let mut b2k = b; + while !b2k.is_one() { + // invariant: b2k = b^(2^k) after entering this loop + b2k.square_in_place(); + k += 1; + } + + if k == (Self::TWO_ADICITY as usize) { + // We are in the case where self^(T * 2^k) = x^(P::MODULUS - 1) = 1, + // which means that no square root exists. + return None; + } + let j = v - k; + w = z; + for _ in 1..j { + w.square_in_place(); + } + + z = w.square(); + b *= &z; + x *= &w; + v = k; + } + // Is x the square root? If so, return it. + if x.square() == *a { + return Some(x); + } else { + // Consistency check that if no square root is found, + // it is because none exists. + #[cfg(debug_assertions)] + { + use crate::fields::LegendreSymbol::*; + if a.legendre() != QuadraticNonResidue { + panic!("Input has a square root per its Legendre symbol, but it was not found") + } + } + None + } + } + + /// Construct a field element from an integer in the range `0..(Self::MODULUS - 1)`. + /// Returns `None` if the integer is outside this range. + fn from_bigint(other: BigInt) -> Option>; + + /// Convert a field element to an integer in the range `0..(Self::MODULUS - 1)`. + fn into_bigint(other: Fp) -> BigInt; +} + +/// Represents an element of the prime field F_p, where `p == P::MODULUS`. +/// This type can represent elements in any field of size at most N * 64 bits. +#[derive(Derivative)] +#[derivative( + Default(bound = ""), + Hash(bound = ""), + Clone(bound = ""), + Copy(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +pub struct Fp( + pub BigInt, + #[derivative(Debug = "ignore")] + #[doc(hidden)] + pub PhantomData

, +); + +pub type Fp64

= Fp; +pub type Fp128

= Fp; +pub type Fp192

= Fp; +pub type Fp256

= Fp; +pub type Fp320

= Fp; +pub type Fp384

= Fp; +pub type Fp448

= Fp; +pub type Fp512

= Fp; +pub type Fp576

= Fp; +pub type Fp640

= Fp; +pub type Fp704

= Fp; +pub type Fp768

= Fp; +pub type Fp832

= Fp; + +impl Fp { + /// Construct a new prime element directly from its underlying + /// [`BigInt`] data type. + #[inline] + pub const fn new(element: BigInt) -> Self { + Self(element, PhantomData) + } +} + +impl, const N: usize> Fp { + #[inline(always)] + pub(crate) fn is_less_than_modulus(&self) -> bool { + self.0 < P::MODULUS + } + + #[inline] + fn subtract_modulus(&mut self) { + if !self.is_less_than_modulus() { + self.0.sub_noborrow(&Self::MODULUS); + } + } + + fn num_bits_to_shave() -> usize { + 64 * N - (Self::MODULUS_BIT_SIZE as usize) + } +} + +impl ark_std::fmt::Debug for Fp { + fn fmt(&self, f: &mut ark_std::fmt::Formatter<'_>) -> ark_std::fmt::Result { + ark_std::fmt::Debug::fmt(&self.0, f) + } +} + +impl, const N: usize> Zero for Fp { + #[inline] + fn zero() -> Self { + P::ZERO + } + + #[inline] + fn is_zero(&self) -> bool { + *self == P::ZERO + } +} + +impl, const N: usize> One for Fp { + #[inline] + fn one() -> Self { + P::ONE + } + + #[inline] + fn is_one(&self) -> bool { + *self == P::ONE + } +} + +impl, const N: usize> Field for Fp { + type BasePrimeField = Self; + + fn extension_degree() -> u64 { + 1 + } + + fn from_base_prime_field_elems(elems: &[Self::BasePrimeField]) -> Option { + if elems.len() != (Self::extension_degree() as usize) { + return None; + } + Some(elems[0]) + } + + #[inline] + fn double(&self) -> Self { + let mut temp = *self; + temp.double_in_place(); + temp + } + + #[inline] + fn double_in_place(&mut self) -> &mut Self { + P::double_in_place(self); + self + } + + #[inline] + fn characteristic() -> &'static [u64] { + P::MODULUS.as_ref() + } + + #[inline] + fn from_random_bytes_with_flags(bytes: &[u8]) -> Option<(Self, F)> { + if F::BIT_SIZE > 8 { + return None; + } else { + let shave_bits = Self::num_bits_to_shave(); + let mut result_bytes = crate::const_helpers::SerBuffer::::zeroed(); + // Copy the input into a temporary buffer. + result_bytes.copy_from_u8_slice(bytes); + // This mask retains everything in the last limb + // that is below `P::MODULUS_BIT_SIZE`. + let last_limb_mask = (u64::MAX >> shave_bits).to_le_bytes(); + let mut last_bytes_mask = [0u8; 9]; + last_bytes_mask[..8].copy_from_slice(&last_limb_mask); + + // Length of the buffer containing the field element and the flag. + let output_byte_size = buffer_byte_size(Self::MODULUS_BIT_SIZE as usize + F::BIT_SIZE); + // Location of the flag is the last byte of the serialized + // form of the field element. + let flag_location = output_byte_size - 1; + + // At which byte is the flag located in the last limb? + let flag_location_in_last_limb = flag_location - (8 * (N - 1)); + + // Take all but the last 9 bytes. + let last_bytes = result_bytes.last_n_plus_1_bytes_mut(); + + // The mask only has the last `F::BIT_SIZE` bits set + let flags_mask = u8::MAX.checked_shl(8 - (F::BIT_SIZE as u32)).unwrap_or(0); + + // Mask away the remaining bytes, and try to reconstruct the + // flag + let mut flags: u8 = 0; + for (i, (b, m)) in last_bytes.zip(&last_bytes_mask).enumerate() { + if i == flag_location_in_last_limb { + flags = *b & flags_mask + } + *b &= m; + } + Self::deserialize(&result_bytes.as_slice()[..(N * 8)]) + .ok() + .and_then(|f| F::from_u8(flags).map(|flag| (f, flag))) + } + } + + #[inline] + fn square(&self) -> Self { + let mut temp = self.clone(); + temp.square_in_place(); + temp + } + + fn square_in_place(&mut self) -> &mut Self { + P::square_in_place(self); + self + } + + #[inline] + fn inverse(&self) -> Option { + P::inverse(&self) + } + + fn inverse_in_place(&mut self) -> Option<&mut Self> { + if let Some(inverse) = self.inverse() { + *self = inverse; + Some(self) + } else { + None + } + } + + /// The Frobenius map has no effect in a prime field. + #[inline] + fn frobenius_map(&mut self, _: usize) {} +} + +impl, const N: usize> PrimeField for Fp { + type BigInt = BigInt; + const MODULUS: Self::BigInt = P::MODULUS; + const GENERATOR: Self = P::GENERATOR; + const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt = P::MODULUS.divide_by_2_round_down(); + const MODULUS_BIT_SIZE: u32 = P::MODULUS.const_num_bits(); + const TRACE: Self::BigInt = P::MODULUS.two_adic_coefficient(); + const TRACE_MINUS_ONE_DIV_TWO: Self::BigInt = Self::TRACE.divide_by_2_round_down(); + + #[inline] + fn from_bigint(r: BigInt) -> Option { + P::from_bigint(r) + } + + fn into_bigint(&self) -> BigInt { + P::into_bigint(*self) + } +} + +impl, const N: usize> FftField for Fp { + const GENERATOR: Self = P::GENERATOR; + const TWO_ADICITY: u32 = P::TWO_ADICITY; + const TWO_ADIC_ROOT_OF_UNITY: Self = P::TWO_ADIC_ROOT_OF_UNITY; + const SMALL_SUBGROUP_BASE: Option = P::SMALL_SUBGROUP_BASE; + const SMALL_SUBGROUP_BASE_ADICITY: Option = P::SMALL_SUBGROUP_BASE_ADICITY; + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = P::LARGE_SUBGROUP_ROOT_OF_UNITY; +} + +impl, const N: usize> SquareRootField for Fp { + #[inline] + fn legendre(&self) -> LegendreSymbol { + use crate::fields::LegendreSymbol::*; + + // s = self^((MODULUS - 1) // 2) + let s = self.pow(Self::MODULUS_MINUS_ONE_DIV_TWO); + if s.is_zero() { + Zero + } else if s.is_one() { + QuadraticResidue + } else { + QuadraticNonResidue + } + } + + #[inline] + fn sqrt(&self) -> Option { + P::square_root(self) + } + + fn sqrt_in_place(&mut self) -> Option<&mut Self> { + (*self).sqrt().map(|sqrt| { + *self = sqrt; + self + }) + } +} + +/// Note that this implementation of `Ord` compares field elements viewing +/// them as integers in the range 0, 1, ..., P::MODULUS - 1. However, other +/// implementations of `PrimeField` might choose a different ordering, and +/// as such, users should use this `Ord` for applications where +/// any ordering suffices (like in a BTreeMap), and not in applications +/// where a particular ordering is required. +impl, const N: usize> Ord for Fp { + #[inline(always)] + fn cmp(&self, other: &Self) -> Ordering { + self.into_bigint().cmp(&other.into_bigint()) + } +} + +/// Note that this implementation of `PartialOrd` compares field elements viewing +/// them as integers in the range 0, 1, ..., `P::MODULUS` - 1. However, other +/// implementations of `PrimeField` might choose a different ordering, and +/// as such, users should use this `PartialOrd` for applications where +/// any ordering suffices (like in a BTreeMap), and not in applications +/// where a particular ordering is required. +impl, const N: usize> PartialOrd for Fp { + #[inline(always)] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl, const N: usize> From for Fp { + fn from(other: u128) -> Self { + let mut default_int = BigInt::default(); + if N == 1 { + default_int.0[0] = (other % u128::from(P::MODULUS.0[0])) as u64; + } else { + let upper = (other >> 64) as u64; + let lower = ((other << 64) >> 64) as u64; + default_int.0[0] = lower; + default_int.0[1] = upper; + } + Self::from_bigint(default_int).unwrap() + } +} + +impl, const N: usize> From for Fp { + fn from(other: i128) -> Self { + let abs = Self::from(other.unsigned_abs()); + if other.is_positive() { + abs + } else { + -abs + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: bool) -> Self { + if N == 1 { + Self::from_bigint(BigInt::from(u64::from(other) % P::MODULUS.0[0])).unwrap() + } else { + Self::from_bigint(BigInt::from(u64::from(other))).unwrap() + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: u64) -> Self { + if N == 1 { + Self::from_bigint(BigInt::from(u64::from(other) % P::MODULUS.0[0])).unwrap() + } else { + Self::from_bigint(BigInt::from(u64::from(other))).unwrap() + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: i64) -> Self { + let abs = Self::from(other.unsigned_abs()); + if other.is_positive() { + abs + } else { + -abs + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: u32) -> Self { + if N == 1 { + Self::from_bigint(BigInt::from(u64::from(other) % P::MODULUS.0[0])).unwrap() + } else { + Self::from_bigint(BigInt::from(u32::from(other))).unwrap() + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: i32) -> Self { + let abs = Self::from(other.unsigned_abs()); + if other.is_positive() { + abs + } else { + -abs + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: u16) -> Self { + if N == 1 { + Self::from_bigint(BigInt::from(u64::from(other) % P::MODULUS.0[0])).unwrap() + } else { + Self::from_bigint(BigInt::from(u16::from(other))).unwrap() + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: i16) -> Self { + let abs = Self::from(other.unsigned_abs()); + if other.is_positive() { + abs + } else { + -abs + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: u8) -> Self { + if N == 1 { + Self::from_bigint(BigInt::from(u64::from(other) % P::MODULUS.0[0])).unwrap() + } else { + Self::from_bigint(BigInt::from(u8::from(other))).unwrap() + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: i8) -> Self { + let abs = Self::from(other.unsigned_abs()); + if other.is_positive() { + abs + } else { + -abs + } + } +} + +impl, const N: usize> ark_std::rand::distributions::Distribution> + for ark_std::rand::distributions::Standard +{ + #[inline] + fn sample(&self, rng: &mut R) -> Fp { + loop { + let mut tmp = Fp::new(rng.sample(ark_std::rand::distributions::Standard)); + let shave_bits = Fp::::num_bits_to_shave(); + // Mask away the unused bits at the beginning. + assert!(shave_bits <= 64); + let mask = if shave_bits == 64 { + 0 + } else { + core::u64::MAX >> shave_bits + }; + tmp.0 .0.last_mut().map(|val| *val &= mask); + + if tmp.is_less_than_modulus() { + return tmp; + } + } + } +} + +impl, const N: usize> CanonicalSerializeWithFlags for Fp { + fn serialize_with_flags( + &self, + writer: W, + flags: F, + ) -> Result<(), SerializationError> { + // All reasonable `Flags` should be less than 8 bits in size + // (256 values are enough for anyone!) + if F::BIT_SIZE > 8 { + return Err(SerializationError::NotEnoughSpace); + } + + // Calculate the number of bytes required to represent a field element + // serialized with `flags`. If `F::BIT_SIZE < 8`, + // this is at most `N * 8 + 1` + let output_byte_size = buffer_byte_size(Self::MODULUS_BIT_SIZE as usize + F::BIT_SIZE); + + // Write out `self` to a temporary buffer. + // The size of the buffer is $byte_size + 1 because `F::BIT_SIZE` + // is at most 8 bits. + let mut bytes = crate::const_helpers::SerBuffer::zeroed(); + bytes.copy_from_u64_slice(&self.into_bigint().0); + // Mask out the bits of the last byte that correspond to the flag. + bytes[output_byte_size - 1] |= flags.u8_bitmask(); + + bytes.write_up_to(writer, output_byte_size)?; + Ok(()) + } + + // Let `m = 8 * n` for some `n` be the smallest multiple of 8 greater + // than `P::MODULUS_BIT_SIZE`. + // If `(m - P::MODULUS_BIT_SIZE) >= F::BIT_SIZE` , then this method returns `n`; + // otherwise, it returns `n + 1`. + fn serialized_size_with_flags(&self) -> usize { + buffer_byte_size(Self::MODULUS_BIT_SIZE as usize + F::BIT_SIZE) + } +} + +impl, const N: usize> CanonicalSerialize for Fp { + #[inline] + fn serialize(&self, writer: W) -> Result<(), SerializationError> { + self.serialize_with_flags(writer, EmptyFlags) + } + + #[inline] + fn serialized_size(&self) -> usize { + self.serialized_size_with_flags::() + } +} + +impl, const N: usize> CanonicalDeserializeWithFlags for Fp { + fn deserialize_with_flags( + reader: R, + ) -> Result<(Self, F), SerializationError> { + // All reasonable `Flags` should be less than 8 bits in size + // (256 values are enough for anyone!) + if F::BIT_SIZE > 8 { + return Err(SerializationError::NotEnoughSpace); + } + // Calculate the number of bytes required to represent a field element + // serialized with `flags`. If `F::BIT_SIZE < 8`, + // this is at most `$byte_size + 1` + let output_byte_size = buffer_byte_size(Self::MODULUS_BIT_SIZE as usize + F::BIT_SIZE); + + let mut masked_bytes = crate::const_helpers::SerBuffer::zeroed(); + masked_bytes.read_exact_up_to(reader, output_byte_size)?; + let flags = F::from_u8_remove_flags(&mut masked_bytes[output_byte_size - 1]) + .ok_or(SerializationError::UnexpectedFlags)?; + + let self_integer = masked_bytes.to_bigint(); + Self::from_bigint(self_integer) + .map(|v| (v, flags)) + .ok_or(SerializationError::InvalidData) + } +} + +impl, const N: usize> CanonicalDeserialize for Fp { + fn deserialize(reader: R) -> Result { + Self::deserialize_with_flags::(reader).map(|(r, _)| r) + } +} + +impl, const N: usize> ToBytes for Fp { + #[inline] + fn write(&self, writer: W) -> IoResult<()> { + self.into_bigint().write(writer) + } +} + +impl, const N: usize> FromBytes for Fp { + #[inline] + fn read(r: R) -> IoResult { + BigInt::read(r) + .and_then(|b| Fp::from_bigint(b).ok_or(crate::error("FromBytes::read failed"))) + } +} + +impl, const N: usize> FromStr for Fp { + type Err = (); + + /// Interpret a string of numbers as a (congruent) prime field element. + /// Does not accept unnecessary leading zeroes or a blank string. + fn from_str(s: &str) -> Result { + if s.is_empty() { + return Err(()); + } + + if s == "0" { + return Ok(Self::zero()); + } + + let mut res = Self::zero(); + + let ten = Self::from(BigInt::from(10u8)); + + let mut first_digit = true; + + for c in s.chars() { + match c.to_digit(10) { + Some(c) => { + if first_digit { + if c == 0 { + return Err(()); + } + + first_digit = false; + } + + res.mul_assign(&ten); + let digit = Self::from(u64::from(c)); + res.add_assign(&digit); + }, + None => { + return Err(()); + }, + } + } + if !res.is_less_than_modulus() { + Err(()) + } else { + Ok(res) + } + } +} + +/// Outputs a string containing the value of `self`, chunked up into +/// 64-bit limbs. +impl, const N: usize> Display for Fp { + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + write!(f, stringify!(Fp "({})"), self.into_bigint()) + } +} + +impl, const N: usize> Neg for Fp { + type Output = Self; + #[inline] + #[must_use] + fn neg(self) -> Self { + if !self.is_zero() { + let mut tmp = P::MODULUS; + tmp.sub_noborrow(&self.0); + Fp::new(tmp) + } else { + self + } + } +} + +impl<'a, P: FpConfig, const N: usize> Add<&'a Fp> for Fp { + type Output = Self; + + #[inline] + fn add(mut self, other: &Self) -> Self { + self.add_assign(other); + self + } +} + +impl<'a, P: FpConfig, const N: usize> Sub<&'a Fp> for Fp { + type Output = Self; + + #[inline] + fn sub(mut self, other: &Self) -> Self { + self.sub_assign(other); + self + } +} + +impl<'a, P: FpConfig, const N: usize> Mul<&'a Fp> for Fp { + type Output = Self; + + #[inline] + fn mul(mut self, other: &Self) -> Self { + self.mul_assign(other); + self + } +} + +impl<'a, P: FpConfig, const N: usize> Div<&'a Fp> for Fp { + type Output = Self; + + /// Returns `self * other.inverse()` if `other.inverse()` is `Some`, and + /// panics otherwise. + #[inline] + fn div(mut self, other: &Self) -> Self { + self.mul_assign(&other.inverse().unwrap()); + self + } +} + +impl<'a, P: FpConfig, const N: usize> AddAssign<&'a Self> for Fp { + #[inline] + fn add_assign(&mut self, other: &Self) { + P::add_assign(self, other) + } +} + +impl<'a, P: FpConfig, const N: usize> SubAssign<&'a Self> for Fp { + #[inline] + fn sub_assign(&mut self, other: &Self) { + P::sub_assign(self, other); + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::Add for Fp { + type Output = Self; + + #[inline] + fn add(mut self, other: Self) -> Self { + self.add_assign(&other); + self + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::Add<&'a mut Self> for Fp { + type Output = Self; + + #[inline] + fn add(mut self, other: &'a mut Self) -> Self { + self.add_assign(&*other); + self + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::Sub for Fp { + type Output = Self; + + #[inline] + fn sub(mut self, other: Self) -> Self { + self.sub_assign(&other); + self + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::Sub<&'a mut Self> for Fp { + type Output = Self; + + #[inline] + fn sub(mut self, other: &'a mut Self) -> Self { + self.sub_assign(&*other); + self + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::iter::Sum for Fp { + fn sum>(iter: I) -> Self { + iter.fold(Self::zero(), core::ops::Add::add) + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::iter::Sum<&'a Self> for Fp { + fn sum>(iter: I) -> Self { + iter.fold(Self::zero(), core::ops::Add::add) + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::AddAssign for Fp { + fn add_assign(&mut self, other: Self) { + self.add_assign(&other) + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::SubAssign for Fp { + fn sub_assign(&mut self, other: Self) { + self.sub_assign(&other) + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::AddAssign<&'a mut Self> for Fp { + fn add_assign(&mut self, other: &'a mut Self) { + self.add_assign(&*other) + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::SubAssign<&'a mut Self> for Fp { + fn sub_assign(&mut self, other: &'a mut Self) { + self.sub_assign(&*other) + } +} + +impl<'a, P: FpConfig, const N: usize> MulAssign<&'a Self> for Fp { + #[inline] + fn mul_assign(&mut self, other: &Self) { + P::mul_assign(self, other) + } +} + +/// Computes `self *= other.inverse()` if `other.inverse()` is `Some`, and +/// panics otherwise. +impl<'a, P: FpConfig, const N: usize> DivAssign<&'a Self> for Fp { + #[inline] + fn div_assign(&mut self, other: &Self) { + self.mul_assign(&other.inverse().unwrap()); + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::Mul for Fp { + type Output = Self; + + #[inline] + fn mul(mut self, other: Self) -> Self { + self.mul_assign(&other); + self + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::Div for Fp { + type Output = Self; + + #[inline] + fn div(mut self, other: Self) -> Self { + self.div_assign(&other); + self + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::Mul<&'a mut Self> for Fp { + type Output = Self; + + #[inline] + fn mul(mut self, other: &'a mut Self) -> Self { + self.mul_assign(&*other); + self + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::Div<&'a mut Self> for Fp { + type Output = Self; + + #[inline] + fn div(mut self, other: &'a mut Self) -> Self { + self.div_assign(&*other); + self + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::iter::Product for Fp { + fn product>(iter: I) -> Self { + iter.fold(Self::one(), core::ops::Mul::mul) + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::iter::Product<&'a Self> for Fp { + fn product>(iter: I) -> Self { + iter.fold(Self::one(), Mul::mul) + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::MulAssign for Fp { + fn mul_assign(&mut self, other: Self) { + self.mul_assign(&other) + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::DivAssign<&'a mut Self> for Fp { + fn div_assign(&mut self, other: &'a mut Self) { + self.div_assign(&*other) + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::MulAssign<&'a mut Self> for Fp { + fn mul_assign(&mut self, other: &'a mut Self) { + self.mul_assign(&*other) + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::DivAssign for Fp { + fn div_assign(&mut self, other: Self) { + self.div_assign(&other) + } +} + +impl, const N: usize> zeroize::Zeroize for Fp { + // The phantom data does not contain element-specific data + // and thus does not need to be zeroized. + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl, const N: usize> From for Fp { + #[inline] + fn from(val: num_bigint::BigUint) -> Fp { + Fp::::from_le_bytes_mod_order(&val.to_bytes_le()) + } +} + +impl, const N: usize> From> for num_bigint::BigUint { + #[inline] + fn from(other: Fp) -> Self { + other.into_bigint().into() + } +} + +impl, const N: usize> Into> for Fp { + fn into(self) -> BigInt { + self.into_bigint() + } +} + +impl, const N: usize> From> for Fp { + /// Converts `Self::BigInteger` into `Self` + fn from(int: BigInt) -> Self { + Self::from_bigint(int).unwrap() + } +} diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs new file mode 100644 index 000000000..0795b877e --- /dev/null +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -0,0 +1,557 @@ +use ark_std::{marker::PhantomData, Zero}; + +use super::{Fp, FpConfig}; +use crate::{biginteger::arithmetic as fa, BigInt, BigInteger}; + +/// A trait that specifies the constants and arithmetic procedures +/// for Montgomery arithmetic over the prime field defined by `MODULUS`. +pub trait MontConfig: 'static + Sync + Send + Sized { + /// The modulus of the field. + const MODULUS: BigInt; + + /// Let `M` be the power of 2^64 nearest to `Self::MODULUS_BITS`. Then + /// `R = M % Self::MODULUS`. + const R: BigInt = Self::MODULUS.montgomery_r(); + + /// R2 = R^2 % Self::MODULUS + const R2: BigInt = Self::MODULUS.montgomery_r2(); + + /// INV = -MODULUS^{-1} mod 2^64 + const INV: u64 = inv(Self::MODULUS); + + /// A multiplicative generator of the field. + /// `Self::GENERATOR` is an element having multiplicative order + /// `Self::MODULUS - 1`. + const GENERATOR: Fp, N>; + + /// Can we use the no-carry optimization for multiplication and squaring + /// outlined [here](https://hackmd.io/@zkteam/modular_multiplication)? + /// + /// This optimization applies if + /// `Self::MODULUS` has (a) a non-zero MSB, and (b) at least one + /// zero bit in the rest of the modulus. + #[doc(hidden)] + const CAN_USE_NO_CARRY_OPT: bool = can_use_no_carry_optimization(&Self::MODULUS); + + /// 2^s root of unity computed by GENERATOR^t + const TWO_ADIC_ROOT_OF_UNITY: Fp, N>; + + /// An integer `b` such that there exists a multiplicative subgroup + /// of size `b^k` for some integer `k`. + const SMALL_SUBGROUP_BASE: Option = None; + + /// The integer `k` such that there exists a multiplicative subgroup + /// of size `Self::SMALL_SUBGROUP_BASE^k`. + const SMALL_SUBGROUP_BASE_ADICITY: Option = None; + + /// GENERATOR^((MODULUS-1) / (2^s * + /// SMALL_SUBGROUP_BASE^SMALL_SUBGROUP_BASE_ADICITY)) Used for mixed-radix + /// FFT. + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option, N>> = None; + + /// Set a += b; + fn add_assign(a: &mut Fp, N>, b: &Fp, N>) { + // This cannot exceed the backing capacity. + a.0.add_nocarry(&b.0); + // However, it may need to be reduced + a.subtract_modulus(); + } + + fn sub_assign(a: &mut Fp, N>, b: &Fp, N>) { + // If `other` is larger than `self`, add the modulus to self first. + if b.0 > a.0 { + a.0.add_nocarry(&Self::MODULUS); + } + a.0.sub_noborrow(&b.0); + } + + fn double_in_place(a: &mut Fp, N>) { + // This cannot exceed the backing capacity. + a.0.mul2(); + // However, it may need to be reduced. + a.subtract_modulus(); + } + + /// This modular multiplication algorithm uses Montgomery + /// reduction for efficient implementation. It also additionally + /// uses the "no-carry optimization" outlined + /// [here](https://hackmd.io/@zkteam/modular_multiplication) if + /// `Self::MODULUS` has (a) a non-zero MSB, and (b) at least one + /// zero bit in the rest of the modulus. + #[inline] + #[ark_ff_asm::unroll_for_loops] + fn mul_assign(a: &mut Fp, N>, b: &Fp, N>) { + // No-carry optimisation applied to CIOS + if Self::CAN_USE_NO_CARRY_OPT { + if N <= 6 && N > 1 && cfg!(use_asm) { + #[cfg(use_asm)] + #[allow(unsafe_code, unused_mut)] + // Tentatively avoid using assembly for `N == 1`. + #[rustfmt::skip] + match N { + 2 => { ark_ff_asm::x86_64_asm_mul!(2, (a.0).0, (b.0).0); }, + 3 => { ark_ff_asm::x86_64_asm_mul!(3, (a.0).0, (b.0).0); }, + 4 => { ark_ff_asm::x86_64_asm_mul!(4, (a.0).0, (b.0).0); }, + 5 => { ark_ff_asm::x86_64_asm_mul!(5, (a.0).0, (b.0).0); }, + 6 => { ark_ff_asm::x86_64_asm_mul!(6, (a.0).0, (b.0).0); }, + _ => unsafe { ark_std::hint::unreachable_unchecked() }, + }; + } else { + let mut r = [0u64; N]; + let mut carry1 = 0u64; + let mut carry2 = 0u64; + + for i in 0..N { + r[0] = fa::mac(r[0], (a.0).0[0], (b.0).0[i], &mut carry1); + let k = r[0].wrapping_mul(Self::INV); + fa::mac_discard(r[0], k, Self::MODULUS.0[0], &mut carry2); + for j in 1..N { + r[j] = fa::mac_with_carry(r[j], (a.0).0[j], (b.0).0[i], &mut carry1); + r[j - 1] = fa::mac_with_carry(r[j], k, Self::MODULUS.0[j], &mut carry2); + } + r[N - 1] = carry1 + carry2; + } + (a.0).0 = r; + } + } else { + // Alternative implementation + *a = a.mul_without_reduce(b, Self::MODULUS, Self::INV); + } + a.subtract_modulus(); + } + + #[inline] + #[ark_ff_asm::unroll_for_loops] + #[allow(unused_braces, clippy::absurd_extreme_comparisons)] + fn square_in_place(a: &mut Fp, N>) { + if N == 1 { + // We default to multiplying with `a` using the `Mul` impl + // for the N == 1 case + let temp = *a; + Self::mul_assign(a, &temp); + return; + } + #[cfg(use_asm)] + #[allow(unsafe_code, unused_mut)] + { + // Checking the modulus at compile time + if N <= 6 && Self::CAN_USE_NO_CARRY_OPT { + #[rustfmt::skip] + match N { + 2 => { ark_ff_asm::x86_64_asm_square!(2, (a.0).0); }, + 3 => { ark_ff_asm::x86_64_asm_square!(3, (a.0).0); }, + 4 => { ark_ff_asm::x86_64_asm_square!(4, (a.0).0); }, + 5 => { ark_ff_asm::x86_64_asm_square!(5, (a.0).0); }, + 6 => { ark_ff_asm::x86_64_asm_square!(6, (a.0).0); }, + _ => unsafe { ark_std::hint::unreachable_unchecked() }, + }; + a.subtract_modulus(); + return; + } + } + let mut r = crate::const_helpers::MulBuffer::::zeroed(); + + let mut carry = 0; + for i in 0..N { + if i < N - 1 { + for j in 0..N { + if j > i { + r[i + j] = fa::mac_with_carry(r[i + j], (a.0).0[i], (a.0).0[j], &mut carry); + } + } + r.b1[i] = carry; + carry = 0; + } + } + r.b1[N - 1] >>= 63; + for i in 0..N { + r[2 * (N - 1) - i] = (r[2 * (N - 1) - i] << 1) | (r[2 * (N - 1) - (i + 1)] >> 63); + } + for i in 3..N { + r[N + 1 - i] = (r[N + 1 - i] << 1) | (r[N - i] >> 63); + } + r.b0[1] <<= 1; + + for i in 0..N { + r[2 * i] = fa::mac_with_carry(r[2 * i], (a.0).0[i], (a.0).0[i], &mut carry); + // need unused assignment because the last iteration of the loop produces an + // assignment to `carry` that is unused. + #[allow(unused_assignments)] + { + r[2 * i + 1] = fa::adc(r[2 * i + 1], 0, &mut carry); + } + } + // Montgomery reduction + let mut carry2 = 0; + for i in 0..N { + let k = r[i].wrapping_mul(Self::INV); + let mut carry = 0; + fa::mac_with_carry(r[i], k, Self::MODULUS.0[0], &mut carry); + for j in 1..N { + r[j + i] = fa::mac_with_carry(r[j + i], k, Self::MODULUS.0[j], &mut carry); + } + r.b1[i] = fa::adc(r.b1[i], carry2, &mut carry); + carry2 = carry; + } + (a.0).0.copy_from_slice(&r.b1); + a.subtract_modulus(); + } + + fn inverse(a: &Fp, N>) -> Option, N>> { + if a.is_zero() { + None + } else { + // Guajardo Kumar Paar Pelzl + // Efficient Software-Implementation of Finite Fields with Applications to + // Cryptography + // Algorithm 16 (BEA for Inversion in Fp) + + let one = BigInt::from(1u64); + + let mut u = a.0; + let mut v = Self::MODULUS; + let mut b = Fp::new(Self::R2); // Avoids unnecessary reduction step. + let mut c = Fp::zero(); + + while u != one && v != one { + while u.is_even() { + u.div2(); + + if b.0.is_even() { + b.0.div2(); + } else { + b.0.add_nocarry(&Self::MODULUS); + b.0.div2(); + } + } + + while v.is_even() { + v.div2(); + + if c.0.is_even() { + c.0.div2(); + } else { + c.0.add_nocarry(&Self::MODULUS); + c.0.div2(); + } + } + + if v < u { + u.sub_noborrow(&v); + b -= &c; + } else { + v.sub_noborrow(&u); + c -= &b; + } + } + + if u == one { + Some(b) + } else { + Some(c) + } + } + } + + fn from_bigint(r: BigInt) -> Option, N>> { + let mut r = Fp::new(r); + if r.is_zero() { + return Some(r); + } else if r.is_less_than_modulus() { + r *= &Fp::new(Self::R2); + Some(r) + } else { + None + } + } + + #[inline] + #[ark_ff_asm::unroll_for_loops] + #[allow(clippy::modulo_one)] + fn into_bigint(a: Fp, N>) -> BigInt { + let mut tmp = a.0; + let mut r = tmp.0; + // Montgomery Reduction + for i in 0..N { + let k = r[i].wrapping_mul(Self::INV); + let mut carry = 0; + + fa::mac_with_carry(r[i], k, Self::MODULUS.0[0], &mut carry); + for j in 1..N { + r[(j + i) % N] = + fa::mac_with_carry(r[(j + i) % N], k, Self::MODULUS.0[j], &mut carry); + } + r[i % N] = carry; + } + tmp.0 = r; + tmp + } +} + +/// Compute -M^{-1} mod 2^64. +pub const fn inv(m: BigInt) -> u64 { + let mut inv = 1u64; + crate::const_for!((_i in 0..63) { + inv = inv.wrapping_mul(inv); + inv = inv.wrapping_mul(m.0[0]); + }); + inv.wrapping_neg() +} + +#[inline] +pub const fn can_use_no_carry_optimization(modulus: &BigInt) -> bool { + // Checking the modulus at compile time + let first_bit_set = modulus.0[N - 1] >> 63 != 0; + // N can be 1, hence we can run into a case with an unused mut. + let mut all_bits_set = modulus.0[N - 1] == !0 - (1 << 63); + crate::const_for!((i in 1..N) { + all_bits_set &= modulus.0[N - i - 1] == !0u64; + }); + !(first_bit_set || all_bits_set) +} + +/// Construct a [`Fp, N>`] element from a literal string. This should +/// be used primarily for constructing constant field elements; in a non-const +/// context, [`Fp::from_str`](`ark_std::str::FromStr::from_str`) is preferable. +/// +/// # Panics +/// +/// If the integer represented by the string cannot fit in the number +/// of limbs of the `Fp`, this macro results in a +/// * compile-time error if used in a const context +/// * run-time error otherwise. +/// +/// # Usage +/// +/// ```rust +/// # use ark_test_curves::{MontFp, One}; +/// # use ark_test_curves::bls12_381 as ark_bls12_381; +/// # use ark_std::str::FromStr; +/// use ark_bls12_381::Fq; +/// const ONE: Fq = MontFp!(Fq, "1"); +/// const NEG_ONE: Fq = MontFp!(Fq, "-1"); +/// +/// fn check_correctness() { +/// assert_eq!(ONE, Fq::one()); +/// assert_eq!(Fq::from_str("1").unwrap(), ONE); +/// assert_eq!(NEG_ONE, -Fq::one()); +/// } +/// ``` +#[macro_export] +macro_rules! MontFp { + ($name:ident, $c0:expr) => {{ + use $crate::PrimeField; + let (is_positive, limbs) = $crate::ark_ff_macros::to_sign_and_limbs!($c0); + $crate::Fp::const_from_str(&limbs, is_positive, $name::R2, $name::MODULUS) + }}; +} + +pub use MontFp; + +pub struct MontBackend(PhantomData); + +impl, const N: usize> FpConfig for MontBackend { + /// The modulus of the field. + const MODULUS: crate::BigInt = T::MODULUS; + + /// A multiplicative generator of the field. + /// `Self::GENERATOR` is an element having multiplicative order + /// `Self::MODULUS - 1`. + const GENERATOR: Fp = T::GENERATOR; + + /// Additive identity of the field, i.e. the element `e` + /// such that, for all elements `f` of the field, `e + f = f`. + const ZERO: Fp = Fp::new(BigInt([0u64; N])); + + /// Multiplicative identity of the field, i.e. the element `e` + /// such that, for all elements `f` of the field, `e * f = f`. + const ONE: Fp = Fp::new(T::R); + + const TWO_ADICITY: u32 = Self::MODULUS.two_adic_valuation(); + const TWO_ADIC_ROOT_OF_UNITY: Fp = T::TWO_ADIC_ROOT_OF_UNITY; + const SMALL_SUBGROUP_BASE: Option = T::SMALL_SUBGROUP_BASE; + const SMALL_SUBGROUP_BASE_ADICITY: Option = T::SMALL_SUBGROUP_BASE_ADICITY; + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option> = T::LARGE_SUBGROUP_ROOT_OF_UNITY; + + fn add_assign(a: &mut Fp, b: &Fp) { + T::add_assign(a, b) + } + + fn sub_assign(a: &mut Fp, b: &Fp) { + T::sub_assign(a, b) + } + + fn double_in_place(a: &mut Fp) { + T::double_in_place(a) + } + + /// This modular multiplication algorithm uses Montgomery + /// reduction for efficient implementation. It also additionally + /// uses the "no-carry optimization" outlined + /// [here](https://hackmd.io/@zkteam/modular_multiplication) if + /// `P::MODULUS` has (a) a non-zero MSB, and (b) at least one + /// zero bit in the rest of the modulus. + #[inline] + #[ark_ff_asm::unroll_for_loops] + fn mul_assign(a: &mut Fp, b: &Fp) { + T::mul_assign(a, b) + } + + #[inline] + #[ark_ff_asm::unroll_for_loops] + #[allow(unused_braces, clippy::absurd_extreme_comparisons)] + fn square_in_place(a: &mut Fp) { + T::square_in_place(a) + } + + fn inverse(a: &Fp) -> Option> { + T::inverse(a) + } + + fn from_bigint(r: BigInt) -> Option> { + T::from_bigint(r) + } + + #[inline] + #[ark_ff_asm::unroll_for_loops] + #[allow(clippy::modulo_one)] + fn into_bigint(a: Fp) -> BigInt { + T::into_bigint(a) + } +} + +impl Fp, N> { + #[ark_ff_asm::unroll_for_loops] + const fn const_is_zero(&self) -> bool { + self.0.const_is_zero() + } + + const fn const_neg(self, modulus: BigInt) -> Self { + if !self.const_is_zero() { + Self::new(Self::sub_noborrow(&modulus, &self.0)) + } else { + self + } + } + + /// Interpret a string of decimal numbers as a prime field element. + /// Does not accept unnecessary leading zeroes or a blank string. + /// For *internal* use only; please use the `ark_ff::MontFp` macro instead + /// of this method + #[doc(hidden)] + pub const fn const_from_str( + limbs: &[u64], + is_positive: bool, + r2: BigInt, + modulus: BigInt, + ) -> Self { + let mut repr = BigInt::([0; N]); + assert!(repr.0.len() == N); + crate::const_for!((i in 0..(limbs.len())) { + repr.0[i] = limbs[i]; + }); + let res = Self::const_from_bigint(repr, r2, modulus); + if is_positive { + res + } else { + res.const_neg(modulus) + } + } + + #[inline] + pub(crate) const fn const_from_bigint( + repr: BigInt, + r2: BigInt, + modulus: BigInt, + ) -> Self { + let mut r = Self::new(repr); + if r.const_is_zero() { + r + } else { + r = r.const_mul(&Fp(r2, PhantomData), modulus); + r + } + } + + #[ark_ff_asm::unroll_for_loops] + const fn mul_without_reduce(mut self, other: &Self, modulus: BigInt, inv: u64) -> Self { + let (mut lo, mut hi) = ([0u64; N], [0u64; N]); + crate::const_for!((i in 0..N) { + let mut carry = 0; + crate::const_for!((j in 0..N) { + let k = i + j; + if k >= N { + hi[k - N] = mac_with_carry!(hi[k - N], (self.0).0[i], (other.0).0[j], &mut carry); + } else { + lo[k] = mac_with_carry!(lo[k], (self.0).0[i], (other.0).0[j], &mut carry); + } + }); + hi[i] = carry; + }); + // Montgomery reduction + let mut carry2 = 0; + crate::const_for!((i in 0..N) { + let tmp = lo[i].wrapping_mul(inv); + let mut carry = 0; + mac_with_carry!(lo[i], tmp, modulus.0[0], &mut carry); + crate::const_for!((j in 1..N) { + let k = i + j; + if k >= N { + hi[k - N] = mac_with_carry!(hi[k - N], tmp, modulus.0[j], &mut carry); + } else { + lo[k] = mac_with_carry!(lo[k], tmp, modulus.0[j], &mut carry); + } + }); + hi[i] = adc!(hi[i], carry2, &mut carry); + carry2 = carry; + }); + + crate::const_for!((i in 0..N) { + (self.0).0[i] = hi[i]; + }); + self + } + + #[ark_ff_asm::unroll_for_loops] + const fn const_mul_without_reduce(self, other: &Self, modulus: BigInt) -> Self { + let inv = inv(modulus); + self.mul_without_reduce(other, modulus, inv) + } + + #[ark_ff_asm::unroll_for_loops] + const fn const_mul(mut self, other: &Self, modulus: BigInt) -> Self { + self = self.const_mul_without_reduce(other, modulus); + self.const_reduce(modulus) + } + + #[ark_ff_asm::unroll_for_loops] + const fn const_is_valid(&self, modulus: BigInt) -> bool { + crate::const_for!((i in 0..N) { + if (self.0).0[(N - i - 1)] < modulus.0[(N - i - 1)] { + return true + } else if (self.0).0[(N - i - 1)] > modulus.0[(N - i - 1)] { + return false + } + }); + false + } + + #[inline] + const fn const_reduce(mut self, modulus: BigInt) -> Self { + if !self.const_is_valid(modulus) { + self.0 = Self::sub_noborrow(&self.0, &modulus); + } + self + } + + const fn sub_noborrow(a: &BigInt, b: &BigInt) -> BigInt { + a.const_sub_noborrow(b).0 + } +} + +impl, const N: usize> Fp, N> { + #[doc(hidden)] + pub const R2: BigInt = T::R2; + #[doc(hidden)] + pub const INV: u64 = T::INV; +} diff --git a/ff/src/fields/models/fp12_2over3over2.rs b/ff/src/fields/models/fp12_2over3over2.rs index bd040f29b..d14e1b543 100644 --- a/ff/src/fields/models/fp12_2over3over2.rs +++ b/ff/src/fields/models/fp12_2over3over2.rs @@ -1,6 +1,6 @@ use super::quadratic_extension::*; use crate::{ - fields::{fp6_3over2::*, Field, Fp2, Fp2Parameters}, + fields::{fp6_3over2::*, Field, Fp2, Fp2Config}, One, }; use core::{ @@ -8,10 +8,10 @@ use core::{ ops::{AddAssign, SubAssign}, }; -type Fp2Params

= <

::Fp6Params as Fp6Parameters>::Fp2Params; +type Fp2Params

= <

::Fp6Params as Fp6Config>::Fp2Params; pub trait Fp12Parameters: 'static + Send + Sync + Copy { - type Fp6Params: Fp6Parameters; + type Fp6Params: Fp6Config; /// This *must* equal (0, 1, 0); /// see [[DESD06, Section 6.1]](https://eprint.iacr.org/2006/471.pdf). @@ -33,8 +33,8 @@ pub trait Fp12Parameters: 'static + Send + Sync + Copy { pub struct Fp12ParamsWrapper(PhantomData

); -impl QuadExtParameters for Fp12ParamsWrapper

{ - type BasePrimeField = as Fp2Parameters>::Fp; +impl QuadExtConfig for Fp12ParamsWrapper

{ + type BasePrimeField = as Fp2Config>::Fp; type BaseField = Fp6; type FrobCoeff = Fp2>; @@ -85,7 +85,7 @@ pub type Fp12

= QuadExtField>; impl Fp12

{ pub fn mul_by_fp( &mut self, - element: &<::Fp2Params as Fp2Parameters>::Fp, + element: &<::Fp2Params as Fp2Config>::Fp, ) { self.c0.mul_by_fp(&element); self.c1.mul_by_fp(&element); @@ -138,7 +138,7 @@ impl Fp12

{ // - Robert Granger and Michael Scott // if characteristic_square_mod_6_is_one(Self::characteristic()) { - let fp2_nr = ::mul_fp2_by_nonresidue; + let fp2_nr = ::mul_fp2_by_nonresidue; let r0 = &self.c0.c0; let r4 = &self.c0.c1; diff --git a/ff/src/fields/models/fp2.rs b/ff/src/fields/models/fp2.rs index db1634e37..4f2fb5800 100644 --- a/ff/src/fields/models/fp2.rs +++ b/ff/src/fields/models/fp2.rs @@ -2,30 +2,32 @@ use super::quadratic_extension::*; use crate::fields::PrimeField; use core::marker::PhantomData; -/// Parameters for defining degree-two extension fields. -pub trait Fp2Parameters: 'static + Send + Sync { +/// Trait that specifies constants and methods for defining degree-two extension fields. +pub trait Fp2Config: 'static + Send + Sync + Sized { /// Base prime field underlying this extension. type Fp: PrimeField; - /// Quadratic non-residue in `Self::Fp` used to construct the extension + /// Quadratic non-residue in [`Self::Fp`] used to construct the extension /// field. That is, `NONRESIDUE` is such that the quadratic polynomial /// `f(X) = X^2 - Self::NONRESIDUE` in Fp\[X\] is irreducible in `Self::Fp`. const NONRESIDUE: Self::Fp; /// A quadratic nonresidue in Fp2, used for calculating square roots in Fp2. - const QUADRATIC_NONRESIDUE: (Self::Fp, Self::Fp); + const QUADRATIC_NONRESIDUE: Fp2; /// Coefficients for the Frobenius automorphism. const FROBENIUS_COEFF_FP2_C1: &'static [Self::Fp]; /// Return `fe * Self::NONRESIDUE`. + /// Intended for specialization when [`Self::NONRESIDUE`] has a special + /// structure that can speed up multiplication #[inline(always)] fn mul_fp_by_nonresidue(fe: &Self::Fp) -> Self::Fp { Self::NONRESIDUE * fe } /// A specializable method for computing `x + mul_base_field_by_nonresidue(y)` - /// This allows for optimizations when the non-residue is + /// This allows for optimizations when [`Self::NONRESIDUE`] is /// canonically negative in the field. #[inline(always)] fn add_and_mul_fp_by_nonresidue(x: &Self::Fp, y: &Self::Fp) -> Self::Fp { @@ -33,7 +35,7 @@ pub trait Fp2Parameters: 'static + Send + Sync { } /// A specializable method for computing `x + y + mul_base_field_by_nonresidue(y)` - /// This allows for optimizations when the non-residue is not `-1`. + /// This allows for optimizations when the [`Self::NONRESIDUE`] is not `-1`. #[inline(always)] fn add_and_mul_fp_by_nonresidue_plus_one(x: &Self::Fp, y: &Self::Fp) -> Self::Fp { let mut tmp = *x; @@ -42,7 +44,7 @@ pub trait Fp2Parameters: 'static + Send + Sync { } /// A specializable method for computing `x - mul_base_field_by_nonresidue(y)` - /// This allows for optimizations when the non-residue is + /// This allows for optimizations when the [`Self::NONRESIDUE`] is /// canonically negative in the field. #[inline(always)] fn sub_and_mul_fp_by_nonresidue(x: &Self::Fp, y: &Self::Fp) -> Self::Fp { @@ -50,10 +52,10 @@ pub trait Fp2Parameters: 'static + Send + Sync { } } -/// Wrapper for Fp2Parameters, allowing combination of Fp2Parameters & QuadExtParameters traits -pub struct Fp2ParamsWrapper(PhantomData

); +/// Wrapper for [`Fp2Config`], allowing combination of the [`Fp2Config`] and [`QuadExtConfig`] traits. +pub struct Fp2ParamsWrapper(PhantomData

); -impl QuadExtParameters for Fp2ParamsWrapper

{ +impl QuadExtConfig for Fp2ParamsWrapper

{ type BasePrimeField = P::Fp; type BaseField = P::Fp; type FrobCoeff = P::Fp; @@ -102,10 +104,9 @@ impl QuadExtParameters for Fp2ParamsWrapper

{ /// instantiations involving `Fp2ParamsWrapper`. pub type Fp2

= QuadExtField>; -impl Fp2

{ - /// In-place multiply both coefficients `c0` & `c1` of the extension field - /// `Fp2` by an element from `Fp`. The coefficients themselves - /// are elements of `Fp`. +impl Fp2

{ + /// In-place multiply both coefficients `c0` and `c1` of `self` + /// by an element from [`Fp`](`Fp2Config::Fp`). /// /// # Examples /// @@ -120,8 +121,8 @@ impl Fp2

{ /// let base_field_element: Fp = Fp::rand(&mut test_rng()); /// ext_element.mul_assign_by_fp(&base_field_element); /// - /// assert_eq!(ext_element.c0, c0*base_field_element); - /// assert_eq!(ext_element.c1, c1*base_field_element); + /// assert_eq!(ext_element.c0, c0 * base_field_element); + /// assert_eq!(ext_element.c1, c1 * base_field_element); /// ``` pub fn mul_assign_by_fp(&mut self, other: &P::Fp) { self.c0 *= other; diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index 809bfa111..bfdee0e0e 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -2,9 +2,14 @@ use super::cubic_extension::*; use crate::fields::*; use core::marker::PhantomData; -pub trait Fp3Parameters: 'static + Send + Sync { +/// Trait that specifies constants and methods for defining degree-three extension fields. +pub trait Fp3Config: 'static + Send + Sync + Sized { + /// Base prime field underlying this extension. type Fp: PrimeField + SquareRootField; + /// Cubic non-residue in `Self::Fp` used to construct the extension + /// field. That is, `NONRESIDUE` is such that the cubic polynomial + /// `f(X) = X^3 - Self::NONRESIDUE` in Fp\[X\] is irreducible in `Self::Fp`. const NONRESIDUE: Self::Fp; const FROBENIUS_COEFF_FP3_C1: &'static [Self::Fp]; @@ -12,19 +17,23 @@ pub trait Fp3Parameters: 'static + Send + Sync { /// p^3 - 1 = 2^s * t, where t is odd. const TWO_ADICITY: u32; - const T_MINUS_ONE_DIV_TWO: &'static [u64]; + const TRACE_MINUS_ONE_DIV_TWO: &'static [u64]; /// t-th power of a quadratic nonresidue in Fp3. - const QUADRATIC_NONRESIDUE_TO_T: (Self::Fp, Self::Fp, Self::Fp); + const QUADRATIC_NONRESIDUE_TO_T: Fp3; + /// Return `fe * Self::NONRESIDUE`. + /// The default implementation can be specialized if [`Self::NONRESIDUE`] has a special + /// structure that can speed up multiplication #[inline(always)] fn mul_fp_by_nonresidue(fe: &Self::Fp) -> Self::Fp { Self::NONRESIDUE * fe } } -pub struct Fp3ParamsWrapper(PhantomData

); +/// Wrapper for [`Fp3Config`], allowing combination of the [`Fp3Config`] and [`CubicExtConfig`] traits. +pub struct Fp3ParamsWrapper(PhantomData

); -impl CubicExtParameters for Fp3ParamsWrapper

{ +impl CubicExtConfig for Fp3ParamsWrapper

{ type BasePrimeField = P::Fp; type BaseField = P::Fp; type FrobCoeff = P::Fp; @@ -53,7 +62,31 @@ impl CubicExtParameters for Fp3ParamsWrapper

{ pub type Fp3

= CubicExtField>; -impl Fp3

{ +impl Fp3

{ + /// In-place multiply all coefficients `c0`, `c1`, and `c2` of `self` + /// by an element from [`Fp`](`Fp3Config::Fp`). + /// + /// # Examples + /// + /// ``` + /// + /// # use ark_test_curves::CubicExt; + /// # use ark_std::test_rng; + /// # use ark_std::UniformRand; + /// # use ark_test_curves::mnt6_753 as ark_mnt6_753; + /// use ark_mnt6_753::{Fq as Fp, Fq3 as Fp3}; + /// let c0: Fp = Fp::rand(&mut test_rng()); + /// let c1: Fp = Fp::rand(&mut test_rng()); + /// let c2: Fp = Fp::rand(&mut test_rng()); + /// let mut ext_element: Fp3 = Fp3::new(c0, c1, c2); + /// + /// let base_field_element: Fp = Fp::rand(&mut test_rng()); + /// ext_element.mul_assign_by_fp(&base_field_element); + /// + /// assert_eq!(ext_element.c0, c0 * base_field_element); + /// assert_eq!(ext_element.c1, c1 * base_field_element); + /// assert_eq!(ext_element.c2, c2 * base_field_element); + /// ``` pub fn mul_assign_by_fp(&mut self, value: &P::Fp) { self.c0.mul_assign(value); self.c1.mul_assign(value); @@ -63,15 +96,11 @@ impl Fp3

{ /// Returns the value of QNR^T. #[inline] pub fn qnr_to_t() -> Self { - Self::new( - P::QUADRATIC_NONRESIDUE_TO_T.0, - P::QUADRATIC_NONRESIDUE_TO_T.1, - P::QUADRATIC_NONRESIDUE_TO_T.2, - ) + P::QUADRATIC_NONRESIDUE_TO_T } } -impl SquareRootField for Fp3

{ +impl SquareRootField for Fp3

{ /// Returns the Legendre symbol. fn legendre(&self) -> LegendreSymbol { self.norm().legendre() diff --git a/ff/src/fields/models/fp4.rs b/ff/src/fields/models/fp4.rs index 290391028..ba0985c98 100644 --- a/ff/src/fields/models/fp4.rs +++ b/ff/src/fields/models/fp4.rs @@ -1,10 +1,10 @@ use super::quadratic_extension::*; use core::marker::PhantomData; -use crate::fields::{Fp2, Fp2Parameters}; +use crate::fields::{Fp2, Fp2Config}; -pub trait Fp4Parameters: 'static + Send + Sync { - type Fp2Params: Fp2Parameters; +pub trait Fp4Config: 'static + Send + Sync { + type Fp2Params: Fp2Config; /// This *must* equal (0, 1); /// see [[DESD06, Section 5.1]](https://eprint.iacr.org/2006/471.pdf). @@ -12,22 +12,19 @@ pub trait Fp4Parameters: 'static + Send + Sync { /// Coefficients for the Frobenius automorphism. /// non_residue^((modulus^i-1)/4) for i=0,1,2,3 - const FROBENIUS_COEFF_FP4_C1: &'static [::Fp]; + const FROBENIUS_COEFF_FP4_C1: &'static [::Fp]; #[inline(always)] fn mul_fp2_by_nonresidue(fe: &Fp2) -> Fp2 { // see [[DESD06, Section 5.1]](https://eprint.iacr.org/2006/471.pdf). - Fp2::new( - ::NONRESIDUE * &fe.c1, - fe.c0, - ) + Fp2::new(::NONRESIDUE * &fe.c1, fe.c0) } } -pub struct Fp4ParamsWrapper(PhantomData

); +pub struct Fp4ParamsWrapper(PhantomData

); -impl QuadExtParameters for Fp4ParamsWrapper

{ - type BasePrimeField = ::Fp; +impl QuadExtConfig for Fp4ParamsWrapper

{ + type BasePrimeField = ::Fp; type BaseField = Fp2; type FrobCoeff = Self::BasePrimeField; @@ -49,8 +46,8 @@ impl QuadExtParameters for Fp4ParamsWrapper

{ pub type Fp4

= QuadExtField>; -impl Fp4

{ - pub fn mul_by_fp(&mut self, element: &::Fp) { +impl Fp4

{ + pub fn mul_by_fp(&mut self, element: &::Fp) { self.c0.mul_assign_by_fp(element); self.c1.mul_assign_by_fp(element); } diff --git a/ff/src/fields/models/fp6_2over3.rs b/ff/src/fields/models/fp6_2over3.rs index 07a42b222..30bd49fb2 100644 --- a/ff/src/fields/models/fp6_2over3.rs +++ b/ff/src/fields/models/fp6_2over3.rs @@ -1,15 +1,15 @@ use super::quadratic_extension::*; use core::{marker::PhantomData, ops::MulAssign}; -use crate::fields::{Fp3, Fp3Parameters}; +use crate::fields::{Fp3, Fp3Config}; -pub trait Fp6Parameters: 'static + Send + Sync { - type Fp3Params: Fp3Parameters; +pub trait Fp6Config: 'static + Send + Sync { + type Fp3Params: Fp3Config; const NONRESIDUE: Fp3; /// Coefficients for the Frobenius automorphism. - const FROBENIUS_COEFF_FP6_C1: &'static [::Fp]; + const FROBENIUS_COEFF_FP6_C1: &'static [::Fp]; #[inline(always)] fn mul_fp3_by_nonresidue(fe: &Fp3) -> Fp3 { @@ -17,15 +17,15 @@ pub trait Fp6Parameters: 'static + Send + Sync { res.c0 = fe.c2; res.c1 = fe.c0; res.c2 = fe.c1; - res.c0 = ::mul_fp_by_nonresidue(&res.c0); + res.c0 = ::mul_fp_by_nonresidue(&res.c0); res } } -pub struct Fp6ParamsWrapper(PhantomData

); +pub struct Fp6ParamsWrapper(PhantomData

); -impl QuadExtParameters for Fp6ParamsWrapper

{ - type BasePrimeField = ::Fp; +impl QuadExtConfig for Fp6ParamsWrapper

{ + type BasePrimeField = ::Fp; type BaseField = Fp3; type FrobCoeff = Self::BasePrimeField; @@ -47,12 +47,12 @@ impl QuadExtParameters for Fp6ParamsWrapper

{ pub type Fp6

= QuadExtField>; -impl Fp6

{ +impl Fp6

{ pub fn mul_by_034( &mut self, - c0: &::Fp, - c3: &::Fp, - c4: &::Fp, + c0: &::Fp, + c3: &::Fp, + c4: &::Fp, ) { let z0 = self.c0.c0; let z1 = self.c0.c1; @@ -66,9 +66,9 @@ impl Fp6

{ let x4 = *c4; let mut tmp1 = x3; - tmp1.mul_assign(&::NONRESIDUE); + tmp1.mul_assign(&::NONRESIDUE); let mut tmp2 = x4; - tmp2.mul_assign(&::NONRESIDUE); + tmp2.mul_assign(&::NONRESIDUE); self.c0.c0 = x0 * &z0 + &(tmp1 * &z5) + &(tmp2 * &z4); self.c0.c1 = x0 * &z1 + &(x3 * &z3) + &(tmp2 * &z5); @@ -80,9 +80,9 @@ impl Fp6

{ pub fn mul_by_014( &mut self, - c0: &::Fp, - c1: &::Fp, - c4: &::Fp, + c0: &::Fp, + c1: &::Fp, + c4: &::Fp, ) { let z0 = self.c0.c0; let z1 = self.c0.c1; @@ -96,9 +96,9 @@ impl Fp6

{ let x4 = *c4; let mut tmp1 = x1; - tmp1.mul_assign(&::NONRESIDUE); + tmp1.mul_assign(&::NONRESIDUE); let mut tmp2 = x4; - tmp2.mul_assign(&::NONRESIDUE); + tmp2.mul_assign(&::NONRESIDUE); self.c0.c0 = x0 * &z0 + &(tmp1 * &z2) + &(tmp2 * &z4); self.c0.c1 = x0 * &z1 + &(x1 * &z0) + &(tmp2 * &z5); diff --git a/ff/src/fields/models/fp6_3over2.rs b/ff/src/fields/models/fp6_3over2.rs index 1fe91c7ee..974f5e85b 100644 --- a/ff/src/fields/models/fp6_3over2.rs +++ b/ff/src/fields/models/fp6_3over2.rs @@ -2,8 +2,8 @@ use super::cubic_extension::*; use crate::fields::*; use core::marker::PhantomData; -pub trait Fp6Parameters: 'static + Send + Sync + Copy { - type Fp2Params: Fp2Parameters; +pub trait Fp6Config: 'static + Send + Sync + Copy { + type Fp2Params: Fp2Config; const NONRESIDUE: Fp2; @@ -17,10 +17,10 @@ pub trait Fp6Parameters: 'static + Send + Sync + Copy { } } -pub struct Fp6ParamsWrapper(PhantomData

); +pub struct Fp6ParamsWrapper(PhantomData

); -impl CubicExtParameters for Fp6ParamsWrapper

{ - type BasePrimeField = ::Fp; +impl CubicExtConfig for Fp6ParamsWrapper

{ + type BasePrimeField = ::Fp; type BaseField = Fp2; type FrobCoeff = Fp2; @@ -48,14 +48,14 @@ impl CubicExtParameters for Fp6ParamsWrapper

{ pub type Fp6

= CubicExtField>; -impl Fp6

{ +impl Fp6

{ pub fn mul_assign_by_fp2(&mut self, other: Fp2) { self.c0 *= &other; self.c1 *= &other; self.c2 *= &other; } - pub fn mul_by_fp(&mut self, element: &::Fp) { + pub fn mul_by_fp(&mut self, element: &::Fp) { self.c0.mul_assign_by_fp(&element); self.c1.mul_assign_by_fp(&element); self.c2.mul_assign_by_fp(&element); diff --git a/ff/src/fields/models/mod.rs b/ff/src/fields/models/mod.rs index 4f70b4fe4..20b0225f3 100644 --- a/ff/src/fields/models/mod.rs +++ b/ff/src/fields/models/mod.rs @@ -1,72 +1,5 @@ -use ark_std::{ - cmp::{Ord, Ordering, PartialOrd}, - fmt::{Display, Formatter, Result as FmtResult}, - io::{Read, Result as IoResult, Write}, - marker::PhantomData, - ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, - str::FromStr, -}; -use num_traits::{One, Zero}; - -use crate::{ - biginteger::{ - arithmetic as fa, BigInt, BigInteger as _BigInteger, BigInteger256, BigInteger320, - BigInteger384, BigInteger448, BigInteger64, BigInteger768, BigInteger832, - }, - bytes::{FromBytes, ToBytes}, - fields::{FftField, Field, FpParameters, LegendreSymbol, PrimeField, SquareRootField}, -}; -use ark_serialize::*; - -impl_Fp!(Fp64, Fp64Parameters, BigInteger64, BigInteger64, 1, "64"); -impl_Fp!( - Fp256, - Fp256Parameters, - BigInteger256, - BigInteger256, - 4, - "256" -); -impl_Fp!( - Fp320, - Fp320Parameters, - BigInteger320, - BigInteger320, - 5, - "320" -); -impl_Fp!( - Fp384, - Fp384Parameters, - BigInteger384, - BigInteger384, - 6, - "384" -); -impl_Fp!( - Fp448, - Fp448Parameters, - BigInteger448, - BigInteger448, - 7, - "448" -); -impl_Fp!( - Fp768, - Fp768Parameters, - BigInteger768, - BigInteger768, - 12, - "768" -); -impl_Fp!( - Fp832, - Fp832Parameters, - BigInteger832, - BigInteger832, - 13, - "832" -); +pub mod fp; +pub use self::fp::*; pub mod fp2; pub use self::fp2::*; @@ -85,8 +18,10 @@ pub use self::fp6_3over2::*; pub mod fp12_2over3over2; pub use self::fp12_2over3over2::*; +#[macro_use] pub mod quadratic_extension; pub use quadratic_extension::*; +#[macro_use] pub mod cubic_extension; pub use cubic_extension::*; diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index 1888297a7..fbcb7f447 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -26,7 +26,7 @@ use crate::{ }; /// Defines a Quadratic extension field from a quadratic non-residue. -pub trait QuadExtParameters: 'static + Send + Sync + Sized { +pub trait QuadExtConfig: 'static + Send + Sync + Sized { /// The prime field that this quadratic extension is eventually an extension of. type BasePrimeField: PrimeField; /// The base field that this field is a quadratic extension of. @@ -127,22 +127,40 @@ pub trait QuadExtParameters: 'static + Send + Sync + Sized { /// represented as c0 + c1 * X, for c0, c1 in `P::BaseField`. #[derive(Derivative)] #[derivative( - Default(bound = "P: QuadExtParameters"), - Hash(bound = "P: QuadExtParameters"), - Clone(bound = "P: QuadExtParameters"), - Copy(bound = "P: QuadExtParameters"), - Debug(bound = "P: QuadExtParameters"), - PartialEq(bound = "P: QuadExtParameters"), - Eq(bound = "P: QuadExtParameters") + Default(bound = "P: QuadExtConfig"), + Hash(bound = "P: QuadExtConfig"), + Clone(bound = "P: QuadExtConfig"), + Copy(bound = "P: QuadExtConfig"), + Debug(bound = "P: QuadExtConfig"), + PartialEq(bound = "P: QuadExtConfig"), + Eq(bound = "P: QuadExtConfig") )] -pub struct QuadExtField { +pub struct QuadExtField { /// Coefficient `c0` in the representation of the field element `c = c0 + c1 * X` pub c0: P::BaseField, /// Coefficient `c1` in the representation of the field element `c = c0 + c1 * X` pub c1: P::BaseField, } -impl QuadExtField

{ +/// Construct a [`QuadExtField`] element from elements of the base field. This should +/// be used primarily for constructing constant field elements; in a non-const +/// context, [`QuadExtField::new`] is preferable. +/// +/// # Usage +/// ```rust +/// # use ark_test_curves::QuadExt; +/// # use ark_test_curves::bls12_381 as ark_bls12_381; +/// use ark_bls12_381::{FQ_ZERO, FQ_ONE, Fq2}; +/// const ONE: Fq2 = QuadExt!(FQ_ONE, FQ_ZERO); +/// ``` +#[macro_export] +macro_rules! QuadExt { + ($c0:expr, $c1:expr $(,)?) => { + $crate::QuadExtField { c0: $c0, c1: $c1 } + }; +} + +impl QuadExtField

{ /// Create a new field element from coefficients `c0` and `c1`, /// so that the result is of the form `c0 + c1 * X`. /// @@ -211,7 +229,7 @@ impl QuadExtField

{ } } -impl Zero for QuadExtField

{ +impl Zero for QuadExtField

{ fn zero() -> Self { QuadExtField::new(P::BaseField::zero(), P::BaseField::zero()) } @@ -221,7 +239,7 @@ impl Zero for QuadExtField

{ } } -impl One for QuadExtField

{ +impl One for QuadExtField

{ fn one() -> Self { QuadExtField::new(P::BaseField::one(), P::BaseField::zero()) } @@ -231,7 +249,7 @@ impl One for QuadExtField

{ } } -impl Field for QuadExtField

{ +impl Field for QuadExtField

{ type BasePrimeField = P::BasePrimeField; fn extension_degree() -> u64 { @@ -369,7 +387,7 @@ impl Field for QuadExtField

{ } } -impl<'a, P: QuadExtParameters> SquareRootField for QuadExtField

+impl<'a, P: QuadExtConfig> SquareRootField for QuadExtField

where P::BaseField: SquareRootField + From, { @@ -412,7 +430,7 @@ where // Compute `(p+1)/2` as `1/2`. // This is cheaper than `P::BaseField::one().double().inverse()` - let mut two_inv = P::BasePrimeField::modulus(); + let mut two_inv = P::BasePrimeField::MODULUS; two_inv.add_nocarry(&1u64.into()); two_inv.div2(); @@ -456,7 +474,7 @@ where } /// `QuadExtField` elements are ordered lexicographically. -impl Ord for QuadExtField

{ +impl Ord for QuadExtField

{ #[inline(always)] fn cmp(&self, other: &Self) -> Ordering { match self.c1.cmp(&other.c1) { @@ -467,14 +485,14 @@ impl Ord for QuadExtField

{ } } -impl PartialOrd for QuadExtField

{ +impl PartialOrd for QuadExtField

{ #[inline(always)] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Zeroize for QuadExtField

{ +impl Zeroize for QuadExtField

{ // The phantom data does not contain element-specific data // and thus does not need to be zeroized. fn zeroize(&mut self) { @@ -483,13 +501,13 @@ impl Zeroize for QuadExtField

{ } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ fn from(other: u128) -> Self { Self::new(other.into(), P::BaseField::zero()) } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ #[inline] fn from(val: i128) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -501,13 +519,13 @@ impl From for QuadExtField

{ } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ fn from(other: u64) -> Self { Self::new(other.into(), P::BaseField::zero()) } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ #[inline] fn from(val: i64) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -519,13 +537,13 @@ impl From for QuadExtField

{ } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ fn from(other: u32) -> Self { Self::new(other.into(), P::BaseField::zero()) } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ #[inline] fn from(val: i32) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -537,13 +555,13 @@ impl From for QuadExtField

{ } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ fn from(other: u16) -> Self { Self::new(other.into(), P::BaseField::zero()) } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ #[inline] fn from(val: i16) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -555,13 +573,13 @@ impl From for QuadExtField

{ } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ fn from(other: u8) -> Self { Self::new(other.into(), P::BaseField::zero()) } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ #[inline] fn from(val: i8) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -573,30 +591,13 @@ impl From for QuadExtField

{ } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ fn from(other: bool) -> Self { Self::new(u8::from(other).into(), P::BaseField::zero()) } } -impl ToBytes for QuadExtField

{ - #[inline] - fn write(&self, mut writer: W) -> IoResult<()> { - self.c0.write(&mut writer)?; - self.c1.write(writer) - } -} - -impl FromBytes for QuadExtField

{ - #[inline] - fn read(mut reader: R) -> IoResult { - let c0 = P::BaseField::read(&mut reader)?; - let c1 = P::BaseField::read(reader)?; - Ok(QuadExtField::new(c0, c1)) - } -} - -impl Neg for QuadExtField

{ +impl Neg for QuadExtField

{ type Output = Self; #[inline] #[must_use] @@ -607,14 +608,14 @@ impl Neg for QuadExtField

{ } } -impl Distribution> for Standard { +impl Distribution> for Standard { #[inline] fn sample(&self, rng: &mut R) -> QuadExtField

{ QuadExtField::new(UniformRand::rand(rng), UniformRand::rand(rng)) } } -impl<'a, P: QuadExtParameters> Add<&'a QuadExtField

> for QuadExtField

{ +impl<'a, P: QuadExtConfig> Add<&'a QuadExtField

> for QuadExtField

{ type Output = Self; #[inline] @@ -624,7 +625,7 @@ impl<'a, P: QuadExtParameters> Add<&'a QuadExtField

> for QuadExtField

{ } } -impl<'a, P: QuadExtParameters> Sub<&'a QuadExtField

> for QuadExtField

{ +impl<'a, P: QuadExtConfig> Sub<&'a QuadExtField

> for QuadExtField

{ type Output = Self; #[inline] @@ -634,7 +635,7 @@ impl<'a, P: QuadExtParameters> Sub<&'a QuadExtField

> for QuadExtField

{ } } -impl<'a, P: QuadExtParameters> Mul<&'a QuadExtField

> for QuadExtField

{ +impl<'a, P: QuadExtConfig> Mul<&'a QuadExtField

> for QuadExtField

{ type Output = Self; #[inline] @@ -644,7 +645,7 @@ impl<'a, P: QuadExtParameters> Mul<&'a QuadExtField

> for QuadExtField

{ } } -impl<'a, P: QuadExtParameters> Div<&'a QuadExtField

> for QuadExtField

{ +impl<'a, P: QuadExtConfig> Div<&'a QuadExtField

> for QuadExtField

{ type Output = Self; #[inline] @@ -654,7 +655,7 @@ impl<'a, P: QuadExtParameters> Div<&'a QuadExtField

> for QuadExtField

{ } } -impl<'a, P: QuadExtParameters> AddAssign<&'a Self> for QuadExtField

{ +impl<'a, P: QuadExtConfig> AddAssign<&'a Self> for QuadExtField

{ #[inline] fn add_assign(&mut self, other: &Self) { self.c0 += &other.c0; @@ -662,7 +663,7 @@ impl<'a, P: QuadExtParameters> AddAssign<&'a Self> for QuadExtField

{ } } -impl<'a, P: QuadExtParameters> SubAssign<&'a Self> for QuadExtField

{ +impl<'a, P: QuadExtConfig> SubAssign<&'a Self> for QuadExtField

{ #[inline] fn sub_assign(&mut self, other: &Self) { self.c0 -= &other.c0; @@ -670,10 +671,10 @@ impl<'a, P: QuadExtParameters> SubAssign<&'a Self> for QuadExtField

{ } } -impl_additive_ops_from_ref!(QuadExtField, QuadExtParameters); -impl_multiplicative_ops_from_ref!(QuadExtField, QuadExtParameters); +impl_additive_ops_from_ref!(QuadExtField, QuadExtConfig); +impl_multiplicative_ops_from_ref!(QuadExtField, QuadExtConfig); -impl<'a, P: QuadExtParameters> MulAssign<&'a Self> for QuadExtField

{ +impl<'a, P: QuadExtConfig> MulAssign<&'a Self> for QuadExtField

{ #[inline] fn mul_assign(&mut self, other: &Self) { // Karatsuba multiplication; @@ -689,20 +690,20 @@ impl<'a, P: QuadExtParameters> MulAssign<&'a Self> for QuadExtField

{ } } -impl<'a, P: QuadExtParameters> DivAssign<&'a Self> for QuadExtField

{ +impl<'a, P: QuadExtConfig> DivAssign<&'a Self> for QuadExtField

{ #[inline] fn div_assign(&mut self, other: &Self) { self.mul_assign(&other.inverse().unwrap()); } } -impl fmt::Display for QuadExtField

{ +impl fmt::Display for QuadExtField

{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "QuadExtField({} + {} * u)", self.c0, self.c1) } } -impl CanonicalSerializeWithFlags for QuadExtField

{ +impl CanonicalSerializeWithFlags for QuadExtField

{ #[inline] fn serialize_with_flags( &self, @@ -720,7 +721,7 @@ impl CanonicalSerializeWithFlags for QuadExtField

{ } } -impl CanonicalSerialize for QuadExtField

{ +impl CanonicalSerialize for QuadExtField

{ #[inline] fn serialize(&self, writer: W) -> Result<(), SerializationError> { self.serialize_with_flags(writer, EmptyFlags) @@ -732,7 +733,7 @@ impl CanonicalSerialize for QuadExtField

{ } } -impl CanonicalDeserializeWithFlags for QuadExtField

{ +impl CanonicalDeserializeWithFlags for QuadExtField

{ #[inline] fn deserialize_with_flags( mut reader: R, @@ -744,7 +745,7 @@ impl CanonicalDeserializeWithFlags for QuadExtField

{ } } -impl CanonicalDeserialize for QuadExtField

{ +impl CanonicalDeserialize for QuadExtField

{ #[inline] fn deserialize(mut reader: R) -> Result { let c0: P::BaseField = CanonicalDeserialize::deserialize(&mut reader)?; @@ -753,7 +754,7 @@ impl CanonicalDeserialize for QuadExtField

{ } } -impl ToConstraintField for QuadExtField

+impl ToConstraintField for QuadExtField

where P::BaseField: ToConstraintField, { @@ -769,6 +770,23 @@ where } } +impl ToBytes for QuadExtField

{ + #[inline] + fn write(&self, mut writer: W) -> IoResult<()> { + self.c0.write(&mut writer)?; + self.c1.write(writer) + } +} + +impl FromBytes for QuadExtField

{ + #[inline] + fn read(mut reader: R) -> IoResult { + let c0 = P::BaseField::read(&mut reader)?; + let c1 = P::BaseField::read(reader)?; + Ok(QuadExtField::new(c0, c1)) + } +} + #[cfg(test)] mod quad_ext_tests { use super::*; diff --git a/ff/src/fields/utils.rs b/ff/src/fields/utils.rs index 340eb4822..e670317b3 100644 --- a/ff/src/fields/utils.rs +++ b/ff/src/fields/utils.rs @@ -1,6 +1,6 @@ /// Calculates the k-adicity of n, i.e., the number of trailing 0s in a base-k /// representation. -pub fn k_adicity(k: usize, mut n: usize) -> u32 { +pub fn k_adicity(k: u64, mut n: u64) -> u32 { let mut r = 0; while n > 1 { if n % k == 0 { diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 3c088a184..35d806aad 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -7,9 +7,8 @@ rust_2021_compatibility )] #![allow(clippy::op_ref, clippy::suspicious_op_assign_impl)] -#![cfg_attr(not(feature = "asm"), forbid(unsafe_code))] +#![deny(unsafe_code)] #![cfg_attr(use_asm, feature(llvm_asm))] -#![cfg_attr(feature = "asm", deny(unsafe_code))] #[macro_use] extern crate ark_std; @@ -29,6 +28,8 @@ pub use self::biginteger::*; pub mod fields; pub use self::fields::*; +pub(crate) mod const_helpers; + pub use ark_std::UniformRand; mod to_field_vec; @@ -36,12 +37,13 @@ pub use to_field_vec::ToConstraintField; pub use num_traits::{One, Zero}; +#[doc(hidden)] pub use ark_std::vec; pub mod prelude { pub use crate::biginteger::BigInteger; - pub use crate::fields::{Field, FpParameters, PrimeField, SquareRootField}; + pub use crate::fields::{Field, PrimeField, SquareRootField}; pub use ark_std::UniformRand; diff --git a/ff/src/to_field_vec.rs b/ff/src/to_field_vec.rs index 721b85d55..7cce46dfb 100644 --- a/ff/src/to_field_vec.rs +++ b/ff/src/to_field_vec.rs @@ -1,4 +1,4 @@ -use crate::{biginteger::BigInteger, Field, FpParameters, PrimeField}; +use crate::{biginteger::BigInteger, Field, PrimeField}; use ark_std::vec::Vec; /// Types that can be converted to a vector of `F` elements. Useful for @@ -42,7 +42,7 @@ impl ToConstraintField for () { impl ToConstraintField for [u8] { #[inline] fn to_field_elements(&self) -> Option> { - let max_size = usize::try_from(::Params::CAPACITY / 8).unwrap(); + let max_size = ((ConstraintF::MODULUS_BIT_SIZE - 1) / 8) as usize; let bigint_size = ::BigInt::NUM_LIMBS * 8; let fes = self .chunks(max_size) diff --git a/poly/Cargo.toml b/poly/Cargo.toml index 1b1e8ee74..134197f55 100644 --- a/poly/Cargo.toml +++ b/poly/Cargo.toml @@ -11,7 +11,7 @@ categories = ["cryptography"] include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] license = "MIT/Apache-2.0" edition = "2021" -rust-version = "1.56" +rust-version = "1.57" [dependencies] ark-ff = { version = "^0.3.0", path = "../ff", default-features = false } diff --git a/poly/src/domain/general.rs b/poly/src/domain/general.rs index 5db417628..45993e15e 100644 --- a/poly/src/domain/general.rs +++ b/poly/src/domain/general.rs @@ -10,7 +10,7 @@ pub use crate::domain::utils::Elements; use crate::domain::{ DomainCoeff, EvaluationDomain, MixedRadixEvaluationDomain, Radix2EvaluationDomain, }; -use ark_ff::{FftField, FftParameters}; +use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ io::{Read, Write}, @@ -75,7 +75,7 @@ impl CanonicalSerialize for GeneralEvaluationDomain { GeneralEvaluationDomain::Radix2(domain) => domain.serialize_uncompressed(&mut writer), GeneralEvaluationDomain::MixedRadix(domain) => { domain.serialize_uncompressed(&mut writer) - } + }, } } @@ -171,7 +171,7 @@ impl EvaluationDomain for GeneralEvaluationDomain { return Some(GeneralEvaluationDomain::Radix2(domain)); } - if F::FftParams::SMALL_SUBGROUP_BASE.is_some() { + if F::SMALL_SUBGROUP_BASE.is_some() { return Some(GeneralEvaluationDomain::MixedRadix( MixedRadixEvaluationDomain::new(num_coeffs)?, )); @@ -186,7 +186,7 @@ impl EvaluationDomain for GeneralEvaluationDomain { return Some(domain_size); } - if F::FftParams::SMALL_SUBGROUP_BASE.is_some() { + if F::SMALL_SUBGROUP_BASE.is_some() { return Some(MixedRadixEvaluationDomain::::compute_size_of_domain( num_coeffs, )?); diff --git a/poly/src/domain/mixed_radix.rs b/poly/src/domain/mixed_radix.rs index 07f350a69..800e51d66 100644 --- a/poly/src/domain/mixed_radix.rs +++ b/poly/src/domain/mixed_radix.rs @@ -14,7 +14,7 @@ use crate::domain::{ utils::{best_fft, bitreverse}, DomainCoeff, EvaluationDomain, }; -use ark_ff::{fields::utils::k_adicity, FftField, FftParameters}; +use ark_ff::{fields::utils::k_adicity, FftField}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ cmp::min, @@ -63,18 +63,18 @@ impl EvaluationDomain for MixedRadixEvaluationDomain { /// Construct a domain that is large enough for evaluations of a polynomial /// having `num_coeffs` coefficients. fn new(num_coeffs: usize) -> Option { - let small_subgroup_base = F::FftParams::SMALL_SUBGROUP_BASE?; + let small_subgroup_base = F::SMALL_SUBGROUP_BASE?; // Compute the best size of our evaluation domain. - let num_coeffs = best_mixed_domain_size::(num_coeffs); + let num_coeffs = best_mixed_domain_size::(num_coeffs) as u64; // Compute the size of our evaluation domain - let q = usize::try_from(small_subgroup_base).unwrap(); + let q = u64::from(small_subgroup_base); let q_adicity = k_adicity(q, num_coeffs); - let q_part = q.pow(q_adicity); + let q_part = q.checked_pow(q_adicity)?; let two_adicity = k_adicity(2, num_coeffs); - let two_part = 1 << two_adicity; + let two_part = 2u64.checked_pow(two_adicity)?; let size = u64::try_from(num_coeffs).unwrap(); let log_size_of_group = two_adicity; @@ -98,25 +98,25 @@ impl EvaluationDomain for MixedRadixEvaluationDomain { size_inv, group_gen, group_gen_inv: group_gen.inverse()?, - generator_inv: F::multiplicative_generator().inverse()?, + generator_inv: F::GENERATOR.inverse()?, }) } fn compute_size_of_domain(num_coeffs: usize) -> Option { - let small_subgroup_base = F::FftParams::SMALL_SUBGROUP_BASE?; + let small_subgroup_base = F::SMALL_SUBGROUP_BASE?; // Compute the best size of our evaluation domain. - let num_coeffs = best_mixed_domain_size::(num_coeffs); + let num_coeffs = best_mixed_domain_size::(num_coeffs) as u64; - let q = usize::try_from(small_subgroup_base).unwrap(); + let q = u64::from(small_subgroup_base); let q_adicity = k_adicity(q, num_coeffs); - let q_part = q.pow(q_adicity); + let q_part = q.checked_pow(q_adicity)?; let two_adicity = k_adicity(2, num_coeffs); - let two_part = 1 << two_adicity; + let two_part = 2u64.checked_pow(two_adicity)?; if num_coeffs == q_part * two_part { - Some(num_coeffs) + Some(num_coeffs as usize) } else { None } @@ -290,8 +290,8 @@ fn mixed_radix_fft_permute( fn best_mixed_domain_size(min_size: usize) -> usize { let mut best = usize::max_value(); - let small_subgroup_base_adicity = F::FftParams::SMALL_SUBGROUP_BASE_ADICITY.unwrap(); - let small_subgroup_base = usize::try_from(F::FftParams::SMALL_SUBGROUP_BASE.unwrap()).unwrap(); + let small_subgroup_base_adicity = F::SMALL_SUBGROUP_BASE_ADICITY.unwrap(); + let small_subgroup_base = usize::try_from(F::SMALL_SUBGROUP_BASE.unwrap()).unwrap(); for b in 0..=small_subgroup_base_adicity { let mut r = small_subgroup_base.pow(b); @@ -302,7 +302,7 @@ fn best_mixed_domain_size(min_size: usize) -> usize { two_adicity += 1; } - if two_adicity <= F::FftParams::TWO_ADICITY { + if two_adicity <= F::TWO_ADICITY { best = min(best, r); } } @@ -319,13 +319,15 @@ pub(crate) fn serial_mixed_radix_fft, F: FftField>( // and then splits into q sub-arrays q_adicity many times. let n = a.len(); - let q = usize::try_from(F::FftParams::SMALL_SUBGROUP_BASE.unwrap()).unwrap(); + let q = usize::try_from(F::SMALL_SUBGROUP_BASE.unwrap()).unwrap(); + let q_u64 = u64::from(F::SMALL_SUBGROUP_BASE.unwrap()); + let n_u64 = n as u64; - let q_adicity = k_adicity(q, n); - let q_part = q.pow(q_adicity); - let two_part = 1 << two_adicity; + let q_adicity = k_adicity(q_u64, n_u64); + let q_part = q_u64.checked_pow(q_adicity).unwrap(); + let two_part = 2u64.checked_pow(two_adicity).unwrap(); - assert_eq!(n, q_part * two_part); + assert_eq!(n_u64, q_part * two_part); let mut m = 1; // invariant: m = 2^{s-1} diff --git a/poly/src/domain/mod.rs b/poly/src/domain/mod.rs index 6ba231866..dabbd865b 100644 --- a/poly/src/domain/mod.rs +++ b/poly/src/domain/mod.rs @@ -143,7 +143,7 @@ pub trait EvaluationDomain: /// in place. #[inline] fn coset_fft_in_place>(&self, coeffs: &mut Vec) { - Self::distribute_powers(coeffs, F::multiplicative_generator()); + Self::distribute_powers(coeffs, F::GENERATOR); self.fft_in_place(coeffs); } @@ -160,7 +160,7 @@ pub trait EvaluationDomain: #[inline] fn coset_ifft_in_place>(&self, evals: &mut Vec) { self.ifft_in_place(evals); - Self::distribute_powers(evals, F::multiplicative_generator().inverse().unwrap()); + Self::distribute_powers(evals, self.generator_inv()); } /// Evaluate all the lagrange polynomials defined by this domain at the @@ -189,7 +189,7 @@ pub trait EvaluationDomain: /// a coset. fn divide_by_vanishing_poly_on_coset_in_place(&self, evals: &mut [F]) { let i = self - .evaluate_vanishing_polynomial(F::multiplicative_generator()) + .evaluate_vanishing_polynomial(F::GENERATOR) .inverse() .unwrap(); diff --git a/poly/src/domain/radix2/mod.rs b/poly/src/domain/radix2/mod.rs index 5900e5ec8..eda5d5590 100644 --- a/poly/src/domain/radix2/mod.rs +++ b/poly/src/domain/radix2/mod.rs @@ -5,7 +5,7 @@ pub use crate::domain::utils::Elements; use crate::domain::{DomainCoeff, EvaluationDomain}; -use ark_ff::{FftField, FftParameters}; +use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ convert::TryFrom, @@ -58,13 +58,13 @@ impl EvaluationDomain for Radix2EvaluationDomain { let log_size_of_group = size.trailing_zeros(); // libfqfft uses > https://github.com/scipr-lab/libfqfft/blob/e0183b2cef7d4c5deb21a6eaf3fe3b586d738fe0/libfqfft/evaluation_domain/domains/basic_radix2_domain.tcc#L33 - if log_size_of_group > F::FftParams::TWO_ADICITY { + if log_size_of_group > F::TWO_ADICITY { return None; } // Compute the generator for the multiplicative subgroup. // It should be the 2^(log_size_of_group) root of unity. - let group_gen = F::get_root_of_unity(usize::try_from(size).unwrap())?; + let group_gen = F::get_root_of_unity(size)?; // Check that it is indeed the 2^(log_size_of_group) root of unity. debug_assert_eq!(group_gen.pow([size]), F::one()); let size_as_field_element = F::from(size); @@ -77,13 +77,13 @@ impl EvaluationDomain for Radix2EvaluationDomain { size_inv, group_gen, group_gen_inv: group_gen.inverse()?, - generator_inv: F::multiplicative_generator().inverse()?, + generator_inv: F::GENERATOR.inverse()?, }) } fn compute_size_of_domain(num_coeffs: usize) -> Option { let size = num_coeffs.checked_next_power_of_two()?; - if size.trailing_zeros() > F::FftParams::TWO_ADICITY { + if size.trailing_zeros() > F::TWO_ADICITY { None } else { Some(size) @@ -362,7 +362,7 @@ mod tests { let poly_evals = domain.fft(&rand_poly.coeffs); let poly_coset_evals = domain.coset_fft(&rand_poly.coeffs); for (i, x) in domain.elements().enumerate() { - let coset_x = Fr::multiplicative_generator() * x; + let coset_x = Fr::GENERATOR * x; assert_eq!(poly_evals[i], rand_poly.evaluate(&x)); assert_eq!(poly_coset_evals[i], rand_poly.evaluate(&coset_x)); @@ -462,7 +462,7 @@ mod tests { } fn serial_radix2_coset_fft(a: &mut [Fr], omega: Fr, log_n: u32) { - let coset_shift = Fr::multiplicative_generator(); + let coset_shift = Fr::GENERATOR; let mut cur_pow = Fr::one(); for coeff in a.iter_mut() { *coeff *= cur_pow; @@ -473,7 +473,7 @@ mod tests { fn serial_radix2_coset_ifft(a: &mut [Fr], omega: Fr, log_n: u32) { serial_radix2_ifft(a, omega, log_n); - let coset_shift = Fr::multiplicative_generator().inverse().unwrap(); + let coset_shift = Fr::GENERATOR.inverse().unwrap(); let mut cur_pow = Fr::one(); for coeff in a.iter_mut() { *coeff *= cur_pow; diff --git a/poly/src/domain/utils.rs b/poly/src/domain/utils.rs index f27f04568..3ea29a7fa 100644 --- a/poly/src/domain/utils.rs +++ b/poly/src/domain/utils.rs @@ -129,7 +129,7 @@ pub(crate) fn parallel_fft, F: FftField>( // These are cosets with generator g^{num_cosets}, and varying shifts. let mut tmp = vec![vec![T::zero(); coset_size]; num_cosets]; let new_omega = omega.pow(&[num_cosets as u64]); - let new_two_adicity = ark_ff::utils::k_adicity(2, coset_size); + let new_two_adicity = ark_ff::utils::k_adicity(2, coset_size as u64); // For each coset, we first build a polynomial of degree |coset size|, // whose evaluations over coset k will agree with the evaluations of a over the coset. diff --git a/poly/src/polynomial/multivariate/mod.rs b/poly/src/polynomial/multivariate/mod.rs index ab6a2a28b..04e63c030 100644 --- a/poly/src/polynomial/multivariate/mod.rs +++ b/poly/src/polynomial/multivariate/mod.rs @@ -68,8 +68,8 @@ impl SparseTerm { prev.1 += pow; continue; } - } - _ => {} + }, + _ => {}, }; term_dedup.push((*var, *pow)); } diff --git a/poly/src/polynomial/multivariate/sparse.rs b/poly/src/polynomial/multivariate/sparse.rs index a2dfdbe29..c7fc690da 100644 --- a/poly/src/polynomial/multivariate/sparse.rs +++ b/poly/src/polynomial/multivariate/sparse.rs @@ -146,7 +146,7 @@ impl<'a, 'b, F: Field, T: Term> Add<&'a SparsePolynomial> for &'b SparsePo let other = other_iter.next().unwrap(); let cur = cur_iter.next().unwrap(); (cur.0 + other.0, cur.1.clone()) - } + }, Some(Ordering::Greater) => other_iter.next().unwrap().clone(), None => break, }; diff --git a/poly/src/polynomial/univariate/mod.rs b/poly/src/polynomial/univariate/mod.rs index ae415d29f..d30ce0ac6 100644 --- a/poly/src/polynomial/univariate/mod.rs +++ b/poly/src/polynomial/univariate/mod.rs @@ -147,18 +147,18 @@ impl<'a, F: 'a + FftField> DenseOrSparsePolynomial<'a, F> { SPolynomial(Cow::Borrowed(s)) => { let evals = domain.elements().map(|elem| s.evaluate(&elem)).collect(); Evaluations::from_vec_and_domain(evals, domain) - } + }, SPolynomial(Cow::Owned(s)) => { let evals = domain.elements().map(|elem| s.evaluate(&elem)).collect(); Evaluations::from_vec_and_domain(evals, domain) - } + }, DPolynomial(Cow::Borrowed(d)) => { Evaluations::from_vec_and_domain(domain.fft(&d.coeffs), domain) - } + }, DPolynomial(Cow::Owned(mut d)) => { domain.fft_in_place(&mut d.coeffs); Evaluations::from_vec_and_domain(d.coeffs, domain) - } + }, } } } diff --git a/serialize-derive/src/lib.rs b/serialize-derive/src/lib.rs index b65623f48..fd07f9c25 100644 --- a/serialize-derive/src/lib.rs +++ b/serialize-derive/src/lib.rs @@ -44,7 +44,7 @@ fn impl_serialize_field( ); idents.pop(); } - } + }, _ => { serialize_body .push(quote! { CanonicalSerialize::serialize(&self.#(#idents).*, &mut writer)?; }); @@ -59,7 +59,7 @@ fn impl_serialize_field( uncompressed_size_body.push( quote! { size += CanonicalSerialize::uncompressed_size(&self.#(#idents).*); }, ); - } + }, } } @@ -82,10 +82,10 @@ fn impl_canonical_serialize(ast: &syn::DeriveInput) -> TokenStream { None => { let index = Index::from(i); idents.push(Box::new(index)); - } + }, Some(ref ident) => { idents.push(Box::new(ident.clone())); - } + }, } impl_serialize_field( &mut serialize_body, @@ -97,7 +97,7 @@ fn impl_canonical_serialize(ast: &syn::DeriveInput) -> TokenStream { &field.ty, ); } - } + }, _ => panic!( "Serialize can only be derived for structs, {} is not a struct", name @@ -164,7 +164,7 @@ fn impl_deserialize_field(ty: &Type) -> (TokenStream, TokenStream, TokenStream) quote! { (#(#uncompressed_fields)*), }, quote! { (#(#unchecked_fields)*), }, ) - } + }, _ => ( quote! { CanonicalDeserialize::deserialize(&mut reader)?, }, quote! { CanonicalDeserialize::deserialize_uncompressed(&mut reader)?, }, @@ -197,7 +197,7 @@ fn impl_canonical_deserialize(ast: &syn::DeriveInput) -> TokenStream { compressed_field_cases.push(compressed); uncompressed_field_cases.push(uncompressed); unchecked_field_cases.push(unchecked); - } + }, // struct field without len_type Some(ident) => { let (compressed_field, uncompressed_field, unchecked_field) = @@ -205,7 +205,7 @@ fn impl_canonical_deserialize(ast: &syn::DeriveInput) -> TokenStream { compressed_field_cases.push(quote! { #ident: #compressed_field }); uncompressed_field_cases.push(quote! { #ident: #uncompressed_field }); unchecked_field_cases.push(quote! { #ident: #unchecked_field }); - } + }, } } @@ -242,7 +242,7 @@ fn impl_canonical_deserialize(ast: &syn::DeriveInput) -> TokenStream { }) }); } - } + }, _ => panic!( "Deserialize can only be derived for structs, {} is not a Struct", name diff --git a/test-curves/src/bls12_381/fq.rs b/test-curves/src/bls12_381/fq.rs index 2a8ded545..57750d749 100644 --- a/test-curves/src/bls12_381/fq.rs +++ b/test-curves/src/bls12_381/fq.rs @@ -1,116 +1,107 @@ use ark_ff::{ - biginteger::BigInt, biginteger::BigInteger384 as BigInteger, - field_new, - fields::{FftParameters, Fp384, Fp384Parameters, FpParameters}, + fields::{Fp384, MontBackend}, + BigInt, MontFp, }; -pub type Fq = Fp384; +pub struct FqConfig; +pub type Fq = Fp384>; -pub struct FqParameters; - -impl Fp384Parameters for FqParameters {} -impl FftParameters for FqParameters { - type BigInt = BigInteger; - - const TWO_ADICITY: u32 = 1; - - #[rustfmt::skip] - const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInt::<6>([ - 0x43f5fffffffcaaae, - 0x32b7fff2ed47fffd, - 0x7e83a49a2e99d69, - 0xeca8f3318332bb7a, - 0xef148d1ea0f4c069, - 0x40ab3263eff0206, - ]); -} -impl FpParameters for FqParameters { +impl ark_ff::MontConfig<6> for FqConfig { /// MODULUS = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 - #[rustfmt::skip] - const MODULUS: BigInteger = BigInt::<6>([ - 0xb9feffffffffaaab, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a, - ]); - - const MODULUS_BITS: u32 = 381; - - const CAPACITY: u32 = Self::MODULUS_BITS - 1; - - const REPR_SHAVE_BITS: u32 = 3; - - /// R = 3380320199399472671518931668520476396067793891014375699959770179129436917079669831430077592723774664465579537268733 - #[rustfmt::skip] - const R: BigInteger = BigInt::<6>([ - 0x760900000002fffd, - 0xebf4000bc40c0002, - 0x5f48985753c758ba, - 0x77ce585370525745, - 0x5c071a97a256ec6d, - 0x15f65ec3fa80e493, - ]); - - #[rustfmt::skip] - const R2: BigInteger = BigInt::<6>([ - 0xf4df1f341c341746, - 0xa76e6a609d104f1, - 0x8de5476c4c95b6d5, - 0x67eb88a9939d83c0, - 0x9a793e85b519952d, - 0x11988fe592cae3aa, - ]); - - const INV: u64 = 0x89f3fffcfffcfffd; + const MODULUS: BigInteger = BigInt!("4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787"); /// GENERATOR = 2 - /// Encoded in Montgomery form, so the value is - /// 2 * R % q = 2758230843577277949620073511305048635578704962089743514587482222134842183668501798417467556318533664893264801977679 - #[rustfmt::skip] - const GENERATOR: BigInteger = BigInt::<6>([ - 0x321300000006554f, - 0xb93c0018d6c40005, - 0x57605e0db0ddbb51, - 0x8b256521ed1f9bcb, - 0x6cf28d7901622c03, - 0x11ebab9dbb81e28c, - ]); + const GENERATOR: Fq = ark_ff::MontFp!(Fq, "2"); - #[rustfmt::skip] - const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<6>([ - 0xdcff7fffffffd555, - 0xf55ffff58a9ffff, - 0xb39869507b587b12, - 0xb23ba5c279c2895f, - 0x258dd3db21a5d66b, - 0xd0088f51cbff34d, - ]); - - /// T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T - /// For T coprime to 2 - #[rustfmt::skip] - const T: BigInteger = BigInt::<6>([ - 0xdcff7fffffffd555, - 0xf55ffff58a9ffff, - 0xb39869507b587b12, - 0xb23ba5c279c2895f, - 0x258dd3db21a5d66b, - 0xd0088f51cbff34d, - ]); - - #[rustfmt::skip] - const T_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<6>([ - 0xee7fbfffffffeaaa, - 0x7aaffffac54ffff, - 0xd9cc34a83dac3d89, - 0xd91dd2e13ce144af, - 0x92c6e9ed90d2eb35, - 0x680447a8e5ff9a6, - ]); + const TWO_ADIC_ROOT_OF_UNITY: Fq = MontFp!(Fq, "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786"); } -pub const FQ_ONE: Fq = field_new!(Fq, "1"); -pub const FQ_ZERO: Fq = field_new!(Fq, "0"); +pub const FQ_ONE: Fq = MontFp!(Fq, "1"); +pub const FQ_ZERO: Fq = MontFp!(Fq, "0"); + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_constants() { + use ark_ff::{MontConfig, PrimeField}; + assert_eq!(Fq::MODULUS_BIT_SIZE, 381); + + assert_eq!(FqConfig::INV, 0x89f3fffcfffcfffd); + + // R = 3380320199399472671518931668520476396067793891014375699959770179129436917079669831430077592723774664465579537268733 + assert_eq!( + FqConfig::R, + BigInt::<6>([ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ]) + ); + + assert_eq!( + FqConfig::R2, + BigInt::<6>([ + 0xf4df1f341c341746, + 0xa76e6a609d104f1, + 0x8de5476c4c95b6d5, + 0x67eb88a9939d83c0, + 0x9a793e85b519952d, + 0x11988fe592cae3aa, + ]) + ); + + assert_eq!( + Fq::TRACE, + BigInt::<6>([ + 0xdcff7fffffffd555, + 0xf55ffff58a9ffff, + 0xb39869507b587b12, + 0xb23ba5c279c2895f, + 0x258dd3db21a5d66b, + 0xd0088f51cbff34d, + ]) + ); + assert_eq!( + Fq::MODULUS_MINUS_ONE_DIV_TWO, + BigInt::<6>([ + 0xdcff7fffffffd555, + 0xf55ffff58a9ffff, + 0xb39869507b587b12, + 0xb23ba5c279c2895f, + 0x258dd3db21a5d66b, + 0xd0088f51cbff34d, + ]) + ); + + assert_eq!( + Fq::TRACE_MINUS_ONE_DIV_TWO, + BigInt::<6>([ + 0xee7fbfffffffeaaa, + 0x7aaffffac54ffff, + 0xd9cc34a83dac3d89, + 0xd91dd2e13ce144af, + 0x92c6e9ed90d2eb35, + 0x680447a8e5ff9a6, + ]) + ); + // GENERATOR = 2 + // Encoded in Montgomery form, so the value is + // 2 * R % q = 2758230843577277949620073511305048635578704962089743514587482222134842183668501798417467556318533664893264801977679 + assert_eq!( + FqConfig::GENERATOR, + Fq::new(BigInt::new([ + 0x321300000006554f, + 0xb93c0018d6c40005, + 0x57605e0db0ddbb51, + 0x8b256521ed1f9bcb, + 0x6cf28d7901622c03, + 0x11ebab9dbb81e28c, + ])) + ); + } +} diff --git a/test-curves/src/bls12_381/fq2.rs b/test-curves/src/bls12_381/fq2.rs index 15cfefa70..853db847b 100644 --- a/test-curves/src/bls12_381/fq2.rs +++ b/test-curves/src/bls12_381/fq2.rs @@ -1,28 +1,28 @@ use crate::bls12_381::*; -use ark_ff::{field_new, fields::*}; +use ark_ff::{fields::*, MontFp, QuadExt}; -pub type Fq2 = Fp2; +pub type Fq2 = Fp2; -pub struct Fq2Parameters; +pub struct Fq2Config; -impl Fp2Parameters for Fq2Parameters { +impl Fp2Config for Fq2Config { type Fp = Fq; /// NONRESIDUE = -1 #[rustfmt::skip] - const NONRESIDUE: Fq = field_new!(Fq, "-1"); + const NONRESIDUE: Fq = MontFp!(Fq, "-1"); /// QUADRATIC_NONRESIDUE = (U + 1) #[rustfmt::skip] - const QUADRATIC_NONRESIDUE: (Fq, Fq) = (FQ_ONE, FQ_ONE); + const QUADRATIC_NONRESIDUE: Fq2 = QuadExt!(FQ_ONE, FQ_ONE); /// Coefficients for the Frobenius automorphism. #[rustfmt::skip] const FROBENIUS_COEFF_FP2_C1: &'static [Fq] = &[ // Fq(-1)**(((q^0) - 1) / 2) - field_new!(Fq, "1"), + MontFp!(Fq, "1"), // Fq(-1)**(((q^1) - 1) / 2) - field_new!(Fq, "-1"), + MontFp!(Fq, "-1"), ]; #[inline(always)] @@ -31,5 +31,5 @@ impl Fp2Parameters for Fq2Parameters { } } -pub const FQ2_ZERO: Fq2 = field_new!(Fq2, FQ_ZERO, FQ_ZERO); -pub const FQ2_ONE: Fq2 = field_new!(Fq2, FQ_ONE, FQ_ZERO); +pub const FQ2_ZERO: Fq2 = QuadExt!(FQ_ZERO, FQ_ZERO); +pub const FQ2_ONE: Fq2 = QuadExt!(FQ_ONE, FQ_ZERO); diff --git a/test-curves/src/bls12_381/fq6.rs b/test-curves/src/bls12_381/fq6.rs index e54b79a03..911aa5b5f 100644 --- a/test-curves/src/bls12_381/fq6.rs +++ b/test-curves/src/bls12_381/fq6.rs @@ -1,86 +1,80 @@ use crate::bls12_381::*; -use ark_ff::{field_new, fields::*}; +use ark_ff::{fields::*, MontFp, QuadExt}; -pub type Fq6 = Fp6; +pub type Fq6 = Fp6; #[derive(Clone, Copy)] -pub struct Fq6Parameters; +pub struct Fq6Config; -impl Fp6Parameters for Fq6Parameters { - type Fp2Params = Fq2Parameters; +impl Fp6Config for Fq6Config { + type Fp2Params = Fq2Config; /// NONRESIDUE = (U + 1) - #[rustfmt::skip] - const NONRESIDUE: Fq2 = field_new!(Fq2, - field_new!(Fq, "1"), - field_new!(Fq, "1"), - ); + const NONRESIDUE: Fq2 = QuadExt!(MontFp!(Fq, "1"), MontFp!(Fq, "1")); #[rustfmt::skip] const FROBENIUS_COEFF_FP6_C1: &'static [Fq2] = &[ // Fp2::NONRESIDUE^(((q^0) - 1) / 3) - field_new!(Fq2, - field_new!(Fq, "1"), - field_new!(Fq, "0"), - ), + QuadExt!(MontFp!(Fq, "1"), MontFp!(Fq, "0")), + // Fp2::NONRESIDUE^(((q^1) - 1) / 3) - field_new!(Fq2, - field_new!(Fq, "0"), - field_new!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), + QuadExt!( + MontFp!(Fq, "0"), + MontFp!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), ), // Fp2::NONRESIDUE^(((q^2) - 1) / 3) - field_new!(Fq2, - field_new!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), - field_new!(Fq, "0"), + QuadExt!( + MontFp!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), + MontFp!(Fq, "0"), ), // Fp2::NONRESIDUE^(((q^3) - 1) / 3) - field_new!(Fq2, - field_new!(Fq, "0"), - field_new!(Fq, "1"), + QuadExt!( + MontFp!(Fq, "0"), + MontFp!(Fq, "1"), ), // Fp2::NONRESIDUE^(((q^4) - 1) / 3) - field_new!(Fq2, - field_new!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), - field_new!(Fq, "0"), + QuadExt!( + MontFp!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), + MontFp!(Fq, "0"), ), // Fp2::NONRESIDUE^(((q^5) - 1) / 3) - field_new!(Fq2, - field_new!(Fq, "0"), - field_new!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), + QuadExt!( + MontFp!(Fq, "0"), + MontFp!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), ), ]; #[rustfmt::skip] const FROBENIUS_COEFF_FP6_C2: &'static [Fq2] = &[ // Fq2(u + 1)**(((2q^0) - 2) / 3) - field_new!(Fq2, - field_new!(Fq, "1"), - field_new!(Fq, "0"), + QuadExt!( + MontFp!(Fq, "1"), + MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^1) - 2) / 3) - field_new!(Fq2, - field_new!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437"), - field_new!(Fq, "0"), + QuadExt!( + MontFp!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437"), + MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^2) - 2) / 3) - field_new!(Fq2, - field_new!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), - field_new!(Fq, "0"), + QuadExt!( + MontFp!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), + MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^3) - 2) / 3) - field_new!(Fq2, - field_new!(Fq, "-1"), - field_new!(Fq, "0"), + QuadExt!( + MontFp!(Fq, "-1"), + MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^4) - 2) / 3) - field_new!(Fq2, - field_new!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), - field_new!(Fq, "0"), + QuadExt!( + MontFp!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), + MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^5) - 2) / 3) - field_new!(Fq2, - field_new!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351"), - field_new!(Fq, "0"), + QuadExt!( + MontFp!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351"), + MontFp!(Fq, "0"), ), ]; diff --git a/test-curves/src/bls12_381/fr.rs b/test-curves/src/bls12_381/fr.rs index 365289484..3d7d0d43c 100644 --- a/test-curves/src/bls12_381/fr.rs +++ b/test-curves/src/bls12_381/fr.rs @@ -1,101 +1,22 @@ use ark_ff::{ - biginteger::BigInt, biginteger::BigInteger256 as BigInteger, - fields::{FftParameters, Fp256, Fp256Parameters, FpParameters}, + fields::{Fp256, MontBackend, MontConfig, MontFp}, + BigInt, }; -pub type Fr = Fp256; +pub struct FrConfig; +pub type Fr = Fp256>; -pub struct FrParameters; - -impl Fp256Parameters for FrParameters {} -impl FftParameters for FrParameters { - type BigInt = BigInteger; - - const TWO_ADICITY: u32 = 32; - - #[rustfmt::skip] - const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInt::<4>([ - 0xb9b58d8c5f0e466a, - 0x5b1b4c801819d7ec, - 0xaf53ae352a31e64, - 0x5bf3adda19e9b27b, - ]); -} -impl FpParameters for FrParameters { +impl MontConfig<4> for FrConfig { /// MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513 - #[rustfmt::skip] - const MODULUS: BigInteger = BigInt::<4>([ - 0xffffffff00000001, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48, - ]); - - const MODULUS_BITS: u32 = 255; - - const CAPACITY: u32 = Self::MODULUS_BITS - 1; - - const REPR_SHAVE_BITS: u32 = 1; - - /// R = 10920338887063814464675503992315976177888879664585288394250266608035967270910 - #[rustfmt::skip] - const R: BigInteger = BigInt::<4>([ - 0x1fffffffe, - 0x5884b7fa00034802, - 0x998c4fefecbc4ff5, - 0x1824b159acc5056f, - ]); - - #[rustfmt::skip] - const R2: BigInteger = BigInt::<4>([ - 0xc999e990f3f29c6d, - 0x2b6cedcb87925c23, - 0x5d314967254398f, - 0x748d9d99f59ff11, - ]); - - const INV: u64 = 0xfffffffeffffffff; + const MODULUS: BigInteger = + BigInt!("52435875175126190479447740508185965837690552500527637822603658699938581184513"); /// GENERATOR = 7 - /// Encoded in Montgomery form, so the value here is - /// 7 * R % q = 24006497034320510773280787438025867407531605151569380937148207556313189711857 - #[rustfmt::skip] - const GENERATOR: BigInteger = BigInt::<4>([ - 0xefffffff1, - 0x17e363d300189c0f, - 0xff9c57876f8457b0, - 0x351332208fc5a8c4, - ]); - - #[rustfmt::skip] - const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<4>([ - 0x7fffffff80000000, - 0xa9ded2017fff2dff, - 0x199cec0404d0ec02, - 0x39f6d3a994cebea4, - ]); - - // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T - // For T coprime to 2 - - // T = (MODULUS - 1) / 2^S = - // 12208678567578594777604504606729831043093128246378069236549469339647 - #[rustfmt::skip] - const T: BigInteger = BigInt::<4>([ - 0xfffe5bfeffffffff, - 0x9a1d80553bda402, - 0x299d7d483339d808, - 0x73eda753, - ]); + const GENERATOR: Fr = MontFp!(Fr, "7"); - // (T - 1) / 2 = - // 6104339283789297388802252303364915521546564123189034618274734669823 - #[rustfmt::skip] - const T_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<4>([ - 0x7fff2dff7fffffff, - 0x4d0ec02a9ded201, - 0x94cebea4199cec04, - 0x39f6d3a9, - ]); + const TWO_ADIC_ROOT_OF_UNITY: Fr = MontFp!( + Fr, + "10238227357739495823651030575849232062558860180284477541189508159991286009131" + ); } diff --git a/test-curves/src/bls12_381/g1.rs b/test-curves/src/bls12_381/g1.rs index 94f7e12b1..1ed997061 100644 --- a/test-curves/src/bls12_381/g1.rs +++ b/test-curves/src/bls12_381/g1.rs @@ -3,7 +3,7 @@ use ark_ec::{ models::{ModelParameters, SWModelParameters}, short_weierstrass_jacobian::*, }; -use ark_ff::{field_new, Zero}; +use ark_ff::{MontFp, Zero}; pub type G1Affine = GroupAffine; pub type G1Projective = GroupProjective; @@ -21,16 +21,16 @@ impl ModelParameters for Parameters { /// COFACTOR_INV = COFACTOR^{-1} mod r /// = 52435875175126190458656871551744051925719901746859129887267498875565241663483 #[rustfmt::skip] - const COFACTOR_INV: Fr = field_new!(Fr, "52435875175126190458656871551744051925719901746859129887267498875565241663483"); + const COFACTOR_INV: Fr = MontFp!(Fr, "52435875175126190458656871551744051925719901746859129887267498875565241663483"); } impl SWModelParameters for Parameters { /// COEFF_A = 0 - const COEFF_A: Fq = field_new!(Fq, "0"); + const COEFF_A: Fq = MontFp!(Fq, "0"); /// COEFF_B = 4 #[rustfmt::skip] - const COEFF_B: Fq = field_new!(Fq, "4"); + const COEFF_B: Fq = MontFp!(Fq, "4"); /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = @@ -45,12 +45,12 @@ impl SWModelParameters for Parameters { /// G1_GENERATOR_X = /// 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507 #[rustfmt::skip] -pub const G1_GENERATOR_X: Fq = field_new!(Fq, "3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507"); +pub const G1_GENERATOR_X: Fq = MontFp!(Fq, "3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507"); /// G1_GENERATOR_Y = /// 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569 #[rustfmt::skip] -pub const G1_GENERATOR_Y: Fq = field_new!(Fq, "1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569"); +pub const G1_GENERATOR_Y: Fq = MontFp!(Fq, "1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569"); #[cfg(test)] mod test { diff --git a/test-curves/src/bls12_381/tests.rs b/test-curves/src/bls12_381/tests.rs index 338770c27..b3954d7fb 100644 --- a/test-curves/src/bls12_381/tests.rs +++ b/test-curves/src/bls12_381/tests.rs @@ -2,12 +2,12 @@ use ark_ec::{models::SWModelParameters, AffineCurve, PairingEngine, ProjectiveCurve}; use ark_ff::{Field, One, SquareRootField, UniformRand, Zero}; -use crate::bls12_381::{g1, Fq, Fq2, Fq6, FqParameters, Fr, G1Affine, G1Projective}; +use crate::bls12_381::{g1, Fq, Fq2, Fq6, FqConfig, Fr, FrConfig, G1Affine, G1Projective}; use ark_algebra_test_templates::{ curves::*, fields::*, generate_field_test, generate_g1_test, groups::*, msm::*, }; use ark_std::ops::{AddAssign, MulAssign, SubAssign}; use ark_std::{rand::Rng, test_rng}; -generate_field_test!(bls12_381; fq2; fq6;); +generate_field_test!(bls12_381; fq2; fq6; mont(6, 4); ); generate_g1_test!(bls12_381; curve_tests; sw_tests;); diff --git a/test-curves/src/bn384_small_two_adicity/fq.rs b/test-curves/src/bn384_small_two_adicity/fq.rs index f96b5c00f..197ade496 100644 --- a/test-curves/src/bn384_small_two_adicity/fq.rs +++ b/test-curves/src/bn384_small_two_adicity/fq.rs @@ -1,138 +1,28 @@ use ark_ff::{ - biginteger::BigInt, biginteger::BigInteger384 as BigInteger, - fields::{FftParameters, Fp384, Fp384Parameters, FpParameters}, + fields::{Fp384, MontBackend}, + BigInt, MontFp, }; -pub type Fq = Fp384; +pub struct FqConfig; +pub type Fq = Fp384>; -pub struct FqParameters; - -impl Fp384Parameters for FqParameters {} -impl FftParameters for FqParameters { - type BigInt = BigInteger; +impl ark_ff::MontConfig<6> for FqConfig { + /// MODULUS = 5945877603251831796258517492029536515488649313567122628447476625319762940580461319088175968449723373773214087057409 + const MODULUS: BigInteger = BigInt!("5945877603251831796258517492029536515488649313567122628447476625319762940580461319088175968449723373773214087057409"); - const TWO_ADICITY: u32 = 12; + /// GENERATOR = 7 + const GENERATOR: Fq = ark_ff::MontFp!(Fq, "7"); - // TWO_ADIC_ROOT_OF_UNITY = GENERATOR ^ t = - // 4563474743154071393992783416618298946273483760389666561454590580850277486490043009369759159902206584965352075028870 - // t is defined below - // This number needs to be in the Montgomery residue form. - // I.e., write TWO_ADIC_ROOT_OF_UNITY * R - // = 31697142653270303559937416477969693485777517469743380851550419037088206541495408586849687582005649424923407072789 - const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInt::<6>([ - 11341361458440748565u64, - 11432203502797436080u64, - 15207341022279519515u64, - 47188373187644751u64, - 123916096934654777u64, - 14839576327112111u64, - ]); + const TWO_ADIC_ROOT_OF_UNITY: Fq = MontFp!(Fq, "4563474743154071393992783416618298946273483760389666561454590580850277486490043009369759159902206584965352075028870"); const SMALL_SUBGROUP_BASE: Option = Some(3); const SMALL_SUBGROUP_BASE_ADICITY: Option = Some(2); // LARGE_SUBGROUP_ROOT_OF_UNITY = GENERATOR ^ (t * 3 ^ 2) = // 203100967768496856767841701771526315192814992286543641883928020883407386213917566206874176054653008117753458021037 - // I.e., write LARGE_SUBGROUP_ROOT_OF_UNITY * R - // = 81125788721017958531970004711554176763707237538772656640376499392204495132484005854811881368159718832226698073199 - const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(BigInt::<6>([ - 6225018931355915375u64, - 180290822448891806u64, - 14465855242330424160u64, - 8575642455718703211u64, - 8320153096556229121u64, - 37980468681094481u64, - ])); + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(MontFp!(Fq, "683178638573601328773157856456805978879544571597638024782973348263890473503149166479735097908137632291366958273030")); } -impl FpParameters for FqParameters { - /// MODULUS = 5945877603251831796258517492029536515488649313567122628447476625319762940580461319088175968449723373773214087057409 - const MODULUS: BigInteger = BigInt::<6>([ - 2340831834029625345u64, - 7249631296803227205u64, - 16747242270977641452u64, - 15205557732015452966u64, - 15076886007691743306u64, - 2783667458303802095u64, - ]); - - const MODULUS_BITS: u32 = 382; - - const CAPACITY: u32 = Self::MODULUS_BITS - 1; - - const REPR_SHAVE_BITS: u32 = 2; - - // R = 2^{384} % MODULUS - // R = 3726740576883488434727935147966394712147843389062710897263433652327144128014442696885210444186575398167343467962362 - const R: BigInteger = BigInt::<6>([ - 4401753069531799546u64, - 11842444440309291617u64, - 10197010816391460981u64, - 1000373976455040278u64, - 1772404322397298239u64, - 1744739323886739041u64, - ]); - - // R2 = R * R % MODULUS - // R2 = 3383647891563276668075677154877236888682502454192504651186644086866057738042913461398173437153800906409349899530047 - const R2: BigInteger = BigInt::<6>([ - 16517710552441204543u64, - 4787934104620433613u64, - 12185556526193827174u64, - 10815510726684521116u64, - 3531299847928964248u64, - 1584114432653590388u64, - ]); - - // INV = -(MODULUS)^{-1} mod 2^64 - const INV: u64 = 887568002135035903u64; - - // GENERATOR = 7 - // This number needs to be in the Montgomery residue form. - // I.e., write 7 * R % MODULUS = - // 2303673625177091858061476067646616923080306469170485767054129065010957133779253601843769235507134292078547927506898 - const GENERATOR: BigInteger = BigInt::<6>([ - 3002200076894543826u64, - 17005097747533029268u64, - 4390106630829661061u64, - 1520619128252124930u64, - 7439518447142769294u64, - 1078505433991964904u64, - ]); - - // (mod - 1) / 2 = 2972938801625915898129258746014768257744324656783561314223738312659881470290230659544087984224861686886607043528704 - const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<6>([ - 10393787953869588480u64, - 3624815648401613602u64, - 8373621135488820726u64, - 7602778866007726483u64, - 16761815040700647461u64, - 1391833729151901047u64, - ]); - - // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T - // S = 12 - - /// T = (MODULUS - 1) / 2^S = - /// 1451630274231404247133427122077523563351721023820098297960809722978457749165151689230511711047295745550101095473 - const T: BigInteger = BigInt::<6>([ - 7228848894076625969u64, - 13746755992250574892u64, - 3633989981855682676u64, - 336978666793584539u64, - 12609256237382989921u64, - 679606313062451u64, - ]); - - /// (T - 1) / 2 = - /// 72581513711570212356671356103876178167586051191004914898040486148922887458257584461525585552364787277505054773 - const T_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<6>([ - 3614424447038312984u64, - 6873377996125287446u64, - 11040367027782617146u64, - 9391861370251568077u64, - 15528000155546270768u64, - 339803156531225u64, - ]); -} +pub const FQ_ONE: Fq = MontFp!(Fq, "1"); +pub const FQ_ZERO: Fq = MontFp!(Fq, "0"); diff --git a/test-curves/src/bn384_small_two_adicity/fr.rs b/test-curves/src/bn384_small_two_adicity/fr.rs index 49f9dccfc..dca388ecc 100644 --- a/test-curves/src/bn384_small_two_adicity/fr.rs +++ b/test-curves/src/bn384_small_two_adicity/fr.rs @@ -1,139 +1,30 @@ use ark_ff::{ - biginteger::BigInt, biginteger::BigInteger384 as BigInteger, - fields::{FftParameters, Fp384, Fp384Parameters, FpParameters}, + fields::{Fp384, MontBackend}, + BigInt, }; -pub type Fr = Fp384; +pub struct FrConfig; +pub type Fr = Fp384>; -pub struct FrParameters; - -pub const FR_ONE: Fr = ark_ff::field_new!(Fr, "1"); - -impl Fp384Parameters for FrParameters {} -impl FftParameters for FrParameters { - type BigInt = BigInteger; +impl ark_ff::MontConfig<6> for FrConfig { + /// MODULUS = 5945877603251831796258517492029536515488649313567122628445038208291596545947608789992834434053176523624102324539393 + const MODULUS: BigInteger = BigInt!("5945877603251831796258517492029536515488649313567122628445038208291596545947608789992834434053176523624102324539393"); - const TWO_ADICITY: u32 = 12; + /// GENERATOR = 5 + const GENERATOR: Fr = ark_ff::MontFp!(Fr, "5"); - // TWO_ADIC_ROOT_OF_UNITY = GENERATOR ^ T = - // 1685271986666084262778868986067286870708440243287855288358961780551611799713704250599068248127477556627411635786779 - // t is defined below - // This number needs to be in the Montgomery residue form. - // I.e., write TWO_ADIC_ROOT_OF_UNITY * R - // = 1539563187696293616856158973955665088899482868488546332850378941921984564611273075190849188323241758701638100060070 - const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInt::<6>([ - 13480433396127238054u64, - 1703594782943735056u64, - 8417751128359587317u64, - 11248980344203883641u64, - 4705241879150942070u64, - 720773657239228462u64, - ]); + /// TWO_ADIC_ROOT_OF_UNITY = GENERATOR ^ T = + /// 1685271986666084262778868986067286870708440243287855288358961780551611799713704250599068248127477556627411635786779 + const TWO_ADIC_ROOT_OF_UNITY: Fr = ark_ff::MontFp!(Fr, "1685271986666084262778868986067286870708440243287855288358961780551611799713704250599068248127477556627411635786779"); const SMALL_SUBGROUP_BASE: Option = Some(3); const SMALL_SUBGROUP_BASE_ADICITY: Option = Some(2); - // LARGE_SUBGROUP_ROOT_OF_UNITY = GENERATOR ^ (T * 3 ^ 2) - // = 3524614118565436050820346784762407349815771892452866211429575895239855511309348587252928054123237406857164753350910 - // This number needs to be in the Montgomery residue form. - // I.e., write LARGE_SUBGROUP_ROOT_OF_UNITY * R - // = 2243640460791708394678669425369274565832631199871689254948845545672204516674256702673568780556211844984291473787379 - const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(BigInt::<6>([ - 16448235414327691763u64, - 6101416213029103415u64, - 1714659905601749299u64, - 18157817127906248745u64, - 7986749858655934624u64, - 1050399849371924948u64, - ])); + // LARGE_SUBGROUP_ROOT_OF_UNITY = GENERATOR ^ (t * 3 ^ 2) = + // 4782263695849493583247475447966822177504391850435302761245199662598017278280257369536403760936410198993405011225872 + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(ark_ff::MontFp!(Fr, "4782263695849493583247475447966822177504391850435302761245199662598017278280257369536403760936410198993405011225872")); } -impl FpParameters for FrParameters { - /// MODULUS = 5945877603251831796258517492029536515488649313567122628445038208291596545947608789992834434053176523624102324539393 - const MODULUS: BigInteger = BigInt::<6>([ - 17382266338285916161u64, - 13339389119208890949u64, - 9581378667081472421u64, - 15205557732015452966u64, - 15076886007691743306u64, - 2783667458303802095u64, - ]); - - const MODULUS_BITS: u32 = 382; - - const CAPACITY: u32 = Self::MODULUS_BITS - 1; - - const REPR_SHAVE_BITS: u32 = 2; - - // R = 2^{384} % MODULUS - // 3726740576883488434727935147966394712147843389062710897278064154496142495811557871457259650565856499062014043070458 - const R: BigInteger = BigInt::<6>([ - 6386866412541812730u64, - 12197385653294412380u64, - 16298704292349371933u64, - 1000373976455040280u64, - 1772404322397298239u64, - 1744739323886739041u64, - ]); - // R2 = R * R % MODULUS - // 743374565348571412572717835265798450620415736052604204514879248137607002524418551738269123252154404143816216787227 - const R2: BigInteger = BigInt::<6>([ - 7278302575398336795u64, - 13899913090107078051u64, - 14214418478611586731u64, - 17879031161354349451u64, - 934436771375522906u64, - 348023912527199718u64, - ]); - - // INV = -(MODULUS)^{-1} mod 2^64 - const INV: u64 = 5652841145273880575; - - // GENERATOR = 5 - // This number needs to be in the Montgomery residue form. - // Here, write 5 * R = 796070074661946784864123263743364014273269004612186601055206147605922841214962987307794950669752924437763241734111 - const GENERATOR: BigInteger = BigInt::<6>([ - 16681021195270418399u64, - 2522016835135837435u64, - 15855897313083339171u64, - 14725428907357497352u64, - 524851736330364506u64, - 372694244522288918u64, - ]); - - // (mod - 1) / 2 = 2972938801625915898129258746014768257744324656783561314222519104145798272973804394996417217026588261812051162269696 - const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<6>([ - 17914505205997733888u64, - 15893066596459221282u64, - 4790689333540736210u64, - 7602778866007726483u64, - 16761815040700647461u64, - 1391833729151901047u64, - ]); - - // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T - // S = 12 - - /// T = (MODULUS - 1) / 2^S = - /// 1451630274231404247133427122077523563351721023820098297960214406321190562975490427244344344251263799712915606577 - const T: BigInteger = BigInt::<6>([ - 2620835100870003761u64, - 11122644166774436482u64, - 3632240503436762713u64, - 336978666793584539u64, - 12609256237382989921u64, - 679606313062451u64, - ]); - - /// (T - 1) / 2 = - /// 725815137115702123566713561038761781675860511910049148980107203160595281487745213622172172125631899856457803288 - const T_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<6>([ - 1310417550435001880u64, - 14784694120241994049u64, - 11039492288573157164u64, - 9391861370251568077u64, - 15528000155546270768u64, - 339803156531225u64, - ]); -} +pub const FR_ONE: Fr = ark_ff::MontFp!(Fr, "1"); +pub const FR_ZERO: Fr = ark_ff::MontFp!(Fr, "0"); diff --git a/test-curves/src/bn384_small_two_adicity/g1.rs b/test-curves/src/bn384_small_two_adicity/g1.rs index 63cd98996..5704db7d2 100644 --- a/test-curves/src/bn384_small_two_adicity/g1.rs +++ b/test-curves/src/bn384_small_two_adicity/g1.rs @@ -2,7 +2,7 @@ use ark_ec::{ models::{ModelParameters, SWModelParameters}, short_weierstrass_jacobian::*, }; -use ark_ff::{field_new, Zero}; +use ark_ff::Zero; use crate::bn384_small_two_adicity::{Fq, Fr, FR_ONE}; @@ -25,10 +25,10 @@ impl ModelParameters for Parameters { impl SWModelParameters for Parameters { /// COEFF_A = 0 - const COEFF_A: Fq = field_new!(Fq, "0"); + const COEFF_A: Fq = ark_ff::MontFp!(Fq, "0"); /// COEFF_B = 17 - const COEFF_B: Fq = field_new!(Fq, "17"); + const COEFF_B: Fq = ark_ff::MontFp!(Fq, "17"); /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = @@ -41,7 +41,7 @@ impl SWModelParameters for Parameters { } /// G1_GENERATOR_X = -1 -pub const G1_GENERATOR_X: Fq = field_new!(Fq, "-1"); +pub const G1_GENERATOR_X: Fq = ark_ff::MontFp!(Fq, "-1"); /// G1_GENERATOR_Y = 4 -pub const G1_GENERATOR_Y: Fq = field_new!(Fq, "4"); +pub const G1_GENERATOR_Y: Fq = ark_ff::MontFp!(Fq, "4"); diff --git a/test-curves/src/bn384_small_two_adicity/tests.rs b/test-curves/src/bn384_small_two_adicity/tests.rs index 32c6438bd..661857977 100644 --- a/test-curves/src/bn384_small_two_adicity/tests.rs +++ b/test-curves/src/bn384_small_two_adicity/tests.rs @@ -3,12 +3,12 @@ use ark_ec::{models::SWModelParameters, AffineCurve, PairingEngine, ProjectiveCu use ark_ff::{Field, One, SquareRootField, UniformRand, Zero}; use ark_std::{rand::Rng, test_rng}; -use crate::bn384_small_two_adicity::{g1, Fq, FqParameters, Fr, G1Affine, G1Projective}; +use crate::bn384_small_two_adicity::{g1, Fq, FqConfig, Fr, FrConfig, G1Affine, G1Projective}; use ark_algebra_test_templates::{ curves::*, fields::*, generate_field_test, generate_g1_test, groups::*, msm::*, }; use ark_std::ops::{AddAssign, MulAssign, SubAssign}; -generate_field_test!(bn384_small_two_adicity;); +generate_field_test!(bn384_small_two_adicity; mont(6, 6);); generate_g1_test!(bn384_small_two_adicity; curve_tests; sw_tests;); diff --git a/test-curves/src/mnt4_753/fq.rs b/test-curves/src/mnt4_753/fq.rs index 27556c0d6..05e659ba1 100644 --- a/test-curves/src/mnt4_753/fq.rs +++ b/test-curves/src/mnt4_753/fq.rs @@ -1,171 +1,22 @@ use ark_ff::{ - biginteger::BigInt, biginteger::BigInteger768 as BigInteger, - fields::{FftParameters, Fp768, Fp768Parameters, FpParameters}, + fields::{Fp768, MontBackend, MontConfig}, + BigInt, }; -pub type Fq = Fp768; +pub type Fq = Fp768>; +pub struct FqConfig; -pub struct FqParameters; - -impl Fp768Parameters for FqParameters {} -impl FftParameters for FqParameters { - type BigInt = BigInteger; +impl MontConfig<12> for FqConfig { + /// MODULUS = 41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888253786114353726529584385201591605722013126468931404347949840543007986327743462853720628051692141265303114721689601 + const MODULUS: BigInteger = BigInt!("41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888253786114353726529584385201591605722013126468931404347949840543007986327743462853720628051692141265303114721689601"); - const TWO_ADICITY: u32 = 15; + const GENERATOR: Fq = ark_ff::MontFp!(Fq, "17"); - const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInt::<12>([ - 0x3b079c7556ac378, - 0x2c8c74d04a3f00d4, - 0xd3b001061b90d4cf, - 0x946e77514891b0e6, - 0x79caec8ad6dc9ea1, - 0xbefd780edc81435d, - 0xe093d4dca630b154, - 0x43a0f673199f1c12, - 0x92276c78436253ff, - 0xe249d1cf014fcd24, - 0x96f36471fb7c3ec5, - 0x1080b8906b7c4, - ]); + const TWO_ADIC_ROOT_OF_UNITY: Fq = ark_ff::MontFp!(Fq, "40577822398412982719876671814347622311725878559400100565221223860226396934830112376659822430317692232440883010225033880793828874730711721234325694240460855741763791540474706150170374090550695427806583236301930157866709353840964"); const SMALL_SUBGROUP_BASE: Option = Some(5); const SMALL_SUBGROUP_BASE_ADICITY: Option = Some(2); - /// LARGE_SUBGROUP_ROOT_OF_UNITY = - /// 12249458902762217747626832919710926618510011455364963726393752854649914979954138109976331601455448780251166045203053508523342111624583986869301658366625356826888785691823710598470775453742133593634524619429629803955083254436531 - const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(BigInt::<12>([ - 8926681816978929800, - 10873079436792120119, - 6519893728366769435, - 7899277225737766970, - 8416573500933450083, - 12951641800297678468, - 7093775028595490583, - 14327009285082556021, - 18228411097456927576, - 2823658094446565457, - 1708328092507553067, - 109589007594791, - ])); -} -impl FpParameters for FqParameters { - /// MODULUS = 41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888253786114353726529584385201591605722013126468931404347949840543007986327743462853720628051692141265303114721689601 - const MODULUS: BigInteger = BigInt::<12>([ - 0x5e9063de245e8001, - 0xe39d54522cdd119f, - 0x638810719ac425f0, - 0x685acce9767254a4, - 0xb80f0da5cb537e38, - 0xb117e776f218059d, - 0x99d124d9a15af79d, - 0x7fdb925e8a0ed8d, - 0x5eb7e8f96c97d873, - 0xb7f997505b8fafed, - 0x10229022eee2cdad, - 0x1c4c62d92c411, - ]); - - const MODULUS_BITS: u32 = 753; - - const CAPACITY: u32 = Self::MODULUS_BITS - 1; - - const REPR_SHAVE_BITS: u32 = 15; - - const R: BigInteger = BigInt::<12>([ - 0x98a8ecabd9dc6f42, - 0x91cd31c65a034686, - 0x97c3e4a0cd14572e, - 0x79589819c788b601, - 0xed269c942108976f, - 0x1e0f4d8acf031d68, - 0x320c3bb713338559, - 0x598b4302d2f00a62, - 0x4074c9cbfd8ca621, - 0xfa47edb3865e88c, - 0x95455fb31ff9a195, - 0x7b479ec8e242, - ]); - - const R2: BigInteger = BigInt::<12>([ - 0x84717088cfd190c8, - 0xc7d9ff8e7df03c0a, - 0xa24bea56242b3507, - 0xa896a656a0714c7d, - 0x80a46659ff6f3ddf, - 0x2f47839ef88d7ce8, - 0xa8c86d4604a3b597, - 0xe03c79cac4f7ef07, - 0x2505daf1f4a81245, - 0x8e4605754c381723, - 0xb081f15bcbfdacaf, - 0x2a33e89cb485, - ]); - - const INV: u64 = 0xf2044cfbe45e7fff; - - const GENERATOR: BigInteger = BigInt::<12>([ - 0xa8f627f0e629635e, - 0x202afce346c36872, - 0x85e1ece733493254, - 0x6d76e610664ac389, - 0xdf542f3f04441585, - 0x3aa4885bf6d4dd80, - 0xeb8b63c1c0fffc74, - 0xd2488e985f6cfa4e, - 0xcce1c2a623f7a66a, - 0x2a060f4d5085b19a, - 0xa9111a596408842f, - 0x11ca8d50bf627, - ]); - - const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<12>([ - 0xaf4831ef122f4000, - 0x71ceaa29166e88cf, - 0x31c40838cd6212f8, - 0x342d6674bb392a52, - 0xdc0786d2e5a9bf1c, - 0xd88bf3bb790c02ce, - 0xcce8926cd0ad7bce, - 0x83fedc92f45076c6, - 0xaf5bf47cb64bec39, - 0xdbfccba82dc7d7f6, - 0x88114811777166d6, - 0xe26316c96208, - ]); - - // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T - - /// T = (MODULUS - 1) / 2^S = - /// 1278640471433073529124274133033466709233725278318907137200424283478556909563327233064541435662546964154604216671394463687571830033251476599169665701965732619291119517454523942352538645255842982596454713491581459512424155325 - const T: BigInteger = BigInt::<12>([ - 0x233ebd20c7bc48bd, - 0x4be1c73aa8a459ba, - 0xa948c71020e33588, - 0xfc70d0b599d2ece4, - 0xb3b701e1b4b96a6, - 0xef3b622fceede430, - 0xdb1b33a249b342b5, - 0xb0e60ffb724bd141, - 0x5fdabd6fd1f2d92f, - 0x9b5b6ff32ea0b71f, - 0x882220452045ddc5, - 0x3898c5b25, - ]); - /// (T - 1) / 2 = - /// 639320235716536764562137066516733354616862639159453568600212141739278454781663616532270717831273482077302108335697231843785915016625738299584832850982866309645559758727261971176269322627921491298227356745790729756212077662 - const T_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<12>([ - 0x119f5e9063de245e, - 0x25f0e39d54522cdd, - 0x54a4638810719ac4, - 0x7e38685acce97672, - 0x59db80f0da5cb53, - 0xf79db117e776f218, - 0xed8d99d124d9a15a, - 0xd87307fdb925e8a0, - 0xafed5eb7e8f96c97, - 0xcdadb7f997505b8f, - 0xc41110229022eee2, - 0x1c4c62d92, - ]); + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(ark_ff::MontFp!(Fq, "12249458902762217747626832919710926618510011455364963726393752854649914979954138109976331601455448780251166045203053508523342111624583986869301658366625356826888785691823710598470775453742133593634524619429629803955083254436531")); } diff --git a/test-curves/src/mnt4_753/fr.rs b/test-curves/src/mnt4_753/fr.rs index e5f7495e5..664658a17 100644 --- a/test-curves/src/mnt4_753/fr.rs +++ b/test-curves/src/mnt4_753/fr.rs @@ -1,154 +1,24 @@ use ark_ff::{ - biginteger::BigInt, biginteger::BigInteger768 as BigInteger, - fields::{FftParameters, Fp768, Fp768Parameters, FpParameters}, + fields::{Fp768, MontBackend}, + BigInt, }; -pub type Fr = Fp768; +pub type Fr = Fp768>; +pub struct FrConfig; -pub struct FrParameters; - -pub const FR_ONE: Fr = ark_ff::field_new!(Fr, "1"); - -impl Fp768Parameters for FrParameters {} -impl FftParameters for FrParameters { - type BigInt = BigInteger; - - const TWO_ADICITY: u32 = 30; - - const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInt::<12>([ - 0x307f66b297671883, - 0xd72a7f2b1e645f4e, - 0x67079daa9a902283, - 0xf33f7620a86c668b, - 0x8878570d66464c12, - 0xa557af5b524f522b, - 0x5fafa3f6ef19319d, - 0x1eb9e04110a65629, - 0x3f96feb3c639a0b0, - 0x4d4fe37df3ffd732, - 0xadc831bd55bcf3e9, - 0x1b9f32a8bd6ab, - ]); -} -impl FpParameters for FrParameters { +impl ark_ff::MontConfig<12> for FrConfig { /// MODULUS = 41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888458477323173057491593855069696241854796396165721416325350064441470418137846398469611935719059908164220784476160001 - const MODULUS: BigInteger = BigInt::<12>([ - 0xd90776e240000001, - 0x4ea099170fa13a4f, - 0xd6c381bc3f005797, - 0xb9dff97634993aa4, - 0x3eebca9429212636, - 0xb26c5c28c859a99b, - 0x99d124d9a15af79d, - 0x7fdb925e8a0ed8d, - 0x5eb7e8f96c97d873, - 0xb7f997505b8fafed, - 0x10229022eee2cdad, - 0x1c4c62d92c411, - ]); - - const MODULUS_BITS: u32 = 753; - - const CAPACITY: u32 = Self::MODULUS_BITS - 1; + const MODULUS: BigInteger = BigInt!("41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888458477323173057491593855069696241854796396165721416325350064441470418137846398469611935719059908164220784476160001"); - const REPR_SHAVE_BITS: u32 = 15; + const GENERATOR: Fr = ark_ff::MontFp!(Fr, "17"); - const R: BigInteger = BigInt::<12>([ - 0xb99680147fff6f42, - 0x4eb16817b589cea8, - 0xa1ebd2d90c79e179, - 0xf725caec549c0da, - 0xab0c4ee6d3e6dad4, - 0x9fbca908de0ccb62, - 0x320c3bb713338498, - 0x598b4302d2f00a62, - 0x4074c9cbfd8ca621, - 0xfa47edb3865e88c, - 0x95455fb31ff9a195, - 0x7b479ec8e242, - ]); + const TWO_ADIC_ROOT_OF_UNITY: Fr = ark_ff::MontFp!(Fr, "40577822398412982719876671814347622311725878559400100565221223860226396934830112376659822430317692232440883010225033880793828874730711721234325694240460855741763791540474706150170374090550695427806583236301930157866709353840964"); - const R2: BigInteger = BigInt::<12>([ - 0x3f9c69c7b7f4c8d1, - 0x70a50fa9ee48d127, - 0xcdbe6702009569cb, - 0x6bd8c6c6c49edc38, - 0x7955876cc35ee94e, - 0xc7285529be54a3f4, - 0xded52121ecec77cf, - 0x99be80f2ee12ee8e, - 0xc8a0ff01493bdcef, - 0xacc27988f3d9a316, - 0xd9e817a8fb44b3c9, - 0x5b58037e0e4, - ]); + const SMALL_SUBGROUP_BASE: Option = Some(5); + const SMALL_SUBGROUP_BASE_ADICITY: Option = Some(2); - const INV: u64 = 0xc90776e23fffffff; - - const GENERATOR: BigInteger = BigInt::<12>([ - 0xeee0a5d37ff6635e, - 0xff458536cfa1cff4, - 0x659af978d8169ab0, - 0x1f1841c24780e3f1, - 0x602213036dcfef3a, - 0xd1d5c8f39d72db20, - 0xeb8b63c1c0ffefab, - 0xd2488e985f6cfa4e, - 0xcce1c2a623f7a66a, - 0x2a060f4d5085b19a, - 0xa9111a596408842f, - 0x11ca8d50bf627, - ]); - - const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<12>([ - 0xec83bb7120000000, - 0xa7504c8b87d09d27, - 0x6b61c0de1f802bcb, - 0x5ceffcbb1a4c9d52, - 0x9f75e54a1490931b, - 0xd9362e14642cd4cd, - 0xcce8926cd0ad7bce, - 0x83fedc92f45076c6, - 0xaf5bf47cb64bec39, - 0xdbfccba82dc7d7f6, - 0x88114811777166d6, - 0xe26316c96208, - ]); - - // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T - - /// T = (MODULUS - 1) / 2^S = - /// 39021010480745652133919498688765463538626870065884617224134041854204007249857398469987226430131438115069708760723898631821547688442835449306011425196003537779414482717728302293895201885929702287178426719326440397855625 - const T: BigInteger = BigInt::<12>([ - 0x3e84e93f641ddb89, - 0xfc015e5d3a82645c, - 0xd264ea935b0e06f0, - 0xa48498dae77fe5d8, - 0x2166a66cfbaf2a50, - 0x856bde76c9b170a3, - 0xa283b63667449366, - 0xb25f61cc1ff6e497, - 0x6e3ebfb57adfa3e5, - 0xbb8b36b6dfe65d41, - 0xb64b1044408a408b, - 0x71318, - ]); - - /// (T - 1) / 2 = - /// 19510505240372826066959749344382731769313435032942308612067020927102003624928699234993613215065719057534854380361949315910773844221417724653005712598001768889707241358864151146947600942964851143589213359663220198927812 - const T_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<12>([ - 0x1f42749fb20eedc4, - 0x7e00af2e9d41322e, - 0x69327549ad870378, - 0x52424c6d73bff2ec, - 0x90b353367dd79528, - 0x42b5ef3b64d8b851, - 0xd141db1b33a249b3, - 0xd92fb0e60ffb724b, - 0xb71f5fdabd6fd1f2, - 0xddc59b5b6ff32ea0, - 0x5b25882220452045, - 0x3898c, - ]); + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(ark_ff::MontFp!(Fr, "12249458902762217747626832919710926618510011455364963726393752854649914979954138109976331601455448780251166045203053508523342111624583986869301658366625356826888785691823710598470775453742133593634524619429629803955083254436531")); } + +pub const FR_ONE: Fr = ark_ff::MontFp!(Fr, "1"); diff --git a/test-curves/src/mnt4_753/g1.rs b/test-curves/src/mnt4_753/g1.rs index f8fe38621..0af29920d 100644 --- a/test-curves/src/mnt4_753/g1.rs +++ b/test-curves/src/mnt4_753/g1.rs @@ -2,7 +2,7 @@ use ark_ec::{ models::{ModelParameters, SWModelParameters}, short_weierstrass_jacobian::*, }; -use ark_ff::field_new; +use ark_ff::MontFp; use crate::mnt4_753::{Fq, Fr, FR_ONE}; @@ -27,12 +27,12 @@ impl ModelParameters for Parameters { impl SWModelParameters for Parameters { /// COEFF_A = 2 #[rustfmt::skip] - const COEFF_A: Fq = field_new!(Fq, "2"); + const COEFF_A: Fq = MontFp!(Fq, "2"); /// COEFF_B = 0x01373684A8C9DCAE7A016AC5D7748D3313CD8E39051C596560835DF0C9E50A5B59B882A92C78DC537E51A16703EC9855C77FC3D8BB21C8D68BB8CFB9DB4B8C8FBA773111C36C8B1B4E8F1ECE940EF9EAAD265458E06372009C9A0491678EF4 /// = 28798803903456388891410036793299405764940372360099938340752576406393880372126970068421383312482853541572780087363938442377933706865252053507077543420534380486492786626556269083255657125025963825610840222568694137138741554679540 #[rustfmt::skip] - const COEFF_B: Fq = field_new!(Fq, "28798803903456388891410036793299405764940372360099938340752576406393880372126970068421383312482853541572780087363938442377933706865252053507077543420534380486492786626556269083255657125025963825610840222568694137138741554679540"); + const COEFF_B: Fq = MontFp!(Fq, "28798803903456388891410036793299405764940372360099938340752576406393880372126970068421383312482853541572780087363938442377933706865252053507077543420534380486492786626556269083255657125025963825610840222568694137138741554679540"); /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = @@ -44,8 +44,8 @@ impl SWModelParameters for Parameters { // Y = 6913648190367314284606685101150155872986263667483624713540251048208073654617802840433842931301128643140890502238233930290161632176167186761333725658542781350626799660920481723757654531036893265359076440986158843531053720994648, /// G1_GENERATOR_X = #[rustfmt::skip] -pub const G1_GENERATOR_X: Fq = field_new!(Fq, "7790163481385331313124631546957228376128961350185262705123068027727518350362064426002432450801002268747950550964579198552865939244360469674540925037890082678099826733417900510086646711680891516503232107232083181010099241949569"); +pub const G1_GENERATOR_X: Fq = MontFp!(Fq, "7790163481385331313124631546957228376128961350185262705123068027727518350362064426002432450801002268747950550964579198552865939244360469674540925037890082678099826733417900510086646711680891516503232107232083181010099241949569"); /// G1_GENERATOR_Y = #[rustfmt::skip] -pub const G1_GENERATOR_Y: Fq = field_new!(Fq, "6913648190367314284606685101150155872986263667483624713540251048208073654617802840433842931301128643140890502238233930290161632176167186761333725658542781350626799660920481723757654531036893265359076440986158843531053720994648"); +pub const G1_GENERATOR_Y: Fq = MontFp!(Fq, "6913648190367314284606685101150155872986263667483624713540251048208073654617802840433842931301128643140890502238233930290161632176167186761333725658542781350626799660920481723757654531036893265359076440986158843531053720994648"); diff --git a/test-curves/src/mnt6_753/fq.rs b/test-curves/src/mnt6_753/fq.rs index 6a78ced45..d623da5f7 100644 --- a/test-curves/src/mnt6_753/fq.rs +++ b/test-curves/src/mnt6_753/fq.rs @@ -1 +1 @@ -pub use crate::mnt4_753::{Fr as Fq, FrParameters as FqParameters}; +pub use crate::mnt4_753::{Fr as Fq, FrConfig as FqConfig}; diff --git a/test-curves/src/mnt6_753/fq3.rs b/test-curves/src/mnt6_753/fq3.rs index f432c9aac..ce314a591 100644 --- a/test-curves/src/mnt6_753/fq3.rs +++ b/test-curves/src/mnt6_753/fq3.rs @@ -1,23 +1,23 @@ use crate::mnt6_753::fq::Fq; use ark_ff::{ - field_new, - fields::fp3::{Fp3, Fp3Parameters}, + fields::fp3::{Fp3, Fp3Config}, + CubicExt, MontFp, }; -pub type Fq3 = Fp3; +pub type Fq3 = Fp3; -pub struct Fq3Parameters; +pub struct Fq3Config; -impl Fp3Parameters for Fq3Parameters { +impl Fp3Config for Fq3Config { type Fp = Fq; #[rustfmt::skip] - const NONRESIDUE: Fq = field_new!(Fq, "11"); + const NONRESIDUE: Fq = MontFp!(Fq, "11"); const TWO_ADICITY: u32 = 30; #[rustfmt::skip] - const T_MINUS_ONE_DIV_TWO: &'static [u64] = &[ + const TRACE_MINUS_ONE_DIV_TWO: &'static [u64] = &[ 15439605736802142541, 18190868848461853149, 6220121510046940818, @@ -57,8 +57,8 @@ impl Fp3Parameters for Fq3Parameters { /// (11^T, 0, 0) #[rustfmt::skip] - const QUADRATIC_NONRESIDUE_TO_T: (Fq, Fq, Fq) = ( - field_new!(Fq, "22168644070733283197994897338612733221095941481265408161807376791727499343083607817089033595478370212662133368413166734396127674284827734481031659015434501966360165723728649019457855887066657739809176476252080335185730833468062"), + const QUADRATIC_NONRESIDUE_TO_T: Fq3 = CubicExt!( + MontFp!(Fq, "22168644070733283197994897338612733221095941481265408161807376791727499343083607817089033595478370212662133368413166734396127674284827734481031659015434501966360165723728649019457855887066657739809176476252080335185730833468062"), FQ_ZERO, FQ_ZERO, ); @@ -70,8 +70,8 @@ impl Fp3Parameters for Fq3Parameters { #[rustfmt::skip] const FROBENIUS_COEFF_FP3_C1: &'static [Fq] = &[ FQ_ONE, - field_new!(Fq, "24129022407817241407134263419936114379815707076943508280977368156625538709102831814843582780138963119807143081677569721953561801075623741378629346409604471234573396989178424163772589090105392407118197799904755622897541183052132"), - field_new!(Fq, "17769468560101711995209951371304522748355002843010440790806134764399814103468274958215310983651375801610927890210888755369611256415970113691066895445191924931148019336171640277697829047741006062493737919155152541323243293107868"), + MontFp!(Fq, "24129022407817241407134263419936114379815707076943508280977368156625538709102831814843582780138963119807143081677569721953561801075623741378629346409604471234573396989178424163772589090105392407118197799904755622897541183052132"), + MontFp!(Fq, "17769468560101711995209951371304522748355002843010440790806134764399814103468274958215310983651375801610927890210888755369611256415970113691066895445191924931148019336171640277697829047741006062493737919155152541323243293107868"), ]; // c2 = {c1[0], c1[2], c1[1]} @@ -83,5 +83,5 @@ impl Fp3Parameters for Fq3Parameters { ]; } -pub const FQ_ZERO: Fq = field_new!(Fq, "0"); -pub const FQ_ONE: Fq = field_new!(Fq, "1"); +pub const FQ_ZERO: Fq = MontFp!(Fq, "0"); +pub const FQ_ONE: Fq = MontFp!(Fq, "1"); diff --git a/test-curves/src/mnt6_753/fr.rs b/test-curves/src/mnt6_753/fr.rs index fd483571c..e1476ae75 100644 --- a/test-curves/src/mnt6_753/fr.rs +++ b/test-curves/src/mnt6_753/fr.rs @@ -1 +1 @@ -pub use crate::mnt4_753::{Fq as Fr, FqParameters as FrParameters}; +pub use crate::mnt4_753::{Fq as Fr, FqConfig as FrConfig}; diff --git a/test-templates/Cargo.toml b/test-templates/Cargo.toml index d8927bfa6..58577765e 100644 --- a/test-templates/Cargo.toml +++ b/test-templates/Cargo.toml @@ -18,6 +18,8 @@ ark-std = { version = "^0.3.0", default-features = false } ark-serialize = { version = "^0.3.0", path = "../serialize", default-features = false } ark-ff = { version = "^0.3.0", path = "../ff", default-features = false } ark-ec = { version = "^0.3.0", path = "../ec", default-features = false } +num-bigint = { version = "0.4", default-features = false } +num-integer = { version = "0.1", default-features = false } [features] default = [] diff --git a/test-templates/src/curves.rs b/test-templates/src/curves.rs index 6e5a58980..e9b2fe2c8 100644 --- a/test-templates/src/curves.rs +++ b/test-templates/src/curves.rs @@ -125,8 +125,8 @@ fn random_multiplication_test() { tmp2.add_assign(&b); // Affine multiplication - let mut tmp3 = a_affine.mul(s.into_repr()); - tmp3.add_assign(&b_affine.mul(s.into_repr())); + let mut tmp3 = a_affine.mul(s.into_bigint()); + tmp3.add_assign(&b_affine.mul(s.into_bigint())); assert_eq!(tmp1, tmp2); assert_eq!(tmp1, tmp3); diff --git a/test-templates/src/fields.rs b/test-templates/src/fields.rs index be0003c28..5a5e9c947 100644 --- a/test-templates/src/fields.rs +++ b/test-templates/src/fields.rs @@ -1,6 +1,9 @@ #![allow(unused)] #![allow(clippy::eq_op)] -use ark_ff::fields::{FftField, FftParameters, Field, LegendreSymbol, PrimeField, SquareRootField}; +use ark_ff::{ + fields::{FftField, Field, LegendreSymbol, PrimeField, SquareRootField}, + Fp, MontBackend, MontConfig, +}; use ark_serialize::{buffer_bit_byte_size, Flags, SWFlags}; use ark_std::{io::Cursor, rand::Rng}; @@ -306,28 +309,28 @@ pub fn field_test(a: F, b: F) { pub fn fft_field_test() { assert_eq!( - F::two_adic_root_of_unity().pow([1 << F::FftParams::TWO_ADICITY]), + F::TWO_ADIC_ROOT_OF_UNITY.pow([1 << F::TWO_ADICITY]), F::one() ); - if let Some(small_subgroup_base) = F::FftParams::SMALL_SUBGROUP_BASE { - let small_subgroup_base_adicity = F::FftParams::SMALL_SUBGROUP_BASE_ADICITY.unwrap(); - let large_subgroup_root_of_unity = F::large_subgroup_root_of_unity().unwrap(); - let pow = (1 << F::FftParams::TWO_ADICITY) - * (small_subgroup_base as u64).pow(small_subgroup_base_adicity); + if let Some(small_subgroup_base) = F::SMALL_SUBGROUP_BASE { + let small_subgroup_base_adicity = F::SMALL_SUBGROUP_BASE_ADICITY.unwrap(); + let large_subgroup_root_of_unity = F::LARGE_SUBGROUP_ROOT_OF_UNITY.unwrap(); + let pow = + (1 << F::TWO_ADICITY) * (small_subgroup_base as u64).pow(small_subgroup_base_adicity); assert_eq!(large_subgroup_root_of_unity.pow([pow]), F::one()); - for i in 0..F::FftParams::TWO_ADICITY { + for i in 0..F::TWO_ADICITY { for j in 0..small_subgroup_base_adicity { use core::convert::TryFrom; let size = usize::try_from(1 << i as usize).unwrap() * usize::try_from((small_subgroup_base as u64).pow(j)).unwrap(); - let root = F::get_root_of_unity(size).unwrap(); + let root = F::get_root_of_unity(size as u64).unwrap(); assert_eq!(root.pow([size as u64]), F::one()); } } } else { - for i in 0..F::FftParams::TWO_ADICITY { + for i in 0..F::TWO_ADICITY { let size = 1 << i; let root = F::get_root_of_unity(size).unwrap(); assert_eq!(root.pow([size as u64]), F::one()); @@ -338,11 +341,50 @@ pub fn fft_field_test() { pub fn primefield_test() { from_str_test::(); let one = F::one(); - assert_eq!(F::from(one.into_repr()), one); + assert_eq!(F::from(one.into_bigint()), one); fft_field_test::(); } +pub fn montgomery_primefield_test, const N: usize>() { + use ark_ff::FpConfig; + use num_bigint::BigUint; + use num_integer::Integer; + let modulus: BigUint = T::MODULUS.into(); + let r = BigUint::from(2u8).modpow(&((N * 64) as u64).into(), &modulus); + let r2 = (&r * &r) % &modulus; + assert_eq!(r, T::R.into()); + assert_eq!(r2, T::R2.into()); + assert_eq!( + Fp::, N>::MODULUS_BIT_SIZE as u64, + modulus.bits() + ); + + let modulus_minus_one = &modulus - 1u8; + assert_eq!( + BigUint::from(Fp::, N>::MODULUS_MINUS_ONE_DIV_TWO), + &modulus_minus_one / 2u32 + ); + + let mut two_adicity = 0; + let mut trace = modulus_minus_one.clone(); + while trace.is_even() { + trace /= 2u8; + two_adicity += 1; + } + assert_eq!(two_adicity, MontBackend::::TWO_ADICITY); + assert_eq!(BigUint::from(Fp::, N>::TRACE), trace); + let trace_minus_one_div_two = (&trace - 1u8) / 2u8; + assert_eq!( + BigUint::from(Fp::, N>::TRACE_MINUS_ONE_DIV_TWO), + trace_minus_one_div_two + ); + + let two_adic_root_of_unity: BigUint = >::TWO_ADIC_ROOT_OF_UNITY.into(); + let generator: BigUint = >::GENERATOR.into_bigint().into(); + assert_eq!(two_adic_root_of_unity, generator.modpow(&trace, &modulus)); +} + pub fn sqrt_field_test(elem: F) { let square = elem.square(); let sqrt = square.sqrt().unwrap(); diff --git a/test-templates/src/lib.rs b/test-templates/src/lib.rs index 3fff305a5..f69987c78 100644 --- a/test-templates/src/lib.rs +++ b/test-templates/src/lib.rs @@ -533,6 +533,19 @@ macro_rules! generate_field_test { generate_field_test!($($tail)*); }; + (mont($fq_num_limbs:expr, $fr_num_limbs:expr); $($tail:tt)*) => { + #[test] + fn test_fq_mont() { + montgomery_primefield_test::(); + } + + #[test] + fn test_fr_mont() { + montgomery_primefield_test::(); + } + + generate_field_test!($($tail)*); + } } #[macro_export] diff --git a/test-templates/src/msm.rs b/test-templates/src/msm.rs index b6f08593f..f66ed6802 100644 --- a/test-templates/src/msm.rs +++ b/test-templates/src/msm.rs @@ -22,7 +22,7 @@ pub fn test_var_base_msm() { let mut rng = ark_std::test_rng(); let v = (0..SAMPLES - 1) - .map(|_| G::ScalarField::rand(&mut rng).into_repr()) + .map(|_| G::ScalarField::rand(&mut rng).into_bigint()) .collect::>(); let g = (0..SAMPLES) .map(|_| G::Projective::rand(&mut rng)) @@ -41,7 +41,7 @@ pub fn test_chunked_pippenger() { let mut rng = ark_std::test_rng(); let v = (0..SAMPLES) - .map(|_| G::ScalarField::rand(&mut rng).into_repr()) + .map(|_| G::ScalarField::rand(&mut rng).into_bigint()) .collect::>(); let g = (0..SAMPLES) .map(|_| G::Projective::rand(&mut rng))