Class BDSStateMap
- All Implemented Interfaces:
Serializable
Every read and every write of the map below is taken on this object's own monitor, and one fact
is behind all of them: XMSSMTPrivateKeyParameters.getBDSState() hands this object out
live, and a signature descends the layers installing the states it builds lazily into the map it
is signing with. An insertion rebalances the TreeMap underneath, so anything walking or
looking up outside the monitor reads a tree part way through being restructured - a
ConcurrentModificationException at best, and at worst a lookup that answers with a null
or with another layer's state. Holding the monitor for the whole of an operation, rather than
once per lookup, is also what makes an answer coherent rather than merely intact: the signer
holds this same monitor for its whole descent, so what an operation here sees is every layer
from before that signature or every layer from after it, never a mixture.
What each method does with that is on the method. None of them repeats this.
- See Also:
-
Constructor Summary
ConstructorsConstructorDescriptionBDSStateMap(long maxIndex) BDSStateMap(XMSSMTParameters params, long globalIndex, byte[] publicSeed, byte[] secretKeySeed) BDSStateMap(BDSStateMap stateMap, long maxIndex) Copy the states of another map, on that map's own monitor for the whole walk - which is what makes this safe to run against a map a key is signing with, for the reason on the class. -
Method Summary
Modifier and TypeMethodDescriptionget(int index) longvoidvalidate(XMSSMTParameters params) voidvalidate(XMSSMTParameters params, long globalIndex) Validate as validate(XMSSMTParameters) and additionally tie each layer's traversal state to the enclosing private key's index.voidvalidateIndex(XMSSMTParameters params, long globalIndex) The index half of validate(XMSSMTParameters, long) on its own: tie each layer's traversal state to the index its enclosing key declares, without re-walking the structure of every state.voidvalidateRoot(XMSSMTParameters params, byte[] expectedRoot) Confirm the top layer's root is the one the enclosing private key declares - the top tree's root is the public root.withMaxIndex(long maxIndex, ASN1ObjectIdentifier digestName, int digestSize) AswithWOTSDigest(ASN1ObjectIdentifier, int), and with a maximum index of the caller's rather than this map's - the state map counterpart ofBDS.withMaxIndex(int, ASN1ObjectIdentifier, int), and whatXMSSMTPrivateKeyParameters.Builder.withBDSStatecopies a state map with, so that a state installed in a key is always one whose WOTS+ parameters the key's own parameter set named.withWOTSDigest(ASN1ObjectIdentifier digestName) withWOTSDigest(ASN1ObjectIdentifier digestName, int digestSize)
-
Constructor Details
-
BDSStateMap
public BDSStateMap(long maxIndex) -
BDSStateMap
Copy the states of another map, on that map's own monitor for the whole walk - which is what makes this safe to run against a map a key is signing with, for the reason on the class.Each layer is copied rather than shared, and the copy is not incidental. A
BDSis filled at construction and never written afterwards - the block aboveBDS's getLive accessors says so, and advancing a layer builds its successor andputs it here - with one exception:markUsed()writes the used mark in place. This constructor has two callers,getNextState(XMSSMTParameters, long, byte[], byte[])andXMSSMTPrivateKeyParameters.extractKeyShard, and it is the second that leaves two live keys holding maps built from one map. A shared layer zero would be those two keys sharing one record of whether the one-time key at that leaf has been spent - the mark one of them made becoming the refusal the other gets, and the mark it did not make becoming the refusal it does not get, which is the direction RFC 8391 sec. 1.1 is about. Only layer zero is ever marked, so sharing the layers above it would be safe asmarkUsed()is written today; that is a fact about that method rather than about this one, and it would buy the copy ongetNextState's roll path alone.The two key builders'
withBDSStateleave two live keys the same way and reach the same guarantee, but not through here: they go throughwithMaxIndex(long, ASN1ObjectIdentifier, int), which builds an empty map and fills it a layer at a time out ofBDS.withWOTSDigest(ASN1ObjectIdentifier), itself a copy. So there are two ways a state map is copied per layer in this package rather than one, and a change to the copying here covers neither builder. -
BDSStateMap
public BDSStateMap(XMSSMTParameters params, long globalIndex, byte[] publicSeed, byte[] secretKeySeed)
-
-
Method Details
-
getMaxIndex
public long getMaxIndex() -
validate
-
validateRoot
Confirm the top layer's root is the one the enclosing private key declares - the top tree's root is the public root. A layer with no state yet is built lazily at signing time and so is not compared (github #2414).- Parameters:
params- the parameters of the enclosing key.expectedRoot- the root the private key declares.
-
validate
Validate as validate(XMSSMTParameters) and additionally tie each layer's traversal state to the enclosing private key's index. RFC 8391 sec. 1.1 requires each one-time key to be used once, and the global index and the per-layer BDS states are two records of the same position, so a stored key whose index has been rolled back while its state stayed advanced - a partial write, a restore from backup, a buggy storage layer - is detectable and must be refused: it would otherwise sign a second message under a one-time key already used, and the signature would verify. The XMSS side has done this since its own state was tied to its index; this is the multi-tree counterpart.- Parameters:
params- the parameters of the enclosing key.globalIndex- the index the enclosing key declares.
-
validateIndex
The index half of validate(XMSSMTParameters, long) on its own: tie each layer's traversal state to the index its enclosing key declares, without re-walking the structure of every state.Separate because the two halves answer at different times. The structure of a state can only be wrong on the way in, so the constructor is where it is checked; the index pair can go wrong every time the key moves, because the two records are advanced by two statements and only the author of those statements keeps them together. So this half runs on every roll and before every encoding, where the full check would be re-walking authentication paths, stacks and tree hashes once per signature to learn nothing new.
- Parameters:
params- the parameters of the enclosing key.globalIndex- the index the enclosing key declares.
-
get
-
withWOTSDigest
-
withWOTSDigest
-
withMaxIndex
AswithWOTSDigest(ASN1ObjectIdentifier, int), and with a maximum index of the caller's rather than this map's - the state map counterpart ofBDS.withMaxIndex(int, ASN1ObjectIdentifier, int), and whatXMSSMTPrivateKeyParameters.Builder.withBDSStatecopies a state map with, so that a state installed in a key is always one whose WOTS+ parameters the key's own parameter set named. Only the map's own maximum index is the caller's: each layer keeps the one its subtree fixes, as it does through every other copy of a state map.The two used to have to be done one after the other, and in one order, because copying a state that had not been given its digest yet was a NullPointerException; they can be done in either order now, and this does them in one pass rather than either.
- Parameters:
maxIndex- the maximum index the copy is to carry.digestName- the tree digest of the key the copy belongs to.digestSize- its output length in bytes, where the digest does not fix one.
-