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

Add (R)OLE to mpz #103

Closed
wants to merge 51 commits into from
Closed

Add (R)OLE to mpz #103

wants to merge 51 commits into from

Conversation

th4s
Copy link
Member

@th4s th4s commented Feb 20, 2024

This PR adds OLE and ROLE to mpz by introducing two new crates and creates the building blocks, like e.g. traits and module structure, for future OLE flavors and additional implementations.

I still need to do some small improvements here and there, but thought it is a good idea to get it out now.
Ready for review.

@th4s th4s changed the base branch from dev to add-ot-core-ideal-rot February 20, 2024 12:09
@th4s th4s force-pushed the add-ot-core-ideal-rot branch from 47766a1 to 9e137d0 Compare February 20, 2024 12:10
@th4s th4s force-pushed the ole-crate branch 4 times, most recently from 3af76ed to 8661279 Compare February 21, 2024 22:28
@th4s th4s requested review from sinui0 and themighty1 February 22, 2024 11:35
@th4s th4s force-pushed the add-ot-core-ideal-rot branch from ccce5dd to ad39a0a Compare February 27, 2024 09:35
@th4s
Copy link
Member Author

th4s commented Mar 4, 2024

This will need to be adapted/rebased to the new architecture for IO.

@th4s th4s force-pushed the add-ot-core-ideal-rot branch from ad39a0a to c70c750 Compare March 7, 2024 09:52
@th4s
Copy link
Member Author

th4s commented Mar 7, 2024

Rebased and adapted to new IO design. Should be ready for review.

@th4s th4s force-pushed the add-ot-core-ideal-rot branch from c70c750 to 950c87b Compare March 7, 2024 17:02
@th4s th4s changed the base branch from add-ot-core-ideal-rot to threading-refactor March 7, 2024 17:23
@th4s
Copy link
Member Author

th4s commented Mar 7, 2024

Rebased onto threading-refactor. Ready for review.

@themighty1
Copy link
Collaborator

Im happy to review this once we all agree on what specific approach we will be taking for E2F and GHASH. For now, we only tentatively agreed to use the PADO's approach with modifications to work around the 0 input issue.
I have not examined PADO's protocols in detail yet.
So, Im expecting the following sequence of events:

  • Jordan ACKs that he's ok with using PADO's E2F and GHASH with our 0-input fix
  • I'll review PADO's E2F and GHASH to make sure they make sense
  • I'll analyze the ROT->ROLE protocol again with greater scrutiny
  • I'll review the rest of this PR

@sinui0
Copy link
Collaborator

sinui0 commented Apr 26, 2024

I haven't gone very deep in review here yet, but lets address some high level points:

  1. I don't think it is appropriate to describe this protocol as Random OLE. That would imply the protocol deals random shares to both parties, which is not the case here.

  2. Looking at your write up, it appears that "Random OLE" is exactly MASCOT (COPEe KOS16) with an additional step where the parties adjust their shares. AFAICT this share adjustment is superfluous, as they already choose them once and can sample them randomly if that is what they want, eg for offline preprocessing. I suggest we remove this step and just implement KOS16 verbatim.

    It recently occurred to me that the best approach is likely to just re-use the PRG seeds shared during the base OT for OT extension. Using the messages from ROT to seed the PRGs in COPEe seems unnecessary, and prevents us from preprocessing the OLEs in parallel with the OT extension.

  3. We should stick with common nomenclature: OLE Sender and Receiver. Renaming these parties to Provider and Evaluator is bound to cause confusion. To help grok these terms: The Sender sends a linear function to the protocol and the Receiver receives an evaluation of that function at the index of their choice.

  4. Regarding the "0-input fix" that should exist outside this OLE implementation entirely. It would be a sub-protocol of GHASH. Let's discuss that later, elsewhere.

  5. The "with errors" suffix should not be present in any of the traits. We should just have an OleSender and OleReceiver trait, and users must understand the real functionality of the protocol they use which implements these traits.

Copy link
Collaborator

@sinui0 sinui0 left a comment

Choose a reason for hiding this comment

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

I had some WIP review here that I'll just post in addition to my previous comment.

Additionally, I was expecting to see the use of a PRF in the OLEe implementation, but saw it no where? It looked like you are operating directly on the ROT messages instead of using them as keys to the PRF.

I think we can avoid any mention of ROT in this crate, we simply use ROT to sample the PRF keys for KOS16.

use rand::{rngs::ThreadRng, thread_rng};

/// The OLE functionality
pub struct OLEFunctionality<F> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I recommend sticking to Ideal*, "functionality" is a mouthful for a type name.

@@ -0,0 +1,3 @@
//! Provides implementations of OLE with errors (OLEe) protocols.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
//! Provides implementations of OLE with errors (OLEe) protocols.
//! Oblivious linear evaluation protocols

The "with errors" should be a caveat documented on the specific implementation, not at the module level

Copy link
Collaborator

Choose a reason for hiding this comment

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

While we're at it, we can be more verbose in our comments "oblivious linear evaluation" is also a short-hand which may be confusing to the uninitiated. The full term "oblivious linear function evalution", i.e. there exists a linear function which gets evaluated obliviously.

@@ -0,0 +1,7 @@
//! This module provides ideal functionalities for OLE and ROLE.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
//! This module provides ideal functionalities for OLE and ROLE.
//! Ideal OLE functionalities.

They're all just variants of OLE, we can keep the module doc general

@@ -0,0 +1,94 @@
//! This module provides an ideal ROLE functionality.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
//! This module provides an ideal ROLE functionality.
//! Ideal ROLE.

Style wise, I think I prefer very succinct module and type headlines. It just reads cleaner with rustdoc to avoid leading words like "this module provides..." etc. Of course, its totally fine to be more verbose in the following description

use mpz_fields::Field;
use rand::{rngs::ThreadRng, thread_rng};

/// The ROLE functionality
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
/// The ROLE functionality
/// Ideal ROLE.

Comment on lines 5 to 6
//! This crate provides implementations of different Oblivious Linear Evaluation with Errors (OLEe)
//! flavors. It provides the core logic of the protocols without I/O.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
//! This crate provides implementations of different Oblivious Linear Evaluation with Errors (OLEe)
//! flavors. It provides the core logic of the protocols without I/O.
//! Core implementations of various Oblivious Linear Evaluation protocols.

Comment on lines 13 to 24
/// Workaround because of feature `generic_const_exprs` not available in stable.
///
/// This is used to check at compile-time that the correct const-generic implementation is used for
/// a specific field.
struct Check<const N: usize, F: Field>(std::marker::PhantomData<F>);

impl<const N: usize, F: Field> Check<N, F> {
const IS_BITSIZE_CORRECT: () = assert!(
N as u32 == F::BIT_SIZE / 8,
"Wrong bit size used for field. You need to use `F::BIT_SIZE` for N."
);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should just add an associated const BYTE_SIZE to Field

Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's remove this entire module and focus on OLEe

Copy link
Member Author

Choose a reason for hiding this comment

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

The nice thing of going from ROLE -> OLE is that ROLE can be preprocessed. If we do not use ROLE to instantiate OLE then we probably go with Gilboa99, which does not allow preprocessing.

@sinui0 sinui0 force-pushed the threading-refactor branch from 00cd519 to 73441ff Compare April 30, 2024 00:35
@th4s
Copy link
Member Author

th4s commented May 6, 2024

Thanks for the review.

  1. Can you explain why you think that the parties are not dealt random shares?

  2. The difference between KOS16 (which is a VOLE) and this ROLE implementation is that in KOS16 the Delta is fixed. So the "Extend" calls cannot be used as a basis for an OLE, because only one party can choose the input. But for E2F or Ghash we need this degree of freedom. Am I missing something?

  3. Agree

  4. The 0-fix is not implemented. It only exists in the research write-up and we probably won't need it.

  5. Agree

@th4s
Copy link
Member Author

th4s commented May 6, 2024

I went the route of using PRNGs for ROLE. So that you also have a Setup call and Extend calls. I don't think that this works. Relevant PR tlsnotary/docs-mdbook#65

@sinui0
Copy link
Collaborator

sinui0 commented May 7, 2024

Can you explain why you think that the parties are not dealt random shares?

In steps 1 and 2 of your Extend the parties sample their target shares, then subsequently use them to adjust the VOLE from COPEe. The functionality is not dealing these shares, the parties are choosing them. There is no constraint on the distribution from which these shares are sampled. I suggest we just skip this step, which is equivalent to COPEe.

The difference between KOS16 (which is a VOLE) and this ROLE implementation is that in KOS16 the Delta is fixed. So the "Extend" calls cannot be used as a basis for an OLE, because only one party can choose the input. But for E2F or Ghash we need this degree of freedom. Am I missing something?

KOS16 indeed does implement VOLE, or in our case $l = 1$ which is a single OLE. You're correct though, we can't reuse the base OTs as I was suggesting earlier, so we can stick with using ROT from OT extension to sample/transfer the PRG seeds.

I'm not quite sure that your protocol is secure. Re-iterating, it looks to me to be COPEe where each extend call to COPEe is then followed by a share adjustment to convert the VOLE into an OLE. This would imply you can get n-OLE from VOLE simply with this share adjustment. Maybe that's true, but it's not self-evident to me that it's secure.

@th4s
Copy link
Member Author

th4s commented May 7, 2024

In steps 1 and 2 of your Extend the parties sample their target shares, then subsequently use them to adjust the VOLE from COPEe. The functionality is not dealing these shares, the parties are choosing them. There is no constraint on the distribution from which these shares are sampled. I suggest we just skip this step, which is equivalent to COPEe.

I'm not quite sure that your protocol is secure. Re-iterating, it looks to me to be COPEe where each extend call to COPEe is then followed by a share adjustment to convert the VOLE into an OLE. This would imply you can get n-OLE from VOLE simply with this share adjustment. Maybe that's true, but it's not self-evident to me that it's secure.

I am not sure what you mean by Extend. For ROLE in the current construction (https://github.com/tlsnotary/docs-mdbook/blob/main/research/ole-flavors.typ#L29-L43) there is no Extend call. The construction is pretty different from COPEe, which was only the starting point.

KOS16 indeed does implement VOLE, or in our case which is a single OLE. You're correct though, we can't reuse the base OTs as I was suggesting earlier, so we can stick with using ROT from OT extension to sample/transfer the PRG seeds.

When I designed this, I tried to come up with with a Setup, Extend approach for ROLE, too, but couldn't get this to work in a way which made me feel safe about it. I did not invest too much time into this, because we have preprocessed random OTs available, so I felt that the performance impact was negligible. I tried using PRG seeds for ROLE, but I was not sure that this is safe.

Copy link
Collaborator

@sinui0 sinui0 left a comment

Choose a reason for hiding this comment

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

Algorithms LGTM 👍

I would suggest that you refactor a bit more to remove the *Sender and *Receiver types, as they have no internal state and complicate the API. Instead of an actor operating on data, we should instead provide newtypes for the data and implement the API directly on them. For example:

pub struct SenderShare<F>(F);

impl<F: Field> SenderShare<F> {
  pub fn new(share: F, corr: [[F; 2]; F::BIT_LENGTH]) -> (Self, MaskedInput<F>) {
    ...
  }
  
  pub fn adjust(self, target: F) -> (SenderAdjust<F>, ShareAdjust<F>) {
    ...
  }
}

pub struct ReceiverShare<F>(F);

impl<F: Field> ReceiverShare<F> {
  pub fn new(
    share: F,
    sender_input: MaskedInput<F>,
    corr: [F; F::BIT_LENGTH]
  ) -> Self {
    ...
  }
  
  pub fn adjust(self, target: F) -> (ReceiverAdjust<F>, ShareAdjust<F>) {
    ...
  }
}

pub struct ShareAdjust<F>(F);

pub struct SenderAdjust<F>(F);

impl<F: Field> SenderAdjust<F> {
  pub fn finish(self, receiver_adjust: ShareAdjust<F>) -> SenderShare<F> {
    ...
  }
}

pub struct ReceiverAdjust<F>(F);

impl<F: Field> ReceiverAdjust<F> {
  pub fn finish(self, sender_adjust: ShareAdjust<F>) -> ReceiverShare<F> {
    ...
  }
}

This would just be the core API, we can still add the sender and receiver types to store the preprocessed OLEs

pub fn generate(
&self,
delta_k: &[F],
t_delta_i: &[[u8; N]],
Copy link
Collaborator

Choose a reason for hiding this comment

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

t_delta_i can instead be [F] and its up to the user to provide it in that format. We can add the bit iterator trait as a bound on F (not on the Field trait itself).

)));
}

let delta_i: Vec<bool> = delta_k.iter_lsb0().collect();
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe we can avoid this extra allocation using iterator combinators

/// # Returns
///
/// * `ui` - The correlations, which will be sent to the receiver.
/// * `t0k` - The sender's final OLE output summands.
Copy link
Collaborator

Choose a reason for hiding this comment

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

These are simply "the Sender's shares", maybe ak, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

I tried to use the MASCOT paper's notation for this module, so that understanding it and checking for correctness is as easy as possible.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Rather than having multiple methods here which mutable some internal state of the functionality, I think it can simply provide a method like:

pub fn execute<F: Field>(
  &mut self, 
  sender_input: Vec<F>, 
  receiver_input: Vec<F>
) -> (Vec<F>, Vec<F>)

@th4s
Copy link
Member Author

th4s commented May 13, 2024

Alright, I tried it out and it seems to work out quite nicely.

th4s added 6 commits May 13, 2024 17:30
- also use correct type for `adjust` methods.
- Shifted share logic to `core` module.
- Added tests.
- Refactored test helper functions.
@th4s
Copy link
Member Author

th4s commented May 14, 2024

Closing in favor of #135.

@th4s th4s closed this May 14, 2024
@sinui0 sinui0 deleted the ole-crate branch June 6, 2024 16:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants