Skip to content

Validate structural arguments (num_bands, truncated sizes) in accounting events#284

Open
r1cksync wants to merge 1 commit into
google-deepmind:mainfrom
r1cksync:harden-accounting-validation
Open

Validate structural arguments (num_bands, truncated sizes) in accounting events#284
r1cksync wants to merge 1 commit into
google-deepmind:mainfrom
r1cksync:harden-accounting-validation

Conversation

@r1cksync

Copy link
Copy Markdown
Contributor

Bug

Several jax_privacy.accounting event builders forward user-controlled structural arguments into divisions / sizing without validating them, so invalid inputs either crash opaquely or are silently accepted:

>>> from jax_privacy import accounting
>>> accounting.amplified_bandmf_event(1.0, 128, num_bands=0, sampling_prob=0.01)
ZeroDivisionError: division by zero
>>> accounting.amplified_bandmf_event(1.0, 128, num_bands=-4, sampling_prob=0.01)
ValueError: Expected iterations=-32 >= 0.          # misleading: blames iterations
>>> accounting.truncated_dpsgd_event(1.0, 10, sampling_prob=0.1,
...     num_examples=-5, truncated_batch_size=-3)
<SelfComposedDpEvent ...>                           # silently accepted, nonsensical

num_bands flows into math.ceil(iterations / num_bands) in amplified_bandmf_event and truncated_amplified_bandmf_event; num_examples / truncated_batch_size flow into TruncatedSubsampledGaussianDpEvent in truncated_dpsgd_event. None were validated, while sibling builders (fixed_dpsgd_event via _validate_fixed_args) already validate their sizes.

Fix

  • _validate.positive(num_bands=num_bands) in both BandMF builders (must be ≥ 1 to partition the data and to divide by).
  • _validate.non_negative(num_examples=..., truncated_batch_size=...) in truncated_dpsgd_event, matching the _validate_fixed_args convention for dataset/batch sizes.

Only previously-invalid inputs (non-positive num_bands, negative sizes) are rejected — valid inputs are unchanged. This mirrors the already-merged #255 and the existing _validate pattern.

Testing

python -m pytest tests/accounting_test.py — 36 passed. The new parameterized tests cover each newly-guarded argument × invalid value, plus positive regressions; they fail (8 failures + 2 ZeroDivisionError) against the pre-fix code and pass after.

@r1cksync r1cksync force-pushed the harden-accounting-validation branch from 887593d to b2c7d0c Compare June 23, 2026 01:19
num_bands flows into math.ceil(iterations / num_bands) in amplified_bandmf_event
and truncated_amplified_bandmf_event but was never validated: num_bands=0 raised
an opaque ZeroDivisionError and num_bands<0 raised a misleading "iterations=..."
error. Likewise truncated_dpsgd_event forwarded num_examples /
truncated_batch_size to TruncatedSubsampledGaussianDpEvent without validation, so
negative sizes were silently accepted and produced a nonsensical event.

Guard num_bands with _validate.positive and the truncated sizes with
_validate.non_negative (matching the existing _validate_fixed_args convention),
so invalid inputs fail fast with a clear, consistent message. Only
previously-invalid inputs are rejected; valid inputs are unchanged. Adds
parameterized regression tests.
@r1cksync r1cksync force-pushed the harden-accounting-validation branch from b2c7d0c to c21fa32 Compare June 23, 2026 01:28
@github-actions

Copy link
Copy Markdown

This PR has been idle for 7 days. Please provide an update or review.

@github-actions github-actions Bot added the Stale label Jun 30, 2026
@arung54 arung54 self-assigned this Jun 30, 2026

@arung54 arung54 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the PR. No issues with the changes in logic, but a few comments to keep the style consistent. Will be happy to approve once they're addressed.

Comment thread tests/accounting_test.py
truncated_batch_size=16,
)

def test_amplified_bandmf_event_valid_num_bands_unchanged(self):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think '_unchanged' here and in the below test names is unnecessary and if anything adds confusion.

Comment thread tests/accounting_test.py
# as the continuous Gaussian with the same sigma.
self.assertAlmostEqual(eps_continuous, eps_discrete, places=4)

# -- Structural-argument validation ----------------------------------------

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think none of the comments introduced in this CL are necessary, and would suggest removing them all.

From the test names I think it is pretty easy to infer what each test is supposed to do, and the logic can be inferred from reading the file being tested. We generally prefer not to include comments if they only explain something that can be inferred by someone with knowledge of Python.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants