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

Use record IDs to index proof batches #1350

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

Conversation

andyleiserson
Copy link
Collaborator

Since we are not guaranteed that all proofs have the same size, I serialize the proof values into fixed-size structures and use one record ID per proof, rather than doing record ID arithmetic, except for PRSS.

Fixes #1269

Copy link

codecov bot commented Oct 15, 2024

Codecov Report

Attention: Patch coverage is 98.06452% with 6 lines in your changes missing coverage. Please review.

Project coverage is 93.49%. Comparing base (da336af) to head (6bb16e1).
Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
...rc/protocol/ipa_prf/malicious_security/lagrange.rs 0.00% 3 Missing ⚠️
...ol/ipa_prf/validation_protocol/proof_generation.rs 95.65% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1350      +/-   ##
==========================================
- Coverage   93.51%   93.49%   -0.03%     
==========================================
  Files         210      210              
  Lines       35032    35211     +179     
==========================================
+ Hits        32759    32919     +160     
- Misses       2273     2292      +19     

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

@andyleiserson
Copy link
Collaborator Author

andyleiserson commented Oct 15, 2024

// $$ depth >= log_8 target_proof_size $$
// Because multiplication intermediate storage gets rounded up to blocks of 256, leaving
// some margin is advised.
pub const MAX_PROOF_RECURSION: usize = 9;
Copy link
Collaborator Author

@andyleiserson andyleiserson Oct 15, 2024

Choose a reason for hiding this comment

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

Recursion depth of 9 corresponds to TARGET_PROOF_SIZE of about 117M. Without quicksort batching, this is not quite enough. So either we can wait for quicksort batching, or we can temporarily increase MAX_PROOF_RECURSION slightly. I lean towards the former unless we identify an urgency to take this change.

// * We need (SRF - 1) at the last level to have room for the masks.
let max_uv_values: usize =
(SRF - 1) * SRF.pow(u32::try_from(MAX_PROOF_RECURSION - 2).unwrap());
tracing::info!("uv_values.len() = {}", uv_values.len());
Copy link
Collaborator

Choose a reason for hiding this comment

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

trace?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I just wanted to see the values in the draft run, I am going to remove this.

.map(|buf| Fp61BitPrime::deserialize(buf.try_into().unwrap()))
.collect::<Result<Vec<_>, _>>()?
.try_into()
.unwrap())
Copy link
Collaborator

Choose a reason for hiding this comment

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

oh this is neat, I didn't know you can go from Result<Vec<_>, _> to Result<Box<_>, _>, I guess because there exists blanket From<Vec<T>> for Box<T>

pub struct RecordIdRange(Range<RecordId>);

impl RecordIdRange {
pub const ALL: RecordIdRange = RecordIdRange(RecordId(0)..RecordId(u32::MAX));
Copy link
Collaborator

Choose a reason for hiding this comment

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

would it be better to add LAST to RecordId and use FIRST..LAST here?

(0..length)
.map(|i| async move { receive_channel_right.receive(RecordId::from(i)).await }),
)
.set_total_records(TotalRecords::Indeterminate)
Copy link
Collaborator

Choose a reason for hiding this comment

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

oh, this is much better than parallel join, can't wait until I see the impact of this change

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't expect that this is big enough contributor that the difference will show up in overall runtime, but I do think that getting rid of the parallel join more than offsets any cost of space overhead in the fixed-size structures.

pub async fn receive_from_right<C>(
ctx: &C,
record_id: RecordId,
length: usize,
Copy link
Collaborator

Choose a reason for hiding this comment

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

How often do we need to shrink?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since many of our batches end up being smaller than the target, reasonably often... but since we do this only once per proof, it doesn't seem worth a lot of effort to optimize.

// Prover `P_i` and verifier `P_{i+1}` both compute q(x)
// therefore the "left" share computed by this verifier corresponds to that which
// was used by the prover to the left.
let (q_mask_from_left_prover, my_q_mask) = ctx.prss().generate_fields(record_counter);
record_counter += 1;
let (q_mask_from_left_prover, my_q_mask) =
Copy link
Collaborator

Choose a reason for hiding this comment

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

record_id_range.next().unwrap() is dominantly used everywhere it seems. I think we should either implement a helper function to make it look less ugly at callsite and potentially not implement the iterator trait for it as we don't have (unless I missed it) for x in range use case

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thoughts on what to call the helper? Maybe expect_next()?

@andyleiserson andyleiserson marked this pull request as ready for review October 17, 2024 21:26
@andyleiserson
Copy link
Collaborator Author

Draft run, 25M: https://draft-mpc.vercel.app/query/view/flaky-stern2024-10-17T2136. 3 hr 16 min, slightly slower than the run in #1355, which was 3 hr 4 min. Not sure if the difference is real or just variation.

@akoshelev
Copy link
Collaborator

akoshelev commented Oct 18, 2024

Not sure if the difference is real or just variation.

seems more than just variation to me, but we could try a few runs.

@andyleiserson andyleiserson linked an issue Oct 18, 2024 that may be closed by this pull request
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.

Add proper DZKP batching to quicksort DZKPs should use record IDs, not steps, to iterate over proof batches
2 participants