Skip to content

Commit

Permalink
Moving difference_to_cap into SaturatingSum with comments
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminsavage committed Sep 25, 2023
1 parent 943e337 commit f01bfdd
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 69 deletions.
80 changes: 79 additions & 1 deletion src/protocol/boolean/saturating_sum.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
error::Error,
ff::Gf2,
ff::{Field, Gf2},
protocol::{boolean::or::or, context::Context, step::BitOpStep, BasicProtocols, RecordId},
secret_sharing::{BitDecomposed, Linear as LinearSecretSharing},
};
Expand Down Expand Up @@ -59,6 +59,39 @@ impl<S: LinearSecretSharing<Gf2>> SaturatingSum<S> {
is_saturated,
))
}

///
/// NOTE: ignores the `is_saturated` flag. The return value is non-sensical if `is_saturated` is true
///
/// Only returns the least significant `num_bits` of the delta.
///
pub async fn truncated_delta_to_saturation_point<C>(
&self,
ctx: C,
record_id: RecordId,
num_bits: usize,
) -> Result<BitDecomposed<S>, Error>
where
C: Context,
S: LinearSecretSharing<Gf2> + BasicProtocols<C, Gf2>,
{
assert!(num_bits <= self.sum.len());

let mut carry_in = S::share_known_value(&ctx, Gf2::ONE);
let mut output = vec![];
for (i, bit) in self.sum.iter().enumerate().take(num_bits) {
let c = ctx.narrow(&BitOpStep::from(i));

let compute_carry_out = i < num_bits - 1;
let (difference_bit, carry_out) =
one_bit_subtractor(c, record_id, &S::ZERO, bit, &carry_in, compute_carry_out)
.await?;

output.push(difference_bit);
carry_in = carry_out;
}
Ok(BitDecomposed::new(output))
}
}

///
Expand Down Expand Up @@ -105,6 +138,51 @@ where
Ok((sum_bit, carry_out))
}

///
/// This improved one-bit subtractor that only requires a single multiplication was taken from:
/// "Improved Garbled Circuit Building Blocks and Applications to Auctions and Computing Minima"
/// `https://encrypto.de/papers/KSS09.pdf`
///
/// Section 3.1 Integer Addition, Subtraction and Multiplication
///
/// For each bit, the `difference_bit` can be efficiently computed as just `d_i = x_i ⊕ !y_i ⊕ c_i`
/// This can be computed "for free" in Gf2
///
/// The `carry_out` bit can be efficiently computed with just a single multiplication as:
/// `c_(i+1) = c_i ⊕ ((x_i ⊕ c_i) ∧ !(y_i ⊕ c_i))`
///
/// Returns (`difference_bit`, `carry_out`)
///
async fn one_bit_subtractor<C, SB>(
ctx: C,
record_id: RecordId,
x: &SB,
y: &SB,
carry_in: &SB,
compute_carry_out: bool,
) -> Result<(SB, SB), Error>
where
C: Context,
SB: LinearSecretSharing<Gf2> + BasicProtocols<C, Gf2>,
{
// compute difference bit as not_y XOR x XOR carry_in
let difference_bit = SB::share_known_value(&ctx, Gf2::ONE) - y + x + carry_in;
if compute_carry_out {
let x_xor_carry_in = x.clone() + carry_in;
let y_xor_carry_in = y.clone() + carry_in;
let not_y_xor_carry_in = SB::share_known_value(&ctx, Gf2::ONE) - &y_xor_carry_in;

let carry_out = x_xor_carry_in
.multiply(&not_y_xor_carry_in, ctx, record_id)
.await?
+ carry_in;

Ok((difference_bit, carry_out))
} else {
Ok((difference_bit, SB::ZERO))
}
}

#[cfg(all(test, unit_test))]
mod tests {
use super::SaturatingSum;
Expand Down
73 changes: 5 additions & 68 deletions src/protocol/prf_sharding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ use crate::{
protocol::{
basics::{SecureMul, ShareKnownValue},
context::{UpgradableContext, UpgradedContext, Validator},
BasicProtocols, RecordId,
RecordId,
},
repeat64str,
secret_sharing::{
replicated::{semi_honest::AdditiveShare as Replicated, ReplicatedSecretSharing},
BitDecomposed, Linear as LinearSecretSharing,
BitDecomposed,
},
};

Expand Down Expand Up @@ -279,66 +279,6 @@ where
}
}

///
/// Returns (`difference_bit`, `carry_out`)
///
async fn one_bit_subtractor<C, SB>(
ctx: C,
record_id: RecordId,
x: &SB,
y: &SB,
carry_in: &SB,
) -> Result<(SB, SB), Error>
where
C: UpgradedContext<Gf2, Share = SB>,
SB: LinearSecretSharing<Gf2> + BasicProtocols<C, Gf2>,
{
// compute difference bit as not_y XOR x XOR carry_in
let difference_bit = SB::share_known_value(&ctx, Gf2::ONE) - y + x + carry_in;

let x_xor_carry_in = x.clone() + carry_in;
let y_xor_carry_in = y.clone() + carry_in;
let not_y_xor_carry_in = SB::share_known_value(&ctx, Gf2::ONE) - &y_xor_carry_in;

let carry_out = x_xor_carry_in
.multiply(&not_y_xor_carry_in, ctx, record_id)
.await?
+ carry_in;

Ok((difference_bit, carry_out))
}

///
/// TODO: optimize this
/// We can avoid doing this many multiplications given the foreknowledge that we are always subtracting from zero
/// There's also no reason to compute the `carry_out` for the final bit since it will go unused
///
async fn compute_truncated_difference_to_cap<C, SB>(
ctx: C,
record_id: RecordId,
cur_sum: &SaturatingSum<SB>,
num_trigger_value_bits: usize,
num_saturating_sum_bits: usize,
) -> Result<BitDecomposed<SB>, Error>
where
C: UpgradedContext<Gf2, Share = SB>,
SB: LinearSecretSharing<Gf2> + BasicProtocols<C, Gf2>,
{
assert!(cur_sum.sum.len() == num_saturating_sum_bits);

let mut carry_in = SB::share_known_value(&ctx, Gf2::ONE);
let mut output = vec![];
for (i, bit) in cur_sum.sum.iter().enumerate().take(num_trigger_value_bits) {
let c = ctx.narrow(&BitOpStep::from(i));
let (difference_bit, carry_out) =
one_bit_subtractor(c, record_id, &SB::ZERO, bit, &carry_in).await?;

output.push(difference_bit);
carry_in = carry_out;
}
Ok(BitDecomposed::new(output))
}

#[allow(clippy::too_many_lines, clippy::too_many_arguments)]
async fn compute_row_with_previous<C, BK, TV>(
ctx: C,
Expand Down Expand Up @@ -468,16 +408,13 @@ where
)
.await?;

let difference_to_cap = BitDecomposed::new(
compute_truncated_difference_to_cap(
let difference_to_cap = updated_sum
.truncated_delta_to_saturation_point(
ctx.narrow(&Step::ComputeDifferenceToCap),
record_id,
&updated_sum,
num_trigger_value_bits,
num_saturating_sum_bits,
)
.await?,
);
.await?;

let narrowed_ctx1 = ctx.narrow(&Step::ComputedCappedAttributedTriggerValueNotSaturatedCase);
let narrowed_ctx2 = ctx.narrow(&Step::ComputedCappedAttributedTriggerValueJustSaturatedCase);
Expand Down

0 comments on commit f01bfdd

Please sign in to comment.