feat(crypto): opt-in constant-time path for secret-exponent modexps [DO NOT MERGE]#8
Draft
piotr-roslaniec wants to merge 2 commits into
Draft
feat(crypto): opt-in constant-time path for secret-exponent modexps [DO NOT MERGE]#8piotr-roslaniec wants to merge 2 commits into
piotr-roslaniec wants to merge 2 commits into
Conversation
Port the upstream constant-time framework (common/constant_time.go, built on filippo.io/bigmod) and wire it, behind a default-off runtime toggle, into the secret-exponent modular exponentiations in Paillier Decrypt/Proof and the DLN, factor, and Paillier-Blum modulus proofs. Mitigates the timing side-channel gap (CVE-2023-26557 class) flagged in the threshold-ECDSA variant analysis. - common: EnableConstantTimeOps / DisableConstantTimeOps / IsConstantTimeEnabled toggle + CTModInt (ExpCT / ModInverseCT / MulCT) over filippo.io/bigmod. - Wired ops use odd moduli only; phi(N)-even inverses stay on math/big. - Default off: zero behavior/perf change unless EnableConstantTimeOps() is called. - Bump go directive 1.16 -> 1.23 (filippo.io/bigmod floor). - Tests: framework equivalence, per-proof byte-identical/verifies equivalence, and full constant-time keygen + signing end-to-end.
Close the secret-exponent coverage gap and fix correctness/robustness issues in the opt-in constant-time path: - Harden the remaining secret-exponent modexps: MtA ProveBobWC (h1^x, h1^y), ProveRangeAlice (h1^m), the ring-Pedersen trapdoor setup in keygen (h1i^alpha), and Paillier Encrypt (gamma^m) / HomoMult (c1^m). - Pad the exponent to a fixed width in ExpCT so its running time no longer leaks the secret exponent's magnitude. - ModInverseCT returns nil for non-coprime inputs (matching math/big.ModInverse) instead of a silent wrong value. - reduceToPaddedBytes reduces unconditionally (no secret-dependent branch). - Assert odd modulus at CTModInt construction (fail at build, not at Exp). - Remove the unused TimingProtection / ConstantTimeCompare / Mod() API (the jitter helper also discarded a rand error -> nil-deref panic path). - Document the hardening coverage scope in the package doc. - Add equivalence/regression tests for every new site.
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.
Summary
Closes the timing side-channel / constant-time gap (CVE-2023-26557 class) identified in the
threshold-ECDSA variant analysis. Ports the upstream BNB
tss-libconstant-time framework(
common/constant_time.go, built onfilippo.io/bigmod—the same constant-time bignum library used inside Go's
crypto/rsa/crypto/ecdsa) and wires it,behind a default-off runtime toggle, into the secret-exponent modular exponentiations.
math/bigis variable-time and leaks information about secret exponents through execution time;this provides a constant-time alternative for the operations that touch long-lived secrets.
What is wired (all behind
common.IsConstantTimeEnabled())crypto/paillier/paillier.goDecryptc^λ,Γ^λ mod N²;ModInverse(Lg, N)ExpCT;NewCTModIntWithPhi.ModInverseCTLambdaN,PhiNcrypto/paillier/paillier.goProofxs[i]^M mod NExpCTM = N⁻¹ mod φcrypto/dlnproof/proof.goNewDLNProofh1^a mod N;c·x mod pqExpCT;MulCTxcrypto/paillier/factor_proof.goFactorProofs^p,s^q mod NTildeExpCTp,qcrypto/paillier/mod_proof.goModProof+ QR helpersy^invN,x^e,x^((p-1)/2)ExpCTφ,p,qEvery modulus fed to bigmod is odd; the two φ(N)-even modular inverses (
M,invN) stay onmath/bigexactly as upstream documents. Eachelsebranch preserves the original code verbatim.Default-off / opt-in
constantTimeEnableddefaults to0. With it off (the default), behavior and performance areidentical to before. A consumer enables it once at startup:
The gap only closes once the consumer opts in. keep-core integration note: call
EnableConstantTimeOps()at startup, and note the Go-version requirement below.Verification
go build ./...,go vet(changed pkgs), fullcommon/crypto/tsssuites,ecdsa/keygen,ecdsa/signingall pass.the deterministic ops (
Decrypt,Proof, QR helpers), verifies for the randomized proofs;full CT-on keygen E2E (all parties agree on the public key) and CT-on signing E2E
(valid ECDSA signature). Every CT test asserts
IsConstantTimeEnabled()so it cannot passvacuously, and the QR helper test covers an explicit non-residue.
Blocking considerations (why "do not merge" yet)
filippo.io/bigmod). keep-core pins this forkand would need to build with Go ≥1.23. The bump also crosses Go 1.22 loop-variable
semantics — broader than just the bigmod floor. This coordination must be agreed before merge.
filippo.io/bigmod v0.1.0.isQuadResidueModPrimeCT-wrapping goes beyond upstream (no analog) and is partial —only the exponentiation is constant-time;
NewCTModInt(p)'s reduction of the secret prime isnot. Consistent with upstream's own
MulCT mod pMulQ, but a future upstream re-sync shows adelta here. Conscious choice, flagged for reviewer agreement.
Verifyis always non-CT over public data) but is not directly tested.Out of scope (separate follow-up)
The secp256k1 EC scalar-mult side channel (2019
btcecNAF →btcec/v2) — large dependencymigration, rated low-exploitability in the variant analysis, and not part of "the constant_time.go
issue."