Remove custom primitive_root_of_unity in extension fields by modifying the generators.

This commit is contained in:
wborgeaud 2021-05-19 09:35:39 +02:00
parent 1cbd12edbd
commit e806d86f86
2 changed files with 56 additions and 39 deletions

View File

@ -83,9 +83,15 @@ impl Field for QuadraticCrandallField {
// Does not fit in 64-bits.
const ORDER: u64 = 0;
const TWO_ADICITY: usize = 29;
const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([CrandallField(3), CrandallField::ONE]);
const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([
CrandallField(6483724566312148654),
CrandallField(12194665049945415126),
]);
// Chosen so that when raised to the power `1<<(Self::TWO_ADICITY-Self::BaseField::TWO_ADICITY)`,
// we get `Self::BaseField::POWER_OF_TWO_GENERATOR`. This makes `primitive_root_of_unity` coherent
// with the base field which implies that the FFT commutes with field inclusion.
const POWER_OF_TWO_GENERATOR: Self =
Self([CrandallField::ZERO, CrandallField(7889429148549342301)]);
Self([CrandallField::ZERO, CrandallField(14420468973723774561)]);
// Algorithm 11.3.4 in Handbook of Elliptic and Hyperelliptic Curve Cryptography.
fn try_inverse(&self) -> Option<Self> {
@ -100,22 +106,6 @@ impl Field for QuadraticCrandallField {
Some(a_pow_r_minus_1 * a_pow_r.0[0].inverse().into())
}
// It's important that the primitive roots of unity are the same as the ones in the base field,
// otherwise the FFT doesn't commute with field inclusion.
fn primitive_root_of_unity(n_log: usize) -> Self {
if n_log <= CrandallField::TWO_ADICITY {
CrandallField::primitive_root_of_unity(n_log).into()
} else {
// The root of unity isn't in the base field so we need to compute it manually.
assert!(n_log <= Self::TWO_ADICITY);
let mut base = Self::POWER_OF_TWO_GENERATOR;
for _ in n_log..Self::TWO_ADICITY {
base = base.square();
}
base
}
}
fn to_canonical_u64(&self) -> u64 {
self.0[0].to_canonical_u64()
}
@ -311,4 +301,22 @@ mod tests {
F::ONE
);
}
#[test]
fn test_power_of_two_gen() {
type F = QuadraticCrandallField;
// F::ORDER = 2^29 * 2762315674048163 * 229454332791453 + 1
assert_eq!(
F::MULTIPLICATIVE_GROUP_GENERATOR
.exp_usize(2762315674048163)
.exp_usize(229454332791453),
F::POWER_OF_TWO_GENERATOR
);
assert_eq!(
F::POWER_OF_TWO_GENERATOR.exp_usize(
1 << (F::TWO_ADICITY - <F as QuadraticFieldExtension>::BaseField::TWO_ADICITY)
),
<F as QuadraticFieldExtension>::BaseField::POWER_OF_TWO_GENERATOR.into()
);
}
}

View File

@ -110,16 +110,19 @@ impl Field for QuarticCrandallField {
const ORDER: u64 = 0;
const TWO_ADICITY: usize = 30;
const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([
CrandallField(3),
CrandallField::ONE,
CrandallField::ZERO,
CrandallField::ZERO,
CrandallField(12476589904174392631),
CrandallField(896937834427772243),
CrandallField(7795248119019507390),
CrandallField(9005769437373554825),
]);
// Chosen so that when raised to the power `1<<(Self::TWO_ADICITY-Self::BaseField::TWO_ADICITY)`,
// we get `Self::BaseField::POWER_OF_TWO_GENERATOR`. This makes `primitive_root_of_unity` coherent
// with the base field which implies that the FFT commutes with field inclusion.
const POWER_OF_TWO_GENERATOR: Self = Self([
CrandallField::ZERO,
CrandallField::ZERO,
CrandallField::ZERO,
CrandallField(14096607364803438105),
CrandallField(15170983443234254033),
]);
// Algorithm 11.3.4 in Handbook of Elliptic and Hyperelliptic Curve Cryptography.
@ -138,22 +141,6 @@ impl Field for QuarticCrandallField {
Some(a_pow_r_minus_1 * a_pow_r.0[0].inverse().into())
}
// It's important that the primitive roots of unity are the same as the ones in the base field,
// otherwise the FFT doesn't commute with field inclusion.
fn primitive_root_of_unity(n_log: usize) -> Self {
if n_log <= CrandallField::TWO_ADICITY {
CrandallField::primitive_root_of_unity(n_log).into()
} else {
// The root of unity isn't in the base field so we need to compute it manually.
assert!(n_log <= Self::TWO_ADICITY);
let mut base = Self::POWER_OF_TWO_GENERATOR;
for _ in n_log..Self::TWO_ADICITY {
base = base.square();
}
base
}
}
fn to_canonical_u64(&self) -> u64 {
self.0[0].to_canonical_u64()
}
@ -370,4 +357,26 @@ mod tests {
F::ONE
);
}
#[test]
fn test_power_of_two_gen() {
type F = QuarticCrandallField;
// F::ORDER = 2^30 * 1090552343587053358839971118999869 * 98885475095492590491252558464653635 + 1
assert_eq!(
exp_naive(
exp_naive(
F::MULTIPLICATIVE_GROUP_GENERATOR,
1090552343587053358839971118999869
),
98885475095492590491252558464653635
),
F::POWER_OF_TWO_GENERATOR
);
assert_eq!(
F::POWER_OF_TWO_GENERATOR.exp_usize(
1 << (F::TWO_ADICITY - <F as QuarticFieldExtension>::BaseField::TWO_ADICITY)
),
<F as QuarticFieldExtension>::BaseField::POWER_OF_TWO_GENERATOR.into()
);
}
}