-
Notifications
You must be signed in to change notification settings - Fork 25
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
Allow addition and multiplication for references to secret shared values #787
Changes from 14 commits
a37c12d
d5dc178
fcf3737
2143a0a
8b3ac2a
53c6883
b6446b2
a7c00df
c9fff40
91e5708
1c960fa
990dd68
efe1261
664b86e
c38f16b
b43905c
d0af8f8
bc6690b
fa7688c
16e8768
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,57 +15,76 @@ use generic_array::{ArrayLength, GenericArray}; | |
pub use prime_field::Fp31; | ||
pub use prime_field::{Fp32BitPrime, PrimeField}; | ||
|
||
use crate::secret_sharing::SharedValue; | ||
|
||
#[derive(Debug, thiserror::Error, PartialEq, Eq)] | ||
pub enum Error { | ||
#[error("unknown field type {type_str}")] | ||
UnknownField { type_str: String }, | ||
} | ||
|
||
pub trait ArithmeticOps: | ||
Add<Output = Self> | ||
+ AddAssign | ||
+ Sub<Output = Self> | ||
+ SubAssign | ||
+ Mul<Output = Self> | ||
+ MulAssign | ||
+ Neg<Output = Self> | ||
+ Sized | ||
/// Arithmetic operations that do not require communication in our MPC setting and can be performed | ||
/// locally. | ||
/// | ||
/// Note: Neg operation is also local, but is causing issues when added as a bound to this trait. | ||
/// The problem is that it does not use `Rhs` generic and rustc overflows trying to compile functions | ||
/// that use HRTB generics bounded by `LocalArithmeticOps`. | ||
pub trait LocalArithmeticOps<Rhs = Self, Output = Self>: | ||
Add<Rhs, Output = Output> + Sub<Rhs, Output = Output> + Sized | ||
{ | ||
} | ||
|
||
impl<T> ArithmeticOps for T where | ||
T: Add<Output = Self> | ||
+ AddAssign | ||
+ Sub<Output = Self> | ||
+ SubAssign | ||
+ Mul<Output = Self> | ||
+ MulAssign | ||
+ Neg<Output = Self> | ||
+ Sized | ||
impl<T, Rhs, Output> LocalArithmeticOps<Rhs, Output> for T where | ||
T: Add<Rhs, Output = Output> + Sub<Rhs, Output = Output> + Sized | ||
{ | ||
} | ||
|
||
pub trait ArithmeticRefOps<V: SharedValue>: | ||
for<'a> Add<&'a Self, Output = Self> | ||
+ for<'a> AddAssign<&'a Self> | ||
+ Neg<Output = Self> | ||
+ for<'a> Sub<&'a Self, Output = Self> | ||
+ for<'a> SubAssign<&'a Self> | ||
+ Mul<V, Output = Self> | ||
pub trait LocalAssignOps<Rhs = Self>: AddAssign<Rhs> + SubAssign<Rhs> {} | ||
impl<T, Rhs> LocalAssignOps<Rhs> for T where T: AddAssign<Rhs> + SubAssign<Rhs> {} | ||
|
||
/// Arithmetic operations that may or may not require communication. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can these really involve communication? None of these traits are async, so this can't do that. That suggests that these are still local operations, but only those that involve value-based l-values. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to distinguish operations that can be safely performed locally and confusing ones like |
||
/// for example, multiplying field values is a local operation, while multiplying secret shares is not. | ||
pub trait ArithmeticOps<Rhs = Self, Output = Self>: | ||
LocalArithmeticOps<Rhs, Output> | ||
+ LocalAssignOps<Rhs> | ||
+ Mul<Rhs, Output = Output> | ||
+ MulAssign<Rhs> | ||
+ Neg<Output = Output> | ||
{ | ||
} | ||
|
||
impl<T, V> ArithmeticRefOps<V> for T | ||
where | ||
T: for<'a> Add<&'a Self, Output = Self> | ||
+ for<'a> AddAssign<&'a Self> | ||
+ Neg<Output = Self> | ||
+ for<'a> Sub<&'a Self, Output = Self> | ||
+ for<'a> SubAssign<&'a Self> | ||
+ Mul<V, Output = Self>, | ||
V: SharedValue, | ||
impl<T, Rhs, Output> ArithmeticOps<Rhs, Output> for T where | ||
T: LocalArithmeticOps<Rhs, Output> | ||
+ LocalAssignOps<Rhs> | ||
+ Mul<Rhs, Output = Output> | ||
+ MulAssign<Rhs> | ||
+ Neg<Output = Output> | ||
{ | ||
} | ||
|
||
/// The trait for references which implement local arithmetic operations, taking the | ||
/// second operand either by value or by reference. | ||
/// | ||
/// The need for this trait is dictated by [`rust-issue`] that causes us not being able to constrain | ||
/// references to `Self`. Once this issue is fixed, we can simply get rid of it. | ||
/// | ||
/// This is automatically implemented for types which implement the operators. The idea is borrowed | ||
/// from [`RefNum`] trait, but I couldn't really make it work with HRTB and secret shares. Primitive | ||
/// types worked just fine though, so it is possible that it is another compiler issue. | ||
/// | ||
/// [`RefNum`]: https://docs.rs/num/0.4.1/num/traits/trait.RefNum.html | ||
/// [`rust-issue`]: https://github.com/rust-lang/rust/issues/20671 | ||
pub trait RefOps<'a, Base: 'a, R: 'a>: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd love to keep There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
LocalArithmeticOps<Base, Base> | ||
+ LocalArithmeticOps<&'a Base, Base> | ||
+ Mul<R, Output = Base> | ||
+ Mul<&'a R, Output = Base> | ||
{ | ||
} | ||
impl<'a, T, Base: 'a, R: 'a> RefOps<'a, Base, R> for T where | ||
T: LocalArithmeticOps<Base, Base> | ||
+ LocalArithmeticOps<&'a Base, Base> | ||
+ 'a | ||
+ Mul<R, Output = Base> | ||
+ Mul<&'a R, Output = Base> | ||
{ | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
use crate::{ | ||
error::Error, | ||
ff::Field, | ||
ff::{Field, RefOps}, | ||
protocol::{basics::SecureMul, context::Context, RecordId}, | ||
secret_sharing::Linear as LinearSecretSharing, | ||
}; | ||
|
@@ -19,6 +19,7 @@ where | |
F: Field, | ||
C: Context, | ||
S: LinearSecretSharing<F> + SecureMul<C>, | ||
for<'a> &'a S: RefOps<'a, S, F>, | ||
{ | ||
// If `condition` is a share of 1 (true), then | ||
// = false_value + 1 * (true_value - false_value) | ||
|
@@ -30,6 +31,6 @@ where | |
// = false_value | ||
Ok(false_value.clone() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missed a clone opportunity? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh my... |
||
+ &condition | ||
.multiply(&(true_value.clone() - false_value), ctx, record_id) | ||
.multiply(&(true_value - false_value), ctx, record_id) | ||
.await?) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addsub?