commonware_math/fields/
goldilocks.rs1use crate::algebra::{Additive, Field, Multiplicative, Object, Ring};
2use commonware_codec::{FixedSize, Read, Write};
3use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
4#[cfg(test)]
5use proptest::prelude::{Arbitrary, BoxedStrategy};
6use rand_core::CryptoRngCore;
7
8const P: u64 = u64::wrapping_neg(1 << 32) + 1;
12
13#[derive(Clone, Copy, PartialEq, Eq)]
15pub struct F(u64);
16
17impl FixedSize for F {
18 const SIZE: usize = u64::SIZE;
19}
20
21impl Write for F {
22 fn write(&self, buf: &mut impl bytes::BufMut) {
23 self.0.write(buf)
24 }
25}
26
27impl Read for F {
28 type Cfg = <u64 as Read>::Cfg;
29
30 fn read_cfg(
31 buf: &mut impl bytes::Buf,
32 cfg: &Self::Cfg,
33 ) -> Result<Self, commonware_codec::Error> {
34 u64::read_cfg(buf, cfg).map(F)
35 }
36}
37
38impl core::fmt::Debug for F {
39 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
40 write!(f, "{:016X}", self.0)
41 }
42}
43
44#[cfg(feature = "arbitrary")]
45impl arbitrary::Arbitrary<'_> for F {
46 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
47 let x = u.arbitrary::<u64>()?;
48 Ok(F::reduce_64(x))
49 }
50}
51
52impl F {
53 #[cfg(test)]
62 pub const GENERATOR: Self = Self(0xd64f951101aff9bf);
63
64 pub const ROOT_OF_UNITY: Self = Self(0xee41f5320c4ea145);
70
71 pub const NOT_ROOT_OF_UNITY: Self = Self(0x79bc2f50acd74161);
73
74 pub const NOT_ROOT_OF_UNITY_INV: Self = Self(0x1036c4023580ce8d);
76
77 const ZERO: Self = Self(0);
81
82 const ONE: Self = Self(1);
86
87 const fn add_inner(self, b: Self) -> Self {
88 let (addition, overflow) = self.0.overflowing_add(b.0);
103 let (subtraction, underflow) = addition.overflowing_sub(P);
107 if overflow || !underflow {
110 Self(subtraction)
111 } else {
112 Self(addition)
113 }
114 }
115
116 const fn sub_inner(self, b: Self) -> Self {
117 let (subtraction, underflow) = self.0.overflowing_sub(b.0);
122 if underflow {
123 Self(subtraction.wrapping_add(P))
124 } else {
125 Self(subtraction)
126 }
127 }
128
129 const fn reduce_64(x: u64) -> Self {
130 let (subtraction, underflow) = x.overflowing_sub(P);
133 if underflow {
134 Self(x)
135 } else {
136 Self(subtraction)
137 }
138 }
139
140 const fn reduce_128(x: u128) -> Self {
142 let a = x as u64;
154 let b = ((x >> 64) & 0xFF_FF_FF_FF) as u64;
155 let c = (x >> 96) as u64;
156
157 Self(a).sub_inner(Self(c)).add_inner(Self((b << 32) - b))
173 }
174
175 const fn mul_inner(self, b: Self) -> Self {
176 Self::reduce_128((self.0 as u128) * (b.0 as u128))
178 }
179
180 const fn neg_inner(self) -> Self {
181 Self::ZERO.sub_inner(self)
182 }
183
184 pub fn inv(self) -> Self {
188 self.exp(&[P - 2])
189 }
190
191 pub fn root_of_unity(lg_k: u8) -> Option<Self> {
195 if lg_k > 32 {
196 return None;
197 }
198 let mut out = Self::ROOT_OF_UNITY;
199 for _ in 0..(32 - lg_k) {
200 out = out * out;
201 }
202 Some(out)
203 }
204
205 pub fn div_2(self) -> Self {
207 if self.0 & 1 == 0 {
209 Self(self.0 >> 1)
211 } else {
212 let (addition, carry) = self.0.overflowing_add(P);
217 Self((u64::from(carry) << 63) | (addition >> 1))
220 }
221 }
222
223 pub fn stream_from_u64s(inner: impl Iterator<Item = u64>) -> impl Iterator<Item = Self> {
225 struct Iter<I> {
226 acc: u128,
227 acc_bits: u32,
228 inner: I,
229 }
230
231 impl<I: Iterator<Item = u64>> Iterator for Iter<I> {
232 type Item = F;
233
234 fn next(&mut self) -> Option<Self::Item> {
235 while self.acc_bits < 63 {
236 let Some(x) = self.inner.next() else {
237 break;
238 };
239 let x = u128::from(x);
240 self.acc |= x << self.acc_bits;
241 self.acc_bits += 64;
242 }
243 if self.acc_bits > 0 {
244 self.acc_bits = self.acc_bits.saturating_sub(63);
245 let out = F((self.acc as u64) & ((1 << 63) - 1));
246 self.acc >>= 63;
247 return Some(out);
248 }
249 None
250 }
251 }
252
253 Iter {
254 acc: 0,
255 acc_bits: 0,
256 inner,
257 }
258 }
259
260 pub fn stream_to_u64s(inner: impl Iterator<Item = Self>) -> impl Iterator<Item = u64> {
264 struct Iter<I> {
265 acc: u128,
266 acc_bits: u32,
267 inner: I,
268 }
269
270 impl<I: Iterator<Item = F>> Iterator for Iter<I> {
271 type Item = u64;
272
273 fn next(&mut self) -> Option<Self::Item> {
274 while self.acc_bits < 64 {
276 let Some(F(x)) = self.inner.next() else {
277 break;
278 };
279 let x = u128::from(x & ((1 << 63) - 1));
281 self.acc |= x << self.acc_bits;
282 self.acc_bits += 63;
283 }
284 if self.acc_bits > 0 {
285 self.acc_bits = self.acc_bits.saturating_sub(64);
286 let out = self.acc as u64;
287 self.acc >>= 64;
288 return Some(out);
289 }
290 None
291 }
292 }
293 Iter {
294 acc: 0,
295 acc_bits: 0,
296 inner,
297 }
298 }
299
300 pub const fn bits_to_elements(bits: usize) -> usize {
304 bits.div_ceil(63)
305 }
306
307 pub const fn to_le_bytes(&self) -> [u8; 8] {
309 self.0.to_le_bytes()
310 }
311
312 pub fn rand(mut rng: impl CryptoRngCore) -> Self {
316 loop {
318 let x = rng.next_u64();
319 if x < P {
320 return Self(x);
321 }
322 }
323 }
324}
325
326impl Object for F {}
327
328impl Add for F {
329 type Output = Self;
330
331 fn add(self, b: Self) -> Self::Output {
332 self.add_inner(b)
333 }
334}
335
336impl<'a> Add<&'a F> for F {
337 type Output = F;
338
339 fn add(self, rhs: &'a F) -> Self::Output {
340 self + *rhs
341 }
342}
343
344impl<'a> AddAssign<&'a F> for F {
345 fn add_assign(&mut self, rhs: &'a F) {
346 *self = *self + rhs
347 }
348}
349
350impl<'a> Sub<&'a F> for F {
351 type Output = Self;
352
353 fn sub(self, rhs: &'a F) -> Self::Output {
354 self - *rhs
355 }
356}
357
358impl<'a> SubAssign<&'a F> for F {
359 fn sub_assign(&mut self, rhs: &'a F) {
360 *self = *self - rhs;
361 }
362}
363
364impl Additive for F {
365 fn zero() -> Self {
366 Self::ZERO
367 }
368}
369
370impl Sub for F {
371 type Output = Self;
372
373 fn sub(self, b: Self) -> Self::Output {
374 self.sub_inner(b)
375 }
376}
377
378impl Mul for F {
379 type Output = Self;
380
381 fn mul(self, b: Self) -> Self::Output {
382 Self::mul_inner(self, b)
383 }
384}
385
386impl<'a> Mul<&'a F> for F {
387 type Output = F;
388
389 fn mul(self, rhs: &'a F) -> Self::Output {
390 self * *rhs
391 }
392}
393
394impl<'a> MulAssign<&'a F> for F {
395 fn mul_assign(&mut self, rhs: &'a F) {
396 *self = *self * rhs;
397 }
398}
399
400impl Multiplicative for F {}
401
402impl Neg for F {
403 type Output = Self;
404
405 fn neg(self) -> Self::Output {
406 self.neg_inner()
407 }
408}
409
410impl From<u64> for F {
411 fn from(value: u64) -> Self {
412 Self::reduce_64(value)
413 }
414}
415
416impl Ring for F {
417 fn one() -> Self {
418 Self::ONE
419 }
420}
421
422impl Field for F {
423 fn inv(&self) -> Self {
424 F::inv(*self)
425 }
426}
427
428#[cfg(test)]
429mod test {
430 use super::*;
431 use crate::algebra;
432 use proptest::prelude::*;
433
434 impl Arbitrary for F {
435 type Parameters = ();
436 type Strategy = BoxedStrategy<Self>;
437
438 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
439 any::<u64>().prop_map_into().boxed()
440 }
441 }
442
443 #[test]
444 fn test_generator_calculation() {
445 assert_eq!(F::GENERATOR, F(7).exp(&[133]));
446 }
447
448 #[test]
449 fn test_root_of_unity_calculation() {
450 assert_eq!(F::ROOT_OF_UNITY, F::GENERATOR.exp(&[(P - 1) >> 32]));
451 }
452
453 #[test]
454 fn test_not_root_of_unity_calculation() {
455 assert_eq!(F::NOT_ROOT_OF_UNITY, F::GENERATOR.exp(&[1 << 32]));
456 }
457
458 #[test]
459 fn test_not_root_of_unity_inv_calculation() {
460 assert_eq!(F::NOT_ROOT_OF_UNITY * F::NOT_ROOT_OF_UNITY_INV, F::one());
461 }
462
463 #[test]
464 fn test_root_of_unity_exp() {
465 assert_eq!(F::ROOT_OF_UNITY.exp(&[1 << 26]), F(8));
466 }
467
468 fn test_stream_roundtrip_inner(data: Vec<u64>) {
469 let mut roundtrip =
470 F::stream_to_u64s(F::stream_from_u64s(data.clone().into_iter())).collect::<Vec<_>>();
471 roundtrip.truncate(data.len());
472 assert_eq!(data, roundtrip);
473 }
474
475 proptest! {
476 #[test]
477 fn test_exp(x: F, k: u8) {
478 let mut naive = F::one();
479 for _ in 0..k {
480 naive = naive * x;
481 }
482 assert_eq!(naive, x.exp(&[k as u64]));
483 }
484
485 #[test]
486 fn test_div2(x: F) {
487 assert_eq!((x + x).div_2(), x)
488 }
489
490 #[test]
491 fn test_stream_roundtrip(xs in proptest::collection::vec(any::<u64>(), 0..128)) {
492 test_stream_roundtrip_inner(xs);
493 }
494 }
495
496 #[test]
497 fn test_field() {
498 algebra::test_suites::test_field(file!(), &F::arbitrary());
499 }
500
501 #[cfg(feature = "arbitrary")]
502 mod conformance {
503 use super::*;
504 use commonware_codec::conformance::CodecConformance;
505
506 commonware_conformance::conformance_tests! {
507 CodecConformance<F>
508 }
509 }
510}