Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

offline-phase: lowgear: shared-random: Implement F_rand subprotocol #69

Merged
merged 1 commit into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion offline-phase/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ mp-spdz-rs = { path = "../mp-spdz-rs" }
futures = "0.3"

# === Misc Dependencies === #
itertools = "0.10"
rand = "0.8"
sha3 = { version = "0.10" }

[dev-dependencies]
ark-bn254 = "0.4"
ark-mpc = { path = "../online-phase", features = ["test_helpers"] }
itertools = "0.10"
tokio = { version = "1", features = ["full"] }
3 changes: 3 additions & 0 deletions offline-phase/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::{error::Error, fmt::Display};
/// The error types for the offline phase
#[derive(Clone, Debug)]
pub enum LowGearError {
/// An invalid commitment was provided in a commit/reveal phase
InvalidCommitment,
/// Error exchanging keys
KeyExchange(String),
/// The lowgear setup params requested before setup
Expand All @@ -17,6 +19,7 @@ pub enum LowGearError {
impl Display for LowGearError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LowGearError::InvalidCommitment => write!(f, "Received invalid commitment"),
LowGearError::KeyExchange(e) => write!(f, "Key exchange error: {e}"),
LowGearError::NotSetup => write!(f, "LowGear not setup"),
LowGearError::SendMessage(e) => write!(f, "Error sending message: {e}"),
Expand Down
1 change: 1 addition & 0 deletions offline-phase/src/lowgear/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! keys, authenticating inputs, etc

pub mod setup;
pub mod shared_random;
pub mod triplets;

use ark_ec::CurveGroup;
Expand Down
89 changes: 89 additions & 0 deletions offline-phase/src/lowgear/shared_random.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//! Implements the F_rand functionality from the LowGear paper

use ark_ec::CurveGroup;
use ark_mpc::{algebra::Scalar, network::MpcNetwork};
use itertools::Itertools;
use rand::rngs::OsRng;
use sha3::{Digest, Sha3_256};

use crate::error::LowGearError;

use super::LowGear;

impl<C: CurveGroup, N: MpcNetwork<C> + Unpin + Send> LowGear<C, N> {
/// Generate a single shared random value via commit/reveal
pub async fn get_shared_randomness(&mut self) -> Result<Scalar<C>, LowGearError> {
Ok(self.get_shared_randomness_vec(1).await?[0])
}

/// Generate a set of shared random values via commit/reveal
///
/// 1. Generate local random values
/// 2. Commit to the random values
/// 3. Send & receive the commitments to/from the counterparty
/// 4. Send & receive the random values to/from the counterparty
/// 5. Verify commitments and construct shared value
pub async fn get_shared_randomness_vec(
&mut self,
n: usize,
) -> Result<Vec<Scalar<C>>, LowGearError> {
// Generate local random values
let mut rng = OsRng;
let my_shares = (0..n).map(|_| Scalar::random(&mut rng)).collect_vec();

let my_comm = Self::commit_randomness(&my_shares);
self.send_network_payload(my_comm).await?;
let their_comm: Scalar<C> = self.receive_network_payload().await?;

self.send_network_payload(my_shares.clone()).await?;
let their_shares: Vec<Scalar<C>> = self.receive_network_payload().await?;

// Verify commitments
let expected_comm = Self::commit_randomness(&their_shares);
if expected_comm != their_comm {
return Err(LowGearError::InvalidCommitment);
}

let final_shares = my_shares
.iter()
.zip(their_shares.iter())
.map(|(my_share, their_share)| my_share + their_share)
.collect_vec();
Ok(final_shares)
}

/// Hash commit to a set of random values
fn commit_randomness(values: &[Scalar<C>]) -> Scalar<C> {
let mut hasher = Sha3_256::new();
for value in values.iter() {
hasher.update(value.to_bytes_be());
}
let hash_output = hasher.finalize();

Scalar::<C>::from_be_bytes_mod_order(&hash_output)
}
}

#[cfg(test)]
mod tests {
use crate::test_helpers::mock_lowgear;

use super::*;

#[tokio::test]
async fn test_get_shared_randomness_vec() {
mock_lowgear(|mut lowgear| async move {
let n = 5;
let shares = lowgear.get_shared_randomness_vec(n).await.unwrap();

assert_eq!(shares.len(), n);

// Send the shares to one another to verify they are the same
lowgear.send_network_payload(shares.clone()).await.unwrap();
let their_shares: Vec<Scalar<_>> = lowgear.receive_network_payload().await.unwrap();

assert_eq!(shares, their_shares);
})
.await;
}
}
Loading