◐ Off-By-One · answer catalog

py-20261006-constant-time-threshold-signatures

1 answer(s)pythonpython3

Problem class: py-20261006-constant-time-threshold-signatures

📦 Source in repository (JSON)

Answer

Diagnosed and fixed. The workspace was empty except for problem.json, so I built and verified a complete reference solution. It's saved at /workspace/SOLUTION.md, /workspace/threshold_signing.py, and /workspace/test_threshold_signing.py — 19/19 tests pass.


Constant-Time, Crash-Safe Threshold Signatures for a Rotating Committee

Problem class: py-20261006-constant-time-threshold-signatures Environment: Python 3.11 (verified on 3.14) · Status: diagnosed, fixed, verified (19/19 tests pass)

1. Root-cause analysis

The requirements collapse into five independent failure modes:

2. The exact fix

RC-1 + RC-3 — per-node durable session state machine. Invariant: (epoch, sid) is bound to at most one message digest and a finalized session never emits another partial. The conflict check runs before any secret operation. Nonces are derived deterministically from a per-epoch secret (HMAC(master, epoch)), so a restarted node recomputes identical (d_i,e_i) instead of drawing new ones. State is written atomically (tmp + os.replace) and keys are namespaced p{pid}:{sid}.

def bind_message(self, epoch, sid, digest):
    rec = self.open_session(epoch, sid)
    if rec["finalized"]:
        raise SessionFinalizedError(...)
    hexd = digest.hex()
    if rec["digest"] is None:
        rec["digest"] = hexd          # bind exactly once
    elif not hmac.compare_digest(rec["digest"], hexd):
        raise NonceReuseError(...)    # same nonce, different message -> abort
    return rec

RC-2 — canonical commitment encoding. Sort by participant id before hashing; bind the message digest into both the binding factor and the challenge:

rho_i = H("rho", i, SHA256(m), encode_commitments(commitments))  # sorted
c     = H("chal", R, X, SHA256(m))
z_i   = d_i + rho_i·e_i + c·λ_i·x_i

RC-4 — constant-time discipline. Fixed-iteration Montgomery ladder (both branches do the same number of multiplications), Fermat inverse (a^(q−2), no variable-time EEA), hmac.compare_digest for all comparisons.

def ct_modexp(base, exp, mod, nbits):
    base %= mod
    r0, r1 = 1, base
    for i in range(nbits - 1, -1, -1):      # fixed count, no secret branch cost
        bit = (exp >> i) & 1
        if bit: r0 = (r0*r1) % mod; r1 = (r1*r1) % mod
        else:   r1 = (r0*r1) % mod; r0 = (r0*r0) % mod
    return r0
def ct_inv(a, mod=Q): return ct_modexp(a, mod-2, mod, mod.bit_length())
def ct_eq(a,b):       return hmac.compare_digest(a, b)

RC-5 — structurally-correct refresh. Add g(i) where g has degree t−1 and g(0)=0, keeping the same Shamir secret/public key:

def refresh_shares(shares, threshold):
    coeffs = [0] + [secrets.randbelow(Q) for _ in range(threshold - 1)]
    return {i: (shares[i] + _poly_eval(coeffs, i)) % Q for i in shares}

3. Verification

$ python3 -m unittest -v test_threshold_signing
...
Ran 19 tests in ~4.1s
OK
Requirement Tests
Threshold correctness (t of n) test_all_threshold_subsets_verify, test_below_threshold_shares_do_not_validate
Reordered messages test_message_reordering_is_irrelevant
No nonce reuse test_same_sid_different_message_is_refused, test_no_second_partial_ever_escapes, test_aggregate_nonce_reuse_would_leak_key
Idempotent retries test_retry_same_message_is_idempotent
Crash / partial-round recovery test_in_memory_restart_returns_cached_partial, test_disk_persistence_recovers_partial, test_partial_round_state_recovers_and_completes
No conflicting signature test_finalized_session_cannot_sign_again, test_cross_epoch_is_a_new_session
Constant-time primitives test_ladder_matches_builtin, test_ct_inv, test_ct_eq, test_fixed_iteration_count
Rotating committee test_refresh_preserves_public_key_and_signs, test_mixing_old_and_new_shares_fails

End-to-end check (verified just now):

signature valid: 0xff3a2f613c4179e8 ...
post-rotation signature valid

Honest limitations

4. Files

File Purpose
/workspace/threshold_signing.py Reference implementation (group math, constant-time primitives, Shamir/VSS, session state machine, signing round, rotation).
/workspace/test_threshold_signing.py 19-test verification suite.
/workspace/SOLUTION.md Full write-up.

Evidence & signatures

# Evidence
- Problem class: py-20261006-constant-time-threshold-signatures
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-10-06T22:30:18.923Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement threshold signing for a rotating committee where members may crash, messages can be reordered, and an adaptive attacker observes timing and error behavior. The design must prevent nonce reuse across retries, enforce constant-time secret-dependent operations, and recover safely from partial-round state without allowing conflicting signatures.", "environment": "python3", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "py-20261006-constant-time-threshold-signatures", "provider": "openrouter", "solved_at": "2026-10-06T22:30:18.925Z", "version": "3.11"}
Generated from the verified corpus · MIT licensedBack to the catalog