diff --git a/Cargo.toml b/Cargo.toml index a4bb9768..809e5b3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "ot/*", "mpz-circuits", "mpz-circuits-macros", + "mpz-fields", "share-conversion/*", "matrix-transpose", "clmul", @@ -19,6 +20,7 @@ mpz-garble-core = { path = "garble/mpz-garble-core" } mpz-garble = { path = "garble/mpz-garble" } mpz-share-conversion-core = { path = "share-conversion/mpz-share-conversion-core" } mpz-share-conversion = { path = "share-conversion/mpz-share-conversion" } +mpz-fields = { path = "mpz-fields" } clmul = { path = "clmul" } matrix-transpose = { path = "matrix-transpose" } diff --git a/mpz-fields/Cargo.toml b/mpz-fields/Cargo.toml new file mode 100644 index 00000000..f68ef65a --- /dev/null +++ b/mpz-fields/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "mpz-fields" +version = "0.1.0" +edition = "2021" + +[lib] +name = "mpz_fields" + +[dependencies] +mpz-core.workspace = true + +rand.workspace = true +ark-ff.workspace = true +ark-secp256r1.workspace = true +ark-serialize.workspace = true +num-bigint.workspace = true +opaque-debug.workspace = true +serde.workspace = true +itybity.workspace = true + +[dev-dependencies] +ghash_rc.workspace = true +criterion.workspace = true + +[[bench]] +name = "inverse_gf2_128" +harness = false diff --git a/share-conversion/mpz-share-conversion-core/benches/inverse_gf2_128.rs b/mpz-fields/benches/inverse_gf2_128.rs similarity index 72% rename from share-conversion/mpz-share-conversion-core/benches/inverse_gf2_128.rs rename to mpz-fields/benches/inverse_gf2_128.rs index 930ec8a8..0c5c9dd1 100644 --- a/share-conversion/mpz-share-conversion-core/benches/inverse_gf2_128.rs +++ b/mpz-fields/benches/inverse_gf2_128.rs @@ -1,10 +1,10 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use mpz_share_conversion_core::fields::{gf2_128::Gf2_128, Field}; +use mpz_core::{prg::Prg, Block}; +use mpz_fields::{gf2_128::Gf2_128, Field}; use rand::{Rng, SeedableRng}; -use rand_chacha::ChaCha12Rng; fn bench_gf2_128_inverse(c: &mut Criterion) { - let mut rng = ChaCha12Rng::seed_from_u64(0); + let mut rng = Prg::from_seed(Block::ZERO); let a: Gf2_128 = rng.gen(); c.bench_function("inverse", move |bench| { diff --git a/share-conversion/mpz-share-conversion-core/src/fields/gf2_128.rs b/mpz-fields/src/gf2_128.rs similarity index 87% rename from share-conversion/mpz-share-conversion-core/src/fields/gf2_128.rs rename to mpz-fields/src/gf2_128.rs index d5b1214a..77d13ff4 100644 --- a/share-conversion/mpz-share-conversion-core/src/fields/gf2_128.rs +++ b/mpz-fields/src/gf2_128.rs @@ -1,4 +1,4 @@ -//! This module implements the extension field GF(2^128) +//! This module implements the extension field GF(2^128). use std::ops::{Add, Mul, Neg}; @@ -10,7 +10,7 @@ use mpz_core::Block; use super::Field; -/// A type for holding field elements of Gf(2^128) +/// A type for holding field elements of Gf(2^128). #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)] pub struct Gf2_128(pub(crate) u128); @@ -18,14 +18,14 @@ opaque_debug::implement!(Gf2_128); impl Gf2_128 { /// Creates a new field element from a u128, - /// mapping the integer to the corresponding polynomial + /// mapping the integer to the corresponding polynomial. /// - /// For example, 5u128 is mapped to the polynomial `1 + x^2` + /// For example, 5u128 is mapped to the polynomial `1 + x^2`. pub fn new(input: u128) -> Self { Gf2_128(input) } - /// Returns the field element as a u128 + /// Returns the field element as a u128. pub fn to_inner(self) -> u128 { self.0 } @@ -61,14 +61,14 @@ impl Add for Gf2_128 { impl Mul for Gf2_128 { type Output = Self; - /// Galois field multiplication of two 128-bit blocks reduced by the GCM polynomial + /// Galois field multiplication of two 128-bit blocks reduced by the GCM polynomial. fn mul(self, rhs: Self) -> Self::Output { - // See NIST SP 800-38D, Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC + // See NIST SP 800-38D, Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC. // // Note that the NIST specification uses a different representation of the polynomial, where the bits are - // reversed. This "bit reflection" is discussed in Intel® Carry-Less Multiplication Instruction and its Usage for Computing the GCM Mode + // reversed. This "bit reflection" is discussed in Intel® Carry-Less Multiplication Instruction and its Usage for Computing the GCM Mode. // - // The irreducible polynomial is the same, ie `x^128 + x^7 + x^2 + x + 1` + // The irreducible polynomial is the same, ie `x^128 + x^7 + x^2 + x + 1`. const R: u128 = 0x00000000000000000000000000000087; @@ -78,7 +78,7 @@ impl Mul for Gf2_128 { // https://en.wikipedia.org/wiki/Finite_field_arithmetic#C_programming_example // - // TODO: Use RustCrypto polyval crate + // TODO: Use RustCrypto polyval crate. while (x != 0) && (y != 0) { z ^= (y & 1) * x; x = (x << 1) ^ ((x >> 127) * R); @@ -112,7 +112,7 @@ impl Field for Gf2_128 { Self(1 << rhs) } - /// Galois field inversion of 128-bit block + /// Galois field inversion of 128-bit block. fn inverse(self) -> Self { let mut a = self; let mut out = Self::one(); @@ -161,7 +161,7 @@ impl FromBitIterator for Gf2_128 { #[cfg(test)] mod tests { use super::Gf2_128; - use crate::fields::{ + use crate::{ tests::{test_field_basic, test_field_bit_ops, test_field_compute_product_repeated}, Field, }; @@ -169,9 +169,8 @@ mod tests { universal_hash::{NewUniversalHash, UniversalHash}, GHash, }; - use mpz_core::Block; + use mpz_core::{prg::Prg, Block}; use rand::SeedableRng; - use rand_chacha::ChaCha12Rng; #[test] fn test_gf2_128_basic() { @@ -192,15 +191,15 @@ mod tests { #[test] fn test_gf2_128_mul() { - // Naive multiplication is the same here + // Naive multiplication is the same here. let a = Gf2_128::new(3); let b = Gf2_128::new(5); - // Here we cannot calculate naively + // Here we cannot calculate naively. let c = Gf2_128::new(3); let d = Gf2_128::new(7); - // Test vector from Intel® Carry-Less Multiplication Instruction and its Usage for Computing the GCM Mode + // Test vector from Intel® Carry-Less Multiplication Instruction and its Usage for Computing the GCM Mode. let e = Gf2_128::new(0x7b5b54657374566563746f725d53475d); let f = Gf2_128::new(0x48692853686179295b477565726f6e5d); @@ -211,9 +210,9 @@ mod tests { } #[test] - // Test multiplication against RustCrypto + // Test multiplication against RustCrypto. fn test_gf2_128_against_ghash_impl() { - let mut rng = ChaCha12Rng::seed_from_u64(0); + let mut rng = Prg::from_seed(Block::ZERO); let a = Block::random(&mut rng); let b = Block::random(&mut rng); @@ -223,7 +222,7 @@ mod tests { let expected = Block::from(g.finalize().into_bytes()); // GHASH reverses the bits of the blocks before performing multiplication - // then reverses the output + // then reverses the output. let a: Gf2_128 = a.reverse_bits().into(); let b: Gf2_128 = b.reverse_bits().into(); let output: Block = (a * b).into(); diff --git a/share-conversion/mpz-share-conversion-core/src/fields/mod.rs b/mpz-fields/src/lib.rs similarity index 79% rename from share-conversion/mpz-share-conversion-core/src/fields/mod.rs rename to mpz-fields/src/lib.rs index 66152622..bfd34d7d 100644 --- a/share-conversion/mpz-share-conversion-core/src/fields/mod.rs +++ b/mpz-fields/src/lib.rs @@ -1,4 +1,8 @@ -//! Types for working with finite fields +//! This crate provides types for working with finite fields. + +#![deny(missing_docs, unreachable_pub, unused_must_use)] +#![deny(clippy::all)] +#![forbid(unsafe_code)] pub mod gf2_128; pub mod p256; @@ -11,7 +15,7 @@ use std::{ use itybity::{BitLength, FromBitIterator, GetBit, Lsb0, Msb0}; use rand::{distributions::Standard, prelude::Distribution, Rng}; -/// A trait for finite fields +/// A trait for finite fields. pub trait Field: Add + Mul @@ -32,34 +36,34 @@ pub trait Field: + GetBit + BitLength { - /// The number of bits of a field element + /// The number of bits of a field element. const BIT_SIZE: u32; - /// Return the additive identity element + /// Return the additive identity element. fn zero() -> Self; - /// Return the multiplicative identity element + /// Return the multiplicative identity element. fn one() -> Self; /// Return a field element from a power of two. fn two_pow(rhs: u32) -> Self; - /// Return the multiplicative inverse + /// Return the multiplicative inverse. fn inverse(self) -> Self; - /// Return field element as little-endian bytes + /// Return field element as little-endian bytes. fn to_le_bytes(&self) -> Vec; - /// Return field element as big-endian bytes + /// Return field element as big-endian bytes. fn to_be_bytes(&self) -> Vec; } -/// A trait for sampling random elements of the field +/// A trait for sampling random elements of the field. /// /// This is helpful, because we do not need to import other traits since this is a supertrait of -/// field (which is not possible with `Standard` and `Distribution`) +/// field (which is not possible with `Standard` and `Distribution`). pub trait UniformRand: Sized { - /// Return a random field element + /// Return a random field element. fn rand(rng: &mut R) -> Self; } @@ -73,14 +77,14 @@ where } } -/// Iteratively multiplies some field element with another field element +/// Iteratively multiplies some field element with another field element. /// /// This function multiplies the last element in `powers` with some other field element `factor` /// and appends the result to `powers`. This process is repeated `count` times. /// -/// * `powers` - The vector to which the new higher powers get pushed -/// * `factor` - The field element with which the last element of the vector is multiplied -/// * `count` - How many products are computed +/// * `powers` - The vector to which the new higher powers get pushed. +/// * `factor` - The field element with which the last element of the vector is multiplied. +/// * `count` - How many products are computed. pub fn compute_product_repeated(powers: &mut Vec, factor: T, count: usize) { for _ in 0..count { let last_power = *powers @@ -94,11 +98,11 @@ pub fn compute_product_repeated(powers: &mut Vec, factor: T, count: mod tests { use super::{compute_product_repeated, Field}; use itybity::{GetBit, Lsb0}; + use mpz_core::{prg::Prg, Block}; use rand::SeedableRng; - use rand_chacha::ChaCha12Rng; pub(crate) fn test_field_basic() { - let mut rng = ChaCha12Rng::from_seed([0; 32]); + let mut rng = Prg::from_seed(Block::ZERO); let a = T::rand(&mut rng); let zero = T::zero(); @@ -113,7 +117,7 @@ mod tests { } pub(crate) fn test_field_compute_product_repeated() { - let mut rng = ChaCha12Rng::from_seed([0; 32]); + let mut rng = Prg::from_seed(Block::ZERO); let a = T::rand(&mut rng); let mut powers = vec![a]; diff --git a/share-conversion/mpz-share-conversion-core/src/fields/p256.rs b/mpz-fields/src/p256.rs similarity index 93% rename from share-conversion/mpz-share-conversion-core/src/fields/p256.rs rename to mpz-fields/src/p256.rs index 5a633dc6..f9f1603e 100644 --- a/share-conversion/mpz-share-conversion-core/src/fields/p256.rs +++ b/mpz-fields/src/p256.rs @@ -1,4 +1,4 @@ -//! This module implements the prime field of P256 +//! This module implements the prime field of P256. use std::ops::{Add, Mul, Neg}; @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; use super::Field; -/// A type for holding field elements of P256 +/// A type for holding field elements of P256. #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)] #[serde(into = "[u8; 32]")] #[serde(try_from = "[u8; 32]")] @@ -140,13 +140,11 @@ impl FromBitIterator for P256 { #[cfg(test)] mod tests { - use rand::{Rng, SeedableRng}; - use super::*; + use mpz_core::{prg::Prg, Block}; + use rand::{Rng, SeedableRng}; - use crate::fields::tests::{ - test_field_basic, test_field_bit_ops, test_field_compute_product_repeated, - }; + use crate::tests::{test_field_basic, test_field_bit_ops, test_field_compute_product_repeated}; #[test] fn test_p256_basic() { @@ -167,7 +165,7 @@ mod tests { #[test] fn test_p256_serialize() { - let mut rng = rand_chacha::ChaCha20Rng::from_seed([0; 32]); + let mut rng = Prg::from_seed(Block::ZERO); for _ in 0..32 { let a = P256(rng.gen()); diff --git a/share-conversion/mpz-share-conversion-core/Cargo.toml b/share-conversion/mpz-share-conversion-core/Cargo.toml index 95595c1c..91d2f1e8 100644 --- a/share-conversion/mpz-share-conversion-core/Cargo.toml +++ b/share-conversion/mpz-share-conversion-core/Cargo.toml @@ -7,24 +7,12 @@ edition = "2021" name = "mpz_share_conversion_core" [dependencies] -mpz-core.workspace = true +mpz-fields.workspace = true -thiserror.workspace = true rand.workspace = true -ark-ff.workspace = true -ark-secp256r1.workspace = true -ark-serialize.workspace = true -num-bigint.workspace = true -opaque-debug.workspace = true serde.workspace = true itybity.workspace = true [dev-dependencies] rstest.workspace = true rand_chacha.workspace = true -ghash_rc.workspace = true -criterion.workspace = true - -[[bench]] -name = "inverse_gf2_128" -harness = false diff --git a/share-conversion/mpz-share-conversion-core/src/lib.rs b/share-conversion/mpz-share-conversion-core/src/lib.rs index a17a2fb9..3082d793 100644 --- a/share-conversion/mpz-share-conversion-core/src/lib.rs +++ b/share-conversion/mpz-share-conversion-core/src/lib.rs @@ -18,16 +18,14 @@ #![deny(clippy::all)] #![deny(unsafe_code)] -pub mod fields; pub mod msgs; mod shares; -pub use fields::Field; pub use shares::{AddShare, MulShare, Share, ShareType}; #[cfg(test)] mod tests { - use crate::fields::{gf2_128::Gf2_128, p256::P256}; + use mpz_fields::{gf2_128::Gf2_128, p256::P256, Field}; use std::marker::PhantomData; diff --git a/share-conversion/mpz-share-conversion-core/src/msgs.rs b/share-conversion/mpz-share-conversion-core/src/msgs.rs index ee3dd1b1..150b3df6 100644 --- a/share-conversion/mpz-share-conversion-core/src/msgs.rs +++ b/share-conversion/mpz-share-conversion-core/src/msgs.rs @@ -1,6 +1,7 @@ //! Message types used in share conversion protocols -use crate::{Field, Share}; +use crate::Share; +use mpz_fields::Field; use serde::{Deserialize, Serialize}; diff --git a/share-conversion/mpz-share-conversion-core/src/shares.rs b/share-conversion/mpz-share-conversion-core/src/shares.rs index 6868a417..284ff3f4 100644 --- a/share-conversion/mpz-share-conversion-core/src/shares.rs +++ b/share-conversion/mpz-share-conversion-core/src/shares.rs @@ -1,6 +1,6 @@ //! Types for representing shares of field elements. -use crate::fields::Field; +use mpz_fields::Field; use itybity::IntoBits; use rand::{CryptoRng, Rng}; diff --git a/share-conversion/mpz-share-conversion/Cargo.toml b/share-conversion/mpz-share-conversion/Cargo.toml index 46d5af6a..e9a7a51b 100644 --- a/share-conversion/mpz-share-conversion/Cargo.toml +++ b/share-conversion/mpz-share-conversion/Cargo.toml @@ -11,12 +11,14 @@ default = ["mock"] mock = [] [dependencies] -thiserror.workspace = true mpz-ot.workspace = true mpz-core.workspace = true mpz-share-conversion-core.workspace = true +mpz-fields.workspace = true + tlsn-utils-aio.workspace = true +thiserror.workspace = true async-trait.workspace = true rand.workspace = true rand_chacha.workspace = true diff --git a/share-conversion/mpz-share-conversion/src/converter.rs b/share-conversion/mpz-share-conversion/src/converter.rs index 47671701..ce976d0f 100644 --- a/share-conversion/mpz-share-conversion/src/converter.rs +++ b/share-conversion/mpz-share-conversion/src/converter.rs @@ -1,7 +1,8 @@ use std::sync::{Arc, Weak}; use async_trait::async_trait; -use mpz_share_conversion_core::{Field, Share}; +use mpz_fields::Field; +use mpz_share_conversion_core::Share; use crate::{ AdditiveToMultiplicative, GilboaReceiver, GilboaSender, MultiplicativeToAdditive, diff --git a/share-conversion/mpz-share-conversion/src/lib.rs b/share-conversion/mpz-share-conversion/src/lib.rs index 9dfbe808..a4ce915d 100644 --- a/share-conversion/mpz-share-conversion/src/lib.rs +++ b/share-conversion/mpz-share-conversion/src/lib.rs @@ -29,10 +29,8 @@ pub use converter::{ ConverterReceiver, ConverterReceiverHandle, ConverterSender, ConverterSenderHandle, }; pub use error::{ShareConversionError, TapeVerificationError}; -pub use mpz_share_conversion_core::{ - fields::{gf2_128::Gf2_128, p256::P256, Field}, - msgs::ShareConversionMessage, -}; +pub use mpz_fields::{gf2_128::Gf2_128, p256::P256, Field}; +pub use mpz_share_conversion_core::msgs::ShareConversionMessage; pub use ot::{OTReceiveElement, OTSendElement}; pub use receiver::GilboaReceiver; pub use sender::GilboaSender; @@ -98,11 +96,9 @@ mod tests { use std::marker::PhantomData; + use mpz_fields::{gf2_128::Gf2_128, p256::P256}; use mpz_ot::ideal::{ideal_ot_shared_pair, IdealSharedOTReceiver, IdealSharedOTSender}; - use mpz_share_conversion_core::{ - fields::{gf2_128::Gf2_128, p256::P256}, - ShareType, - }; + use mpz_share_conversion_core::ShareType; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; diff --git a/share-conversion/mpz-share-conversion/src/mock.rs b/share-conversion/mpz-share-conversion/src/mock.rs index 23e06ce9..701b0ca4 100644 --- a/share-conversion/mpz-share-conversion/src/mock.rs +++ b/share-conversion/mpz-share-conversion/src/mock.rs @@ -3,8 +3,8 @@ use crate::{OTReceiveElement, OTSendElement}; use super::{ConverterReceiver, ConverterSender, ReceiverConfig, SenderConfig}; +use mpz_fields::Field; use mpz_ot::ideal::{ideal_ot_shared_pair, IdealSharedOTReceiver, IdealSharedOTSender}; -use mpz_share_conversion_core::fields::Field; use utils_aio::duplex::MemoryDuplex; /// A mock converter sender diff --git a/share-conversion/mpz-share-conversion/src/ot.rs b/share-conversion/mpz-share-conversion/src/ot.rs index 662a400b..7681dca7 100644 --- a/share-conversion/mpz-share-conversion/src/ot.rs +++ b/share-conversion/mpz-share-conversion/src/ot.rs @@ -1,7 +1,7 @@ use async_trait::async_trait; use mpz_core::Block; -use mpz_share_conversion_core::fields::{gf2_128::Gf2_128, p256::P256, Field}; +use mpz_fields::{gf2_128::Gf2_128, p256::P256, Field}; /// A trait for sending field elements via oblivious transfer. #[async_trait] diff --git a/share-conversion/mpz-share-conversion/src/receiver.rs b/share-conversion/mpz-share-conversion/src/receiver.rs index e50e34d0..b94631b8 100644 --- a/share-conversion/mpz-share-conversion/src/receiver.rs +++ b/share-conversion/mpz-share-conversion/src/receiver.rs @@ -4,8 +4,8 @@ use std::sync::Mutex; use futures::{Stream, StreamExt}; +use mpz_fields::Field; use mpz_share_conversion_core::{ - fields::Field, msgs::{SenderRecordings, ShareConversionMessage}, Share, }; diff --git a/share-conversion/mpz-share-conversion/src/sender.rs b/share-conversion/mpz-share-conversion/src/sender.rs index 2390bd77..2d3c9074 100644 --- a/share-conversion/mpz-share-conversion/src/sender.rs +++ b/share-conversion/mpz-share-conversion/src/sender.rs @@ -6,8 +6,8 @@ use futures::{Sink, SinkExt}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; +use mpz_fields::Field; use mpz_share_conversion_core::{ - fields::Field, msgs::{SenderRecordings, ShareConversionMessage}, Share, }; diff --git a/share-conversion/mpz-share-conversion/src/tape.rs b/share-conversion/mpz-share-conversion/src/tape.rs index 0f4710c2..39aa733b 100644 --- a/share-conversion/mpz-share-conversion/src/tape.rs +++ b/share-conversion/mpz-share-conversion/src/tape.rs @@ -1,6 +1,7 @@ use crate::TapeVerificationError; -use mpz_share_conversion_core::{fields::Field, Share}; +use mpz_fields::Field; +use mpz_share_conversion_core::Share; use rand::SeedableRng; use rand_chacha::ChaCha20Rng;