Class XMSSEngine
This is the only public class of the package besides the two opaque BDS traversal-state types
(BDS and BDSStateMap, which an XMSS / XMSS^MT private key carries as a field and
so cannot be package-private). Everything else here - WOTS+, the hash addressing scheme, the
keyed hash functions, the tree arithmetic and the signature structures - is implementation
detail, and no compatibility is promised for it.
-
Method Summary
Modifier and TypeMethodDescriptionstatic voidclearSecrets(BDS bdsState) Zeroize the secret material a BDS traversal state retains - the WOTS+ secret key its hash-function instance imported for the last leaf it processed, which is a future leaf's one-time key while the tree is not exhausted.static voidclearSecrets(BDSStateMap bdsState) Zeroize the secret material retained by every layer of an XMSS^MT traversal state; seeclearSecrets(BDS).static BDScreateBDS(XMSSParameters params, byte[] publicSeed, byte[] secretKeySeed, int index) A fresh BDS traversal state for a key atindex, built at the all-zero OTS hash address an XMSS key starts from.static BDSStateMapcreateBDSStateMap(XMSSMTParameters params, byte[] publicSeed, byte[] secretKeySeed, long globalIndex) A fresh BDS traversal state map for an XMSS^MT key atglobalIndex, the multi-tree counterpart ofcreateBDS(XMSSParameters, byte[], byte[], int).static AsymmetricCipherKeyPairgenerateKeyPair(XMSSParameters params, SecureRandom prng) Generate an XMSS key pair (RFC 8391 sec.static AsymmetricCipherKeyPairgenerateMTKeyPair(XMSSMTParameters params, SecureRandom prng) Generate an XMSS^MT key pair (RFC 8391 sec.static byte[]generateMTSignature(XMSSMTPrivateKeyParameters privateKey, byte[] message) Generate an XMSS^MT signature overmessageand advance the key's traversal state (RFC 8391 sec.static byte[]generateSignature(XMSSPrivateKeyParameters privateKey, byte[] message) Generate an XMSS signature overmessageand advance the key's traversal state (RFC 8391 sec.static BDSgetBDSFromEncoding(byte[] encoding, byte[] publicSeed) Recover an XMSS BDS traversal state from a private key encoding, checking its checksum against the owning key's public seed (github #2414).static BDSStateMapgetBDSStateMapFromEncoding(byte[] encoding, byte[] publicSeed) Recover an XMSS^MT BDS traversal state from a private key encoding, checking its checksum against the owning key's public seed (github #2414).static DigestA tree digest by its OID.static StringThe algorithm name of a tree digest OID.static ASN1ObjectIdentifiergetDigestOID(String name) The OID of a digest by its algorithm name, for the tree digest of an XMSS parameter set.static intThe output size in bytes of a tree digest, the security parameter n.static byte[]getEncodedBDSState(BDS bdsState, byte[] publicSeed) The BDS traversal state as it is carried in an XMSS private key encoding, with its checksum bound to the owning key's public seed (github #2414).static byte[]getEncodedBDSState(BDSStateMap bdsState, byte[] publicSeed) The BDS traversal state as it is carried in an XMSS^MT private key encoding, with its checksum bound to the owning key's public seed (github #2414).static BDSgetNextBDSState(BDS bdsState, byte[] publicSeed, byte[] secretKeySeed) The traversal state for the next index, i.e.static BDSStateMapgetNextBDSStateMap(BDSStateMap bdsState, XMSSMTParameters params, long globalIndex, byte[] publicSeed, byte[] secretKeySeed) The XMSS^MT traversal state for the leaf afterglobalIndex, for the key parameters class rolling its own key on.static intgetWOTSPlusLen(ASN1ObjectIdentifier treeDigestOID, int digestSize) The number of n-byte elements in a WOTS+ key or signature, len = len1 + len2 (RFC 8391 sec.static booleanhasTraversalState(XMSSMTPrivateKeyParameters privateKey) Whether the key's BDS traversal state has been initialised, i.e.static booleanhasTraversalState(XMSSPrivateKeyParameters privateKey) Whether the key's BDS traversal state has been initialised, i.e.static booleanisStoredIndexValid(int height, long index) Whetherindexis in range for the index field of a stored private key over a tree of this height, i.e.static intlookupXMSSMTOid(String treeDigest, int digestSize, int winternitzParameter, int len, int height, int layers) The RFC 8391 sec.static intlookupXMSSOid(String treeDigest, int digestSize, int winternitzParameter, int len, int height) The RFC 8391 sec.static byte[]validateOrAllocate(byte[] value, int size, String name) Returnvalueonce it is confirmed to besizebytes long, or a freshly allocated all-zero array of that size ifvalueis null.static voidvalidateShardSize(int usageCount, long usagesRemaining) Refuse a request for a key shard ofusageCountsignatures from a key withusagesRemainingleft: a shard of none, and a shard of more than the key has.static booleanverifyMTSignature(XMSSMTPublicKeyParameters publicKey, byte[] message, byte[] signature) Verify an XMSS^MT signature (RFC 8391 sec.static booleanverifySignature(XMSSPublicKeyParameters publicKey, byte[] message, byte[] signature) Verify an XMSS signature (RFC 8391 sec.
-
Method Details
-
getDigestOID
The OID of a digest by its algorithm name, for the tree digest of an XMSS parameter set. -
getDigestName
The algorithm name of a tree digest OID. -
getDigestSize
The output size in bytes of a tree digest, the security parameter n. -
getDigest
A tree digest by its OID. Note the SP 800-208 SHAKE256/192 and SHAKE256/256 parameter sets name id-shake256-len, which no other algorithm in this package uses. -
getWOTSPlusLen
The number of n-byte elements in a WOTS+ key or signature, len = len1 + len2 (RFC 8391 sec. 3.1.1). Rejects a tree digest and security parameter that are not a registered WOTS+ combination, which is where an unusable XMSS parameter set is caught. -
lookupXMSSOid
public static int lookupXMSSOid(String treeDigest, int digestSize, int winternitzParameter, int len, int height) The RFC 8391 sec. 5.3 XMSS parameter-set identifier for this combination, or 0 when the combination is not one of the registered sets. -
lookupXMSSMTOid
public static int lookupXMSSMTOid(String treeDigest, int digestSize, int winternitzParameter, int len, int height, int layers) The RFC 8391 sec. 5.4 XMSS^MT parameter-set identifier for this combination, or 0 when the combination is not one of the registered sets. -
generateKeyPair
Generate an XMSS key pair (RFC 8391 sec. 4.1.7). -
generateMTKeyPair
Generate an XMSS^MT key pair (RFC 8391 sec. 4.2.5). -
hasTraversalState
Whether the key's BDS traversal state has been initialised, i.e. whether it can sign. A key decoded from an encoding that carried no traversal state has none.This and the XMSS^MT overload below are the only place the question is asked. What counts as no state differs between the two families - a lone BDS with no authentication path, a state map with no layers in it - and the signature methods below had a copy of the answer for their own family inlined beside the copy the signers were already calling, so widening what counts would have had to be applied to a public helper and to two private call sites that did not go through it.
-
hasTraversalState
Whether the key's BDS traversal state has been initialised, i.e. whether it can sign. -
generateSignature
Generate an XMSS signature overmessageand advance the key's traversal state (RFC 8391 sec. 4.1.9).The key is held locked across the whole check, sign and advance sequence. RFC 8391 sec. 1.1 requires each one-time key to be used exactly once, and this method both reads the index and rolls the key past it: two threads entering with the same key and nothing serializing them sign different messages under the same one-time key, and a WOTS+ key used twice discloses enough of itself to forge. The key's own accessors are individually synchronized, which does not make the compound sequence atomic, so the lock is taken here rather than left to the caller - this is a public entry point and cannot assume one.
XMSSSignerholds the same monitor and Java monitors are reentrant, so that path is unchanged; LMS takes the equivalent lock inside the key itself. -
verifySignature
public static boolean verifySignature(XMSSPublicKeyParameters publicKey, byte[] message, byte[] signature) Verify an XMSS signature (RFC 8391 sec. 4.1.10). A signature that will not decode at all is reported as a failed verification rather than raised, per the JCA contract the signers above this present. An absent one is not the same thing: there are no bytes to decode, so a null signature is the caller's mistake and is raised. -
generateMTSignature
Generate an XMSS^MT signature overmessageand advance the key's traversal state (RFC 8391 sec. 4.2.7). The key is held locked for the whole sequence, for the reason given ongenerateSignature(XMSSPrivateKeyParameters, byte[]). -
verifyMTSignature
public static boolean verifyMTSignature(XMSSMTPublicKeyParameters publicKey, byte[] message, byte[] signature) Verify an XMSS^MT signature (RFC 8391 sec. 4.2.8). As with XMSS above, a signature that will not decode is reported as a failed verification rather than raised, and an absent one is raised. -
createBDS
public static BDS createBDS(XMSSParameters params, byte[] publicSeed, byte[] secretKeySeed, int index) A fresh BDS traversal state for a key atindex, built at the all-zero OTS hash address an XMSS key starts from.- Throws:
IllegalArgumentException- ifindexis out of range for the parameter set.
-
createBDSStateMap
public static BDSStateMap createBDSStateMap(XMSSMTParameters params, byte[] publicSeed, byte[] secretKeySeed, long globalIndex) A fresh BDS traversal state map for an XMSS^MT key atglobalIndex, the multi-tree counterpart ofcreateBDS(XMSSParameters, byte[], byte[], int).The map a key at index 0 gets is empty, and stays that way until a signature needs a layer: XMSS^MT builds each layer's state lazily. So an empty map is not a missing one, and nothing downstream can tell an out-of-range index by looking at what this returns - the structural check in
BDSStateMap.validate()passes over a map with no layers in it, and the index check walks the layers it does have. That is what makes the bound here the only place the index is answered, rather than one of two.- Throws:
IllegalArgumentException- ifglobalIndexis out of range for the parameter set.
-
getNextBDSState
-
getEncodedBDSState
The BDS traversal state as it is carried in an XMSS private key encoding, with its checksum bound to the owning key's public seed (github #2414). The form is the versioned oneBDSStateCodecdefines, and this is where every one written comes from: the key parameters class reaches it for toByteArray() and for the state half of equals(), and XmssKeyUtil for the PKCS#8 encoding.The legacy Java-serialized form is a decode-side concern only. A key written before that codec existed carries one and
getBDSFromEncoding(byte[], byte[])still reads it, but nothing has written one since.- Throws:
IOException
-
getEncodedBDSState
The BDS traversal state as it is carried in an XMSS^MT private key encoding, with its checksum bound to the owning key's public seed (github #2414).- Throws:
IOException
-
clearSecrets
Zeroize the secret material a BDS traversal state retains - the WOTS+ secret key its hash-function instance imported for the last leaf it processed, which is a future leaf's one-time key while the tree is not exhausted. The tree nodes are kept; they are not secret.Here rather than as a public method on
BDSbecause the state classes are the engine's and the caller isXMSSPrivateKeyParameters.destroy()in another package: this is the same reasongetEncodedBDSState(BDS, byte[])andhasTraversalState(XMSSPrivateKeyParameters)sit here. -
clearSecrets
Zeroize the secret material retained by every layer of an XMSS^MT traversal state; seeclearSecrets(BDS). -
getNextBDSStateMap
public static BDSStateMap getNextBDSStateMap(BDSStateMap bdsState, XMSSMTParameters params, long globalIndex, byte[] publicSeed, byte[] secretKeySeed) The XMSS^MT traversal state for the leaf afterglobalIndex, for the key parameters class rolling its own key on. The state passed in is left where it is and a new one comes back, asgetNextBDSState(BDS, byte[], byte[])does for the single tree.That it returns the advanced state rather than advancing the one it is given is what makes it safe to be public - and public it has to be, the key parameters class being in another package and Java having no way to say "callable from these two packages only". A state map is reachable from a live private key through its getBDSState(), so a version of this that advanced its argument let a holder move a key's state out from under the index the key still reported. A key whose two records of its position disagree signs a second message under a one-time key it has already spent, against RFC 8391 sec. 1.1, and that signature verifies.
With the state replaced instead, the two records move together or not at all: the key assigns both, a failure part way through leaves it on the index it was already on, and a holder calling this gets a state map of its own while the key keeps the one it had. Nothing is left for the signer to check, and the one remaining way for a key's index and state to part - a stored key written or restored wrongly - is refused when the key is built.
-
getBDSFromEncoding
public static BDS getBDSFromEncoding(byte[] encoding, byte[] publicSeed) throws IOException, ClassNotFoundException Recover an XMSS BDS traversal state from a private key encoding, checking its checksum against the owning key's public seed (github #2414).- Throws:
IOExceptionClassNotFoundException
-
getBDSStateMapFromEncoding
public static BDSStateMap getBDSStateMapFromEncoding(byte[] encoding, byte[] publicSeed) throws IOException, ClassNotFoundException Recover an XMSS^MT BDS traversal state from a private key encoding, checking its checksum against the owning key's public seed (github #2414).- Throws:
IOExceptionClassNotFoundException
-
isStoredIndexValid
public static boolean isStoredIndexValid(int height, long index) Whetherindexis in range for the index field of a stored private key over a tree of this height, i.e. 0 <= index <= 2^height.The bound is one leaf wider than the 0 <= index < 2^height an index a signature can be made at satisfies, because a key that has been used up carries the index one past its last leaf: that is the placeholder traversal state
BDSinstalls when the final one-time key is consumed, it is what makes the key report no usages remaining, and bothBDS.validate()and the BDS serialization admit it. A key's final state is the one state that most needs to survive being written out and read back, so the private key encoding has to carry it rather than reject it. The tighter bound against the key's own maximum index is applied byBDS.validate()once the traversal state itself has been recovered. -
validateOrAllocate
Returnvalueonce it is confirmed to besizebytes long, or a freshly allocated all-zero array of that size ifvalueis null.nameis how the field is named in the message a wrong-sized one is refused with.Shared by the four key parameter classes and the two signature classes, which take their optional n-byte fields on the same terms and so must say the same thing about one that is the wrong size.
-
validateShardSize
public static void validateShardSize(int usageCount, long usagesRemaining) Refuse a request for a key shard ofusageCountsignatures from a key withusagesRemainingleft: a shard of none, and a shard of more than the key has.Shared by the two private key classes, which mean the same thing by both and had said it in the same words twice - and the words are the contract, since a message is what a caller catching IllegalArgumentException has to tell the two cases apart by. Beside validateOrAllocate above for the same reason it is here: the four key classes and the two signature classes take their optional n-byte fields on the same terms, and this is the terms both key classes hand out a shard on.
- Parameters:
usageCount- signatures asked for.usagesRemaining- signatures the key has left, read under the key's own monitor.
-