org.bouncycastle.crypto.signers.mldsa
Class MLDSAEngine
java.lang.Object
org.bouncycastle.crypto.signers.mldsa.MLDSAEngine
- public class MLDSAEngine
- extends java.lang.Object
Lightweight ML-DSA (FIPS 204) engine — key generation, signing and verification.
Constant-time note. ML-DSA is designed to admit a constant-time implementation,
and this engine keeps the secret-sensitive arithmetic branchless and free of
secret-indexed memory access: the NTT (Ntt), the Montgomery/Barrett reductions
and (Reduce), Rounding#decompose and
all operate over public loop bounds with mask-select rather than
data-dependent branches, and ML-DSA uses no secret-indexed table lookups.
The following operations are deliberately variable-time. Each matches the
FIPS 204 / pq-crystals reference and its accepted side-channel model — do not "simplify"
them into a shape that leaks more:
Rejection sampling of / (Poly#uniformEta): the number
of SHAKE bytes consumed depends on the secret seed, but only the reject count between
accepted coefficients leaks — never an accepted coefficient value. Matches reference .
The Fiat-Shamir-with-aborts loop (generateSignature(byte[], org.bouncycastle.crypto.digests.SHAKEDigest, byte[], byte[], byte[], byte[], byte[], byte[])): the iteration count
and which / bound triggered the restart leak through timing.
A rejected attempt discards and resamples, so this reveals nothing about the long-term key.
Poly#checkNorm early-returns on the first out-of-bound coefficient. The absolute
value is computed branchlessly first so a secret coefficient's sign never leaks — only the
rejection event does, exactly as the reference intends.
Rounding#makeHint branches on its inputs, but the result is the hint bit that
ships in the signature — information-equivalent to public output.
Poly#challenge (SampleInBall) has a data-dependent rejection loop and
access, but derives from the public commitment hash c~ (part of the signature / recomputed
by the verifier), so no secret is involved.
The performance refactor of this package (in-place NTT, fused pointwise-accumulate, direct
coefficient access, packed ) preserves all of the above: it adds no
secret-dependent branch, memory index, or variable-latency operation.
|
Method Summary |
byte[] |
deriveT1(byte[] rho,
byte[] key,
byte[] tr,
byte[] s1Enc,
byte[] s2Enc,
byte[] t0Enc)
|
byte[][] |
generateKeyPair()
|
byte[][] |
generateKeyPairInternal(byte[] seed)
|
byte[] |
generateMu(SHAKEDigest shake256Digest)
|
byte[] |
generateSignature(byte[] mu,
SHAKEDigest shake256Digest,
byte[] rho,
byte[] key,
byte[] t0Enc,
byte[] s1Enc,
byte[] s2Enc,
byte[] rnd)
|
int |
getDilithiumK()
|
int |
getDilithiumL()
|
int |
getDilithiumPolyEtaPackedBytes()
|
static MLDSAEngine |
getInstance(MLDSAParameters mldsaParameters,
java.security.SecureRandom random)
|
SHAKEDigest |
getShake256Digest()
|
protected org.bouncycastle.crypto.signers.mldsa.Symmetric |
GetSymmetric()
|
void |
initSign(byte[] tr,
boolean isPreHash,
byte[] ctx)
|
void |
initVerify(byte[] rho,
byte[] encT1,
boolean isPreHash,
byte[] ctx)
|
byte[] |
signInternal(byte[] msg,
int msglen,
byte[] rho,
byte[] key,
byte[] t0Enc,
byte[] s1Enc,
byte[] s2Enc,
byte[] rnd)
|
boolean |
verifyInternal(byte[] sig,
int siglen,
SHAKEDigest shake256Digest,
byte[] rho,
byte[] encT1)
|
boolean |
verifyInternalMu(byte[] providedMu)
|
boolean |
verifyInternalMuSignature(byte[] mu,
byte[] sig,
int siglen,
SHAKEDigest shake256Digest,
byte[] rho,
byte[] encT1)
|
| Methods inherited from class java.lang.Object |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
DilithiumN
public static final int DilithiumN
- See Also:
- Constant Field Values
DilithiumQ
public static final int DilithiumQ
- See Also:
- Constant Field Values
DilithiumQinv
public static final int DilithiumQinv
- See Also:
- Constant Field Values
DilithiumD
public static final int DilithiumD
- See Also:
- Constant Field Values
SeedBytes
public static final int SeedBytes
- See Also:
- Constant Field Values
CrhBytes
public static final int CrhBytes
- See Also:
- Constant Field Values
RndBytes
public static final int RndBytes
- See Also:
- Constant Field Values
TrBytes
public static final int TrBytes
- See Also:
- Constant Field Values
DilithiumPolyT1PackedBytes
public static final int DilithiumPolyT1PackedBytes
- See Also:
- Constant Field Values
DilithiumPolyT0PackedBytes
public static final int DilithiumPolyT0PackedBytes
- See Also:
- Constant Field Values
GetSymmetric
protected org.bouncycastle.crypto.signers.mldsa.Symmetric GetSymmetric()
getDilithiumPolyEtaPackedBytes
public int getDilithiumPolyEtaPackedBytes()
getDilithiumK
public int getDilithiumK()
getDilithiumL
public int getDilithiumL()
getInstance
public static MLDSAEngine getInstance(MLDSAParameters mldsaParameters,
java.security.SecureRandom random)
generateKeyPairInternal
public byte[][] generateKeyPairInternal(byte[] seed)
deriveT1
public byte[] deriveT1(byte[] rho,
byte[] key,
byte[] tr,
byte[] s1Enc,
byte[] s2Enc,
byte[] t0Enc)
getShake256Digest
public SHAKEDigest getShake256Digest()
initSign
public void initSign(byte[] tr,
boolean isPreHash,
byte[] ctx)
initVerify
public void initVerify(byte[] rho,
byte[] encT1,
boolean isPreHash,
byte[] ctx)
signInternal
public byte[] signInternal(byte[] msg,
int msglen,
byte[] rho,
byte[] key,
byte[] t0Enc,
byte[] s1Enc,
byte[] s2Enc,
byte[] rnd)
generateMu
public byte[] generateMu(SHAKEDigest shake256Digest)
generateSignature
public byte[] generateSignature(byte[] mu,
SHAKEDigest shake256Digest,
byte[] rho,
byte[] key,
byte[] t0Enc,
byte[] s1Enc,
byte[] s2Enc,
byte[] rnd)
verifyInternalMu
public boolean verifyInternalMu(byte[] providedMu)
verifyInternalMuSignature
public boolean verifyInternalMuSignature(byte[] mu,
byte[] sig,
int siglen,
SHAKEDigest shake256Digest,
byte[] rho,
byte[] encT1)
verifyInternal
public boolean verifyInternal(byte[] sig,
int siglen,
SHAKEDigest shake256Digest,
byte[] rho,
byte[] encT1)
generateKeyPair
public byte[][] generateKeyPair()