From e6c3f354313b57e1b85e85d36635a49da235bc40 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 13 Dec 2021 14:35:05 +0100 Subject: [PATCH 1/5] working --- src/field/extension_field/quadratic.rs | 3 +-- src/field/extension_field/quartic.rs | 3 +-- src/field/field_types.rs | 26 ++++++++++++++++++-------- src/field/goldilocks_field.rs | 3 +-- src/field/packed_field.rs | 2 -- src/field/secp256k1_base.rs | 4 +--- src/field/secp256k1_scalar.rs | 4 +--- 7 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index b724095a..dfb861c2 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -50,8 +50,6 @@ impl> From for QuadraticExtension { } impl> Field for QuadraticExtension { - type PrimeField = F; - const ZERO: Self = Self([F::ZERO; 2]); const ONE: Self = Self([F::ONE, F::ZERO]); const TWO: Self = Self([F::TWO, F::ZERO]); @@ -63,6 +61,7 @@ impl> Field for QuadraticExtension { // long as `F::TWO_ADICITY >= 2`, `p` can be written as `4n + 1`, so `p + 1` can be written as // `2(2n + 1)`, which has a 2-adicity of 1. const TWO_ADICITY: usize = F::TWO_ADICITY + 1; + const CHARACTERISTIC_TWO_ADICITY: usize = F::CHARACTERISTIC_TWO_ADICITY; const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self(F::EXT_MULTIPLICATIVE_GROUP_GENERATOR); const POWER_OF_TWO_GENERATOR: Self = Self(F::EXT_POWER_OF_TWO_GENERATOR); diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 0d221401..1a34d40a 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -51,8 +51,6 @@ impl> From for QuarticExtension { } impl> Field for QuarticExtension { - type PrimeField = F; - const ZERO: Self = Self([F::ZERO; 4]); const ONE: Self = Self([F::ONE, F::ZERO, F::ZERO, F::ZERO]); const TWO: Self = Self([F::TWO, F::ZERO, F::ZERO, F::ZERO]); @@ -65,6 +63,7 @@ impl> Field for QuarticExtension { // `2(2n + 1)`, which has a 2-adicity of 1. A similar argument can show that `p^2 + 1` also has // a 2-adicity of 1. const TWO_ADICITY: usize = F::TWO_ADICITY + 2; + const CHARACTERISTIC_TWO_ADICITY: usize = F::CHARACTERISTIC_TWO_ADICITY; const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self(F::EXT_MULTIPLICATIVE_GROUP_GENERATOR); const POWER_OF_TWO_GENERATOR: Self = Self(F::EXT_POWER_OF_TWO_GENERATOR); diff --git a/src/field/field_types.rs b/src/field/field_types.rs index a3affc13..dec22c9d 100644 --- a/src/field/field_types.rs +++ b/src/field/field_types.rs @@ -42,8 +42,6 @@ pub trait Field: + Serialize + DeserializeOwned { - type PrimeField: PrimeField; - const ZERO: Self; const ONE: Self; const TWO: Self; @@ -54,6 +52,9 @@ pub trait Field: /// The 2-adicity of this field's multiplicative group. const TWO_ADICITY: usize; + /// The 2-adicity of this field's multiplicative group. + const CHARACTERISTIC_TWO_ADICITY: usize; + /// Generator of the entire multiplicative group, i.e. all non-zero elements. const MULTIPLICATIVE_GROUP_GENERATOR: Self; /// Generator of a multiplicative subgroup of order `2^TWO_ADICITY`. @@ -212,17 +213,17 @@ pub trait Field: // TWO_ADICITY. Can remove the branch and simplify if that // saving isn't worth it. - if exp > Self::PrimeField::TWO_ADICITY { + if exp > Self::CHARACTERISTIC_TWO_ADICITY { // NB: This should be a compile-time constant let inverse_2_pow_adicity: Self = - Self::from_canonical_u64(p - ((p - 1) >> Self::PrimeField::TWO_ADICITY)); + Self::from_canonical_u64(p - ((p - 1) >> Self::CHARACTERISTIC_TWO_ADICITY)); let mut res = inverse_2_pow_adicity; - let mut e = exp - Self::PrimeField::TWO_ADICITY; + let mut e = exp - Self::CHARACTERISTIC_TWO_ADICITY; - while e > Self::PrimeField::TWO_ADICITY { + while e > Self::CHARACTERISTIC_TWO_ADICITY { res *= inverse_2_pow_adicity; - e -= Self::PrimeField::TWO_ADICITY; + e -= Self::CHARACTERISTIC_TWO_ADICITY; } res * Self::from_canonical_u64(p - ((p - 1) >> e)) } else { @@ -404,7 +405,7 @@ pub trait Field: } /// A finite field of prime order less than 2^64. -pub trait PrimeField: Field { +pub trait PrimeField: Field { const ORDER: u64; /// The number of bits required to encode any field element. @@ -449,6 +450,15 @@ pub trait PrimeField: Field { } } +pub trait SmallCharacteristicField: Field { + const SMALLCHAR: u64; + + #[inline] + fn inverse_2exp(exp: usize) -> Self { + todo!() + } +} + /// An iterator over the powers of a certain base element `b`: `b^0, b^1, b^2, ...`. #[derive(Clone)] pub struct Powers { diff --git a/src/field/goldilocks_field.rs b/src/field/goldilocks_field.rs index 058b6db8..7bdd3c77 100644 --- a/src/field/goldilocks_field.rs +++ b/src/field/goldilocks_field.rs @@ -62,8 +62,6 @@ impl Debug for GoldilocksField { } impl Field for GoldilocksField { - type PrimeField = Self; - const ZERO: Self = Self(0); const ONE: Self = Self(1); const TWO: Self = Self(2); @@ -71,6 +69,7 @@ impl Field for GoldilocksField { const CHARACTERISTIC: u64 = Self::ORDER; const TWO_ADICITY: usize = 32; + const CHARACTERISTIC_TWO_ADICITY: usize = Self::TWO_ADICITY; // Sage: `g = GF(p).multiplicative_generator()` const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self(7); diff --git a/src/field/packed_field.rs b/src/field/packed_field.rs index f2b0c83e..00b99d6c 100644 --- a/src/field/packed_field.rs +++ b/src/field/packed_field.rs @@ -39,7 +39,6 @@ where Self::Scalar: Sub, { type Scalar: Field; - type PackedPrimeField: PackedField::PrimeField>; const WIDTH: usize; const ZERO: Self; @@ -102,7 +101,6 @@ where unsafe impl PackedField for F { type Scalar = Self; - type PackedPrimeField = F::PrimeField; const WIDTH: usize = 1; const ZERO: Self = ::ZERO; diff --git a/src/field/secp256k1_base.rs b/src/field/secp256k1_base.rs index b3fb0148..32615187 100644 --- a/src/field/secp256k1_base.rs +++ b/src/field/secp256k1_base.rs @@ -68,9 +68,6 @@ impl Debug for Secp256K1Base { } impl Field for Secp256K1Base { - // TODO: fix - type PrimeField = GoldilocksField; - const ZERO: Self = Self([0; 4]); const ONE: Self = Self([1, 0, 0, 0]); const TWO: Self = Self([2, 0, 0, 0]); @@ -84,6 +81,7 @@ impl Field for Secp256K1Base { // TODO: fix const CHARACTERISTIC: u64 = 0; const TWO_ADICITY: usize = 1; + const CHARACTERISTIC_TWO_ADICITY: usize = Self::TWO_ADICITY; // Sage: `g = GF(p).multiplicative_generator()` const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([5, 0, 0, 0]); diff --git a/src/field/secp256k1_scalar.rs b/src/field/secp256k1_scalar.rs index f4f2e6ab..44907b7a 100644 --- a/src/field/secp256k1_scalar.rs +++ b/src/field/secp256k1_scalar.rs @@ -71,9 +71,6 @@ impl Debug for Secp256K1Scalar { } impl Field for Secp256K1Scalar { - // TODO: fix - type PrimeField = GoldilocksField; - const ZERO: Self = Self([0; 4]); const ONE: Self = Self([1, 0, 0, 0]); const TWO: Self = Self([2, 0, 0, 0]); @@ -88,6 +85,7 @@ impl Field for Secp256K1Scalar { const CHARACTERISTIC: u64 = 0; const TWO_ADICITY: usize = 6; + const CHARACTERISTIC_TWO_ADICITY: usize = 6; // Sage: `g = GF(p).multiplicative_generator()` const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([7, 0, 0, 0]); From fb168b5d93fffd9514ca59f473a84d1537e829dc Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 13 Dec 2021 16:20:39 +0100 Subject: [PATCH 2/5] Replace characteristic with option --- src/field/extension_field/quadratic.rs | 5 +-- src/field/extension_field/quartic.rs | 5 +-- src/field/field_types.rs | 55 +++++++++++--------------- src/field/goldilocks_field.rs | 4 +- src/field/prime_field_testing.rs | 2 +- src/field/secp256k1_base.rs | 5 +-- src/field/secp256k1_scalar.rs | 6 +-- 7 files changed, 33 insertions(+), 49 deletions(-) diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index dfb861c2..16743f12 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -55,13 +55,12 @@ impl> Field for QuadraticExtension { const TWO: Self = Self([F::TWO, F::ZERO]); const NEG_ONE: Self = Self([F::NEG_ONE, F::ZERO]); - const CHARACTERISTIC: u64 = F::CHARACTERISTIC; - // `p^2 - 1 = (p - 1)(p + 1)`. The `p - 1` term has a two-adicity of `F::TWO_ADICITY`. As // long as `F::TWO_ADICITY >= 2`, `p` can be written as `4n + 1`, so `p + 1` can be written as // `2(2n + 1)`, which has a 2-adicity of 1. const TWO_ADICITY: usize = F::TWO_ADICITY + 1; - const CHARACTERISTIC_TWO_ADICITY: usize = F::CHARACTERISTIC_TWO_ADICITY; + const CHARACTERISTIC_WITH_TWO_ADICITY: Option<(u64, usize)> = + F::CHARACTERISTIC_WITH_TWO_ADICITY; const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self(F::EXT_MULTIPLICATIVE_GROUP_GENERATOR); const POWER_OF_TWO_GENERATOR: Self = Self(F::EXT_POWER_OF_TWO_GENERATOR); diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 1a34d40a..77329c94 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -56,14 +56,13 @@ impl> Field for QuarticExtension { const TWO: Self = Self([F::TWO, F::ZERO, F::ZERO, F::ZERO]); const NEG_ONE: Self = Self([F::NEG_ONE, F::ZERO, F::ZERO, F::ZERO]); - const CHARACTERISTIC: u64 = F::ORDER; - // `p^4 - 1 = (p - 1)(p + 1)(p^2 + 1)`. The `p - 1` term has a two-adicity of `F::TWO_ADICITY`. // As long as `F::TWO_ADICITY >= 2`, `p` can be written as `4n + 1`, so `p + 1` can be written as // `2(2n + 1)`, which has a 2-adicity of 1. A similar argument can show that `p^2 + 1` also has // a 2-adicity of 1. const TWO_ADICITY: usize = F::TWO_ADICITY + 2; - const CHARACTERISTIC_TWO_ADICITY: usize = F::CHARACTERISTIC_TWO_ADICITY; + const CHARACTERISTIC_WITH_TWO_ADICITY: Option<(u64, usize)> = + F::CHARACTERISTIC_WITH_TWO_ADICITY; const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self(F::EXT_MULTIPLICATIVE_GROUP_GENERATOR); const POWER_OF_TWO_GENERATOR: Self = Self(F::EXT_POWER_OF_TWO_GENERATOR); diff --git a/src/field/field_types.rs b/src/field/field_types.rs index dec22c9d..14426212 100644 --- a/src/field/field_types.rs +++ b/src/field/field_types.rs @@ -47,13 +47,12 @@ pub trait Field: const TWO: Self; const NEG_ONE: Self; - const CHARACTERISTIC: u64; - /// The 2-adicity of this field's multiplicative group. const TWO_ADICITY: usize; - /// The 2-adicity of this field's multiplicative group. - const CHARACTERISTIC_TWO_ADICITY: usize; + /// The field's characteristic and it's 2-adicity. + /// Set to `None` when the characteristic doesn't fit in a u64. + const CHARACTERISTIC_WITH_TWO_ADICITY: Option<(u64, usize)>; /// Generator of the entire multiplicative group, i.e. all non-zero elements. const MULTIPLICATIVE_GROUP_GENERATOR: Self; @@ -205,29 +204,32 @@ pub trait Field: // exp exceeds t, we repeatedly multiply by 2^-t and reduce // exp until it's in the right range. - let p = Self::CHARACTERISTIC; + if let Some((p, two_adicity)) = Self::CHARACTERISTIC_WITH_TWO_ADICITY { + // NB: The only reason this is split into two cases is to save + // the multiplication (and possible calculation of + // inverse_2_pow_adicity) in the usual case that exp <= + // TWO_ADICITY. Can remove the branch and simplify if that + // saving isn't worth it. - // NB: The only reason this is split into two cases is to save - // the multiplication (and possible calculation of - // inverse_2_pow_adicity) in the usual case that exp <= - // TWO_ADICITY. Can remove the branch and simplify if that - // saving isn't worth it. + if exp > two_adicity { + // NB: This should be a compile-time constant + let inverse_2_pow_adicity: Self = + Self::from_canonical_u64(p - ((p - 1) >> two_adicity)); - if exp > Self::CHARACTERISTIC_TWO_ADICITY { - // NB: This should be a compile-time constant - let inverse_2_pow_adicity: Self = - Self::from_canonical_u64(p - ((p - 1) >> Self::CHARACTERISTIC_TWO_ADICITY)); + let mut res = inverse_2_pow_adicity; + let mut e = exp - two_adicity; - let mut res = inverse_2_pow_adicity; - let mut e = exp - Self::CHARACTERISTIC_TWO_ADICITY; - - while e > Self::CHARACTERISTIC_TWO_ADICITY { - res *= inverse_2_pow_adicity; - e -= Self::CHARACTERISTIC_TWO_ADICITY; + while e > two_adicity { + res *= inverse_2_pow_adicity; + e -= two_adicity; + } + res * Self::from_canonical_u64(p - ((p - 1) >> e)) + } else { + Self::from_canonical_u64(p - ((p - 1) >> exp)) } - res * Self::from_canonical_u64(p - ((p - 1) >> e)) } else { - Self::from_canonical_u64(p - ((p - 1) >> exp)) + dbg!("yo"); + Self::TWO.inverse().exp_u64(exp as u64) } } @@ -450,15 +452,6 @@ pub trait PrimeField: Field { } } -pub trait SmallCharacteristicField: Field { - const SMALLCHAR: u64; - - #[inline] - fn inverse_2exp(exp: usize) -> Self { - todo!() - } -} - /// An iterator over the powers of a certain base element `b`: `b^0, b^1, b^2, ...`. #[derive(Clone)] pub struct Powers { diff --git a/src/field/goldilocks_field.rs b/src/field/goldilocks_field.rs index 7bdd3c77..14c0a281 100644 --- a/src/field/goldilocks_field.rs +++ b/src/field/goldilocks_field.rs @@ -66,10 +66,10 @@ impl Field for GoldilocksField { const ONE: Self = Self(1); const TWO: Self = Self(2); const NEG_ONE: Self = Self(Self::ORDER - 1); - const CHARACTERISTIC: u64 = Self::ORDER; const TWO_ADICITY: usize = 32; - const CHARACTERISTIC_TWO_ADICITY: usize = Self::TWO_ADICITY; + const CHARACTERISTIC_WITH_TWO_ADICITY: Option<(u64, usize)> = + Some((Self::ORDER, Self::TWO_ADICITY)); // Sage: `g = GF(p).multiplicative_generator()` const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self(7); diff --git a/src/field/prime_field_testing.rs b/src/field/prime_field_testing.rs index 9dae4896..1b7b97eb 100644 --- a/src/field/prime_field_testing.rs +++ b/src/field/prime_field_testing.rs @@ -144,7 +144,7 @@ macro_rules! test_prime_field_arithmetic { fn inverse_2exp() { type F = $field; - let v = ::PrimeField::TWO_ADICITY; + let v = ::TWO_ADICITY; for e in [0, 1, 2, 3, 4, v - 2, v - 1, v, v + 1, v + 2, 123 * v] { let x = F::TWO.exp_u64(e as u64); diff --git a/src/field/secp256k1_base.rs b/src/field/secp256k1_base.rs index 32615187..3e0d0ef0 100644 --- a/src/field/secp256k1_base.rs +++ b/src/field/secp256k1_base.rs @@ -11,7 +11,6 @@ use rand::Rng; use serde::{Deserialize, Serialize}; use crate::field::field_types::Field; -use crate::field::goldilocks_field::GoldilocksField; /// The base field of the secp256k1 elliptic curve. /// @@ -78,10 +77,8 @@ impl Field for Secp256K1Base { 0xFFFFFFFFFFFFFFFF, ]); - // TODO: fix - const CHARACTERISTIC: u64 = 0; const TWO_ADICITY: usize = 1; - const CHARACTERISTIC_TWO_ADICITY: usize = Self::TWO_ADICITY; + const CHARACTERISTIC_WITH_TWO_ADICITY: Option<(u64, usize)> = None; // Sage: `g = GF(p).multiplicative_generator()` const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([5, 0, 0, 0]); diff --git a/src/field/secp256k1_scalar.rs b/src/field/secp256k1_scalar.rs index 44907b7a..595a27a3 100644 --- a/src/field/secp256k1_scalar.rs +++ b/src/field/secp256k1_scalar.rs @@ -12,7 +12,6 @@ use rand::Rng; use serde::{Deserialize, Serialize}; use crate::field::field_types::Field; -use crate::field::goldilocks_field::GoldilocksField; /// The base field of the secp256k1 elliptic curve. /// @@ -81,11 +80,8 @@ impl Field for Secp256K1Scalar { 0xFFFFFFFFFFFFFFFF, ]); - // TODO: fix - const CHARACTERISTIC: u64 = 0; - const TWO_ADICITY: usize = 6; - const CHARACTERISTIC_TWO_ADICITY: usize = 6; + const CHARACTERISTIC_WITH_TWO_ADICITY: Option<(u64, usize)> = None; // Sage: `g = GF(p).multiplicative_generator()` const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([7, 0, 0, 0]); From 1d215d5d59c1004858063734975bc7f11157f198 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 13 Dec 2021 16:23:39 +0100 Subject: [PATCH 3/5] Remove dbg --- src/field/field_types.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/field/field_types.rs b/src/field/field_types.rs index 14426212..cce96bec 100644 --- a/src/field/field_types.rs +++ b/src/field/field_types.rs @@ -228,7 +228,6 @@ pub trait Field: Self::from_canonical_u64(p - ((p - 1) >> exp)) } } else { - dbg!("yo"); Self::TWO.inverse().exp_u64(exp as u64) } } From 073fe7a6d9375b17235b7ace6af5cfb2ad0b11db Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 13 Dec 2021 16:40:00 +0100 Subject: [PATCH 4/5] New clippy lints --- src/field/fft.rs | 2 +- src/gadgets/sorting.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/field/fft.rs b/src/field/fft.rs index 76e0fd42..ba94f6a7 100644 --- a/src/field/fft.rs +++ b/src/field/fft.rs @@ -43,7 +43,7 @@ fn fft_dispatch( } else { Some(fft_root_table(input.len())) }; - let used_root_table = root_table.or_else(|| computed_root_table.as_ref()).unwrap(); + let used_root_table = root_table.or(computed_root_table.as_ref()).unwrap(); fft_classic(input, zero_factor.unwrap_or(0), used_root_table) } diff --git a/src/gadgets/sorting.rs b/src/gadgets/sorting.rs index 2059a888..c4378ab9 100644 --- a/src/gadgets/sorting.rs +++ b/src/gadgets/sorting.rs @@ -128,8 +128,7 @@ impl, const D: usize> SimpleGenerator fn dependencies(&self) -> Vec { self.input_ops .iter() - .map(|op| vec![op.is_write.target, op.address, op.timestamp, op.value]) - .flatten() + .flat_map(|op| vec![op.is_write.target, op.address, op.timestamp, op.value]) .collect() } From 9211bcfed50c405381a3892e30010732ba60d138 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 14 Dec 2021 17:12:14 +0100 Subject: [PATCH 5/5] Move characteristic to its own fn --- src/field/extension_field/quadratic.rs | 6 ++++-- src/field/extension_field/quartic.rs | 6 ++++-- src/field/field_types.rs | 17 +++++++++-------- src/field/goldilocks_field.rs | 6 ++++-- src/field/secp256k1_base.rs | 5 ++++- src/field/secp256k1_scalar.rs | 5 ++++- 6 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index 16743f12..2243612e 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -59,8 +59,7 @@ impl> Field for QuadraticExtension { // long as `F::TWO_ADICITY >= 2`, `p` can be written as `4n + 1`, so `p + 1` can be written as // `2(2n + 1)`, which has a 2-adicity of 1. const TWO_ADICITY: usize = F::TWO_ADICITY + 1; - const CHARACTERISTIC_WITH_TWO_ADICITY: Option<(u64, usize)> = - F::CHARACTERISTIC_WITH_TWO_ADICITY; + const CHARACTERISTIC_TWO_ADICITY: usize = F::CHARACTERISTIC_TWO_ADICITY; const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self(F::EXT_MULTIPLICATIVE_GROUP_GENERATOR); const POWER_OF_TWO_GENERATOR: Self = Self(F::EXT_POWER_OF_TWO_GENERATOR); @@ -70,6 +69,9 @@ impl> Field for QuadraticExtension { fn order() -> BigUint { F::order() * F::order() } + fn characteristic() -> BigUint { + F::characteristic() + } #[inline(always)] fn square(&self) -> Self { diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 77329c94..781f79f5 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -61,8 +61,7 @@ impl> Field for QuarticExtension { // `2(2n + 1)`, which has a 2-adicity of 1. A similar argument can show that `p^2 + 1` also has // a 2-adicity of 1. const TWO_ADICITY: usize = F::TWO_ADICITY + 2; - const CHARACTERISTIC_WITH_TWO_ADICITY: Option<(u64, usize)> = - F::CHARACTERISTIC_WITH_TWO_ADICITY; + const CHARACTERISTIC_TWO_ADICITY: usize = F::CHARACTERISTIC_TWO_ADICITY; const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self(F::EXT_MULTIPLICATIVE_GROUP_GENERATOR); const POWER_OF_TWO_GENERATOR: Self = Self(F::EXT_POWER_OF_TWO_GENERATOR); @@ -72,6 +71,9 @@ impl> Field for QuarticExtension { fn order() -> BigUint { F::order().pow(4u32) } + fn characteristic() -> BigUint { + F::characteristic() + } #[inline(always)] fn square(&self) -> Self { diff --git a/src/field/field_types.rs b/src/field/field_types.rs index cce96bec..f3d1c946 100644 --- a/src/field/field_types.rs +++ b/src/field/field_types.rs @@ -4,7 +4,7 @@ use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use num::bigint::BigUint; -use num::{Integer, One, Zero}; +use num::{Integer, One, ToPrimitive, Zero}; use rand::Rng; use serde::de::DeserializeOwned; use serde::Serialize; @@ -52,7 +52,7 @@ pub trait Field: /// The field's characteristic and it's 2-adicity. /// Set to `None` when the characteristic doesn't fit in a u64. - const CHARACTERISTIC_WITH_TWO_ADICITY: Option<(u64, usize)>; + const CHARACTERISTIC_TWO_ADICITY: usize; /// Generator of the entire multiplicative group, i.e. all non-zero elements. const MULTIPLICATIVE_GROUP_GENERATOR: Self; @@ -62,6 +62,7 @@ pub trait Field: const BITS: usize; fn order() -> BigUint; + fn characteristic() -> BigUint; #[inline] fn is_zero(&self) -> bool { @@ -204,24 +205,24 @@ pub trait Field: // exp exceeds t, we repeatedly multiply by 2^-t and reduce // exp until it's in the right range. - if let Some((p, two_adicity)) = Self::CHARACTERISTIC_WITH_TWO_ADICITY { + if let Some(p) = Self::characteristic().to_u64() { // NB: The only reason this is split into two cases is to save // the multiplication (and possible calculation of // inverse_2_pow_adicity) in the usual case that exp <= // TWO_ADICITY. Can remove the branch and simplify if that // saving isn't worth it. - if exp > two_adicity { + if exp > Self::CHARACTERISTIC_TWO_ADICITY { // NB: This should be a compile-time constant let inverse_2_pow_adicity: Self = - Self::from_canonical_u64(p - ((p - 1) >> two_adicity)); + Self::from_canonical_u64(p - ((p - 1) >> Self::CHARACTERISTIC_TWO_ADICITY)); let mut res = inverse_2_pow_adicity; - let mut e = exp - two_adicity; + let mut e = exp - Self::CHARACTERISTIC_TWO_ADICITY; - while e > two_adicity { + while e > Self::CHARACTERISTIC_TWO_ADICITY { res *= inverse_2_pow_adicity; - e -= two_adicity; + e -= Self::CHARACTERISTIC_TWO_ADICITY; } res * Self::from_canonical_u64(p - ((p - 1) >> e)) } else { diff --git a/src/field/goldilocks_field.rs b/src/field/goldilocks_field.rs index 14c0a281..d963fb9e 100644 --- a/src/field/goldilocks_field.rs +++ b/src/field/goldilocks_field.rs @@ -68,8 +68,7 @@ impl Field for GoldilocksField { const NEG_ONE: Self = Self(Self::ORDER - 1); const TWO_ADICITY: usize = 32; - const CHARACTERISTIC_WITH_TWO_ADICITY: Option<(u64, usize)> = - Some((Self::ORDER, Self::TWO_ADICITY)); + const CHARACTERISTIC_TWO_ADICITY: usize = Self::TWO_ADICITY; // Sage: `g = GF(p).multiplicative_generator()` const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self(7); @@ -86,6 +85,9 @@ impl Field for GoldilocksField { fn order() -> BigUint { Self::ORDER.into() } + fn characteristic() -> BigUint { + Self::order() + } #[inline(always)] fn try_inverse(&self) -> Option { diff --git a/src/field/secp256k1_base.rs b/src/field/secp256k1_base.rs index 3e0d0ef0..0d79000f 100644 --- a/src/field/secp256k1_base.rs +++ b/src/field/secp256k1_base.rs @@ -78,7 +78,7 @@ impl Field for Secp256K1Base { ]); const TWO_ADICITY: usize = 1; - const CHARACTERISTIC_WITH_TWO_ADICITY: Option<(u64, usize)> = None; + const CHARACTERISTIC_TWO_ADICITY: usize = Self::TWO_ADICITY; // Sage: `g = GF(p).multiplicative_generator()` const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([5, 0, 0, 0]); @@ -94,6 +94,9 @@ impl Field for Secp256K1Base { 0xFFFFFFFF, ]) } + fn characteristic() -> BigUint { + Self::order() + } fn try_inverse(&self) -> Option { if self.is_zero() { diff --git a/src/field/secp256k1_scalar.rs b/src/field/secp256k1_scalar.rs index 595a27a3..a5b7a315 100644 --- a/src/field/secp256k1_scalar.rs +++ b/src/field/secp256k1_scalar.rs @@ -81,7 +81,7 @@ impl Field for Secp256K1Scalar { ]); const TWO_ADICITY: usize = 6; - const CHARACTERISTIC_WITH_TWO_ADICITY: Option<(u64, usize)> = None; + const CHARACTERISTIC_TWO_ADICITY: usize = Self::TWO_ADICITY; // Sage: `g = GF(p).multiplicative_generator()` const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([7, 0, 0, 0]); @@ -103,6 +103,9 @@ impl Field for Secp256K1Scalar { 0xFFFFFFFF, ]) } + fn characteristic() -> BigUint { + Self::order() + } fn try_inverse(&self) -> Option { if self.is_zero() {