Skip to content

Commit 4dfe325

Browse files
committed
field: add ability to multiply by integers
Adds a CHARACTERISTIC constant to the Field trait, so this is yet another breaking change (though in practice I don't think anybody is implementing Field on their own types).
1 parent 74ec75f commit 4dfe325

File tree

3 files changed

+52
-1
lines changed

3 files changed

+52
-1
lines changed

src/primitives/field.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ pub trait Field:
4444
/// A primitive element, i.e. a generator of the multiplicative group of the field.
4545
const GENERATOR: Self;
4646

47+
/// The smallest integer n such that 1 + ... + 1, n times, equals 0.
48+
///
49+
/// If this is 0, this indicates that no such integer exists.
50+
const CHARACTERISTIC: usize;
51+
4752
/// The order of the multiplicative group of the field.
4853
const MULTIPLICATIVE_ORDER: usize;
4954

@@ -56,6 +61,47 @@ pub trait Field:
5661
/// Computes the multiplicative inverse of an element.
5762
fn multiplicative_inverse(self) -> Self;
5863

64+
/// Takes the element times some integer.
65+
fn muli(&self, mut n: i64) -> Self {
66+
let base = if n >= 0 {
67+
self.clone()
68+
} else {
69+
n *= -1;
70+
self.clone().multiplicative_inverse()
71+
};
72+
73+
let mut ret = Self::ZERO;
74+
// Special case some particular characteristics
75+
match Self::CHARACTERISTIC {
76+
1 => unreachable!("no field has characteristic 1"),
77+
2 => {
78+
// Special-case 2 because it's easy and also the only characteristic used
79+
// within the library. The compiler should prune away the other code.
80+
if n % 2 == 0 {
81+
Self::ZERO
82+
} else {
83+
self.clone()
84+
}
85+
}
86+
x => {
87+
// This is identical to powi below, but with * replaced by +.
88+
if x > 0 {
89+
n %= x as i64;
90+
}
91+
92+
let mut mask = x.next_power_of_two() as i64;
93+
while mask > 0 {
94+
ret += ret.clone();
95+
if n & mask != 0 {
96+
ret += &base;
97+
}
98+
mask >>= 1;
99+
}
100+
ret
101+
}
102+
}
103+
}
104+
59105
/// Takes the element to the power of some integer.
60106
fn powi(&self, mut n: i64) -> Self {
61107
let base = if n >= 0 {
@@ -71,7 +117,7 @@ pub trait Field:
71117
while mask > 0 {
72118
ret *= ret.clone();
73119
if n & mask != 0 {
74-
ret *= base.clone();
120+
ret *= &base;
75121
}
76122
mask >>= 1;
77123
}

src/primitives/gf32.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ impl Field for Fe32 {
300300
const ZERO: Self = Fe32::Q;
301301
const ONE: Self = Fe32::P;
302302
const GENERATOR: Self = Fe32::Z;
303+
const CHARACTERISTIC: usize = 2;
303304
const MULTIPLICATIVE_ORDER: usize = 31;
304305
const MULTIPLICATIVE_ORDER_FACTORS: &'static [usize] = &[1, 31];
305306

src/primitives/gf32_ext.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ impl Field for Fe1024 {
150150
/// A generator of the field.
151151
const GENERATOR: Self = Self::new([Fe32::P, Fe32::H]);
152152

153+
const CHARACTERISTIC: usize = 2;
154+
153155
/// The order of the multiplicative group of the field.
154156
///
155157
/// This constant also serves as a compile-time check that we can count
@@ -235,6 +237,8 @@ impl Field for Fe32768 {
235237
/// The one element of the field.
236238
const ONE: Self = Self::new([Fe32::P, Fe32::Q, Fe32::Q]);
237239

240+
const CHARACTERISTIC: usize = 2;
241+
238242
// Chosen somewhat arbitrarily, by just guessing values until one came
239243
// out with the correct order.
240244
/// A generator of the field.

0 commit comments

Comments
 (0)