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

[Decrypt script] In case decryption fails for a record, ignore and continue to decrypt #1270

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

richajaindce
Copy link
Contributor

@richajaindce richajaindce commented Sep 10, 2024

In case a record fails decryption, we will log it on the console and the output file. However, we will let the processing complete for all the records before erroring out completely.

File output

Decryption failed Record: 0 Reason:en/decryption failure: Failed to open ciphertext
203,9361892166529446633,0,0,0
0,8452333888243494998,0,0,0
279,9361892166529446633,0,0,0
0,13796936852565581985,0,0,0
342,9361892166529446633,0,0,0
1,2805086832267079501,0,0,0
Decryption failed Record: 8 Reason:en/decryption failure: Failed to open ciphertext

Console output

Decryption failed Record: 0 Reason:en/decryption failure: Failed to open ciphertext
Decryption failed Record: 7 Reason:en/decryption failure: Failed to open ciphertext
Error: Crypt(Other)

FYI: i ended up not adding a flag for this as this is useful information while running a script

Copy link

codecov bot commented Sep 10, 2024

Codecov Report

Attention: Patch coverage is 83.78378% with 12 lines in your changes missing coverage. Please review.

Project coverage is 93.49%. Comparing base (f199c46) to head (bd65cb5).
Report is 8 commits behind head on main.

Files with missing lines Patch % Lines
ipa-core/src/cli/crypto.rs 83.78% 12 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1270      +/-   ##
==========================================
+ Coverage   92.47%   93.49%   +1.01%     
==========================================
  Files         201      202       +1     
  Lines       31925    32714     +789     
==========================================
+ Hits        29522    30585    +1063     
+ Misses       2403     2129     -274     

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

Copy link
Collaborator

@akoshelev akoshelev left a comment

Choose a reason for hiding this comment

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

Do we still want to use this command to verify end-to-end encryption cycle with iOS/Android? Swallowing errors may prevent us from catching issues here. Maybe we should provide an extra flag (disabled by default) that will instruct the CLI to skip over malformed reports

trigger_value,
)?;
}
_ => println!("Decryption failed for record no {idx}"),
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
_ => println!("Decryption failed for record no {idx}"),
_ => eprintln!("Decryption failed for record no {idx}"),

Copy link
Contributor Author

@richajaindce richajaindce Sep 13, 2024

Choose a reason for hiding this comment

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

FYI I ended up not adding a flag for this as this is useful information while decrypting rows @akoshelev

@richajaindce
Copy link
Contributor Author

Do we still want to use this command to verify end-to-end encryption cycle with iOS/Android? Swallowing errors may prevent us from catching issues here. Maybe we should provide an extra flag (disabled by default) that will instruct the CLI to skip over malformed reports

Yes, let me add a flag to do this.
What we observed was that sometimes the public key is not propagated for all the users who are getting targeted for the ads. In that case, they would still be using the stale keys. In such cases, mpc should throw away the records it can't decrypt. This change will let us do sanity check our iOS/android/dataswarm implementation.

Having said that, is there a way to "throw away" non-decryptable records while running query today @akoshelev ?

@eriktaubeneck
Copy link
Member

I'm not convinced this is the right approach. For example, if different records are not decryptable across helpers, it will result in errors downstream or potentially just incorrect results. Moreover, decryption happens independently across helpers, so there would be some need for helpersto align o. which events they dropped.

I think we should instead require the report collector to only include events encrypted towards a given HPN to be submitted, and to panic if any are not decryptable.

@richajaindce
Copy link
Contributor Author

I'm not convinced this is the right approach. For example, if different records are not decryptable across helpers, it will result in errors downstream or potentially just incorrect results. Moreover, decryption happens independently across helpers, so there would be some need for helpersto align o. which events they dropped.

I think we should instead require the report collector to only include events encrypted towards a given HPN to be submitted, and to panic if any are not decryptable.

Just wanted to check the purpose of this decrypt script? I assume it is for our own testing as a validation step before we can run a real test (where we won't be able to use this script due to no access to private keys). While testing our integration, before this change, the script just returned an error. However, it was able to decrypt most of them except a few rows due to public key mismatch.

With this change, hoping we can get to finer details with a single run. And we can gate this with an argument as Alex suggested. WDYT?

@eriktaubeneck
Copy link
Member

it's concerning to me that we wouldn't know what keys an event was encrypted with. this util is to assist with testing, and it doesn't aid in that functionality if it succeeds on files that would fail
in an actual run. as I currently understand it, we assume all events submitted to the HPN are decryptable, so relaxing that assumption here may result in unexpected behavior.

given this is a testing util, we could provide better error handling, such as notifying the user as to which reports were not decryptable.

@akoshelev
Copy link
Collaborator

Having said that, is there a way to "throw away" non-decryptable records while running query today @akoshelev ?

We don't have it currently, but we discussed it with @danielmasny and this should be eventually in our roadmap. It requires communication across helpers, but generally they should be able to tell others to toss certain reports away. There should be some limits on this functionality (what if one helpers tells others to remove everything but two), but generally it is desirable to have I think

@eriktaubeneck
Copy link
Member

it makes sense to eventually support (bits will inevitably get flipped occasionally). until we have that functionality, I think we should keep this util
in line with existing functionality, and we'd be better served by providing clearer error reporting for testing so that we can remove corrupt reports.

@danielmasny
Copy link
Collaborator

There are several things we would need, one is to sync with the other helpers that the report should be ignored. The second is that we also need to check the shares for consistency, i.e. both helper decrypt the same share. It would be quite bad if the whole query fails just because of a single bad report.

Copy link
Member

@eriktaubeneck eriktaubeneck left a comment

Choose a reason for hiding this comment

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

a few comments below, but this approach works much better. we need to make sure we log all the errors, and we may even want to differentiate the case where a given row is un-decryptable by all 3 helpers vs only an individual helper.

)?;
}
// error handling in case decryption failed
(Err(e1), _, _) => {
Copy link
Member

Choose a reason for hiding this comment

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

this will end up only matching one of the errors, but it's probably useful to log all 3 if they fail, right?

}
// error handling in case decryption failed
(Err(e1), _, _) => {
writeln!(writer, "Decryption failed Record: {idx} Reason:{e1}",)?;
Copy link
Member

Choose a reason for hiding this comment

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

do we actually want to write these to the file?


for (dec_report1, (dec_report2, dec_report3)) in
decrypted_reports1.zip(decrypted_reports2.zip(decrypted_reports3))
let mut first_error = Ok(());
Copy link
Member

Choose a reason for hiding this comment

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

what is this for?

breakdown_key,
trigger_value,
)?;
match (dec_report1, dec_report2, dec_report3) {
Copy link
Member

Choose a reason for hiding this comment

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

it may make sense to check each for errors explicitly up top, so that we make sure we log all 3. we'll want to make sure that all 3 are not decryptable. the suggestion is just a sketch, don't merge it directly.

Suggested change
match (dec_report1, dec_report2, dec_report3) {
if dec_report1.is_err() { # log here }
if dec_report2.is_err() { # log here }
if dec_report3.is_err() { # log here }
match (dec_report1, dec_report2, dec_report3) {
(Ok(dec_report1), Ok(dec_report2), Ok(dec_report3)) => { ... }
_ => { ... }
}

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.

4 participants