Highlights
Bug-fix release rolling up the security + correctness remediation from a code/security re-review of v0.2.2.
Security
- Secret-key isolation —
make_evaluator_contextnow serialises the inner TenSEAL Context without the secret key and rebuilds the wrapper from explicit fields. The keyholder's context is never mutated and shares no mutable state with the evaluator copy. - Sub-128-bit CKKS refused —
build_contextvalidates(poly_modulus_degree, coeff_mod_bit_sizes)against the HE-standard 128-bit table. Sub-128-bit configurations require explicitinsecure_allow_low_security=Trueand emitInsecureCKKSParametersWarning. - Signature downgrade closed — Signed envelopes write the canonical
signature_b64field.validate_enveloperejects legacyvalue-only blocks (closes the relay-strip downgrade vector).verify_envelope_signaturestill readsvaluefor back-compat verification of v0.2.2 envelopes. min_security_bitsfloor —validate_envelopedefaults to 128. Pass0to opt out.- CLI
--require-signatureenforces verification — Single error per failure mode (no key, key read failure, missing signature block, bad signature). No more silent satisfaction when only a signature block is present. - ANSI / Unicode sanitisation —
_safe_str(used byinspect) strips full CSI/OSC sequences and Unicode bidi / zero-width characters.
Correctness
- Per-thread
op_session()— New context manager withthreading.localstack. True isolation under concurrent audits — the previousreset_op_counters+ snapshot pattern interleaved across threads. - Encrypted-mask MSE depth fix —
_per_group_mse_termsre-foldsmask · swinto a single ct×pt before the ct×ct against ŷ², landing at depth 2 (was 3). - MAE opt-in —
mean_absolute_error_group_max(..., approximate=True)(default) acknowledges thesqrt(MSE)approximation;approximate=FalseraisesNotImplementedError. _safe_divconsolidated — Single canonical implementation in_circuitsused by base, scoring, and regression metrics.EncryptedVector.encryptbounds-checks — Rejects vectors larger thanctx.n_slotsinstead of silently truncating.- Scoring closures —
_group_min/_group_max/_group_difference/_group_ratiocapturereductionas an explicit closure variable. Plaintext fallback when fairlearn lacks the helper. audit_metricrecordsn_groups=0when no sensitive features.- Misc — Fixed double-indented
_build_encryptedbody, liftedfunctoolsimport out of hot loop, vectorisedgroup_masksfor single-column sensitive features.
Tests
Test fixture upgraded to N=16384 with an 8-prime chain (depth 6, 128-bit security). Two new regression suites — tests/test_review_v0_2_3_fixes.py and tests/test_review_v0_2_4_fixes.py — totalling 44 tests. 385 tests passing.
Migration
- Envelopes signed by v0.2.2 still verify cryptographically via
verify_envelope_signature. To passvalidate_envelopethey must be re-signed with v0.2.3 (the canonicalsignature_b64field is now required). - Callers building contexts with custom
coeff_mod_bit_sizesmay need to pick parameters from the HE-standard 128-bit table or passinsecure_allow_low_security=True.
Full diff: v0.2.2...v0.2.3