Class XMSSMTSigner

  • All Implemented Interfaces:
    Signer

    public class XMSSMTSigner
    extends java.lang.Object
    implements Signer
    XMSS^MT Signer class.
    • Constructor Summary

      Constructors 
      Constructor Description
      XMSSMTSigner()  
    • Method Summary

      All Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      byte[] generateSignature()
      generate a signature for the message we've been loaded with using the key we were initialised with.
      AsymmetricKeyParameter getUpdatedPrivateKey()  
      long getUsagesRemaining()
      Return the number of signatures the key this signer holds can still produce.
      void init​(boolean forSigning, CipherParameters param)
      Initialise for signing or verification.
      void reset()
      reset the internal state
      void update​(byte b)
      Absorb a byte of the message to be signed or verified.
      void update​(byte[] in, int off, int len)
      update the internal digest with the byte array in
      boolean verifySignature​(byte[] signature)
      Verify the buffered message against the passed in signature.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Constructor Detail

      • XMSSMTSigner

        public XMSSMTSigner()
    • Method Detail

      • init

        public void init​(boolean forSigning,
                         CipherParameters param)
        Initialise for signing or verification. A ParametersWithRandom wrapper is accepted and unwrapped before either branch is entered, the way LMSSigner.init accepts it, so a caller that wraps its key once and drives both sides is not refused by the verification one; the random the wrapper carries is not used. The randomizer r is derived from the key itself - r = PRF(SK_PRF, toByte(idx, 32)), RFC 8391 sec. 4.2.7 - so a SecureRandom supplied here has nothing to drive and is discarded, the way SPHINCS256Signer discards it. On the signing side accepting the wrapper is what BC itself needs: XMSSMTSignatureSpi.engineInitSign(PrivateKey, SecureRandom) wraps the key whenever a random is supplied, so initSign(key, random) used to fail on the cast.
        Specified by:
        init in interface Signer
        Parameters:
        forSigning - true for signing, false for verification.
        param - the key, optionally wrapped in ParametersWithRandom.
      • generateSignature

        public byte[] generateSignature()
        Description copied from interface: Signer
        generate a signature for the message we've been loaded with using the key we were initialised with.
        Specified by:
        generateSignature in interface Signer
      • verifySignature

        public boolean verifySignature​(byte[] signature)
        Verify the buffered message against the passed in signature.

        No monitor is taken here, the way the legacy signer and LMSSigner take none. This reads the public key and the mode flag, spends no one-time key and advances no traversal state, so there is nothing for a lock to serialize; and it could not serialize the message in any case, since update(byte) and reset() write the buffer without one, so a monitor held over the read alone excludes nothing a caller sharing one signer across threads is doing. What the signing side takes this monitor for is the private key field, which getUpdatedPrivateKey() reassigns; nothing reassigns the public key but init(boolean, CipherParameters), and re-initialising a signer under a running operation is the caller error it is in every other signer here.

        Specified by:
        verifySignature in interface Signer
      • getUsagesRemaining

        public long getUsagesRemaining()
        Return the number of signatures the key this signer holds can still produce. A signer that has never been initialised for signing, or one whose key has already been handed back by getUpdatedPrivateKey(), holds no key and so reports zero - reading the absent key would otherwise raise a NullPointerException.

        Initialising for verification is not one of those cases: init(boolean, org.bouncycastle.crypto.CipherParameters) deliberately leaves the private key in place, so that sign then verify then collect stays a legitimate sequence, and a signer that has signed and then been re-initialised to verify goes on reporting that key's count. What this answers is what the key it holds has left, not whether the signer is currently able to sign.

        No monitor is taken, the way the legacy signer takes none and the two key parameter classes LMS was promoted as leave their own getUsagesRemaining() unsynchronized. What this returns is a count and not a reservation: it is out of date the moment any monitor held over it is dropped, because the next signature made on that key - by this signer or by another holding it - moves it. The field read is of a reference and so cannot tear, and the key's own accessor takes the key's monitor for the traversal state the count is derived from.

      • update

        public void update​(byte[] in,
                           int off,
                           int len)
        Description copied from interface: Signer
        update the internal digest with the byte array in
        Specified by:
        update in interface Signer
      • reset

        public void reset()
        Description copied from interface: Signer
        reset the internal state
        Specified by:
        reset in interface Signer