Skip to content

Commit

Permalink
Move fields into its own crate (#106)
Browse files Browse the repository at this point in the history
* Create new crate `mpz-fields` and move `mpc-share-conversion-core/fields`.

* Adapt `mpz` to refactoring

* Remove unnecessary dependencies
  • Loading branch information
th4s authored Mar 4, 2024
1 parent 5f376ca commit f5911bc
Show file tree
Hide file tree
Showing 18 changed files with 99 additions and 82 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ members = [
"ot/*",
"mpz-circuits",
"mpz-circuits-macros",
"mpz-fields",
"share-conversion/*",
"matrix-transpose",
"clmul",
Expand All @@ -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" }

Expand Down
27 changes: 27 additions & 0 deletions mpz-fields/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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| {
Expand Down
Original file line number Diff line number Diff line change
@@ -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};

Expand All @@ -10,22 +10,22 @@ 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);

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
}
Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -161,17 +161,16 @@ 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,
};
use ghash_rc::{
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() {
Expand All @@ -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);

Expand All @@ -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);
Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<Output = Self>
+ Mul<Output = Self>
Expand All @@ -32,34 +36,34 @@ pub trait Field:
+ GetBit<Msb0>
+ 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<u8>;

/// Return field element as big-endian bytes
/// Return field element as big-endian bytes.
fn to_be_bytes(&self) -> Vec<u8>;
}

/// 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<R: Rng + ?Sized>(rng: &mut R) -> Self;
}

Expand All @@ -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<T: Field>(powers: &mut Vec<T>, factor: T, count: usize) {
for _ in 0..count {
let last_power = *powers
Expand All @@ -94,11 +98,11 @@ pub fn compute_product_repeated<T: Field>(powers: &mut Vec<T>, 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<T: Field>() {
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();
Expand All @@ -113,7 +117,7 @@ mod tests {
}

pub(crate) fn test_field_compute_product_repeated<T: Field>() {
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];
Expand Down
Original file line number Diff line number Diff line change
@@ -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};

Expand All @@ -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]")]
Expand Down Expand Up @@ -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() {
Expand All @@ -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());
Expand Down
14 changes: 1 addition & 13 deletions share-conversion/mpz-share-conversion-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 1 addition & 3 deletions share-conversion/mpz-share-conversion-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
3 changes: 2 additions & 1 deletion share-conversion/mpz-share-conversion-core/src/msgs.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down
2 changes: 1 addition & 1 deletion share-conversion/mpz-share-conversion-core/src/shares.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down
Loading

0 comments on commit f5911bc

Please sign in to comment.