public class MLDSAEngine
extends java.lang.Object
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 conditionalAddQ (Reduce), Rounding.decompose(int, int) and
power2RoundAll 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:
s1/s2 (Poly.uniformEta(byte[], short)): 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 rej_eta.generateSignature(byte[], org.bouncycastle.crypto.digests.SHAKEDigest, byte[], byte[], byte[], byte[], byte[], byte[])): the iteration count
and which checkNorm/makeHint bound triggered the restart leak through timing.
A rejected attempt discards y and resamples, so this reveals nothing about the long-term key.Poly.checkNorm(int) 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 poly_chknorm intends.Rounding.makeHint(int, int, org.bouncycastle.crypto.signers.mldsa.MLDSAEngine) branches on its inputs, but the result is the hint bit that
ships in the signature — information-equivalent to public output.Poly.challenge(byte[], int, int) (SampleInBall) has a data-dependent rejection loop and c[b]
access, but b derives from the public commitment hash c~ (part of the signature / recomputed
by the verifier), so no secret is involved.decompose) preserves all of the above: it adds no
secret-dependent branch, memory index, or variable-latency operation.| Modifier and Type | Field and Description |
|---|---|
static int |
CrhBytes |
static int |
DilithiumD |
static int |
DilithiumN |
static int |
DilithiumPolyT0PackedBytes |
static int |
DilithiumPolyT1PackedBytes |
static int |
DilithiumQ |
static int |
DilithiumQinv |
static int |
RndBytes |
static int |
SeedBytes |
static int |
TrBytes |
| Modifier and Type | Method and Description |
|---|---|
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) |
public static final int DilithiumN
public static final int DilithiumQ
public static final int DilithiumQinv
public static final int DilithiumD
public static final int SeedBytes
public static final int CrhBytes
public static final int RndBytes
public static final int TrBytes
public static final int DilithiumPolyT1PackedBytes
public static final int DilithiumPolyT0PackedBytes
protected org.bouncycastle.crypto.signers.mldsa.Symmetric GetSymmetric()
public int getDilithiumPolyEtaPackedBytes()
public int getDilithiumK()
public int getDilithiumL()
public static MLDSAEngine getInstance(MLDSAParameters mldsaParameters, java.security.SecureRandom random)
public byte[][] generateKeyPairInternal(byte[] seed)
public byte[] deriveT1(byte[] rho,
byte[] key,
byte[] tr,
byte[] s1Enc,
byte[] s2Enc,
byte[] t0Enc)
public SHAKEDigest getShake256Digest()
public void initSign(byte[] tr,
boolean isPreHash,
byte[] ctx)
public void initVerify(byte[] rho,
byte[] encT1,
boolean isPreHash,
byte[] ctx)
public byte[] signInternal(byte[] msg,
int msglen,
byte[] rho,
byte[] key,
byte[] t0Enc,
byte[] s1Enc,
byte[] s2Enc,
byte[] rnd)
public byte[] generateMu(SHAKEDigest shake256Digest)
public byte[] generateSignature(byte[] mu,
SHAKEDigest shake256Digest,
byte[] rho,
byte[] key,
byte[] t0Enc,
byte[] s1Enc,
byte[] s2Enc,
byte[] rnd)
public boolean verifyInternalMu(byte[] providedMu)
public boolean verifyInternalMuSignature(byte[] mu,
byte[] sig,
int siglen,
SHAKEDigest shake256Digest,
byte[] rho,
byte[] encT1)
public boolean verifyInternal(byte[] sig,
int siglen,
SHAKEDigest shake256Digest,
byte[] rho,
byte[] encT1)
public byte[][] generateKeyPair()