`VA 20190`

`VA 20190`

`VA 20190`

`VA 20190`

- Node Set
- A set of nodes, each of which is part of a union of tree structures either as a leaf node whose value is the hash of a single data value, or an internal node whose value is the hash of two child nodes. The node set is acyclic, i.e., every node is either a leaf node or the ancestor of two or more leaf nodes, and no node is an ancestor of itself. Every node set has one or more root nodes, i.e., nodes that have no ancestors.
- Rung
- A node from a node set that can be used to authenticate one or more leaf nodes within that node set.
- Ladder
- A collection of one or more rungs that can be used to verify an authentication path.
- Authentication Path
- The set of sibling hash values from a leaf hash value to a rung
- Message
- A set of bytes that are intended to be signed and later verified.

- ** : a ** b denotes the value of a raised to the power of b
- * : a * b denotes the product of a multiplied by b
- / : a / b denotes the quotient of a divided by b
- + : a + b denotes the sum of a and b when a and b are numbers
- - : a - b denotes the difference of a and b
- = : a = b denotes assigning the value of b to a

- & : a & b denotes the bitwise AND of the unsigned integers a and b
- | : a | b denotes the bitwise OR of the unsigned integers a and b
- ~ : ~a denotes the bitwise NOT of the unsigned integer a
- >> : a >> i denotes a right bit shift (non-rotating) of a by i bit positions to the right.
- << : a << i denotes a left bit shift (non-rotating) of a by i bit positions to the left.

- == : a == b denotes the comparison between a and b to see if the two values are equal
- <= : a <= b denotes the comparison between a and b to see if a is less than or equal to b
- >= : a >= b denotes the comparison between a and b to see if a is greater than or equal to b
- != : a != b denotes the comparison between a and b to see if a is not equal to b

- The notation A[i] represents the ith element of array A.

- + : a + b denotes the concatenation of values a and b when a and b are byte strings.

- Classes and data structures are written in all uppercase (e.g. MTLNS)
- Constant values are also written as all uppercase with _ separating words (e.g. MTL_SIG_CONDENSED)
- Variables are written in all lowercase with _ separating words as needed (e.g. left_hash or tree)
- Functions are written in all lower case and proceeded by a comment block that highlights the input and output parameters.

- The signer maintains a dynamic data structure called a Merkle node set. The leaf nodes of the node set correspond to the messages that are being "signed" for later authentication and the internal nodes of the node sets are the hashes of two child nodes. Similar to a Merkle tree structure, ancestors authenticate or "cover" their descendants. A Merkle node set is more general than a Merkle tree in that more than one node can be a root node (i.e., a node without ancestors). For instance, a Merkle node set could include multiple trees.
- As the node set evolves, the signer occasionally selects a set of nodes from the node set that collectively cover all the leaf nodes. Such a set is called a "ladder" and each node within the set is called a "rung." The rungs are selected according to a "binary rung strategy" where each rung is the root of a perfect binary tree (see
). - The signer signs each ladder with the private key of the underlying signature scheme. The signature on the ladder is the "MTL mode signature" of the set of messages covered by the ladder.
- For each message of interest to a verifier, the signer provides the verifier a Merkle authentication path from the leaf node corresponding to the message to a rung in the then-current ladder. Similar to a Merkle tree structure, the authentication path includes the sibling hashes on the path from the leaf node to a rung on the ladder that covers the leaf node.
- If the verifier has a ladder that is "compatible" with the authentication path, the verifier verifies the authentication path on the message relative to the ladder.
- If not, the verifier requests the signed ladder that the authentication path was computed relative to. (Alternatively, the verifier may request a "full" signature on the message that includes both the authentication path and the signed ladder that it is computed relative to, which could be the current ladder. See
for a description of a full signature.) - The signer provides the signed ladder. (Or, alternatively, the signer provides a full signature including the authentication path together with a signed ladder.)
- The verifier verifies the signature on the signed ladder and returns to Step 5.

- MTL_LADDER_SEP is the integer 129 (a new domain separator value that provides easy visual separation in hexadecimal from the identifiers 0 and 1 in NIST's proposal)
- ctx is an application-specified context string at most 255 octets (bytes) long (default is the empty string)
- OID_MTL is the DER encoding of the object identifier of the selected instantiation of MTL mode (see
for the list of instantiations; the object identifiers are TBD) - ladder is the Merkle tree ladder being signed or verified

- MTL_MSG_SEP is the integer 128 (a counterpart to MTL_LADDER_SEP's 129 above)
- ctx is an application-specified context string at most 255 octets (bytes) long (default is the empty string)
- value is the rest of the value being input to the function

- H_msg_mtl(R_mtl, PK.seed, PK.root, M) -> md maps a n-byte randomizer, a n-byte public seed, a n-byte public root and a variable-length message to a n-byte hash value md.

- R_mtl is the randomizer for the message digest operation
- PK.seed the public seed from the public key
- PK.root is the public root from the public key
- M is the message being processed.

- PRF_msg(SK.prf, OptRand, M) -> R_mtl maps a n-byte secret PRF key, a n-byte optional random value, and a variable-length message to a n-byte randomizer R_mtl.

- SK.prf is the secret PRF key from the private key.
- OptRand depends on whether an implementation wants deterministic signing. If it does, then OptRand SHOULD be a fixed value, e.g., all 0s or PK.seed. (The SPHINCS+ specification suggests both options in different places for its internal use of OptRand.) If not, then OptRand MUST be a randomly generated value.
- M is the message being processed.

- F(PK.seed, ADRS, M_1) -> md maps a n-byte public seed, a 32-byte address value and a n-byte message value to a n-byte hash value
- H(PK.seed, ADRS, M_1 || M_2) -> md maps a n-byte public seed, a 32-byte address value and the concatenation of two n-byte message values to a n-byte hash value

- PK.seed is the public seed from the public key. This value is a "tweak" to the hash function that separates uses of the function with different public keys (assuming different public keys have different public seeds, as they almost always will if the public seeds are generated at random).
- ADRS is the address associated with the call to the function. This value is another "tweak" that separates uses of the function for different purposes.
- M_1 (input to F) is a n-byte value being hashed.
- M_1 || M_2 (input to H) is the concatenation of two n-byte values being hashed together.

- MTL Message Hash (type MTL_MSG = 16). This type is used in the address value that is prepended to a message when calling PRF_msg to compute a randomizer or when calling H_msg_mtl to compute a data value from a message. For this type, the sixth and seventh words MUST be 0 and the eighth word MUST be the message index (i.e., the leaf index of the corresponding leaf node).
- MTL Data Value (type MTL_DATA = 17). This type is used when calling F to compute a leaf node hash value from a data value. For this type, the sixth and seventh words MUST be 0 and the eighth word MUST be the leaf index.
- MTL Tree (type MTL_TREE = 18). This type is used when calling H to compute an internal node hash value from two child node hash values. For this type, the sixth word MUST be 0, the seventh word MUST be the left index associated with the internal node and the eighth word MUST be the right index associated with the internal node.

- When calling H_msg_mtl to compute a data value from a message, see
and , a MTL message domain separator and an address value of type MTL_MSG are prepended to the message, where the address value includes the message index - When calling the underlying signature scheme to sign a ladder or verify a signature on a ladder (see
), a MTL ladder domain separator is prepended to the ladder

- Form an address value ADRS of type MTL_MSG from the series identifier and the message index as described in Section 4.6.
- Format a MTL message domain separator sep from the context string as follows:

- With deterministic hashing, let OptRand be the public seed PK.seed
Generate a randomizer R_mtl using a secure random generator [RFC4086]. An implementation MAY use the following steps: - With randomized hashing, let OptRand be a random n-byte value
- Compute a randomizer by applying PRF_msg to a secret PRF key, SK.prf, the optional random value and the address value prepended with the domain separator

- Compute the data value by applying H_msg_mtl to the randomizer, the public seed, the public root and the message prepended with the same address value

- Form an address value ADRS of type MTL_MSG from the series identifier and the message index as described in Section 4.6.
- Format a MTL message domain separator sep from the context string as follows:

- Compute the data value by applying H_msg_mtl to the randomizer, the public seed, the public root and the message prepended with the domain separator and the address value:

- L is the node's left index, a non-negative integer
- R is the node's right index, a non-negative integer
- V is the node's hash value

- L <= leaf_index <= R, ensuring the leaf index is covered by the rung
- (L = 0 or degree <= lsb(L)-1) and R-L+1 = 2^degree, where degree = lsb(R-L+1)-1, ensuring the rung is indeed an apex of a perfect binary tree in the binary rung strategy
- lsb(R-L+1) is less than or equal to the number of sibling hash values in the authentication path, ensuring the authentication path can reach the rung

- flags, a 2-byte string providing future extensibility; the initial value for this field MUST be 0
- sid, the series identifier, a 8-byte string
- rung_count, the number of rungs in the ladder, a positive integer between 1 and 2^16-1
- rungs, one or more rung data structures

- left_index, the left index of the rung, a non-negative integer
- right_index, the right index of the rung, a non-negative integer
- hash, the rung hash value, a n-byte string

- flags, a 2-byte string providing future extensibility; it MUST be 0 for this version of the document
- sid, the series identifier, a 8-byte string
- leaf_index, the leaf index of the data value being authenticated, a non-negative integer
- sibling_hash_count, the number of sibling hash values in the authentication path, a non-negative integer between 0 and 2^16-1
- sibling_hashes, zero or more sibling hash values, each a n-byte string
- rung_left, the left index of the target rung, a non-negative integer
- rung_right, the right index of the target rung, a non-negative integer

- the public seed MUST be a n-byte string
- the series identifier MUST be a 8-byte string
- the various node indexes (leaf_index, left_index, right_index, etc.) MUST be non-negative integers between 0 and 2^32-1 (so they can be represented as 4-byte strings in big endian notation)
- the data value MUST be a n-byte string
- the various hash values (leaf_hash, left_hash, right_hash, internal_hash, etc.) MUST be a n-byte strings

- Generate a public / private key pair for an underlying signature scheme, where the public key includes a public seed and a public root and the private key includes a public seed, a public root, and a secret PRF key.

- Initialize a node set for the series from a public seed and a series identifier using mtl_initns. The message index for the message series is set to 0 in this step.

Compute a randomizer and a data value from the message, the context string, the series identifier and the message index for the message series as described in . Note that a domain separator of type MTL_MSG_SEP is prepended to the inputs to functions in . (See for further discussion.) Append the data value to the node set for the message series using mtl_append. The message index for the message series is incremented in this step.

Compute the current ladder for the node set using mtl_ladder. Format a domain separator sep from the context string as follows:

- Provide the signed ladder associated with a specified ladder identifier.

- Compute an authentication path for the data value at a specified message index relative to the current ladder using mtl_authpath.

- Provide the authentication path and the randomizer associated with a message to be authenticated, e.g., in a condensed signature. The signer MAY also provide an explicit ladder identifier for the ladder that the authentication path was computed relative to - see
. Alternatively, the signer may offer the option of requesting a full signature that includes the authentication path, the randomizer and a signed ladder.

- Obtain the signer's public key for the underlying signature scheme, where the public key includes a public seed and a public root.

Obtain the authentication path and the randomizer associated with the message to be authenticated, e.g., in a condensed signature. The verifier MAY also obtain an explicit ladder identifier for the ladder that the authentication path was computed relative to - see . Determine whether any of ladders held by the verifier includes a rung compatible with the authentication path, e.g., using mtl_rung. If not, then proceed to Step 6 and return here. Re-compute a data value from the message, the context string, the series identifier in the authentication path and the message index in the authentication path and the randomizer as described in . Note that a domain separator of type MTL_MSG_SEP is prepended to the message prior to calling the functions in . (See for further discussion). Verify the authentication path for the data value at a specified message index relative to the compatible rung using mtl_verify.

Obtain the signed ladder associated with a specified ladder identifier. Alternatively, the verifier may request a full signature including an authentication path and the signed ladder that it is computed relative to. Format a domain separator sep from the context string and the MTL mode object identifier as follows:

- Identifying the ladder based on a public key identifier and information in the authentication path itself, i.e., the series identifier and the target index pair. This combination is sufficient to identify the public key, the series of data values (and thus the MTL node set), and the ladder of interest (given the target index pair, with the binary rung strategy).
- Identifying the ladder with a URI or other explicit identifier that refers to a location where the signed ladder is stored or to the signed ladder itself. This URI can be conveyed together with the authentication path in an application.
- Specifying interest in a ladder implicitly by setting a flag in the request for a message and its associated authentication path. When the flag is not set, the message and authentication path would be returned (producing a condensed signature - see
). When the flag is set, the message, the signed ladder is also would be returned (producing a full signature - see ).

- R_mtl, the randomizer, a n-byte string
- auth_path, the authentication path
- ladder, the ladder
- sig_len, the length in bytes of the underlying signature on the ladder, a positive integer between 1 and 2^32-1 (so it can be represented as 4-byte string in big endian notation)
- sig, the underlying signature on the ladder, a scheme-specific string

- R_mtl, the randomizer, a n-byte string
- auth_path, the authentication path (
)

- ladder, the ladder (
) - sig_len, the length in bytes of the underlying signature on the ladder, a positive integer between 1 and 2^32-1 (so it can be represented as 4-byte string in big endian notation)
- sig, the underlying signature on the ladder, a scheme-specific string

- SPHINCS+-MTL-{hash}-{bitsec}{opt}-{variant}

{hash} is the underlying hash function. For this version of the document, it MUST be "SHAKE" or "SHA2", corresponding to the underlying hash function. {bitsec} is the target bit security. It MUST be "128", "192" or "256", corresponding to the "bitsec" value in . The security parameter n is the target bit security level divided by 8, i.e., 16, 24 or 32. The corresponding NIST security levels for these bit security levels are 1, 3 and 5. {opt} is the optimization goal. It MUST be "s" or "f". As discussed in , the "s" optimization results in smaller signature sizes, while the "f" optimization results in faster signing operations. {variant} is the style of the tweakable hash function. It must be "simple" or "robust". As discussed in , the "simple" style results in faster operations, while the "robust" style results in more conservative security proofs.

- H_msg_mtl(R, PK.seed, PK.root, M) = SHAKE256(R || PK.seed || PK.root || M, 8n)

- PRF_msg(SK.prf, OptRand, M) = SHAKE256(SK.prf || OptRand || M, 8n)

- F(PK.seed, ADRS, M_1) = SHAKE256(PK.seed || ADRS || M_1*, 8n)
- H(PK.seed, ADRS, M_1, M_2) = SHAKE256(PK.seed || ADRS || (M_1 ||M_2)*, 8n)

- M_1* = M_1 xor SHAKE256(PK.seed, ADRS, 8n)
- (M_1 || M_2)* = (M_1 || M_2)* xor SHAKE256(PK.seed, ADRS, 16n)

- F(PK.seed, ADRS, M_1) = SHAKE256(PK.seed||ADRS||M_1, 8n)
- H(PK.seed, ADRS, M_1, M_2) = SHAKE256(PK.seed || ADRS || M_1 || M_2, 8n)

- H_msg_mtl(R, PK.seed, PK.root, M) = MGF1-SHA-X(R || PK.seed || SHA-X(R || PK.seed || PK.root || M), n).

- PRF_msg(SK.prf, OptRand, M) = HMAC-SHA-X(SK.prf, OptRand || M)

- F(PK.seed, ADRS, M_1) = SHA2-256(BlockPad(PK.seed) || ADRS^c || M_1*)
- H(PK.seed, ADRS, M_1, M_2) = SHA-X(BlockPad(PK.seed) || ADRS^c || (M_1 ||M_2)*)

- BlockPad(PK.seed) = PK.seed || toByte(0, bl-n) where bl=64 for SHA2-256 and bl=128 for SHA-512.
- ADRS^c is a 22-byte "compressed" version of the address value that omits bytes 1-3, 5-8 and 21-23. (In MTL mode, the omitted bytes are all zeros because the address type is one byte long - see Section 3.4.)
- M_1* = M_1 xor MGF1-SHA-X(PK.seed, ADRS, 8n)
- (M_1 || M_2)* = (M_1 || M_2)* xor MGF1-SHA-X(PK.seed, ADRS, 16n)

- F(PK.seed, ADRS, M_1) = SHA2-256(BlockPad(PK.seed) || ADRS^c || M_1)
- H(PK.seed, ADRS, M_1, M_2) = SHA-X(BlockPad(PK.seed) || ADRS^c || (M_1 ||M_2))

- n = Security parameter for the underlying signature scheme (
) - USS = Size of underlying signature (Table 1 SLH-DSA parameter sets in
) - N = Number of messages in message series

- Max Condensed Signature Size = n + 24 + (n * floor(log2N)) (
, , ) - Max Signed Ladder Size = 16 + ((8 + n) * ceiling(log2(N))) + USS (
, , ) - Max Full Signature Size = Max Condensed Signature Size + Max Signed Ladder Size (
)

- flag values for the ladder and authentication path data structures;
- object identifiers for the various instantiations of MTL mode combined with underlying signature schemes;
- the domain separator types MTL_MSG_SEP and possibly MTL_LADDER_SEP; and
- the address types MTL_MSG, MTL_DATA, and MTL_TREE.

- 00: Initial draft of the document.
- 01: Fixed 10.2.3 Tweakable hash functions definitions. Fixed typo in
. Added text to help clarify inputs to the H_msg_mtl and PRF_msg functions. Added reference to draft FIPS 205. - 02: Updated algorithm IDs for alignment with draft FIPS 205. Fixed a typo in Sections 13 and 9.1.
- 03: Generalized how MTL mode randomizer is generated so that the message does not need to be an input to PRF_msg. Updated cryptographic separation to use "pre-hash" domain separator format for input to the underlying signature scheme for compatibility with NIST's recently proposed guidance for FIPS 204 and FIPS 205 pre-hashing. Added security considerations on randomizer generation and on message privacy. Other minor edits.