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

Sum To Zero Check Protocol #1040

Merged
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
2 changes: 2 additions & 0 deletions ipa-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ pub enum Error {
ContextUnsafe(String),
#[error("DZKP Validation failed")]
DZKPValidationFailed,
#[error("Inconsistent shares")]
InconsistentShares,
}

impl Default for Error {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use sha2::{

use crate::{
ff::{PrimeField, Serializable},
helpers::MpcMessage,
protocol::prss::FromRandomU128,
};

Expand All @@ -28,6 +29,12 @@ impl Serializable for Hash {
}
}

impl MpcMessage for Hash {}

/// Computes Hash of serializable values from an iterator
///
/// ## Panics
/// Panics when Iterator is empty.
pub fn compute_hash<'a, I, S>(input: I) -> Hash
where
I: IntoIterator<Item = &'a S>,
Expand Down Expand Up @@ -106,7 +113,7 @@ mod test {
use super::{compute_hash, Hash};
use crate::{
ff::{Fp31, Fp32BitPrime, Serializable},
protocol::ipa_prf::malicious_security::hashing::hash_to_field,
helpers::hashing::hash_to_field,
};

#[test]
Expand Down
1 change: 1 addition & 0 deletions ipa-core/src/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mod buffers;
mod error;
mod futures;
mod gateway;
pub mod hashing;
pub(crate) mod prss_protocol;
pub mod stream;
mod transport;
Expand Down
1 change: 1 addition & 0 deletions ipa-core/src/protocol/basics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub(crate) mod mul;
mod reshare;
mod reveal;
mod share_known_value;
pub mod share_validation;
pub mod sum_of_product;

use std::ops::Not;
Expand Down
174 changes: 174 additions & 0 deletions ipa-core/src/protocol/basics/share_validation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
use futures_util::future::try_join;
danielmasny marked this conversation as resolved.
Show resolved Hide resolved

use crate::{
error::Error,
helpers::{
hashing::{compute_hash, Hash},
Direction,
},
protocol::{context::Context, RecordId},
secret_sharing::SharedValue,
};

/// This function checks that a vector of shares are consistent across helpers
/// i.e. `H1` holds `(x0,x1)`, `H2` holds `(x1,x2)`, `H3` holds `(x2,x0)`
/// the function verifies that `H1.x0 == H3.x0`, `H1.x1 == H2.x1`, `H2.x2 == H3.x2`
///
/// We use a hash based approach that is secure in the random oracle model
/// further, only one of left and right helper check the equality of the shares
/// this is might not be sufficient in some applications to prevent malicious behavior
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand where the typo is

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra "is"

/// this might not be sufficient in some applications to prevent malicious behavior

///
/// The left helper simply hashes the vector and sends it to the right,
/// the right helper hashes his vector and compares it to the received hash
///
/// # Errors
/// propagates errors from send and receive
pub async fn validate_replicated_shares<'a, 'b, C, I, J, S>(
ctx: C,
input_left: I,
input_right: J,
) -> Result<(), Error>
where
C: Context,
I: IntoIterator<Item = &'a S>,
J: IntoIterator<Item = &'b S>,
S: SharedValue,
{
// compute hash of `left`
let hash_left = compute_hash(input_left);

// set up context
let ctx_new = &(ctx.set_total_records(1usize));
// set up channels
let send_channel = ctx_new.send_channel::<Hash>(ctx.role().peer(Direction::Right));
let receive_channel = ctx_new.recv_channel::<Hash>(ctx.role().peer(Direction::Left));

let ((), hash_received) = try_join(
// send hash
send_channel.send(RecordId::FIRST, compute_hash(input_right)),
receive_channel.receive(RecordId::FIRST),
)
.await?;

if hash_left == hash_received {
Ok(())
} else {
Err(Error::InconsistentShares)
}
}

/// This function is similar to validate the consistency of shares with the difference
/// that it validates that tuple of shares sum to zero rather than being identical
/// i.e. `H1` holds `(H1_x0,H1_x1)`, `H2` holds `(H2_x1,H2_x2)`, `H3` holds `(H3_x2,H3_x0)`
/// the function verifies that `H1_x0 == -H3_x0`, `H1_x1 == -H2_x1`, `H2_x2 == -H3_x2`
///
/// We use a hash based approach that is secure in the random oracle model
/// further, only one of left and right helper check that it is zero
/// this is sufficient for Distributed Zero Knowledge Proofs
/// but might not be sufficient for other applications
///
/// The left helper simply hashes the vector and sends it to the right,
/// the right helper negates his vector, hashes it and compares it to the received hash
///
/// # Errors
/// propagates errors from `validate_replicated_shares`
pub async fn validate_three_two_way_sharing_of_zero<'a, C, I, S>(
ctx: C,
input_left: I,
input_right: I,
) -> Result<(), Error>
where
C: Context,
I: IntoIterator<Item = &'a S>,
S: SharedValue,
{
// compute left.neg
let left_neg = input_left.into_iter().map(|x| x.neg()).collect::<Vec<_>>();

validate_replicated_shares(ctx, &left_neg, input_right).await
}

#[cfg(all(test, unit_test))]
mod test {
danielmasny marked this conversation as resolved.
Show resolved Hide resolved
use std::ops::Neg;

use ipa_macros::Step;
use rand::{thread_rng, Rng};

use crate::{
error::Error,
ff::{Field, Fp61BitPrime},
protocol::{
basics::share_validation::validate_three_two_way_sharing_of_zero, context::Context,
},
secret_sharing::replicated::ReplicatedSecretSharing,
test_executor::run,
test_fixture::{Runner, TestWorld},
};

#[derive(Step)]
pub(crate) enum Step {
Correctness,
Misaligned,
Changed,
}

// Test three two way shares of zero
// we generated replicated shares of a vector of random values
// each helper party negates one of its shares
// we then check whether validate_three_two_way_sharing_of_zero succeeds
// we also test for failure when the shares are misaligned or one of them has been changed
#[test]
fn three_two_way_shares_of_zero() {
run(|| async move {
let world = TestWorld::default();
let mut rng = thread_rng();

let len: usize = rng.gen_range(50..100);

let r = (0..len)
.map(|_| rng.gen::<Fp61BitPrime>())
.collect::<Vec<_>>();

let _ = world
.semi_honest(r.into_iter(), |ctx, input| async move {
let r_right = input.iter().map(|x| x.right().neg()).collect::<Vec<_>>();
let mut r_left = input
.iter()
.map(ReplicatedSecretSharing::left)
.collect::<Vec<_>>();

validate_three_two_way_sharing_of_zero(
ctx.narrow(&Step::Correctness),
&r_left,
&r_right,
)
.await
.unwrap();

// check misaligned causes error
let error = validate_three_two_way_sharing_of_zero(
ctx.narrow(&Step::Misaligned),
&r_left[0..len - 1],
&r_right[1..len],
)
.await;

assert!(matches!(error, Err(Error::InconsistentShares)));

// check changing causes error
r_left[5] += Fp61BitPrime::ONE;

let error = validate_three_two_way_sharing_of_zero(
ctx.narrow(&Step::Changed),
&r_left[0..len - 1],
&r_right[1..len],
)
.await;

assert!(matches!(error, Err(Error::InconsistentShares)));
})
.await;
});
}
}
1 change: 0 additions & 1 deletion ipa-core/src/protocol/ipa_prf/malicious_security/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
mod hashing;
pub mod lagrange;
pub mod prover;
pub mod verifier;
2 changes: 1 addition & 1 deletion ipa-core/src/protocol/ipa_prf/malicious_security/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use std::{
use generic_array::{sequence::GenericSequence, ArrayLength, GenericArray};
use typenum::{Diff, Sum, U1};

use super::hashing::{compute_hash, hash_to_field};
use crate::{
ff::PrimeField,
helpers::hashing::{compute_hash, hash_to_field},
protocol::ipa_prf::malicious_security::lagrange::{
CanonicalLagrangeDenominator, LagrangeTable,
},
Expand Down