Skip to content

Commit

Permalink
Merge pull request #40 from martinthomson/prss
Browse files Browse the repository at this point in the history
Outline of a PRSS framework
  • Loading branch information
benjaminsavage authored Jul 12, 2022
2 parents 31a8d4e + 3b1cd82 commit 1853457
Show file tree
Hide file tree
Showing 5 changed files with 676 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ self-signed-certs = ["hyper-tls"]
[dependencies]
axum = { version = "0.5.7", optional = true, features = ["http2"] }
axum-server = { version = "0.4.0", optional = true, features = ["rustls", "rustls-pemfile", "tls-rustls"] }
aes = "0.8"
byteorder = "1"
# rust-elgamal (via curve25519-dalek-ng) only works with digest 0.9, not 0.10
digest = "0.9"
hex = { version = "0.4", optional = true }
Expand All @@ -23,6 +25,9 @@ hkdf = "0.11"
hyper = { version = "0.14.19", optional = true, features = ["client", "h2"] }
hyper-tls = { version = "0.5.0", optional = true }
log = "0.4"
# This is stupid, but we have packages that want this old interface
# those have to use the same RNG as packages that want the new interface.
old_rand_core = { package = "rand_core", version = "0.5", default-features = false }
rand = "0.8"
rand_core = "0.6"
redis = "0.21.5"
Expand All @@ -37,6 +42,7 @@ tokio = { version = "1.19.2", optional = true, features = ["rt", "rt-multi-threa
tower-http = { version = "0.3.4", optional = true, features = ["trace"] }
tracing = "0.1.35"
tracing-subscriber = { version = "0.3.14", optional = true }
x25519-dalek = "1"

[dev-dependencies]
hex = "0.4"
Expand Down
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use thiserror::Error;
pub enum Error {
#[error("already exists")]
AlreadyExists,
#[error("already setup")]
AlreadySetup,
#[error("internal")]
Internal,
#[error("invalid id")]
Expand Down
146 changes: 146 additions & 0 deletions src/field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use std::{
fmt::Debug,
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};

pub trait Field:
Add<Output = Self>
+ AddAssign
+ Neg<Output = Self>
+ Sub<Output = Self>
+ SubAssign
+ Mul<Output = Self>
+ MulAssign
+ From<u128>
+ Clone
+ Copy
+ PartialEq
+ Debug
+ Sized
{
type Integer;
const PRIME: Self::Integer;
}

// TODO(mt) - this code defining fields can be turned into a macro if we ever
// need lots of fields with different primes.

#[derive(Clone, Copy, PartialEq)]
pub struct Fp31(<Self as Field>::Integer);

impl Field for Fp31 {
type Integer = u8;
const PRIME: Self::Integer = 31;
}

impl Add for Fp31 {
type Output = Self;

fn add(self, rhs: Self) -> Self::Output {
// TODO(mt) - constant time?
Self((self.0 + rhs.0) % Self::PRIME)
}
}

impl AddAssign for Fp31 {
#[allow(clippy::assign_op_pattern)]
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}

impl Neg for Fp31 {
type Output = Self;

fn neg(self) -> Self::Output {
Self((Self::PRIME - self.0) % Self::PRIME)
}
}

impl Sub for Fp31 {
type Output = Self;

fn sub(self, rhs: Self) -> Self::Output {
// TODO(mt) - constant time?
// Note: no upcast needed here because `2*p < u8::MAX`.
Self((Self::PRIME + self.0 - rhs.0) % Self::PRIME)
}
}

impl SubAssign for Fp31 {
#[allow(clippy::assign_op_pattern)]
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}

impl Mul for Fp31 {
type Output = Self;

fn mul(self, rhs: Self) -> Self::Output {
// TODO(mt) - constant time?
let c = u16::from;
#[allow(clippy::cast_possible_truncation)]
Self(((c(self.0) * c(rhs.0)) % c(Self::PRIME)) as <Self as Field>::Integer)
}
}

impl MulAssign for Fp31 {
#[allow(clippy::assign_op_pattern)]
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}

/// An infallible conversion from `u128` to this type. This can be used to draw
/// a random value in the field. This introduces bias into the final value
/// but for our purposes that bias is small provided that `2^128 >> PRIME`, which
/// is true provided that `PRIME` is kept to at most 64 bits in value.
///
/// This method is simpler than rejection sampling for these small prime fields.
impl<T: Into<u128>> From<T> for Fp31 {
fn from(v: T) -> Self {
#[allow(clippy::cast_possible_truncation)]
Self((v.into() % u128::from(Self::PRIME)) as <Self as Field>::Integer)
}
}

impl Debug for Fp31 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}_mod{}", self.0, Self::PRIME)
}
}

#[cfg(test)]
mod test {
use crate::field::Field;

use super::Fp31;

#[test]
fn fp31() {
let x = Fp31(24);
let y = Fp31(23);

assert_eq!(Fp31(16), x + y);
assert_eq!(Fp31(25), x * y);
assert_eq!(Fp31(1), x - y);

let mut x = Fp31(1);
x += Fp31(2);
assert_eq!(Fp31(3), x);
}

#[test]
fn zero() {
assert_eq!(
Fp31(0),
Fp31::from(<Fp31 as Field>::PRIME),
"from takes a modulus"
);
assert_eq!(Fp31(0), Fp31(0) + Fp31(0));
assert_eq!(Fp31(0), Fp31(0) + Fp31(0));
assert_eq!(Fp31(<Fp31 as Field>::PRIME - 1), Fp31(0) - Fp31(1));
assert_eq!(Fp31(0), Fp31(0) * Fp31(1));
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
#[cfg(feature = "cli")]
pub mod cli;
pub mod error;
pub mod field;
pub mod helpers;
pub mod net;
pub mod prss;
pub mod report;
pub mod threshold;
pub mod user;
Loading

0 comments on commit 1853457

Please sign in to comment.