diff --git a/Cargo.lock b/Cargo.lock index 28bccf3e3..b81ac8e2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -477,6 +477,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71a816c97c42258aa5834d07590b718b4c9a598944cd39a52dc25b351185d678" +[[package]] +name = "impl_ops" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f97a5f38dd3ccfbe7aa80f4a0c00930f21b922c74195be0201c51028f22dcf" + [[package]] name = "inout" version = "0.1.3" @@ -789,6 +795,7 @@ dependencies = [ "hex-literal", "hmac", "iai", + "impl_ops", "itertools 0.11.0", "modinverse", "num-bigint", diff --git a/Cargo.toml b/Cargo.toml index 157177a5c..8add617d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ fiat-crypto = { version = "0.2.1", optional = true } fixed = { version = "1.23", optional = true } getrandom = { version = "0.2.10", features = ["std"] } hmac = { version = "0.12.1", optional = true } +impl_ops = "0.1.1" num-bigint = { version = "0.4.4", optional = true, features = ["rand", "serde"] } num-integer = { version = "0.1.45", optional = true } num-iter = { version = "0.1.43", optional = true } diff --git a/src/field.rs b/src/field.rs index fb931de2d..55962f9d5 100644 --- a/src/field.rs +++ b/src/field.rs @@ -11,7 +11,7 @@ use crate::prng::{Prng, PrngError}; use crate::{ codec::{CodecError, Decode, Encode}, - fp::{FP128, FP32, FP64}, + fp::{FP32, FP64}, }; use serde::{ de::{DeserializeOwned, Visitor}, @@ -31,6 +31,10 @@ use std::{ }; use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq}; +mod fiat_crypto_fp128; +mod field128; +pub use field128::Field128; + #[cfg(feature = "experimental")] mod field255; @@ -733,14 +737,6 @@ make_field!( 8, ); -make_field!( - /// `GF(340282366920938462946865773367900766209)`, a 128-bit field. - Field128, - u128, - FP128, - 16, -); - /// Merge two vectors of fields by summing other_vector into accumulator. /// /// # Errors diff --git a/src/field/fiat_crypto_fp128.rs b/src/field/fiat_crypto_fp128.rs new file mode 100644 index 000000000..341d30f5a --- /dev/null +++ b/src/field/fiat_crypto_fp128.rs @@ -0,0 +1,582 @@ +//! Autogenerated: 'fiat-crypto/word_by_word_montgomery' --output fiat_crypto_fp128.rs --lang Rust --inline --inline-internal --no-prefix-fiat --public-function-case snake_case --private-function-case camelCase --public-type-case UpperCamelCase fp128 64 '(2^62-2^3+1)*2^66+1' add sub mul opp from_montgomery to_montgomery to_bytes from_bytes +//! curve description: fp128 +//! machine_wordsize = 64 (from "64") +//! requested operations: add, sub, mul, opp, from_montgomery, to_montgomery, to_bytes, from_bytes +//! m = 0xffffffffffffffe40000000000000001 (from "(2^62-2^3+1)*2^66+1") +//! +//! NOTE: In addition to the bounds specified above each function, all +//! functions synthesized for this Montgomery arithmetic require the +//! input to be strictly less than the prime modulus (m), and also +//! require the input to be in the unique saturated representation. +//! All functions also ensure that these two properties are true of +//! return values. +//! +//! Computed values: +//! eval z = z[0] + (z[1] << 64) +//! bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) +//! twos_complement_eval z = let x1 := z[0] + (z[1] << 64) in +//! if x1 & (2^128-1) < 2^127 then x1 & (2^128-1) else (x1 & (2^128-1)) - 2^128 + +#![allow(unused_parens)] +#![allow(non_camel_case_types)] + +/** Fp128U1 represents a byte. */ +pub type Fp128U1 = u8; +/** Fp128I1 represents a byte. */ +pub type Fp128I1 = i8; +/** Fp128I2 represents a byte. */ +pub type Fp128I2 = i8; + +/** The type Fp128MontgomeryDomainFieldElement is a field element in the Montgomery domain. */ +/** Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] */ +#[derive(Clone, Copy)] +pub struct Fp128MontgomeryDomainFieldElement(pub [u64; 2]); + +impl core::ops::Index for Fp128MontgomeryDomainFieldElement { + type Output = u64; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + &self.0[index] + } +} + +impl core::ops::IndexMut for Fp128MontgomeryDomainFieldElement { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.0[index] + } +} + +/** The type Fp128NonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain. */ +/** Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] */ +#[derive(Clone, Copy)] +pub struct Fp128NonMontgomeryDomainFieldElement(pub [u64; 2]); + +impl core::ops::Index for Fp128NonMontgomeryDomainFieldElement { + type Output = u64; + #[inline] + fn index(&self, index: usize) -> &Self::Output { + &self.0[index] + } +} + +impl core::ops::IndexMut for Fp128NonMontgomeryDomainFieldElement { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.0[index] + } +} + + +/// The function fp128_addcarryx_u64 is an addition with carry. +/// +/// Postconditions: +/// out1 = (arg1 + arg2 + arg3) mod 2^64 +/// out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋ +/// +/// Input Bounds: +/// arg1: [0x0 ~> 0x1] +/// arg2: [0x0 ~> 0xffffffffffffffff] +/// arg3: [0x0 ~> 0xffffffffffffffff] +/// Output Bounds: +/// out1: [0x0 ~> 0xffffffffffffffff] +/// out2: [0x0 ~> 0x1] +#[inline(always)] +pub fn fp128_addcarryx_u64(out1: &mut u64, out2: &mut Fp128U1, arg1: Fp128U1, arg2: u64, arg3: u64) { + let x1: u128 = (((arg1 as u128) + (arg2 as u128)) + (arg3 as u128)); + let x2: u64 = ((x1 & (0xffffffffffffffff_u64 as u128)) as u64); + let x3: Fp128U1 = ((x1 >> 64) as Fp128U1); + *out1 = x2; + *out2 = x3; +} + +/// The function fp128_subborrowx_u64 is a subtraction with borrow. +/// +/// Postconditions: +/// out1 = (-arg1 + arg2 + -arg3) mod 2^64 +/// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋ +/// +/// Input Bounds: +/// arg1: [0x0 ~> 0x1] +/// arg2: [0x0 ~> 0xffffffffffffffff] +/// arg3: [0x0 ~> 0xffffffffffffffff] +/// Output Bounds: +/// out1: [0x0 ~> 0xffffffffffffffff] +/// out2: [0x0 ~> 0x1] +#[inline(always)] +pub fn fp128_subborrowx_u64(out1: &mut u64, out2: &mut Fp128U1, arg1: Fp128U1, arg2: u64, arg3: u64) { + let x1: i128 = (((arg2 as i128) - (arg1 as i128)) - (arg3 as i128)); + let x2: Fp128I1 = ((x1 >> 64) as Fp128I1); + let x3: u64 = ((x1 & (0xffffffffffffffff_u64 as i128)) as u64); + *out1 = x3; + *out2 = (((0x0_u8 as Fp128I2) - (x2 as Fp128I2)) as Fp128U1); +} + +/// The function fp128_mulx_u64 is a multiplication, returning the full double-width result. +/// +/// Postconditions: +/// out1 = (arg1 * arg2) mod 2^64 +/// out2 = ⌊arg1 * arg2 / 2^64⌋ +/// +/// Input Bounds: +/// arg1: [0x0 ~> 0xffffffffffffffff] +/// arg2: [0x0 ~> 0xffffffffffffffff] +/// Output Bounds: +/// out1: [0x0 ~> 0xffffffffffffffff] +/// out2: [0x0 ~> 0xffffffffffffffff] +#[inline(always)] +pub fn fp128_mulx_u64(out1: &mut u64, out2: &mut u64, arg1: u64, arg2: u64) { + let x1: u128 = ((arg1 as u128) * (arg2 as u128)); + let x2: u64 = ((x1 & (0xffffffffffffffff_u64 as u128)) as u64); + let x3: u64 = ((x1 >> 64) as u64); + *out1 = x2; + *out2 = x3; +} + +/// The function fp128_cmovznz_u64 is a single-word conditional move. +/// +/// Postconditions: +/// out1 = (if arg1 = 0 then arg2 else arg3) +/// +/// Input Bounds: +/// arg1: [0x0 ~> 0x1] +/// arg2: [0x0 ~> 0xffffffffffffffff] +/// arg3: [0x0 ~> 0xffffffffffffffff] +/// Output Bounds: +/// out1: [0x0 ~> 0xffffffffffffffff] +#[inline(always)] +pub fn fp128_cmovznz_u64(out1: &mut u64, arg1: Fp128U1, arg2: u64, arg3: u64) { + let x1: Fp128U1 = (!(!arg1)); + let x2: u64 = ((((((0x0_u8 as Fp128I2) - (x1 as Fp128I2)) as Fp128I1) as i128) & (0xffffffffffffffff_u64 as i128)) as u64); + let x3: u64 = ((x2 & arg3) | ((!x2) & arg2)); + *out1 = x3; +} + +/// The function fp128_add adds two field elements in the Montgomery domain. +/// +/// Preconditions: +/// 0 ≤ eval arg1 < m +/// 0 ≤ eval arg2 < m +/// Postconditions: +/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m +/// 0 ≤ eval out1 < m +/// +#[inline(always)] +pub fn fp128_add(out1: &mut Fp128MontgomeryDomainFieldElement, arg1: &Fp128MontgomeryDomainFieldElement, arg2: &Fp128MontgomeryDomainFieldElement) { + let mut x1: u64 = 0; + let mut x2: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x1, &mut x2, 0x0_u8, (arg1[0]), (arg2[0])); + let mut x3: u64 = 0; + let mut x4: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x3, &mut x4, x2, (arg1[1]), (arg2[1])); + let mut x5: u64 = 0; + let mut x6: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x5, &mut x6, 0x0_u8, x1, (0x1_u8 as u64)); + let mut x7: u64 = 0; + let mut x8: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x7, &mut x8, x6, x3, 0xffffffffffffffe4_u64); + let mut x9: u64 = 0; + let mut x10: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x9, &mut x10, x8, (x4 as u64), (0x0_u8 as u64)); + let mut x11: u64 = 0; + fp128_cmovznz_u64(&mut x11, x10, x5, x1); + let mut x12: u64 = 0; + fp128_cmovznz_u64(&mut x12, x10, x7, x3); + out1[0] = x11; + out1[1] = x12; +} + +/// The function fp128_sub subtracts two field elements in the Montgomery domain. +/// +/// Preconditions: +/// 0 ≤ eval arg1 < m +/// 0 ≤ eval arg2 < m +/// Postconditions: +/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m +/// 0 ≤ eval out1 < m +/// +#[inline(always)] +pub fn fp128_sub(out1: &mut Fp128MontgomeryDomainFieldElement, arg1: &Fp128MontgomeryDomainFieldElement, arg2: &Fp128MontgomeryDomainFieldElement) { + let mut x1: u64 = 0; + let mut x2: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x1, &mut x2, 0x0_u8, (arg1[0]), (arg2[0])); + let mut x3: u64 = 0; + let mut x4: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x3, &mut x4, x2, (arg1[1]), (arg2[1])); + let mut x5: u64 = 0; + fp128_cmovznz_u64(&mut x5, x4, (0x0_u8 as u64), 0xffffffffffffffff_u64); + let mut x6: u64 = 0; + let mut x7: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x6, &mut x7, 0x0_u8, x1, (((x5 & (0x1_u8 as u64)) as Fp128U1) as u64)); + let mut x8: u64 = 0; + let mut x9: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x8, &mut x9, x7, x3, (x5 & 0xffffffffffffffe4_u64)); + out1[0] = x6; + out1[1] = x8; +} + +/// The function fp128_mul multiplies two field elements in the Montgomery domain. +/// +/// Preconditions: +/// 0 ≤ eval arg1 < m +/// 0 ≤ eval arg2 < m +/// Postconditions: +/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m +/// 0 ≤ eval out1 < m +/// +#[inline(always)] +pub fn fp128_mul(out1: &mut Fp128MontgomeryDomainFieldElement, arg1: &Fp128MontgomeryDomainFieldElement, arg2: &Fp128MontgomeryDomainFieldElement) { + let x1: u64 = (arg1[1]); + let x2: u64 = (arg1[0]); + let mut x3: u64 = 0; + let mut x4: u64 = 0; + fp128_mulx_u64(&mut x3, &mut x4, x2, (arg2[1])); + let mut x5: u64 = 0; + let mut x6: u64 = 0; + fp128_mulx_u64(&mut x5, &mut x6, x2, (arg2[0])); + let mut x7: u64 = 0; + let mut x8: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x7, &mut x8, 0x0_u8, x6, x3); + let x9: u64 = ((x8 as u64) + x4); + let mut x10: u64 = 0; + let mut x11: u64 = 0; + fp128_mulx_u64(&mut x10, &mut x11, x5, 0xffffffffffffffff_u64); + let mut x12: u64 = 0; + let mut x13: u64 = 0; + fp128_mulx_u64(&mut x12, &mut x13, x10, 0xffffffffffffffe4_u64); + let mut x14: u64 = 0; + let mut x15: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x14, &mut x15, 0x0_u8, x5, x10); + let mut x16: u64 = 0; + let mut x17: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x16, &mut x17, x15, x7, x12); + let mut x18: u64 = 0; + let mut x19: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x18, &mut x19, x17, x9, x13); + let mut x20: u64 = 0; + let mut x21: u64 = 0; + fp128_mulx_u64(&mut x20, &mut x21, x1, (arg2[1])); + let mut x22: u64 = 0; + let mut x23: u64 = 0; + fp128_mulx_u64(&mut x22, &mut x23, x1, (arg2[0])); + let mut x24: u64 = 0; + let mut x25: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x24, &mut x25, 0x0_u8, x23, x20); + let x26: u64 = ((x25 as u64) + x21); + let mut x27: u64 = 0; + let mut x28: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x27, &mut x28, 0x0_u8, x16, x22); + let mut x29: u64 = 0; + let mut x30: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x29, &mut x30, x28, x18, x24); + let mut x31: u64 = 0; + let mut x32: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x31, &mut x32, x30, (x19 as u64), x26); + let mut x33: u64 = 0; + let mut x34: u64 = 0; + fp128_mulx_u64(&mut x33, &mut x34, x27, 0xffffffffffffffff_u64); + let mut x35: u64 = 0; + let mut x36: u64 = 0; + fp128_mulx_u64(&mut x35, &mut x36, x33, 0xffffffffffffffe4_u64); + let mut x37: u64 = 0; + let mut x38: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x37, &mut x38, 0x0_u8, x27, x33); + let mut x39: u64 = 0; + let mut x40: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x39, &mut x40, x38, x29, x35); + let mut x41: u64 = 0; + let mut x42: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x41, &mut x42, x40, x31, x36); + let x43: u64 = ((x42 as u64) + (x32 as u64)); + let mut x44: u64 = 0; + let mut x45: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x44, &mut x45, 0x0_u8, x39, (0x1_u8 as u64)); + let mut x46: u64 = 0; + let mut x47: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x46, &mut x47, x45, x41, 0xffffffffffffffe4_u64); + let mut x48: u64 = 0; + let mut x49: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x48, &mut x49, x47, x43, (0x0_u8 as u64)); + let mut x50: u64 = 0; + fp128_cmovznz_u64(&mut x50, x49, x44, x39); + let mut x51: u64 = 0; + fp128_cmovznz_u64(&mut x51, x49, x46, x41); + out1[0] = x50; + out1[1] = x51; +} + +/// The function fp128_opp negates a field element in the Montgomery domain. +/// +/// Preconditions: +/// 0 ≤ eval arg1 < m +/// Postconditions: +/// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m +/// 0 ≤ eval out1 < m +/// +#[inline(always)] +pub fn fp128_opp(out1: &mut Fp128MontgomeryDomainFieldElement, arg1: &Fp128MontgomeryDomainFieldElement) { + let mut x1: u64 = 0; + let mut x2: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x1, &mut x2, 0x0_u8, (0x0_u8 as u64), (arg1[0])); + let mut x3: u64 = 0; + let mut x4: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x3, &mut x4, x2, (0x0_u8 as u64), (arg1[1])); + let mut x5: u64 = 0; + fp128_cmovznz_u64(&mut x5, x4, (0x0_u8 as u64), 0xffffffffffffffff_u64); + let mut x6: u64 = 0; + let mut x7: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x6, &mut x7, 0x0_u8, x1, (((x5 & (0x1_u8 as u64)) as Fp128U1) as u64)); + let mut x8: u64 = 0; + let mut x9: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x8, &mut x9, x7, x3, (x5 & 0xffffffffffffffe4_u64)); + out1[0] = x6; + out1[1] = x8; +} + +/// The function fp128_from_montgomery translates a field element out of the Montgomery domain. +/// +/// Preconditions: +/// 0 ≤ eval arg1 < m +/// Postconditions: +/// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^2) mod m +/// 0 ≤ eval out1 < m +/// +#[inline(always)] +pub fn fp128_from_montgomery(out1: &mut Fp128NonMontgomeryDomainFieldElement, arg1: &Fp128MontgomeryDomainFieldElement) { + let x1: u64 = (arg1[0]); + let mut x2: u64 = 0; + let mut x3: u64 = 0; + fp128_mulx_u64(&mut x2, &mut x3, x1, 0xffffffffffffffff_u64); + let mut x4: u64 = 0; + let mut x5: u64 = 0; + fp128_mulx_u64(&mut x4, &mut x5, x2, 0xffffffffffffffe4_u64); + let mut x6: u64 = 0; + let mut x7: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x6, &mut x7, 0x0_u8, x1, x2); + let mut x8: u64 = 0; + let mut x9: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x8, &mut x9, x7, (0x0_u8 as u64), x4); + let mut x10: u64 = 0; + let mut x11: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x10, &mut x11, 0x0_u8, x8, (arg1[1])); + let mut x12: u64 = 0; + let mut x13: u64 = 0; + fp128_mulx_u64(&mut x12, &mut x13, x10, 0xffffffffffffffff_u64); + let mut x14: u64 = 0; + let mut x15: u64 = 0; + fp128_mulx_u64(&mut x14, &mut x15, x12, 0xffffffffffffffe4_u64); + let mut x16: u64 = 0; + let mut x17: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x16, &mut x17, 0x0_u8, x10, x12); + let mut x18: u64 = 0; + let mut x19: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x18, &mut x19, x17, ((x11 as u64) + ((x9 as u64) + x5)), x14); + let x20: u64 = ((x19 as u64) + x15); + let mut x21: u64 = 0; + let mut x22: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x21, &mut x22, 0x0_u8, x18, (0x1_u8 as u64)); + let mut x23: u64 = 0; + let mut x24: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x23, &mut x24, x22, x20, 0xffffffffffffffe4_u64); + let mut x25: u64 = 0; + let mut x26: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x25, &mut x26, x24, (0x0_u8 as u64), (0x0_u8 as u64)); + let mut x27: u64 = 0; + fp128_cmovznz_u64(&mut x27, x26, x21, x18); + let mut x28: u64 = 0; + fp128_cmovznz_u64(&mut x28, x26, x23, x20); + out1[0] = x27; + out1[1] = x28; +} + +/// The function fp128_to_montgomery translates a field element into the Montgomery domain. +/// +/// Preconditions: +/// 0 ≤ eval arg1 < m +/// Postconditions: +/// eval (from_montgomery out1) mod m = eval arg1 mod m +/// 0 ≤ eval out1 < m +/// +#[inline(always)] +pub fn fp128_to_montgomery(out1: &mut Fp128MontgomeryDomainFieldElement, arg1: &Fp128NonMontgomeryDomainFieldElement) { + let x1: u64 = (arg1[1]); + let x2: u64 = (arg1[0]); + let mut x3: u64 = 0; + let mut x4: u64 = 0; + fp128_mulx_u64(&mut x3, &mut x4, x2, 0x5587_u64); + let mut x5: u64 = 0; + let mut x6: u64 = 0; + fp128_mulx_u64(&mut x5, &mut x6, x2, 0xfffffffffffffcf1_u64); + let mut x7: u64 = 0; + let mut x8: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x7, &mut x8, 0x0_u8, x6, x3); + let mut x9: u64 = 0; + let mut x10: u64 = 0; + fp128_mulx_u64(&mut x9, &mut x10, x5, 0xffffffffffffffff_u64); + let mut x11: u64 = 0; + let mut x12: u64 = 0; + fp128_mulx_u64(&mut x11, &mut x12, x9, 0xffffffffffffffe4_u64); + let mut x13: u64 = 0; + let mut x14: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x13, &mut x14, 0x0_u8, x5, x9); + let mut x15: u64 = 0; + let mut x16: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x15, &mut x16, x14, x7, x11); + let mut x17: u64 = 0; + let mut x18: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x17, &mut x18, x16, ((x8 as u64) + x4), x12); + let mut x19: u64 = 0; + let mut x20: u64 = 0; + fp128_mulx_u64(&mut x19, &mut x20, x1, 0x5587_u64); + let mut x21: u64 = 0; + let mut x22: u64 = 0; + fp128_mulx_u64(&mut x21, &mut x22, x1, 0xfffffffffffffcf1_u64); + let mut x23: u64 = 0; + let mut x24: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x23, &mut x24, 0x0_u8, x22, x19); + let mut x25: u64 = 0; + let mut x26: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x25, &mut x26, 0x0_u8, x15, x21); + let mut x27: u64 = 0; + let mut x28: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x27, &mut x28, x26, x17, x23); + let mut x29: u64 = 0; + let mut x30: u64 = 0; + fp128_mulx_u64(&mut x29, &mut x30, x25, 0xffffffffffffffff_u64); + let mut x31: u64 = 0; + let mut x32: u64 = 0; + fp128_mulx_u64(&mut x31, &mut x32, x29, 0xffffffffffffffe4_u64); + let mut x33: u64 = 0; + let mut x34: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x33, &mut x34, 0x0_u8, x25, x29); + let mut x35: u64 = 0; + let mut x36: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x35, &mut x36, x34, x27, x31); + let mut x37: u64 = 0; + let mut x38: Fp128U1 = 0; + fp128_addcarryx_u64(&mut x37, &mut x38, x36, (((x28 as u64) + (x18 as u64)) + ((x24 as u64) + x20)), x32); + let mut x39: u64 = 0; + let mut x40: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x39, &mut x40, 0x0_u8, x35, (0x1_u8 as u64)); + let mut x41: u64 = 0; + let mut x42: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x41, &mut x42, x40, x37, 0xffffffffffffffe4_u64); + let mut x43: u64 = 0; + let mut x44: Fp128U1 = 0; + fp128_subborrowx_u64(&mut x43, &mut x44, x42, (x38 as u64), (0x0_u8 as u64)); + let mut x45: u64 = 0; + fp128_cmovznz_u64(&mut x45, x44, x39, x35); + let mut x46: u64 = 0; + fp128_cmovznz_u64(&mut x46, x44, x41, x37); + out1[0] = x45; + out1[1] = x46; +} + +/// The function fp128_to_bytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order. +/// +/// Preconditions: +/// 0 ≤ eval arg1 < m +/// Postconditions: +/// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..15] +/// +/// Input Bounds: +/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +/// Output Bounds: +/// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] +#[inline(always)] +pub fn fp128_to_bytes(out1: &mut [u8; 16], arg1: &[u64; 2]) { + let x1: u64 = (arg1[1]); + let x2: u64 = (arg1[0]); + let x3: u8 = ((x2 & (0xff_u8 as u64)) as u8); + let x4: u64 = (x2 >> 8); + let x5: u8 = ((x4 & (0xff_u8 as u64)) as u8); + let x6: u64 = (x4 >> 8); + let x7: u8 = ((x6 & (0xff_u8 as u64)) as u8); + let x8: u64 = (x6 >> 8); + let x9: u8 = ((x8 & (0xff_u8 as u64)) as u8); + let x10: u64 = (x8 >> 8); + let x11: u8 = ((x10 & (0xff_u8 as u64)) as u8); + let x12: u64 = (x10 >> 8); + let x13: u8 = ((x12 & (0xff_u8 as u64)) as u8); + let x14: u64 = (x12 >> 8); + let x15: u8 = ((x14 & (0xff_u8 as u64)) as u8); + let x16: u8 = ((x14 >> 8) as u8); + let x17: u8 = ((x1 & (0xff_u8 as u64)) as u8); + let x18: u64 = (x1 >> 8); + let x19: u8 = ((x18 & (0xff_u8 as u64)) as u8); + let x20: u64 = (x18 >> 8); + let x21: u8 = ((x20 & (0xff_u8 as u64)) as u8); + let x22: u64 = (x20 >> 8); + let x23: u8 = ((x22 & (0xff_u8 as u64)) as u8); + let x24: u64 = (x22 >> 8); + let x25: u8 = ((x24 & (0xff_u8 as u64)) as u8); + let x26: u64 = (x24 >> 8); + let x27: u8 = ((x26 & (0xff_u8 as u64)) as u8); + let x28: u64 = (x26 >> 8); + let x29: u8 = ((x28 & (0xff_u8 as u64)) as u8); + let x30: u8 = ((x28 >> 8) as u8); + out1[0] = x3; + out1[1] = x5; + out1[2] = x7; + out1[3] = x9; + out1[4] = x11; + out1[5] = x13; + out1[6] = x15; + out1[7] = x16; + out1[8] = x17; + out1[9] = x19; + out1[10] = x21; + out1[11] = x23; + out1[12] = x25; + out1[13] = x27; + out1[14] = x29; + out1[15] = x30; +} + +/// The function fp128_from_bytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order. +/// +/// Preconditions: +/// 0 ≤ bytes_eval arg1 < m +/// Postconditions: +/// eval out1 mod m = bytes_eval arg1 mod m +/// 0 ≤ eval out1 < m +/// +/// Input Bounds: +/// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] +/// Output Bounds: +/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +#[inline(always)] +pub fn fp128_from_bytes(out1: &mut [u64; 2], arg1: &[u8; 16]) { + let x1: u64 = (((arg1[15]) as u64) << 56); + let x2: u64 = (((arg1[14]) as u64) << 48); + let x3: u64 = (((arg1[13]) as u64) << 40); + let x4: u64 = (((arg1[12]) as u64) << 32); + let x5: u64 = (((arg1[11]) as u64) << 24); + let x6: u64 = (((arg1[10]) as u64) << 16); + let x7: u64 = (((arg1[9]) as u64) << 8); + let x8: u8 = (arg1[8]); + let x9: u64 = (((arg1[7]) as u64) << 56); + let x10: u64 = (((arg1[6]) as u64) << 48); + let x11: u64 = (((arg1[5]) as u64) << 40); + let x12: u64 = (((arg1[4]) as u64) << 32); + let x13: u64 = (((arg1[3]) as u64) << 24); + let x14: u64 = (((arg1[2]) as u64) << 16); + let x15: u64 = (((arg1[1]) as u64) << 8); + let x16: u8 = (arg1[0]); + let x17: u64 = (x15 + (x16 as u64)); + let x18: u64 = (x14 + x17); + let x19: u64 = (x13 + x18); + let x20: u64 = (x12 + x19); + let x21: u64 = (x11 + x20); + let x22: u64 = (x10 + x21); + let x23: u64 = (x9 + x22); + let x24: u64 = (x7 + (x8 as u64)); + let x25: u64 = (x6 + x24); + let x26: u64 = (x5 + x25); + let x27: u64 = (x4 + x26); + let x28: u64 = (x3 + x27); + let x29: u64 = (x2 + x28); + let x30: u64 = (x1 + x29); + out1[0] = x23; + out1[1] = x30; +} diff --git a/src/field/field128.rs b/src/field/field128.rs new file mode 100644 index 000000000..391cf0be1 --- /dev/null +++ b/src/field/field128.rs @@ -0,0 +1,380 @@ +// Copyright (c) 2023 ISRG +// Copyright (c) 2023 Cloudflare Inc. +// +// SPDX-License-Identifier: MPL-2.0 + +//! Finite field arithmetic for `GF((2^62-2^3+1)*2^66+1)`. + +use super::{ + fiat_crypto_fp128::{ + fp128_add, fp128_from_bytes, fp128_from_montgomery, fp128_mul, fp128_opp, fp128_sub, + fp128_to_bytes, fp128_to_montgomery, Fp128MontgomeryDomainFieldElement, + Fp128NonMontgomeryDomainFieldElement, + }, + FftFriendlyFieldElement, FieldElement, FieldElementVisitor, FieldElementWithInteger, + FieldError, +}; +use crate::codec::{CodecError, Decode, Encode}; +use impl_ops::impl_op; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::{ + convert::{TryFrom, TryInto}, + fmt::{Debug, Display, Formatter}, + hash::{Hash, Hasher}, + io::{Cursor, Read}, + marker::PhantomData, + ops, +}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; + +impl From for u128 { + fn from(x: Fp128NonMontgomeryDomainFieldElement) -> Self { + ((x.0[1] as u128) << 64) | (x.0[0] as u128) + } +} + +impl From for Fp128NonMontgomeryDomainFieldElement { + // This From function tolerates values in the full range of u128, + // those above the prime modulus are reduced modulo p. + fn from(x: u128) -> Self { + let mut v = x; + if x >= FIELD128_PRIME { + v = x % FIELD128_PRIME; + } + Self([v as u64, (v >> 64) as u64]) + } +} + +impl From for Fp128NonMontgomeryDomainFieldElement { + fn from(x: Fp128MontgomeryDomainFieldElement) -> Self { + let mut z = Self(Default::default()); + fp128_from_montgomery(&mut z, &x); + z + } +} + +impl From for Fp128MontgomeryDomainFieldElement { + fn from(x: Fp128NonMontgomeryDomainFieldElement) -> Self { + let mut z = Self(Default::default()); + fp128_to_montgomery(&mut z, &x); + z + } +} + +impl From for u128 { + fn from(x: Fp128MontgomeryDomainFieldElement) -> Self { + u128::from(Fp128NonMontgomeryDomainFieldElement::from(x)) + } +} + +impl From for Fp128MontgomeryDomainFieldElement { + fn from(x: u128) -> Self { + Self::from(Fp128NonMontgomeryDomainFieldElement::from(x)) + } +} + +impl PartialEq for Fp128MontgomeryDomainFieldElement { + fn eq(&self, rhs: &Self) -> bool { + self.0[0] == rhs.0[0] && self.0[1] == rhs.0[1] + } +} + +impl Eq for Fp128MontgomeryDomainFieldElement {} + +impl Hash for Fp128MontgomeryDomainFieldElement { + fn hash(&self, state: &mut H) { + self.0.hash(state) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] + +/// Field128 represents an element of the prime field GF((2^62-2^3+1)*2^66+1). +/// +/// Internally, elements use Montgomery representation and its +/// implementation is provided by fiat-crypto tool that produces +/// formally-verified prime field arithmetic. +pub struct Field128(Fp128MontgomeryDomainFieldElement); + +/// safeFpFromConst constructs a Field128 given constant values that +/// represent an element in Montgomery representation. +macro_rules! safeFpFromConst { + ($u0:expr, $u1:expr) => { + Field128(Fp128MontgomeryDomainFieldElement([$u0, $u1])) + }; +} + +impl Default for Field128 { + #[inline(always)] + fn default() -> Self { + safeFpFromConst!(u64::default(), u64::default()) // returns zero. + } +} + +impl From for Field128 { + #[inline(always)] + fn from(x: Fp128MontgomeryDomainFieldElement) -> Self { + Self(x) + } +} + +impl ConstantTimeEq for Field128 { + #[inline(always)] + fn ct_eq(&self, rhs: &Self) -> Choice { + u64::ct_eq(&self.0[0], &rhs.0[0]) & u64::ct_eq(&self.0[1], &rhs.0[1]) + } +} + +impl ConditionallySelectable for Field128 { + #[inline(always)] + fn conditional_select(a: &Self, b: &Self, c: Choice) -> Self { + safeFpFromConst!( + u64::conditional_select(&a.0[0], &b.0[0], c), + u64::conditional_select(&a.0[1], &b.0[1], c) + ) + } +} + +impl_op!(-|a: Field128| -> Field128 { + let mut out = Self::default(); + fp128_opp(&mut out.0, &a.0); + out +}); + +impl_op!(+|a:Field128, b:Field128| -> Field128 { + let mut out = Self::default(); + fp128_add(&mut out.0, &a.0, &b.0); + out +}); + +impl_op!(-|a: Field128, b: Field128| -> Field128 { + let mut out = Self::default(); + fp128_sub(&mut out.0, &a.0, &b.0); + out +}); + +impl_op!(*|a: Field128, b: Field128| -> Field128 { + let mut out = Self::default(); + fp128_mul(&mut out.0, &a.0, &b.0); + out +}); + +impl_op!(/|a: Field128, b: Field128| -> Field128 { a * b.inv() }); + +impl_op!(-|a: &Field128| -> Field128 { -(*a) }); +impl_op!(+|a: &Field128, b: &Field128| -> Field128 { *a + *b }); +impl_op!(-|a: &Field128, b: &Field128| -> Field128 { *a - *b }); +impl_op!(*|a: &Field128, b: &Field128| -> Field128 { *a * *b }); +impl_op!(/|a: &Field128, b: &Field128| -> Field128 { *a / *b }); + +impl_op!(+= |a:&mut Field128, b:Field128| {*a = *a + b}); +impl_op!(-= |a:&mut Field128, b:Field128| {*a = *a - b}); +impl_op!(*= |a:&mut Field128, b:Field128| {*a = *a * b}); +impl_op!(/= |a:&mut Field128, b:Field128| {*a = *a / b}); + +impl From for Field128 { + fn from(x: u128) -> Self { + Self::from(Fp128MontgomeryDomainFieldElement::from(x)) + } +} + +impl From for u128 { + fn from(x: Field128) -> Self { + u128::from(Fp128NonMontgomeryDomainFieldElement::from(x.0)) + } +} + +impl<'a> TryFrom<&'a [u8]> for Field128 { + type Error = FieldError; + fn try_from(bytes: &[u8]) -> Result { + let array: [u8; FIELD128_ENCODED_SIZE] = + bytes.try_into().map_err(|_| FieldError::ShortRead)?; + + if u128::from_le_bytes(array) >= FIELD128_PRIME { + return Err(FieldError::ModulusOverflow); + } + + let mut non_mont = Fp128NonMontgomeryDomainFieldElement(Default::default()); + fp128_from_bytes(&mut non_mont.0, &array); + Ok(Field128(Fp128MontgomeryDomainFieldElement::from(non_mont))) + } +} + +impl From for [u8; FIELD128_ENCODED_SIZE] { + fn from(elem: Field128) -> Self { + let mut slice = Self::default(); + let non_mont: Fp128NonMontgomeryDomainFieldElement = elem.0.into(); + fp128_to_bytes(&mut slice, &non_mont.0); + slice + } +} + +impl From for Vec { + fn from(elem: Field128) -> Self { + <[u8; FIELD128_ENCODED_SIZE]>::from(elem).to_vec() + } +} + +impl Display for Field128 { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + write!(f, "{}", u128::from(*self)) + } +} + +impl Debug for Field128 { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", u128::from(*self)) + } +} + +impl Serialize for Field128 { + fn serialize(&self, serializer: S) -> Result { + let bytes: [u8; FIELD128_ENCODED_SIZE] = (*self).into(); + serializer.serialize_bytes(&bytes) + } +} + +impl<'de> Deserialize<'de> for Field128 { + fn deserialize>(deserializer: D) -> Result { + deserializer.deserialize_bytes(FieldElementVisitor { + phantom: PhantomData, + }) + } +} + +impl Encode for Field128 { + fn encode(&self, bytes: &mut Vec) { + let slice = <[u8; FIELD128_ENCODED_SIZE]>::from(*self); + bytes.extend_from_slice(&slice); + } + + fn encoded_len(&self) -> Option { + Some(FIELD128_ENCODED_SIZE) + } +} + +impl Decode for Field128 { + fn decode(bytes: &mut Cursor<&[u8]>) -> Result { + let mut value = [0u8; FIELD128_ENCODED_SIZE]; + bytes.read_exact(&mut value)?; + Field128::try_from(value.as_slice()).map_err(|e| { + CodecError::Other(Box::new(e) as Box) + }) + } +} + +impl FieldElement for Field128 { + const ENCODED_SIZE: usize = FIELD128_ENCODED_SIZE; + + fn inv(&self) -> Self { + self.pow(FIELD128_PRIME - 2) + } + + fn try_from_random(bytes: &[u8]) -> Result { + Field128::try_from(bytes) + } + + fn zero() -> Self { + Self::default() + } + + fn one() -> Self { + // By definition, FIELD128_UROOTS[0] = 1. + FIELD128_UROOTS[0] + } +} + +impl FieldElementWithInteger for Field128 { + type Integer = u128; + type IntegerTryFromError = >::Error; + type TryIntoU64Error = >::Error; + + // pow is a non-constant-time operation with respect to the bits of the exponent. + fn pow(&self, exp: Self::Integer) -> Self { + let mut t = Self::one(); + for i in (0..u128::BITS - exp.leading_zeros()).rev() { + t *= t; + if (exp >> i) & 1 != 0 { + t *= *self; + } + } + t + } + + fn modulus() -> Self::Integer { + FIELD128_PRIME + } +} + +impl FftFriendlyFieldElement for Field128 { + fn generator() -> Self { + FIELD128_PRIMITIVE_UROOT + } + + fn generator_order() -> Self::Integer { + 1 << FIELD128_NUM_UROOTS + } + + fn root(l: usize) -> Option { + if l < FIELD128_UROOTS.len() { + Some(FIELD128_UROOTS[l]) + } else { + None + } + } +} + +/// The prime modulus `p=(2^62-2^3+1)*2^66+1`. +const FIELD128_PRIME: u128 = 340282366920938462946865773367900766209; + +/// Size in bytes used to store a Field128 element. +const FIELD128_ENCODED_SIZE: usize = 16; + +/// The `2^num_roots`-th -principal root of unity. This element is used to generate the +/// elements of `roots`. +/// +/// In sage this is calculated as: +/// PRIMITIVE_UROOT = GF(p).primitive_element()^(2^62-2^3+1) +/// = 7^(2^62-2^3+1) +/// = 145091266659756586618791329697897684742 +/// Then, converted to Montgomery domain with R=2^128. +/// toMont = lambda x: x*2**128 +/// FIELD128_PRIMITIVE_UROOT = toMont(PRIMITIVE_UROOT) +/// = 0x50f8f7f554db309cf0111fb98c6b9875 +static FIELD128_PRIMITIVE_UROOT: Field128 = + safeFpFromConst!(0xf0111fb98c6b9875, 0x50f8f7f554db309c); + +/// The number of principal roots of unity in `roots`. +const FIELD128_NUM_UROOTS: usize = 66; + +/// `FIELD128_UROOTS[l]` is the `2^l`-th principal root of unity, i.e., `roots[l]` has order `2^l` in the +/// multiplicative group. `roots[0]` is equal to one by definition. +/// +/// In sage this is calculated as: +/// PRIMITIVE_UROOT = GF(p).primitive_element()^(2^62-2^3+1) +/// toMont = lambda x: x*2**128 +/// toHex = lambda x: list(map(hex, ZZ(x).digits(2**64))) +/// FIELD128_UROOTS = [ toHex(toMont(PRIMITIVE_UROOT**(2**i))) for i in range(66,66-21,-1) ] +static FIELD128_UROOTS: [Field128; 20 + 1] = [ + safeFpFromConst!(0xffffffffffffffff, 0x000000000000001b), + safeFpFromConst!(0x0000000000000002, 0xffffffffffffffc8), + safeFpFromConst!(0x8ff94ea745b7d9d6, 0x6171e408747992c7), + safeFpFromConst!(0x1323bb095fba9556, 0x7f2a4e6655e5a49c), + safeFpFromConst!(0xd1c455956aafabfc, 0x3d661493c5e89442), + safeFpFromConst!(0x416d53fbcdfcc65c, 0x5c159e1cffd5eca0), + safeFpFromConst!(0x1428d15e766f5f3e, 0x960d5c8696ec3aa3), + safeFpFromConst!(0x8f0cef59f8c23f3e, 0xcce83f596bb28730), + safeFpFromConst!(0x432d8d01ae187081, 0x12b496afe629224c), + safeFpFromConst!(0x0edc26fa686e3d3b, 0xc2026e57b1554ea9), + safeFpFromConst!(0x79663ccecfe8c86c, 0xf38c95d1e57405ea), + safeFpFromConst!(0xfecc377cf0f47a9f, 0x2b486d42d73283bd), + safeFpFromConst!(0x0ab1068497116540, 0x70866815dbf52bac), + safeFpFromConst!(0x2d9420dc5196c01a, 0x852c9b234b09c7df), + safeFpFromConst!(0x1a491a6cf3399115, 0xca4b831e2e621692), + safeFpFromConst!(0xb99152aabeebd757, 0xb7fbf514f82e2269), + safeFpFromConst!(0xb8da2f851dfd594a, 0x597c0e93a246d640), + safeFpFromConst!(0xf2888c210ef9f1c4, 0x97f929a5d52ab886), + safeFpFromConst!(0xe6a0ccbc956fc7fb, 0xfa4748aea960d0eb), + safeFpFromConst!(0xe53d6d96e1ec92a0, 0xc24ed95c3c013bcc), + safeFpFromConst!(0x6cc6e9129e1679c0, 0x6f825f88648b270c), +]; diff --git a/src/fp.rs b/src/fp.rs index d4c0dcdc2..364d46b99 100644 --- a/src/fp.rs +++ b/src/fp.rs @@ -388,38 +388,6 @@ pub(crate) const FP64: FieldParameters = FieldParameters { ], }; -pub(crate) const FP128: FieldParameters = FieldParameters { - p: 340282366920938462946865773367900766209, // 128-bit prime - mu: 18446744073709551615, - r2: 403909908237944342183153, - g: 107630958476043550189608038630704257141, - num_roots: 66, - bit_mask: 340282366920938463463374607431768211455, - roots: [ - 516508834063867445247, - 340282366920938462430356939304033320962, - 129526470195413442198896969089616959958, - 169031622068548287099117778531474117974, - 81612939378432101163303892927894236156, - 122401220764524715189382260548353967708, - 199453575871863981432000940507837456190, - 272368408887745135168960576051472383806, - 24863773656265022616993900367764287617, - 257882853788779266319541142124730662203, - 323732363244658673145040701829006542956, - 57532865270871759635014308631881743007, - 149571414409418047452773959687184934208, - 177018931070866797456844925926211239962, - 268896136799800963964749917185333891349, - 244556960591856046954834420512544511831, - 118945432085812380213390062516065622346, - 202007153998709986841225284843501908420, - 332677126194796691532164818746739771387, - 258279638927684931537542082169183965856, - 148221243758794364405224645520862378432, - ], -}; - // Compute the ceiling of the base-2 logarithm of `x`. pub(crate) fn log2(x: u128) -> u128 { let y = (127 - x.leading_zeros()) as u128; @@ -467,12 +435,6 @@ mod tests { expected_g: 1753635133440165772, expected_order: 1 << 32, }, - TestFieldParametersData { - fp: FP128, - expected_p: 340282366920938462946865773367900766209, - expected_g: 145091266659756586618791329697897684742, - expected_order: 1 << 66, - }, ]; for t in test_fps.into_iter() { diff --git a/src/lib.rs b/src/lib.rs index c9d4e22c4..dc82d2bfb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,9 @@ //! //! [vdaf]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/05/ +#[macro_use] +extern crate impl_ops; + pub mod benchmarked; pub mod codec; #[cfg(feature = "experimental")]