mpc-tls: size GHASH preprocessing to the configured record length - #1174
Open
SipengXie2024 wants to merge 2 commits into
Open
mpc-tls: size GHASH preprocessing to the configured record length#1174SipengXie2024 wants to merge 2 commits into
SipengXie2024 wants to merge 2 commits into
Conversation
GHASH preprocessing always allocated 1026 exponents, which is exactly one maximum-size TLS record: 1024 ciphertext blocks plus an AAD block and a length block. A connection that provisions far less still paid for a full record in both directions. Ghash::alloc now takes a max_power that MpcGhash stores, and setup, compute_shares and compute all read that stored value. The AES-GCM caller derives it from the allocation it already receives via powers_for_len, which clamps to the old bound so any caller provisioning at least one maximum-size record is unchanged, and rounds up to an even value because odd powers are converted in pairs. All four sites had to change together: compute derives its block offset from shares.len(), and that subtraction is only safe while the length guard and the share vector share one bound. Parameterising alloc alone would let it wrap in release builds and fold an empty iterator into a zero tag share with no error. alloc now also rejects bounds it cannot honour. Tests: bounded shares equal the unbounded prefix for several bounds; the derived bound always covers the input, stays even and clamps; invalid bounds are rejected; and a four-power instance reproduces the reference GHASH tag at its limit while erroring one byte past it, in both roles. Measured on a downstream TLSNotary application with an 855-byte sent allocation and a 64-byte online receive allocation: 4,123,934 fewer bytes per session (-14.1%), split almost evenly between the two directions.
prove_hash sampled the blinder itself, so a prover could not know the commitment value until the proving phase and could not start work that depends on it any earlier. ProveConfig now carries optional prover-local blinders, and prove_hash uses a supplied one when present. The field is serde(skip) and absent from ProveRequest: the verifier still learns commitment values only from the proving computation, so a prover that supplies a blinder gains nothing and the verifier assumes nothing new. Blinder::new lets a caller construct one from its own randomness. Callers remain responsible for using a cryptographically secure source and one blinder per commitment; omitting it keeps the previous sampling behaviour.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
GHASH preprocessing allocates 1026 exponents unconditionally, which is exactly one maximum-size TLS record: 1024 ciphertext blocks plus an AAD block and a length block. A connection that provisions far less still pays for a full record in both directions.
Ghash::allocnow takes amax_powerthatMpcGhashstores, andsetup,compute_sharesandcomputeall read that stored value. The AES-GCM caller derives it from the allocation it already receives:The clamp preserves existing behaviour exactly: any caller provisioning at least one maximum-size record still allocates 1026. Rounding up to an even value is required because odd powers are converted in pairs.
All four sites had to change together.
computederives its block offset fromshares.len():That subtraction is only safe while the
block_count > MAX_POWERguard and the share vector share one bound. Parameterisingallocalone would let it wrap in release builds, skip past the end of the iterator, and fold an empty zip intoGf2_128::zero()— a wrong tag share with no error.allocalso now rejects bounds it cannot honour (odd, below 2, aboveMAX_POWER).Tests added:
bounded_shares_match_the_unbounded_prefix— for bounds 2, 4, 56 and 1026, the bounded share vector equals the corresponding prefix of the full one.powers_for_len_covers_the_input_and_clamps— the bound always coversceil(len/16) + 2, stays even, and clamps.alloc_rejects_bounds_it_cannot_honor.bounded_ghash_accepts_its_limit_and_rejects_one_block_more— a four-power instance reproduces the reference GHASH tag at its limit and errors one byte past it, in both roles.Measured on a downstream application with an 855-byte sent allocation and a 64-byte online receive allocation: 4,123,934 fewer bytes per session (−14.1%), split almost evenly between the two directions, with latency unchanged.
The branch also contains a second, independent commit adding an optional prover-supplied hash commitment blinder; happy to split it into its own PR if you prefer to review them separately.