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

test manipulated bit multiplication fails verification #1181

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

danielmasny
Copy link
Collaborator

No description provided.

Copy link

codecov bot commented Jul 3, 2024

Codecov Report

Attention: Patch coverage is 98.94737% with 1 line in your changes missing coverage. Please review.

Project coverage is 92.05%. Comparing base (671fb4d) to head (808046e).

Files Patch % Lines
ipa-core/src/protocol/basics/mul/dzkp_malicious.rs 98.94% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1181      +/-   ##
==========================================
+ Coverage   92.01%   92.05%   +0.03%     
==========================================
  Files         195      195              
  Lines       29130    29224      +94     
==========================================
+ Hits        26805    26901      +96     
+ Misses       2325     2323       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Collaborator

@benjaminsavage benjaminsavage left a comment

Choose a reason for hiding this comment

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

The fact that this fails for just one verifier is extremely concerning to me. I'm worried this means there is a logical error in our malicious security code.

Comment on lines +123 to +129
let mut prss_left = prss.left_arr().clone();
if ctx.role() == cheater {
prss_left += <<F as Vectorizable<N>>::Array>::from_fn(|_| F::ONE);
};

let z =
multiplication_protocol(&ctx, record_id, a, b, &prss_left, prss.right_arr()).await?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I find it just adds an extra level of confusion that we achieve this bit flip specifically through manipulating the prss... I would rather just mutate z after computing it.

Comment on lines +131 to +145
let segment = Segment::from_entries(
F::as_segment_entry(a.left_arr()),
F::as_segment_entry(a.right_arr()),
F::as_segment_entry(b.left_arr()),
F::as_segment_entry(b.right_arr()),
F::as_segment_entry(prss.left_arr()),
F::as_segment_entry(prss.right_arr()),
F::as_segment_entry(z.right_arr()),
);

// add segment to the batch that needs to be verified by the dzkp prover and verifiers
ctx.push(record_id, segment);

Ok(z)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This approach leads to a lot of code duplication. Why not just invoke the normal protocol (which already does all of this segment entry stuff), and just mutate the result (apply an additive attack)?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree. These tests are running against reference implementation and not intended to be formal verification methods that explore all possible states the system can be it. There are better tools than our poor in-memory infra for that.

Modelling the state of malicious adversaries does not seem very useful - there are infinite combinatorial states they can be it. The threat model allows them to delay response infinitely, respond with errors, run Byzantine attacks etc. Instead of focusing on what malicious adversaries can do, it may be easier to shift our attention to what honest helpers can see from such entities. This greatly simplifies testing imo, because there are only a few things a malicious actor can do:

  1. It may never respond to multiplication requests
  2. It can send correct values and tamper the proof
  3. It can send corrupted values and proof for correct values
  4. It can send corrupted values and proof that matches them

For the first 3 we don't need to duplicate protocols (#1202 covers 2 and 3 and 1 will be covered after #1205). I could be wrong, but test here seems to be checking 3) so we could leverage our new infrastructure capabilities and avoid copy-pasting the segment construction logic.

Both @danielmasny and @andyleiserson expressed interest in covering 4) which is an interesting exercise. I think code duplication is probably wrong for it in the long term as well - we need to figure out how to do it without cloning our MPC circuits.

let [(_, s_1), (_, s_2), (v_3, s_3)] = world
.malicious((), |ctx, ()| async move {
let [a, b, prss] = all_combination_of_inputs(ctx.role(), i);
let validator = ctx.narrow(&TestStep::Counter(i)).dzkp_validator(10);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't know what this "10" is / does.

let [a, b, prss] = all_combination_of_inputs(ctx.role(), i);
let validator = ctx.narrow(&TestStep::Counter(i)).dzkp_validator(10);
let mctx = validator.context();
let product = multiply_with_cheater(
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think I would rather have the other two parties call the normal protocol, and only one call multiply_with_cheater. I realize that only the person with the correct role is going to actually cheat, but this seems riskier than just testing the verifiers running the normal code.

.await;

// H1 cheats means H3 fails
// since always verifier on the left of the cheating prover fails
Copy link
Collaborator

Choose a reason for hiding this comment

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

This makes zero sense to me. I cannot think of any reason why just one verifier should fail.

Both verifiers should be checking that all of the b shares sum to zero. If it fails for one, it should fail for both.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

lets sync on this once you are back next week.

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