One document matched: draft-mcgrew-hash-sigs-03.xml
<?xml version="1.0" encoding="US-ASCII"?>
<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
<!ENTITY rfc2119 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml">
<!ENTITY rfc2246 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.2246.xml">
<!ENTITY rfc4346 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.4346.xml">
<!--
<!ENTITY rfc4347 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.4347.xml">
-->
<!ENTITY rfc4309 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.4309.xml">
<!ENTITY rfc4366 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.4366.xml">
<!ENTITY rfc5288 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5288.xml">
<!ENTITY ietf-tls-rfc4346-bis SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-tls-rfc4346-bis.xml">
<!ENTITY ietf-tls-rfc4347-bis SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-tls-rfc4347-bis.xml">
<!ENTITY ietf-tls-ctr SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-tls-ctr.xml">
<!ENTITY rescorla-tls-suiteb SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml3/reference.I-D.rescorla-tls-suiteb.xml">
<!ENTITY I-D.draft-mcgrew-fundamental-ecc PUBLIC "" "http://xml2rfc.ietf.org/public/rfc/bibxml3/reference.I-D.draft-mcgrew-fundamental-ecc-04.xml">
<!--
<!ENTITY I-D.draft-ietf-tls-rfc4347-bis PUBLIC "" "http://xml2rfc.ietf.org/public/rfc/bibxml3/reference.I-D.draft-ietf-tls-rfc4347-bis-03.xml">
-->
<!ENTITY rfc2434 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.2434.xml">
<!ENTITY rfc4309 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.4309.xml">
<!ENTITY rfc4506 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.4506.xml">
<!ENTITY rfc5246 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5246.xml">
<!ENTITY rfc5116 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5116.xml">
<!ENTITY rfc5430 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5430.xml">
<!ENTITY rfc5246 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5246.xml">
<!ENTITY rfc4492 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.4492.xml">
<!ENTITY rfc6090 SYSTEM "http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.6090.xml">
]>
<?rfc toc="yes"?>
<?rfc tocompact="no"?>
<?rfc tocdepth="6"?>
<?rfc symrefs="yes"?>
<?rfc sortrefs="yes"?>
<?rfc compact="no"?>
<rfc ipr="trust200902" category="info" docName="draft-mcgrew-hash-sigs-03">
<front>
<title abbrev="Hash-Based Signatures">Hash-Based Signatures</title>
<author fullname="David McGrew" initials="D" surname="McGrew">
<organization>Cisco Systems</organization>
<address>
<postal>
<street>13600 Dulles Technology Drive</street>
<city>Herndon</city>
<code>20171</code>
<region>VA</region>
<country>USA</country>
</postal>
<email>mcgrew@cisco.com</email>
</address>
</author>
<author fullname="Michael Curcio" initials="M" surname="Curcio">
<organization>Cisco Systems</organization>
<address>
<postal>
<street>7025-2 Kit Creek Road</street>
<city>Research Triangle Park</city>
<code>27709-4987</code>
<region>NC</region>
<country>USA</country>
</postal>
<email>micurcio@cisco.com</email>
</address>
</author>
<!--
<author fullname="Scott Fluhrer" initials="S" surname="Fluhrer">
<organization>Cisco Systems</organization>
<address>
<postal>
<street>170 West Tasman Drive</street>
<city>San Jose</city>
<region>CA</region>
<country>USA</country>
</postal>
<email>sfluhrer@cisco.com</email>
</address>
</author>
-->
<date month="October" year="2015"/>
<!-- Is the "Security" area applicable here? -->
<area> IRTF </area>
<workgroup> Crypto Forum Research Group</workgroup>
<abstract>
<t>
This note describes a digital signature system based on
cryptographic hash functions, following the seminal work in this
area of Lamport, Diffie, Winternitz, and Merkle, as adapted by
Leighton and Micali in 1995. It specifies a one-time signature
scheme and a general signature scheme. These systems provide
asymmetric authentication without using large integer
mathematics and can achieve a high security level. They are
suitable for compact implementations, are relatively simple to
implement, and naturally resist side-channel attacks. Unlike
most other signature systems, hash-based signatures would still
be secure even if it proves feasible for an attacker to build a
quantum computer.
</t>
</abstract>
</front>
<middle>
<section title="Introduction">
<t>
One-time signature systems, and general purpose signature systems
built out of one-time signature systems, have been known since 1979
<xref target="Merkle79"/>, were well studied in the 1990s <xref
target="USPTO5432852"/>, and have benefited from renewed attention
in the last decade. The characteristics of these signature systems
are small private and public keys and fast signature generation and
verification, but large signatures and relatively slow key generation.
In recent years there has been interest in these systems because of
their post-quantum security
<!-- (see <xref target="pq"/>) --> and their
suitability for compact implementations.
</t>
<t>
This note describes the Leighton and Micali adaptation <xref
target="USPTO5432852"/> of the original
Lamport-Diffie-Winternitz-Merkle one-time signature system
<xref target="Merkle79"/> <xref target="C:Merkle87"/><xref
target="C:Merkle89a"/><xref target="C:Merkle89b"/> and general
signature system <xref target="Merkle79"/> with enough specificity to
ensure interoperability between implementations.
An example implementation is given in an appendix.
</t>
<!-- DAM - add Lamport, Diffie, and Winternitz citations -->
<t>
A signature system provides asymmetric message authentication. The
key generation algorithm produces a public/private key pair. A
message is signed by a private key, producing a signature, and a
message/signature pair can be verified by a public key. A One-Time
Signature (OTS) system can be used to sign exactly one message
securely, but cannot securely sign more than one. An N-time signature
system can be used to sign N or fewer messages securely. A Merkle
tree signature scheme is an N-time signature system that uses an OTS
system as a component. In this note we describe the Leighton-Micali
Signature (LMS) system, which is a variant of the Merkle scheme. We
denote the one-time signature scheme that it incorporates as LM-OTS.
</t>
<t>
</t>
<t>
This note is structured as follows. Notation is introduced in
<xref target="notation"/>. The LM-OTS signature system is described in
<xref target="ldwm"/>, and the LMS N-time signature system is
described in <xref target="merkle"/>. Sufficient detail is
provided to ensure interoperability.
<!--
<xref target="testing"/>
describes test considerations and contains test cases that can be used
to validate an implementation.
-->
The IANA registry for these signature
systems is described in <xref target="IANA"/>. Security
considerations are presented in <xref target="Security"/>.
</t>
<section title="Conventions Used In This Document">
<t>
The key words "MUST", "MUST NOT", "REQUIRED",
"SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY",
and "OPTIONAL" in this document are to be interpreted as described
in <xref target="RFC2119" />.
</t>
</section>
</section>
<!--
<section title="Architecture">
<t>
An OTS signature system consists of thee functions:
<list>
<t>
OTS-GENPRIV
</t>
<t>
OTS-PRIV_TO_PUB
</t>
<t>
OTS-GENSIG
</t>
</list>
</t>
</section>
-->
<section title="Interface" anchor="interface">
<t>
The LMS signing algorithm is stateful; once a particular value of the
private key is used to sign one message, it MUST NOT be used to sign
another. To make this fact explicit in the interface, we use a
functional programming approach, in which the key generation,
signing, and verification algorithms do not have any side effects.
The signing algorithm returns both a signature and a different
private key value, which can be used to sign additional messages.
</t>
<t>
<list>
<t>
The key generation algorithm takes as input an indication of the
parameters for the signature system. If it is successful, it
returns both a private key and a public key. Otherwise, it returns
an indication of failure.
</t>
<t>
The signing algorithm takes as input the message to be signed and
the current value of the private key. If successful, it returns a
signature and the next value of the private key, if there is such
a value. After the private key of an N-time signature system has
signed N messages, the signing algorithm returns the signature and
an indication that there is no next value of the private key that
can be used for signing. If unsuccessful, it returns an
indication of failure.
</t>
<t>
The verification algorithm takes as input the public key, a
message, and a signature, and returns an indication of whether or
not the signature and message pair are valid.
</t>
</list>
</t>
<t>
A message/signature pair are valid if the signature was returned by
the signing algorithm upon input of the message and the private key
corresponding to the public key; otherwise, the signature and
message pair are not valid with probability very close to one.
</t>
</section>
<section title="Notation" anchor="notation">
<section title="Data Types" anchor="datatypes">
<t>
Bytes and byte strings are the fundamental data types. A single byte
is denoted as a pair of hexadecimal digits with a leading "0x". A
byte string is an ordered sequence of zero or more bytes and is
denoted as an ordered sequence of hexadecimal characters with a
leading "0x". For example, 0xe534f0 is a byte string with a length of
three. An array of byte strings is an ordered set, indexed starting at zero,
in which all strings have the same length.
</t>
<t>
Unsigned integers are converted into byte strings by representing them
in network byte order. To make the number of bytes in the
representation explicit, we define the functions uint8str(X),
uint16str(X), and uint32str(X), which return one, two, and four byte
values, respectively.
</t>
<section title="Operators" anchor="operators">
<t>
When a and b are real numbers, mathematical operators are defined as follows:
<list>
<t>^ : a ^ b denotes the result of a raised to the power of b</t>
<t>* : a * b denotes the product of a multiplied by b</t>
<t>/ : a / b denotes the quotient of a divided by b</t>
<t>% : a % b denotes the remainder of the integer division of a by b</t>
<t>+ : a + b denotes the sum of a and b</t>
<t>- : a - b denotes the difference of a and b</t>
</list>
The standard order of operations is used when evaluating arithmetic expressions.
</t>
<t>
If A and B are bytes, then A AND B denotes the bitwise logical and
operation.
</t>
<t>
When B is a byte and i is an integer, then B >> i denotes the logical
right-shift operation.
Similarly, B << i denotes the logical left-shift operation.
</t>
<t>
If S and T are byte strings, then S || T denotes the concatenation
of S and T.
</t>
<t>
The i^th byte string in an array A is denoted as A[i].
</t>
</section>
<section title="Strings of w-bit elements">
<t>
If S is a byte string, then byte(S, i) denotes its i^th byte, where
byte(S, 0) is the leftmost byte. In addition, bytes(S, i, j) denotes the
range of bytes from the i^th to the j^th byte, inclusive. For example, if
S = 0x02040608, then byte(S, 0) is 0x02 and bytes(S, 1, 2) is 0x0406.
</t>
<t>
A byte string can be considered to be a string of w-bit unsigned
integers; the correspondence is defined by the function coef(S, i, w) as follows:
</t>
<figure>
<preamble>If S is a string, i is a positive integer, and w is a member of the set { 1, 2, 4, 8 }, then
coef(S, i, w) is the i^th, w-bit value, if S is interpreted as a
sequence of w-bit values. That is,
</preamble>
<artwork>
coef(S, i, w) = (2^w - 1) AND
( byte(S, floor(i * w / 8)) >>
(8 - (w * (i % (8 / w)) + w)) )
</artwork>
</figure>
<figure>
<preamble>For example, if S is the string 0x1234,
then coef(S, 7, 1) is 0 and coef(S, 0, 4) is 1.</preamble>
<artwork>
<![CDATA[
S (represented as bits)
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| 0| 0| 0| 1| 0| 0| 1| 0| 0| 0| 1| 1| 0| 1| 0| 0|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
^
|
coef(S, 7, 1)
S (represented as four-bit values)
+-----------+-----------+-----------+-----------+
| 1 | 2 | 3 | 4 |
+-----------+-----------+-----------+-----------+
^
|
coef(S, 0, 4)]]>
</artwork>
</figure>
<t>
The return value of coef is an unsigned integer.
If i is larger than the number of w-bit values in S, then
coef(S, i, w) is undefined, and an attempt to compute
that value should raise an error.
</t>
</section>
</section>
<section anchor="secstring" title="Security string">
<t>
To improve security against attacks that amortize their effort against
multiple invocations of the hash function H, Leighton and Micali
introduce a "security string" that is distinct for each invocation of
H. The following fields can appear in a security string:
</t>
<t>
<list>
<t> I - an identifier for the private key. This value is 31 bytes
long, and it MUST be distinct from all other such identifiers. It
SHOULD be chosen uniformly at random, or via a pseudorandom
process, in order to ensure that it will be distinct with
probability close to one, but it MAY be a structured identifier.
</t>
<t>
D - a domain separation parameter, which is a single byte that
takes on different values in the different algorithms in which
H is invoked. D takes on the following values:
<list>
<t>
D_ITER = 0x00 in the iterations of the LM-OTS algorithms
</t>
<t>
D_PBLC = 0x01 when computing the hash of all of the
iterates in the LM-OTS algorithm
</t>
<t>
D_MESG = 0x02 when computing the hash of the message in
the LM-OTS algorithms
</t>
<t>
D_LEAF = 0x03 when computing the hash of the leaf of an LMS tree
</t>
<t>
D_INTR = 0x04 when computing the hash of an interior node
of an LMS tree
</t>
</list>
</t>
<t>
C - an n-byte randomizer that is included with the message
whenever it is being hashed to improve security. C MUST be chosen
uniformly at random, or via a pseudorandom process.
</t>
<t>
i - in the LM-OTS one-time signature scheme, i is the index of the
private key element upon which H is being applied. It is
represented as a 16-bit (two byte) unsigned integer in network byte
order.
</t>
<t>
j - in the LM-OTS one-time signature scheme, j is the iteration
number used when the private key element is being iteratively
hashed. It is represented as an 8-bit (one byte) unsigned
integer.
</t>
<t>
q - in the LM-OTS one-time signature scheme, q is a diversification
string provided as input. In the LMS N-time signature scheme, a
distinct value of q is provided for each distinct LM-OTS
public/private keypair. It is represented as a four byte string.
</t>
<t>
r - in the LMS N-time signature scheme, the node number r
associated with a particular node of the hash tree is used as an
input to the hash used to compute that node. This value is
represented as a 32-bit (four byte) unsigned integer in network
byte order.
</t>
</list>
</t>
<!--
<t>A node number is computed as follows. The initial leaf is zero,
and successive leaves take the values 1, 2, ..., (2^h)-1 where h is
the height of the tree, that is, the number of levels. Leaves are
considered to be at level zero. Node (2^h) is the first node of level
one. In general, the jth node at level L has node number 2^(h-L) + j.
The node number can conveniently be computed when it is needed in the
LMS algorithms, as described in those algorithms.
</t>
-->
</section>
<section title="Functions" anchor="functions">
<t>
If r is a non-negative real number, then we define the following functions:
<list>
<t>ceil(r) : returns the smallest integer larger than r</t>
<t>floor(r) : returns the largest integer smaller than r</t>
<t>lg(r) : returns the base-2 logarithm of r</t>
</list>
</t>
<!--
<t>
When F is a function that takes r-byte strings as input and returns
r-byte strings as output, we denote the repeated applications of F
with itself a non-negative, integral number of times i as F^i.
</t>
<figure>
<preamble>Thus for any m-byte string x ,</preamble>
<artwork>
F^i(x) = / F( F^(i-1)(x) ) for i > 0
\ x for i = 0.
</artwork>
<postamble>For example, F^2(x) = F(F(x)).</postamble>
</figure>
-->
<!--
<t>
The direct product of two sets S1 and S2 is denoted as S1 x S2.
</t>
-->
<!--
<t>
We describe the inputs and outputs of a function F using
the mathematical notation, as
<artwork>
F : InputSet -> OutputSet,
</artwork>
where InputSet is the set of all possible inputs, and OutputSet
is the set of all possible outputs. For instance, if the function
F took as input a w-bit integer and an arbitrary length byte
string, and returned a single bit value, that fact is denoted as
<artwork>
F : { 0, 1, ... , 2^w-1 } x B^* -> { 0, 1 }.
</artwork>
</t>
-->
</section>
</section>
<!--
<section title="Interface" anchor="interface">
<t>
The LM-OTS and Merkle signature system have the following functions:
<list>
<t>
GeneratePrivateKey : B^m -> PrivateKey
</t>
<t>
GeneratePublicKey : PrivateKey -> PublicKey
</t>
<t>
GenerateSignature : PrivateKey x B^* -> Signature
</t>
<t>
VerifySignature : PublicKey x B^* -> { 0, 1 }
</t>
</list>
The sets PrivateKey, PublicKey, and Signature are different
for each signature system, as described below.
</t>
</section>
-->
<section anchor="ldwm" title="LM-OTS One-Time Signatures">
<t>
This section defines LM-OTS signatures. The signature is used to validate
the authenticity of a message by associating a secret private key with
a shared public key. These are one-time signatures; each
private key MUST be used only one time to sign any given message.
</t>
<t>
As part of the signing process, a digest of the original message is
computed using the cryptographic hash function H (see <xref
target='ldwm_hash_func' />), and the resulting digest is signed.
</t>
<t>
In order to facilitate its use in an N-time signature system, the
LM-OTS key generation, signing, and verification algorithms all take
as input a diversification parameter q. When the LM-OTS signature
system is used outside of an N-time signature system, this value
SHOULD be set to the all-zero value.
</t>
<section title='Parameters' anchor='ldwm_params'>
<t>
The signature system uses the parameters n and w, which are both
positive integers. The algorithm description also makes use of the
internal parameters p and ls, which are dependent on n and w. These
parameters are summarized as follows:
<list>
<!-- <t>m : the length in bytes of each element of an LM-OTS signature</t> -->
<t>n : the number of bytes of the output of the hash function</t>
<t>w : the Winternitz parameter; it is a member of the set { 1, 2, 4, 8 }</t>
<t>p : the number of n-byte string elements that make up the LM-OTS signature</t>
<t>ls : the number of left-shift bits used in the checksum function Cksm (defined in <xref target='ldwm_msg_chksum'/>).
</t>
</list>
</t>
<t>
The value of n is determined by the functions selected for use as part
of the LM-OTS algorithm; the choice of this value has a strong
effect on the security of the system. The parameter w can be chosen
to set the number of bytes in the signature; it has little effect on
security. Note however, that there is a larger computational cost to
generate and verify a shorter signature. The values of p and ls are
dependent on the choices of the parameters n and w, as described in
<xref target='ldwm_param_opts' />. A table illustrating various
combinations of n, w, p, and ls is provided in <xref
target='ldwm_sig_table' />.
</t>
</section>
<section title='Hashing Functions' anchor='ldwm_hash_func'>
<t>
The LM-OTS algorithm uses a hash function H that accepts byte strings of
any length, and returns an n-byte string.
<!-- F has m-byte inputs and m-byte outputs. -->
</t>
</section>
<section title='Signature Methods' anchor='ldwm_methods'>
<t>
To fully describe a LM-OTS signature method, the parameters n and
w, as well as the function H, MUST be specified. This section defines
several LM-OTS signature systems, each of which is identified by a
name. Values for p and ls are provided as a convenience.
</t>
<texttable anchor='ldwm_sig_table'>
<ttcol align='left'>Name</ttcol>
<ttcol align='left'>H</ttcol>
<ttcol align='left'>n</ttcol>
<ttcol align='left'>w</ttcol>
<ttcol align='left'>p</ttcol>
<ttcol align='left'>ls</ttcol>
<c>LMOTS_SHA256_N32_W1</c> <c>SHA256</c> <c>32</c> <c>1</c> <c>265</c> <c>7</c>
<c>LMOTS_SHA256_N32_W2</c> <c>SHA256</c> <c>32</c> <c>2</c> <c>133</c> <c>6</c>
<c>LMOTS_SHA256_N32_W4</c> <c>SHA256</c> <c>32</c> <c>4</c> <c>67</c> <c>4</c>
<c>LMOTS_SHA256_N32_W8</c> <c>SHA256</c> <c>32</c> <c>8</c> <c>34</c> <c>0</c>
<c>LMOTS_SHA256_N16_W1</c> <c>SHA256-16</c> <c>16</c> <c>1</c> <c>68</c> <c>8</c>
<c>LMOTS_SHA256_N16_W2</c> <c>SHA256-16</c> <c>16</c> <c>2</c> <c>68</c> <c>8</c>
<c>LMOTS_SHA256_N16_W4</c> <c>SHA256-16</c> <c>16</c> <c>4</c> <c>35</c> <c>4</c>
<c>LMOTS_SHA256_N16_W8</c> <c>SHA256-16</c> <c>16</c> <c>8</c> <c>18</c> <c>0</c>
</texttable>
<t>
Here SHA256 denotes the NIST standard hash function <xref
target="FIPS180"/>. SHA256-16 denotes the SHA256 hash function with
its final output truncated to return the leftmost 16 bytes.
</t>
</section>
<section title='Private Key' anchor='ldwm_prv_key'>
<t>
The LM-OTS private key consists of an array of size p containing n-byte
strings. Let x denote the private key. This
private key must be used to sign one and only one message. It must
therefore be unique from all other private keys. The following
algorithm shows pseudocode for generating x.
</t>
<figure>
<preamble>Algorithm 0: Generating a Private Key</preamble>
<artwork>
for ( i = 0; i < p; i = i + 1 ) {
set x[i] to a uniformly random n-byte string
}
return x
</artwork>
<postamble>
<!-- an LM-OTS private key is an array of p+1 m-byte strings -->
<!-- DAM - need to clarify
uniformly random value is generated pseudorandomly as a function of a single random seed, e.g., with a key derivation function
-->
</postamble>
</figure>
<t>
An implementation MAY use a pseudorandom method to compute x[i], as
suggested in <xref target="Merkle79"/>, page 46. The details of the
pseudorandom method do not affect interoperability, but the
cryptographic strength MUST match that of the LM-OTS algorithm.
</t>
<!--
<section title="Pseudorandom Private Key Generation">
<t>
ctr_kdf_sp800_108() implements the hash/hmac based counter mode key
derivation function, or CTR KDF, as it is specified in NIST Special
Publication 800-108, Section 5.1. The details of this
implementation are:
- the counter field "i" is a four-byte unsigned integer
- the Label field consists of a one-byte value indicating the
purpose of the derived keying material (0xf0 is for LDWM, and
0x40 is for MTS) followed by a seven-byte unsigned integer that
indicates the element number for LDWM, and indicates the leaf
number for MTS.
- the Context field is empty, i.e. a zero-length string
- the field "L" that specifies the length, in bits, of the
derived keying material is a four-byte unsigned integer. In
our case, it is always equal to 256 for SHA-256.
</t>
</section>
-->
</section>
<section title='Public Key' anchor='ldwm_pub_key'>
<t>
The LM-OTS public key is generated from the private key by iteratively
applying the function H to each individual element of x, for 2^w - 1
iterations, then hashing all of the resulting values.
</t>
<t>
Each public/private key pair is associated with a single identifier
I. This string MUST be 31 bytes long, and be generated as described
in <xref target="secstring"/>.
</t>
<t>
The diversification parameter q is an input to the algorithm, as
described in <xref target="secstring"/>.
</t>
<t>
<!--
through a series of
hashing operations using the functions F and H. Its value is the hash
(using H) of the concatenation of the elements of an array y. The content
of y is generated by iteratively hashing (using F) each element of
array x, (2^w - 1) times.
-->
The following algorithm shows pseudocode for
generating the public key, where the array x is the private key.
</t>
<figure>
<preamble>Algorithm 1: Generating a Public Key From a Private Key</preamble>
<artwork>
for ( i = 0; i < p; i = i + 1 ) {
tmp = x[i]
for ( j = 0; j < 2^w - 1; j = j + 1 ) {
tmp = H(tmp || I || q || uint16str(i) || uint8str(j) || D_ITER)
}
y[i] = tmp
}
return H(I || q || y[0] || y[1] || ... || y[p-1] || D_PBLC)
</artwork>
</figure>
<t>
The public key is the string consisting of a four-byte enumeration
that identifies the parameters in use, followed by the value
returned by Algorithm 1. <xref target="ldwm_xdr"/> specifies the
enumeration and more formally defines the format.
</t>
<!--
tmp - n=16 bytes (or 32 bytes for postquantum)
I - 31 bytes
q - 4 bytes
i - 2 bytes
j - 1 bytes
D - 1 bytes
total - 56 bytes (needs to be <= 55 for sha256)
-->
</section>
<section title='Checksum' anchor='ldwm_msg_chksum'>
<t>
A checksum is used to ensure that any forgery attempt that manipulates
the elements of an existing signature will be detected. The security
property that it provides is detailed in <xref target='Security' />.
The checksum function Cksm is defined as follows, where S denotes
the byte string that is input to that function, and the value
sum is a 16-bit unsigned integer:
</t>
<figure>
<preamble>Algorithm 2: Checksum Calculation</preamble>
<artwork>
sum = 0
for ( i = 0; i < u; i = i + 1 ) {
sum = sum + (2^w - 1) - coef(S, i, w)
}
return (sum << ls)
</artwork>
<postamble>Because of the left-shift operation, the rightmost bits of
the result of Cksm will often be zeros. Due to the value of p, these
bits will not be used during signature generation or
verification.</postamble>
</figure>
<!--
<t>
<list style="empty">
<t>
Implementation Note: Based on the previous fact, an implementation
MAY choose to optimize the width of sum to (v * w) bits and
set ls to 0. The rationale for this is given that (2^w - 1) *
ceil(8*n/w) is the maximum value of sum and the value of (2^w - 1) is
represented by w bits, the result of adding u w-bit numbers, where u =
ceil(8*n/w), requires at most (ceil(lg(u)) + w) bits. Dividing by w
and taking the next largest integer gives the total required number of
w-bit fields and gives (ceil(lg(u)) / w) + 1, or v. Thus sum requires
a minimum width of (v * w) bits and no left-shift operation is
performed.
</t>
</list>
</t>
-->
</section>
<section title='Signature Generation' anchor='ldwm_sig_gen'>
<t>
The LM-OTS signature of a message is generated by first appending the
randomizer C, the identifier string I, and the diversification string
q to the message, then using H to compute the hash of the resulting
string, concatenating the checksum of the hash to the hash itself,
then considering the resulting value as a sequence of w-bit values,
and using each of the the w-bit values to determine the number of
times to apply the function H to the corresponding element of the
private key. The outputs of the function H are concatenated together
and returned as the signature. The pseudocode for this procedure is
shown below.
</t>
<t>
The identifier string I and diversification string q are
the same as in <xref target="ldwm_pub_key"/>.
</t>
<figure>
<preamble>Algorithm 3: Generating a Signature From a Private Key and a Message</preamble>
<artwork>
set C to a uniformly random n-byte string
set type to the appropriate ots_algorithm_type
Q = H(message || C || I || q || D_MESG)
for ( i = 0; i < p; i = i + 1 ) {
a = coef(Q || Cksm(Q), i, w)
tmp = x[i]
for ( j = 0; j < a; j = j + 1 ) {
tmp = H(tmp || I || q || uint16str(i) || uint8str(j) || D_ITER)
}
y[i] = tmp
}
return type || C || I || 0x00 || q || (y[0] || y[1] || ... || y[p-1])
</artwork>
<postamble>Note that this algorithm results in a signature whose
elements are intermediate values of the elements computed by the
public key algorithm in <xref target='ldwm_pub_key' />.</postamble>
</figure>
<t>
The signature is the string consisting of a four-byte enumeration
that identifies the parameters in use, followed by the value
returned by Algorithm 3. <xref target="ldwm_xdr"/> specifies the
enumeration and more formally defines the format.
</t>
<!--
Implementation note: when n=16, the number of bytes in
tmp || I || q || i || j || D_ITER
is 16+31+4+2+1+1 = 55
Thus, the invocation of H() that is repeated many times in Algorithms
2 and 3 will each use only one invocation of the compression function.
<t>
The signature should be provided by the signer to the verifier,
with the message and the public key.
</t>
-->
</section>
<section title='Signature Verification' anchor='ldwm_sig_vrf'>
<t>
In order to verify a message with its signature (an array of n-byte
strings, denoted as y), the receiver must "complete" the series of
applications of H using the w-bit values of the message hash and its
checksum. This computation should result in a value that matches the
provided public key.
</t>
<figure>
<preamble>Algorithm 4: Verifying a Signature and Message Using a
Public Key</preamble>
<artwork>
parse C, I, q, and y from the signature as follows:
type = first 4 bytes
C = next n bytes
I = next 31 bytes
NULL = next byte; this padding value is discarded
q = next four bytes
y[0] = next n bytes
y[1] = next n bytes
...
y[p-1] = next n bytes
Q = H(message || C || I || q || D_MESG)
for ( i = 0; i < p; i = i + 1 ) {
a = (2^w - 1) - coef(Q || Cksm(Q), i, w)
tmp = y[i]
for ( j = a+1; j < 2^w - 1; j = j + 1 ) {
tmp = H(tmp || I || q || uint16str(i) || uint8str(j) || D_ITER)
}
z[i] = tmp
}
candidate = H(z[0] || z[1] || ... || z[p-1] || I || q || D_PBLC)
if (candidate = public_key)
return 1 // message/signature pair is valid
else
return 0 // message/signature pair is invalid
</artwork>
</figure>
</section>
<!-- must the private key and public key be equal in length? -->
<!--t>
An LDWM private key is an n-byte string, and an LDWM public key is
also an n-byte string. During signature creation and verification, the byte string
( message || checksum ) is divided into a number of w-bit fields, p. An LDWM
signature thus consists of an array of p elements, each element of which is an m-byte
string. Therefore, the value of p is determined by the values of n and w.
</t>
<t>
The signature method uses the following functions:
<list>
<t>
A one-way function F that has m-byte inputs and m-byte outputs.
</t>
<t>
A hash function H that has inputs of any integral byte length
and has n-byte outputs.
</t>
</list>
Internally, the following functions are used:
<list>
<t>
A function Count that has n-byte inputs and outputs that are two bytes in length.
</t>
</list>
</t-->
<!--t>
The function count is defined as follows, where the variable sum is a
16-bit nonnegative integer:
<artwork>
sum = 0
for i=0 to (n/w)-1
sum = sum + (2^w - 1) - coef(S, i, w)
endfor
shift sum left by LS bits
return sum
</artwork>
The value LS depends on n and w, is given by the "Left Shift" column
in the table above. Because of the left shft operation, the rightmost
bits of Count will often be zeros.
</t-->
<!--t>
The relationships between the parameters is as given by the table below;
these relationships are explained in <xref target="rationale"/>.
</t-->
<!--section title="LDWM Private Key Generation">
Algorithm 0: generating a private key:
<artwork>
for i=0,p-1,
set x[i] to a uniformly random value
endfor
return x
</artwork>
</section>
<section title="LDWM Public Key Generation">
Algorithm 1: generating a public key from a private key:
<artwork>
e = 2^w - 1
for i=0,p-1,
y[i] = F^e(x[i])
endfor
return hash(y[0] || y[1] || ... || y[p-1])
</artwork>
</section-->
<!--section title="LDWM Signature Generation">
Algorithm 2: generating a signature from a private key and a message:
<artwork>
V = hash(message) || Count(hash(message))
for i=0,p-1:
a = coef(V, i, w)
s[i] = F^a(x[i])
endfor
return s[0] || s[1] || ... || s[p-1]
</artwork>
<t>
</t>
</section-->
<!--section title="LDWM Signature Verification">
Algorithm 3: verifying a signature and message using a public key:
<artwork>
V = hash(message) || count(hash(message))
for i=0,p-1:
a = (2^w - 1) - coef(V, i, w)
z[i] = F^a(x[i])
endfor
if public key is equal to hash(z[0] || z[1] || ... || z[p-1])
return 1 (signature is valid)
else
return 0 (signature is invalid)
</artwork>
</section-->
<section title="Notes" anchor="ldwm_notes">
<t>
A future version of this specification may
define a method for computing the signature
of a very short message in which the hash
is not applied to the message during
the signature computation. That
would allow the signatures to have reduced size.
</t>
</section>
<!--
<section title="Parameters">
<t>
To fully describe a LM-OTS signature method, the parameters m, n, and w,
as well as the function H MUST be specified. This section defines
several LM-OTS signature systems, each of which is identified by a name.
</t>
<texttable anchor='ldwm_sig_table2'>
<ttcol align='left'>Name</ttcol>
<ttcol align='left'>Hash</ttcol>
<ttcol align='left'>n</ttcol>
<ttcol align='left'>w</ttcol>
<ttcol align='left'>p</ttcol>
<c>LMOTS_SHA256_M16_W1</c> <c>SHA-256</c> <c>16</c> <c>1</c> <c>265</c>
<c>LMOTS_SHA256_M16_W2</c> <c>SHA-256</c> <c>16</c> <c>2</c> <c>133</c>
<c>LMOTS_SHA256_M16_W4</c> <c>SHA-256</c> <c>16</c> <c>4</c> <c>67</c>
<c>LMOTS_SHA256_M16_W8</c> <c>SHA-256</c> <c>16</c> <c>8</c> <c>34</c>
<c>LMOTS_SHA256_N32_W1</c> <c>SHA-256</c> <c>32</c> <c>1</c> <c>265</c>
<c>LMOTS_SHA256_N32_W2</c> <c>SHA-256</c> <c>32</c> <c>2</c> <c>133</c>
<c>LMOTS_SHA256_N32_W4</c> <c>SHA-256</c> <c>32</c> <c>4</c> <c>67</c>
<c>LMOTS_SHA256_N32_W8</c> <c>SHA-256</c> <c>32</c> <c>8</c> <c>34</c>
</texttable>
<artwork>
<![CDATA[
Name H n w p ls
- - - - - - - - - - - - - - - - - - - - - - -
LMOTS_SHA256_N16_W1 SHA-256 16 1 265 8
LMOTS_SHA256_N16_W2 SHA-256 16 2 133 8
LMOTS_SHA256_N16_W4 SHA-256 16 4 67 4
LMOTS_SHA256_N16_W8 SHA-256 16 8 34 0
LMOTS_SHA256_N32_W1 SHA-256 32 1 265 8
LMOTS_SHA256_N32_W2 SHA-256 32 2 133 8
LMOTS_SHA256_N32_W4 SHA-256 32 4 67 4
LMOTS_SHA256_N32_W8 SHA-256 32 8 34 0]]>
</artwork>
<t>
Here SHA-256 denotes the NIST standard hash function.
SHA-256-20 denotes that hash function with its output truncated
to 20 bytes.
</t>
</section>
-->
<section title="Formats" anchor="ldwm_xdr">
<figure>
<preamble>The signature and public key formats are formally defined
using the External Data Representation (XDR) <xref target="RFC4506" />
in order to provide an unambiguous, machine readable definition. For
clarity, we also include a private key format as well, though
consistency is not needed for interoperability and an implementation
MAY use any private key format. Though XDR is used, these formats are
simple and easy to parse without any special tools.
<!-- To avoid the need
to convert to and from network / host byte order, the enumeration
values are all palindromes.
-->
The definitions are as follows:</preamble>
<artwork>
<![CDATA[
/*
* ots_algorithm_type identifies a particular signature algorithm
*/
enum ots_algorithm_type {
ots_reserved = 0,
lmots_sha256_m16_w1 = 0x00000001,
lmots_sha256_m16_w2 = 0x00000002,
lmots_sha256_m16_w4 = 0x00000003,
lmots_sha256_m16_w8 = 0x00000004,
lmots_sha256_n32_w1 = 0x00000005,
lmots_sha256_n32_w2 = 0x00000006,
lmots_sha256_n32_w4 = 0x00000007,
lmots_sha256_n32_w8 = 0x00000008
};
/*
* byte strings (for n=16 and n=32)
*/
typedef opaque bytestring16[16];
typedef opaque bytestring32[32];
union ots_signature switch (ots_algorithm_type type) {
case lmots_sha256_n16_w1:
bytestring16 y_n16_p265[265];
case lmots_sha256_n16_w2:
bytestring16 y_n16_p133[133];
case lmots_sha256_n16_w4:
bytestring16 y_n16_p67[67];
case lmots_sha256_n16_w8:
bytestring16 y_n16_p34[34];
case lmots_sha256_n32_w1:
bytestring32 y_n32_p265[265];
case lmots_sha256_n32_w2:
bytestring32 y_m3_p133[133];
case lmots_sha256_n32_w4:
bytestring32 y_n32_y_p67[67];
case lmots_sha256_n32_w8:
bytestring32 y_n32_p34[34];
default:
void; /* error condition */
};
union ots_public_key switch (ots_algorithm_type type) {
case lmots_sha256_n16_w1:
case lmots_sha256_n16_w2:
case lmots_sha256_n16_w4:
case lmots_sha256_n16_w8:
case lmots_sha256_n32_w1:
case lmots_sha256_n32_w2:
case lmots_sha256_n32_w4:
case lmots_sha256_n32_w8:
bytestring32 y32;
default:
void; /* error condition */
};
union ots_private_key switch (ots_algorithm_type type) {
case lmots_sha256_m16_w1:
case lmots_sha256_m16_w2:
case lmots_sha256_m16_w4:
case lmots_sha256_m16_w8:
bytestring20 x20;
case lmots_sha256_n32_w1:
case lmots_sha256_n32_w2:
case lmots_sha256_n32_w4:
case lmots_sha256_n32_w8:
bytestring32 x32;
default:
void; /* error condition */
};]]>
</artwork>
</figure>
<t>
Though the data formats are formally defined by XDR, we include
diagrams as well as a convenience to the reader. An example of the
format of an lmots_signature is illustrated below, for
lmots_sha256_n32_w1. An ots_signature consists of a 32-bit unsigned
integer that indicates the ots_algorithm_type, followed by other data,
whose format depends only on the ots_algorithm_type. For
LM-OTS, that data is an array of equal-length byte strings. The number
of bytes in each byte string, and the number of elements in the array,
are determined by the ots_algorithm_type field. In the case of
lmots_sha256_n32_w1, the array has 265 elements, each of which is a
32-byte string. The XDR array y_n32_p265 denotes the array y as used
in the algorithm descriptions above, using the parameters of n=32 and
p=265 for lmots_sha256_n32_w1.
</t>
<t> A verifier MUST check the ots_algorithm_type field, and a
verification operation on a signature with an unknown
lmots_algorithm_type MUST return FAIL.
</t>
<figure>
<artwork>
<![CDATA[
+---------------------------------+
| ots_algorithm_type |
+---------------------------------+
| |
| y_n32_p265[0] |
| |
+---------------------------------+
| |
| y_n32_p265[1] |
| |
+---------------------------------+
| |
~ .... ~
| |
+---------------------------------+
| |
| y_n32_p265[264] |
| |
+---------------------------------+]]>
</artwork>
</figure>
</section>
</section>
<section anchor="merkle" title="Leighton Micali Signatures">
<t>
The Leighton Micali Signature (LMS) method can sign a potentially large
but fixed number of messages. An LMS system uses two cryptographic
components: a one-time signature method and a hash function. Each LMS
public/private key pair is associated with a perfect binary tree, each
node of which contains an n-byte value. Each leaf of the tree
contains the value of the public key of an LM-OTS public/private key
pair. The value contained by the root of the tree is the LMS public
key. Each interior node is computed by applying the hash function to
the concatenation of the values of its children nodes.
</t>
<t>
An LMS system has the following parameters:
<list>
<t>
h : the height (number of levels - 1) in the tree, and
</t>
<t>
n : the number of bytes associated with each node.
</t>
</list>
There are 2^h leaves in the tree.
</t>
<section anchor="mts_priv" title="LMS Private Key">
<t>
An LMS private key consists of 2^h one-time signature private keys
and the leaf number of the next LM-OTS private key that has not yet
been used. The leaf number is initialized to zero when the LMS
private key is created.
</t>
<t>
An LMS private key MAY be generated pseudorandomly from a secret
value, in which case the secret value MUST be at least n bytes long, be
uniformly random, and MUST NOT be used for any other purpose than
the generation of the LMS private key. The details of how this
process is done do not affect interoperability; that is, the public
key verification operation is independent of these details.
</t>
</section>
<section anchor="mts_alg" title="LMS Public Key">
<t>
An LMS public key is defined as follows, where we denote the public
key associated with the i^th LM-OTS private key as OTS_PUBKEY[i], with
i ranging from 0 to (2^h)-1. Each instance of an LMS public/private
key pair is associated with a perfect binary tree, and the nodes of
that tree are indexed from 1 to 2^(h+1)-1. Each node is associated with
an n-byte string, and the string for the rth node is denoted as T[r]
and is defined as
</t>
<figure>
<artwork>
T[r] = / H(OTS_PUBKEY[r-2^h] || I || uint32str(r) || D_LEAF) if r >= 2^h
\ H(T[2*r] || T[2*r+1] || I || uint32str(r) || D_INTR) otherwise.
</artwork>
</figure>
<t>
The LMS public key is the string consisting of a four-byte
enumeration that identifies the parameters in use, followed by the
string T[1]. <xref target="mts_xdr"/> specifies the enumeration and
more formally defines the format. The value T[1] can be computed
via recursive application of the above equation, or by any
equivalent method. An iterative procedure is outlined in <xref
target="iterativeLMS"/>.
</t>
</section>
<section anchor="mts_sig" title="LMS Signature">
<t>
An LMS signature consists of
<list>
<t>
a typecode indicating the particular LMS algorithm,
</t>
<t>
an LM-OTS signature, and
</t>
<t>
an array of values that is associated with the path through the
tree from the leaf associated with the LM-OTS signature to the
root.
</t>
</list>
The array of values contains the siblings of the nodes on the path
from the leaf to the root but does not contain the nodes on the path
itself. The array for a tree with height h will have h values. The
first value is the sibling of the leaf, the next value is the sibling
of the parent of the leaf, and so on up the path to the root.
</t>
<section anchor="mts_sig_gen" title="LMS Signature Generation">
<t>
To compute the LMS signature of a message with an LMS private key,
the signer first computes the LM-OTS signature of the message
using the leaf number of the next unused LM-OTS private key.
Before releasing the signature, the leaf number in the LMS private
key MUST be incremented to prevent the LM-OTS private key from
being used again. The node number in the signature is set to the
leaf number of the LMS private key that was used in the signature.
Then the signature and the LMS private key are returned.
</t>
<t>
The array of node values in the signature MAY be computed in any
way. There are many potential time/storage tradeoffs that can be
applied. The fastest alternative is to store all of the nodes of
the tree and set the array in the signature by copying them. The
least storage intensive alternative is to recompute all of the
nodes for each signature. Note that the details of this procedure
are not important for interoperability; it is not necessary to
know any of these details in order to perform the signature
verification operation. The internal nodes of the tree need not
be kept secret, and thus a node-caching scheme that stores only
internal nodes can sidestep the need for strong protections.
</t>
<t>
One useful time/storage tradeoff is described in Column 19 of
<xref target="USPTO5432852"/>.
</t>
</section>
</section>
<section anchor="mts_sig_vrf" title="LMS Signature Verification">
<t>
An LMS signature is verified by first using the LM-OTS signature
verification algorithm to compute the LM-OTS public key from the LM-OTS
signature and the message. The value of that public key
is then assigned to the associated leaf of the LMS tree,
then the root of the tree is computed from the leaf value
and the node array (path[]) as described below. If the root
value matches the public key, then the signature is valid;
otherwise, the signature fails.
</t>
<t>
<figure>
<preamble>Algorithm 6: LMS Signature Verification </preamble>
<artwork>
identify the height h of the tree from the algorithm type
determine the leaf number the LM-OTS q value to an integer
n = node number = 2^h + leaf_number
tmp = candidate public key computed from LM-OTS signature and message
tmp = H(tmp || I || uint32str(node_num) || D_LEAF)
i = 0
while (node_num > 1) {
if (node_num is odd):
tmp = H(path[i] || tmp || I || uint32str(node_num/2) || D_INTR)
else:
tmp = H(tmp || path[i] || I || uint32str(node_num/2) || D_INTR)
node_num = node_num/2
i = i + 1
if (tmp == lms_public_key)
return 1 // message/signature pair is valid
else
return 0 // message/signature pair is invalid
</artwork>
<postamble>Upon completion, v contains the value of the root of the
LMS tree for comparison.
</postamble>
</figure>
</t>
<t>
The verifier MAY cache interior node values that have been computed
during a successful signature verification for use in
subsequent signature verifications. However, any implementation
that does so MUST make sure any nodes that are cached during
a signature verification process are deleted if that
process does not result in a successful match between
the root of the tree and the LMS public key.
</t>
</section>
<section anchor="mts_xdr" title="LMS Formats">
<figure>
<preamble>LMS signatures and public keys are defined using XDR syntax as follows:</preamble>
<artwork>
<![CDATA[enum lms_algorithm_type {
lms_reserved = 0x00000000,
lms_sha256_n32_h20 = 0x00000001,
lms_sha256_n32_h10 = 0x00000002,
lms_sha256_n32_h5 = 0x00000003
lms_sha256_n16_h20 = 0x00000004,
lms_sha256_n16_h10 = 0x00000005,
lms_sha256_n16_h5 = 0x00000006
};
union lms_path switch (lms_algorithm_type type) {
case lms_sha256_n32_h20:
bytestring32 path_n32_h20[20];
case lms_sha256_n32_h10:
bytestring32 path_n32_h10[10];
case lms_sha256_n32_h5:
bytestring32 path_n32_h5[5];
case lms_sha256_n16_h20:
bytestring32 path_n16_h20[20];
case lms_sha256_n16_h10:
bytestring32 path_n16_h10[10];
case lms_sha256_n16_h5:
bytestring32 path_n16_h5[5];
default:
void; /* error condition */
};
struct lms_signature {
ots_signature ots_sig;
lms_path nodes;
};
struct lms_public_key_n16 {
ots_algorithm_type ots_alg_type;
opaque value[16]; /* public key */
};
struct lms_public_key_n64 {
ots_algorithm_type ots_alg_type;
opaque value[64]; /* public key */
opaque I[31]; /* identity */
};
union lms_public_key switch (lms_algorithm_type type) {
case lms_sha256_n32_h20:
case lms_sha256_n32_h10:
case lms_sha256_n32_h5:
lms_public_key_n32 z_n32;
case lms_sha256_n16_h20:
case lms_sha256_n16_h10:
case lms_sha256_n16_h5:
lms_public_key_n16 z_n16;
default:
void; /* error condition */
};
]]>
</artwork>
</figure>
</section>
</section>
<section title="Hierarchical signatures">
<t>
In scenarios where it is necessary to minimize the time taken by the
public key generation process, a hierarchical N-time signature scheme
can be used. Leighton and Micali describe a scheme in which an LMS
public key is used to sign a second LMS public key, which is then
distributed along with the signatures generated with the second public
key <xref target="USPTO5432852"/>. This hierarchical scheme, which we
describe in this section, uses an LMS scheme as a component, and it
has two levels. Each level is associated with an LMS public key,
private key, and signature. The following notation is used, where i
is an integer between 1 and 2 inclusive:
<list>
<t>
prv[i] is the private key of the ith level,
</t>
<t>
pub[i] is the public key of the ith level, and
</t>
<t>
sig[i] is the signature of the ith level.
</t>
</list>
In this section, we say that an N-time private key is exhausted when
it has signed all N messages, and thus it can no longer be used for
signing.
</t>
<section title="Key Generation">
<t>
To generate an HLMS private and public key pair, new LMS private and
public keys are generated for prv[i] and pub[i] for i=1,2. These
key pairs MUST be generated independently.
</t>
<t>
The public key of the HLMS scheme is pub[1], the public key of the
first level. The HLMS private key consists of prv[1] and prv[2].
The values pub[1] and prv[1] do not change, though the values of
pub[2] and prv[2] are dynamic, and are changed by the signature
generation algorithm.
</t>
</section>
<section title="Signature Generation">
<t>
To sign a message using the private key prv, the following
steps are performed:
<list>
<t>
The message is signed with prv[2], and the value sig[2] is set to
that result.
</t>
<t>
The value of the HLMS signature is set to type || pub[2] || sig[1] || sig[2],
where type is the typecode for the particular HLMS algorithm.
</t>
<t>
If prv[2] is exhausted, then a new LMS public and private key pair
is generated, and pub[2] and prv[2] are set to those values.
pub[2] is signed with prv[1], and sig[1] is set to the resulting
value.
</t>
</list>
</t>
</section>
<section title="Signature Verification">
<t>
To verify a signature sig and message using the public key pub, the
following steps are performed:
<list>
<t>
The signature sig is parsed into its components type, pub[2],
sig[1] and sig[2].
</t>
<t>
The signature sig[2] and message is verified using the public key
pub[2]. If verification fails, then an indication of failure is
returned. Otherwise, processing continues as follows.
</t>
<t>
The signature sig[1] of the "message" pub[2] is verified using the
public key pub. If verification fails, then an indication of
failure is returned. Otherwise, an indication of success is
returned.
</t>
</list>
</t>
</section>
</section>
<section anchor="rationale" title="Rationale">
<t>
The goal of this note is to describe the LM-OTS and LMS algorithms
following the original references and present the modern security
analysis of those algorithms. Other signature methods are out of
scope and may be interesting follow-on work.
</t>
<t>
We adopt the techniques described by Leighton and Micali to mitigate
attacks that amortize their work over multiple invocations of the
hash function.
</t>
<t>
The values taken by the identifier I across different LMS
public/private key pairs are required to be distinct in order to
improve security. That distinctness ensures the uniqueness of the
inputs to H across all of those public/private key pair instances,
which is important for provable security in the random oracle model.
The length of I is set at 31 bytes so that randomly chosen values of
I will be distinct with probability at least 1 - 1/2^128 as long as
there are 2^60 or fewer instances of LMS public/private key pairs.
</t>
<t>
The sizes of the parameters in the security string are such that,
for n=16, the LM-OTS iterates a 55-byte value (that is, the string
that is input to H() during the iteration over j during signature
generation and verification is 55 bytes long). Thus, when SHA-256
is used as the function H, only a single invocation of its
compression function is needed.
</t>
<t>
The signature and public key formats are designed so that they are
easy to parse. Each format starts with a 32-bit enumeration value
that indicates all of the details of the signature algorithm and hence
defines all of the information that is needed in order to parse the
format.
</t>
<!--
<t>
The enumeration values used in this note are palindromes, which have
the same byte representation in either host order or network order.
This fact allows an implementation to omit the conversion between
byte order for those enumerations. Note however that the leaf
number field used in the LMS signature and keys must be properly
converted to and from network byte order; this is the only field
that requires such conversion. There are 2^32 XDR enumeration
values, 2^16 of which are palindromes, which is more than enough for
the foreseeable future. If there is a need for more assignments,
non-palindromes can be assigned.
</t>
-->
<!--t>
The largest possible value of C(S), where S is an n-byte string,
can be computed as follows.
There are n/w terms in S used to compute the sum, and the maximum value
of each term is 2^w - 1, so the maximum value of C(S) is (2^w - 1) * (n/w) = (2^w -
1)*(8/w)*hash_len. This number can be expressed using the same number
of bits used to express n, or the same number of bits needed to
express 8*hash_len.
</t-->
<t>
The Checksum <xref target="ldwm_msg_chksum"/> is calculated using a
non-negative integer "sum", whose width was chosen to be an integer
number of w-bit fields such that it is capable of holding the
difference of the total possible number of applications of the
function H as defined in the signing algorithm of <xref
target='ldwm_sig_gen' /> and the total actual number. In the worst
case (i.e. the actual number of times H is iteratively applied is 0),
the sum is (2^w - 1) * ceil(8*n/w). Thus for the purposes of this
document, which describes signature methods based on H = SHA256 (n =
32 bytes) and w = { 1, 2, 4, 8 }, the sum variable is a 16-bit
non-negative integer for all combinations of n and w. The calculation
uses the parameter ls defined in <xref target="ldwm_params"/> and
calculated in <xref target='ldwm_param_opts' />, which indicates the
number of bits used in the left-shift operation.
</t>
</section>
<section title="History">
<t>
This is the third version version of this draft. It has the
following changes:
<list>
<t>
It adopts the "security string" approach of Leighton and Micali
<xref target="USPTO5432852"/> in order to improve security.
</t>
<t>
It adopts Leighton and Micali's idea of hashing a randomizer string
(C, as defined in <xref target="secstring"/>) with the message, so
that finding an arbitrary collision in H will not lead to a
forgery.
</t>
<t>
It defines a multi-level signature scheme, again following that
described by Leighton and Micali.
</t>
<t>
It eliminates the function F and its iterates; the function H is
used in its stead. The adoption of the security string makes this
simplification possible.
</t>
<t>
It fixes the branching number at two for simplicity.
</t>
</list>
</t>
<t>
This section is to be removed by the RFC editor upon publication.
</t>
</section>
<section anchor="IANA" title="IANA Considerations">
<t>
The Internet Assigned Numbers Authority (IANA) is requested to create
two registries: one for OTS signatures, which includes all of the
LM-OTS signatures as defined in Section 3, and one for Leighton-Micali
Signatures, as defined in Section 4. Additions to these registries
require that a specification be documented in an RFC or another
permanent and readily available reference in sufficient detail that
interoperability between independent implementations is possible.
Each entry in the registry contains the following elements:
<list>
<t>a short name, such as "LMS_SHA256_n32_h10", </t>
<t>a positive number, and</t>
<t>a reference to a specification that completely defines the
signature method test cases that can be used to verify the
correctness of an implementation.</t>
</list>
Requests to add an entry to the registry MUST include the name and the
reference. The number is assigned by IANA. These number assignments
SHOULD use the smallest available palindromic number. Submitters
SHOULD have their requests reviewed by the IRTF Crypto Forum Research
Group (CFRG) at cfrg@ietf.org. Interested applicants that are
unfamiliar with IANA processes should visit http://www.iana.org.
</t>
<t>
The numbers between 0xDDDDDDDD (decimal 3,722,304,989) and
0xFFFFFFFF (decimal 4,294,967,295) inclusive, will not be
assigned by IANA, and are reserved for private use; no attempt
will be made to prevent multiple sites from using the same
value in different (and incompatible) ways
<xref target="RFC2434"/>.
</t>
<t>
The LM-OTS registry is as follows.
</t>
<texttable anchor="iana_reg_ldwm">
<ttcol align="left">Name</ttcol>
<ttcol align="center">Reference</ttcol>
<ttcol align="center">Numeric Identifier</ttcol>
<c> LMOTS_SHA256_N16_W1 </c><c> <xref target="ldwm"/></c><c> 0x00000001 </c>
<c> LMOTS_SHA256_N16_W2 </c><c> <xref target="ldwm"/></c><c> 0x00000002 </c>
<c> LMOTS_SHA256_N16_W4 </c><c> <xref target="ldwm"/></c><c> 0x00000003 </c>
<c> LMOTS_SHA256_N16_W8 </c><c> <xref target="ldwm"/></c><c> 0x00000004 </c>
<c> LMOTS_SHA256_N32_W1 </c><c> <xref target="ldwm"/></c><c> 0x00000005 </c>
<c> LMOTS_SHA256_N32_W2 </c><c> <xref target="ldwm"/></c><c> 0x00000006 </c>
<c> LMOTS_SHA256_N32_W4 </c><c> <xref target="ldwm"/></c><c> 0x00000007 </c>
<c> LMOTS_SHA256_N32_W8 </c><c> <xref target="ldwm"/></c><c> 0x00000008 </c>
</texttable>
<t>
The LMS registry is as follows.
</t>
<texttable anchor="iana_reg_mts">
<ttcol align="left">Name</ttcol>
<ttcol align="center">Reference</ttcol>
<ttcol align="center">Numeric Identifier</ttcol>
<c> LMS_SHA256_N32_H20</c><c> <xref target="merkle"/></c><c> 0x00000001 </c>
<c> LMS_SHA256_N32_H10</c><c> <xref target="merkle"/></c><c> 0x00000002 </c>
<c> LMS_SHA256_N32_H5</c><c> <xref target="merkle"/></c><c> 0x00000003 </c>
<c> LMS_SHA256_N16_H20</c><c> <xref target="merkle"/></c><c> 0x00000004 </c>
<c> LMS_SHA256_N16_H10</c><c> <xref target="merkle"/></c><c> 0x00000005 </c>
<c> LMS_SHA256_N16_H5</c><c> <xref target="merkle"/></c><c> 0x00000006 </c>
</texttable>
<t>
An IANA registration of a signature system does not constitute an
endorsement of that system or its security.
</t>
</section>
<section anchor="Security" title="Security Considerations">
<t>
The security goal of a signature system is to prevent forgeries. A
successful forgery occurs when an attacker who does not know the
private key associated with a public key can find a message and
signature that are valid with that public key (that is, the Signature
Verification algorithm applied to that signature and message and
public key will return "valid"). Such an attacker, in the strongest
case, may have the ability to forge valid signatures for an
arbitrary number of other messages.
</t>
<t>
LM-OTS and LMS are provably secure in the random oracle model, as
shown by Katz <xref target="Katz15"/>. From Theorem 8 of that
reference:
<list>
<t>
For any adversary attacking arbitrarily many instances of the
one-time signature scheme, and making at most q hash queries, the
probability with which the adversary is able to forge a signature
with respect to any of the instances is at most q2^(1-8n).
</t>
</list>
Here n is the number of bytes in the output of the hash function (as
defined in <xref target="ldwm_params"/>). Thus, the security of the
algorithms defined in this note can be roughly described as follows.
For a security level of roughly 128 bits, assuming that there are no
quantum computers, use n=16 by selecting an algorithm identifier with
N16 in its name. For a security level of roughly 128 bits, assuming
that there are quantum computers that can compute the input to an
arbitrary function with computational cost equivalent to the square
root of the size of the domain of that function <xref
target="Grover96"/>, use n=32 by selecting an algorithm identifier
with N32 in its name.
</t>
<!--
<t>
There are several formal security proofs for one time signatures and
Merkle tree signatures in the cryptographic literature. Several of
these analyze variants of those algorithms, and are not directly
applicable to the original algorithms; thus caution is needed when
applying these analyses. The LMS scheme has been shown to provide
roughly b bits of security when used with a hash function with an
output size of 2*b bits <xref target="BDM08"/>. (A cryptographic
scheme has b bits of security when an attacker must perform O(2^b)
computations to defeat it.) More precisely, that analysis shows that
LMS is existentially unforgeable under an adaptive chosen message
attack. However, the analysis assumes that the hash function is
chosen uniformly at random from a family of hash functions, and thus
is not completely applicable. Similarly, LM-OTS with w=1 has been shown
to be existentially unforgeable under an adaptive chosen message
attack, when F is a one-way function <xref target="BDM08"/>, when F is
chosen uniformly at random from a family of one-way functions; when F
has c-bit inputs and outputs, it provides roughly b bits of security.
LM-OTS signatures, as specified in this note, have been shown to be
secure based on the collision resistance of F <xref
target="C:Dods05"/>; that analysis provides a lower bound on security
(and it appears to be pessimistic, especially in the case of the n=20
signatures).
</t>
<t>
It may be desirable to adapt this specification in a way that better
aligns with the security proofs. In particular, a random "salt" value
could be generated along with the key, used as an additional input to
F and H, and then provided as part of the public key. This change
appears to make the analysis of <xref target="BDM08"/> applicable, and
it would improve the resistance of these signature schemes against key
collision attacks, that is, scenarios in which an attacker
concurrently attacks many signatures made with many private keys.
</t>
-->
<!--
<texttable anchor='ldwm_sec_table'>
<ttcol align='left'>Name</ttcol>
<ttcol align='right'>Classical</ttcol>
<ttcol align='right'>Postquantum</ttcol>
<c>LMOTS_SHA256_M20_W1</c> <c> 72</c> <c> 45</c>
<c>LMOTS_SHA256_M20_W2</c> <c> 71</c> <c> 44</c>
<c>LMOTS_SHA256_M20_W4</c> <c> 70</c> <c> 43</c>
<c>LMOTS_SHA256_M20_W8</c> <c> 67</c> <c> 40</c>
<c>LMOTS_SHA256_N32_W1</c> <c> 120</c> <c> 77</c>
<c>LMOTS_SHA256_N32_W2</c> <c> 119</c> <c> 76</c>
<c>LMOTS_SHA256_N32_W4</c> <c> 118</c> <c> 75</c>
<c>LMOTS_SHA256_N32_W8</c> <c> 115</c> <c> 72</c>
<c>LMOTS_SHA512_M64_W1</c> <c> 248</c> <c> 163</c>
<c>LMOTS_SHA512_M64_W2</c> <c> 247</c> <c> 162</c>
<c>LMOTS_SHA512_M64_W4</c> <c> 246</c> <c> 161</c>
<c>LMOTS_SHA512_M64_W8</c> <c> 243</c> <c> 150</c>
</texttable>
-->
<section title="Stateful signature algorithm" anchor="stateful">
<t>
The LMS signature system, like all N-time signature systems,
requires that the signer maintain state across different invocations
of the signing algorithm, to ensure that none of the component
one-time signature systems are used more than once. This section
calls out some important practical considerations around this
statefulness.
</t>
<t>
In a typical computing environment, a private key will be stored in
non-volatile media such as on a hard drive. Before it is used to
sign a message, it will be read into an application's Random Access
Memory (RAM). After a signature is generated, the value of the
private key will need to be updated by writing the new value of the
private key into non-volatile storage. It is essential for security
that the application ensure that this value is actually written into
that storage, yet there may be one or more memory caches between it
and the application. Memory caching is commonly done in the file
system, and in a physical memory unit on the hard disk that is
dedicated to that purpose. To ensure that the updated value is
written to physical media, the application may need to take several
special steps. In a POSIX environment, for instance,the O_SYNC flag
(for the open() system call) will cause invocations of the write()
system call to block the calling process until the data has been to
the underlying hardware. However, if that hardware has its own
memory cache, it must be separately dealt with using an operating
system or device specific tool such as hdparm to flush the on-drive
cache, or turn off write caching for that drive. Because these
details vary across different operating systems and devices, this
note does not attempt to provide complete guidance; instead, we call
the implementer's attention to these issues.
</t>
<t>
When hierarchical signatures are used, an easy way to minimize the
private key synchronization issues is to have the private key for
the second level resident in RAM only, and never write that value
into non-volatile memory. A new second level public/private key
pair will be generated whenever the application (re)starts; thus,
failures such as a power outage or application crash are
automatically accommodated. Implementations SHOULD use this approach
wherever possible.
</t>
</section>
<section title="Security of LM-OTS Checksum">
<t>
To show the security of LM-OTS checksum, we consider the signature y of
a message with a private key x and let h = H(message) and
c = Cksm(H(message)) (see <xref target='ldwm_sig_gen' />). To attempt
a forgery, an attacker may try to change the values of h and c. Let
h' and c' denote the values used in the forgery attempt. If for some integer j
in the range 0 to (u-1), inclusive,
<list style="empty">
<t>
a' = coef(h', j, w),
</t>
<t>
a = coef(h, j, w), and
</t>
<t>
a' > a
</t>
</list>
then the attacker can compute F^a'(x[j]) from F^a(x[j]) = y[j] by
iteratively applying function F to the j^th term of the signature an
additional (a' - a) times. However, as a result of the increased
number of hashing iterations, the checksum value c' will decrease
from its original value of c. Thus a valid signature's checksum will
have, for some number k in the range u to (p-1), inclusive,
<list style="empty">
<t>
b' = coef(c', k, w),
</t>
<t>
b = coef(c, k, w), and
</t>
<t>
b' < b
</t>
</list>
Due to the one-way property of F, the attacker cannot easily compute F^b'(x[k])
from F^b(x[k]) = y[k].
</t>
</section>
<!--
<section title="Security Conjectures">
<t>
LM-OTS and LMS signatures rely on a minimum of security conjectures. In
particular, their security does not rely on the computational
difficulty of factoring composites with large prime factors (as does
RSA) or the difficulty of computing the discrete logarithm in a finite
field (as does DSA) or an elliptic curve group (as does ECDSA). All
of these signature schemes also rely on the security of the hash
function that they use, but with LM-OTS and LMS, the security of the
hash function is sufficient.
</t>
</section>
<section title="Post-Quantum Security" anchor="pq">
<t>
A post-quantum cryptosystem is a system that is secure against quantum
computers that have more than a trivial number of quantum bits. It is
open to conjecture whether or not it is feasible to build such
a machine.
</t>
<t>
The LM-OTS and Merkle signature systems are post-quantum secure if they
are used with an appropriate underlying hash function. In contrast,
the signature systems in wide use (RSA, DSA, and ECDSA) are not
post-quantum secure.
</t>
</section>
-->
</section>
<!--section anchor="params" title="Parameter Choices">
<t>
The parameters m and n are chosen to ensure an appropriate level of
security. The value of p is determined by the choice of n. The
parameter w can be chosen to set the number of bytes in the signature;
it has little effect on security. Note however, that there is a
larger computational cost to generate and verify a shorter signature.
Parameter choices are reviewed below.
<artwork>
Hash w-bit Number
Length Elements Left of
(bytes) w in Count Shift Elements
20 1 8 8 168
20 2 4 8 84
20 4 3 4 43
20 8 2 0 22
32 1 9 7 265
32 2 5 6 133
32 4 3 4 67
32 8 2 0 34
48 1 9 7 393
48 2 5 6 197
48 4 3 4 99
48 8 2 0 50
64 1 10 6 522
64 2 5 6 261
64 4 3 4 131
64 8 2 0 66
</artwork-->
<!--
<artwork>
lmax(w,t) = number of bits needed to encode Count
t=160 t=256 t=384 t=512
w=1 8 8 9 9
w=2 8 9 10 10
w=4 10 10 11 11
w=8 13 13 14 14
</artwork>
<artwork>
degree(w,t) = number of w-bit windows needed to encode Count
t=160 t=256 t=384 t=512
w=1 4 4 5 5
w=2 4 5 5 5
w=4 5 5 6 6
w=8 7 7 7 7
</artwork>
<artwork>
shift(w,t) = 16 - 2 * degree(w,t)
t=160 t=256 t=384 t=512
w=1 8 8 6 6
w=2 8 6 6 6
w=4 6 6 4 4
w=8 4 4 4 4
</artwork>
-->
<!--/t>
</section-->
<section anchor="Acknowledgements" title="Acknowledgements">
<t>
Thanks are due to Chirag Shroff, Andreas Hulsing, Burt Kaliski, Eric
Osterweil, Ahmed Kosba, Russ Housley, and Scott Fluhrer for
constructive suggestions and valuable detailed review. We esepcially
acknowledge Jerry Solinas, Laurie Law, and Kevin Igoe, who pointed out
the security benefits of the approach of Leighton and Micali <xref
target="USPTO5432852"/> and Jonathan Katz, who gave us security
guidance.
</t>
</section>
</middle>
<back>
<references title="Normative References">
&rfc2119;
&rfc2434;
&rfc4506;
<reference anchor="FIPS180">
<front>
<title>Secure Hash Standard (SHS)</title>
<author>
<organization>National Institute of Standards and Technology</organization>
</author>
<date month="March" year="2012"></date>
</front>
<seriesInfo name="FIPS" value="180-4"></seriesInfo>
</reference>
<reference anchor="USPTO5432852">
<front>
<title>Large provably fast and secure digital signature schemes from secure hash functions</title>
<author surname="Leighton" initials="T.">
</author>
<author surname="Micali" initials="S.">
</author>
<date month="July" year="1995"></date>
</front>
<seriesInfo name="U.S. Patent" value="5,432,852"></seriesInfo>
</reference>
</references>
<references title="Informative References">
<reference anchor="Katz15">
<front>
<title>Analysis of a proposed hash-based signature standard</title>
<author surname="Katz" initials="J.">
<organization />
</author>
<date year="2015" />
</front>
<seriesInfo name="Contribution to IRTF" value="http://www.cs.umd.edu/~jkatz/papers/HashBasedSigs.pdf" />
</reference>
<reference anchor="Grover96">
<front>
<title>A fast quantum mechanical algorithm for database search</title>
<author surname="Grover" initials="L.K.">
<organization />
</author>
<date year="1996" />
</front>
<seriesInfo name="28th ACM Symposium on the Theory of Computing" value="p. 212" />
</reference>
<!--
<reference anchor="BDM08">
<front>
<title>
Hash-based Digital Signature Schemes
</title>
<author surname="Buchmann" initials="J.">
<organization />
</author>
<author surname="Dahmen" initials="E.">
<organization />
</author>
<author surname="Szydlo" initials="M.">
<organization />
</author>
<date year="2008" />
</front>
<seriesInfo name="Technische Universitat Darmstadt Technical Report"
value="https://www.cdc.informatik.tu-darmstadt.de/~dahmen/papers/hashbasedcrypto.pdf" />
</reference>
<reference anchor="C:Dods05">
<front>
<title>Hash Based Digital Signature Schemes</title>
<author surname="Dods" initials="C.">
<organization />
</author>
<author surname="Smart" initials="N.P.">
<organization />
</author>
<author surname="Stam" initials="M.">
<organization />
</author>
<date year="2005" />
</front>
<seriesInfo name="Lecture Notes in Computer Science vol. 3796" value="Cryptography and Coding" />
</reference>
-->
<reference anchor="C:Merkle89a">
<front>
<title>A Certified Digital Signature</title>
<author surname="Merkle" initials="R. C.">
<organization />
</author>
<date year="1990" />
</front>
<seriesInfo name="Lecture Notes in Computer Science" value="crypto89vol" />
</reference>
<reference anchor="C:Merkle89b">
<front>
<title>One Way Hash Functions and DES</title>
<author surname="Merkle" initials="R. C.">
<organization />
</author>
<date year="1990" />
</front>
<seriesInfo name="Lecture Notes in Computer Science" value="crypto89vol" />
</reference>
<reference anchor="C:Merkle87">
<front>
<title>A Digital Signature Based on a Conventional Encryption Function</title>
<author surname="Merkle" initials="R. C.">
<organization />
</author>
<date year="1988" />
</front>
<seriesInfo name="Lecture Notes in Computer Science" value="crypto87vol" />
</reference>
<reference anchor="Merkle79">
<front>
<title>Secrecy, Authentication, and Public Key Systems</title>
<author surname="Merkle" initials="R. C.">
<organization />
</author>
<date year="1979" />
</front>
<seriesInfo name="Stanford University Information Systems Laboratory" value="Technical Report 1979-1" />
</reference>
</references>
<section title='LM-OTS Parameter Options' anchor='ldwm_param_opts'>
<!-- might want to add a table showing example values of signature size vs. computational overhead -->
<t>
A table illustrating various combinations of n and w with the associated values of
u, v, ls, and p is provided in
<xref target='tbl_ldwm_params' />.
</t>
<figure>
<preamble>The parameters u, v, ls, and p are computed as follows:</preamble>
<artwork>
u = ceil(8*n/w)
v = ceil((floor(lg((2^w - 1) * u)) + 1) / w)
ls = (number of bits in sum) - (v * w)
p = u + v
</artwork>
<postamble>
Here u and v represent the number of w-bit fields required to contain the
hash of the message and the checksum byte strings, respectively. The "number
of bits in sum" is defined according to <xref target='ldwm_msg_chksum'/>. And
as the value of p is the number of w-bit elements of
( H(message) || Cksm(H(message)) ), it is also equivalently
the number of byte strings that form the private key and the number of byte
strings in the signature.
</postamble>
</figure>
<texttable anchor='tbl_ldwm_params'>
<ttcol align='center'>Hash Length in Bytes (n)</ttcol>
<ttcol align='center'>Winternitz Parameter (w)</ttcol>
<ttcol align='center'>w-bit Elements in Hash (u)</ttcol>
<ttcol align='center'>w-bit Elements in Checksum (v)</ttcol>
<ttcol align='center'>Left Shift (ls)</ttcol>
<ttcol align='center'>Total Number of w-bit Elements (p)</ttcol>
<c>16</c> <c>1</c> <c>128</c> <c>8</c> <c>8</c> <c>137</c>
<c>16</c> <c>2</c> <c>64</c> <c>4</c> <c>8</c> <c>68</c>
<c>16</c> <c>4</c> <c>32</c> <c>3</c> <c>4</c> <c>35</c>
<c>16</c> <c>8</c> <c>16</c> <c>2</c> <c>0</c> <c>18</c>
<c>32</c> <c>1</c> <c>256</c> <c>9</c> <c>7</c> <c>265</c>
<c>32</c> <c>2</c> <c>128</c> <c>5</c> <c>6</c> <c>133</c>
<c>32</c> <c>4</c> <c>64</c> <c>3</c> <c>4</c> <c>67</c>
<c>32</c> <c>8</c> <c>32</c> <c>2</c> <c>0</c> <c>34</c>
</texttable>
</section>
<section anchor="iterativeLMS" title="An iterative algorithm for computing an LMS public key">
<t>
The LMS public key can be computed using the following algorithm or
any equivalent method. The algorithm uses a stack of hashes for data
and a separate stack of integers to keep track of the level of the
tree. It also makes use of a hash function with the typical
init/update/final interface to hash functions; the result of the
invocations hash_init(), hash_update(N[1]), hash_update(N[2]), ... ,
hash_update(N[n]), v = hash_final(), in that order, is identical to
that of the invocation of H(N[1] || N[2] || ... || N[n]).
</t>
<figure>
<preamble>Generating an LMS Public Key From an LMS Private Key</preamble>
<artwork>
for ( i = 0; i < num_lmots_keys; i = i + 2 ) {
level = 0;
for ( j = 0; j < 2; j = j + 1 ) {
r = node number
push H(OTS_PUBKEY[i+j] || I || uint32str(r) || D_LEAF) onto data stack
push level onto the integer stack
}
while ( height of the integer stack >= 2 ) {
if level of the top 2 elements on the integer stack are equal {
hash_init()
siblings = ""
repeat ( 2 ) {
siblings = (pop(data stack) || siblings)
level = pop(integer stack)
}
hash_update(siblings)
r = node number
hash_update(I || uint32str(r) || D_INTR)
push hash_final() onto the data stack
push (level + 1) onto the integer stack
}
}
}
public_key = pop(data stack)
</artwork>
<postamble>Note that this pseudocode expects that all 2^h leaves of
the tree have equal depth. Neither stack ever contains more
than h+1 elements. For typical parameters, these stacks will
hold around 512 bytes of data.
</postamble>
</figure>
</section>
<section title="Example implementation">
<figure>
<artwork><![CDATA[
# example implementation for Leighton-Micali hash based signatures
# Internet draft
#
# Notes:
#
# * only a limted set of parameters are supported; in particular,
# * w=8 and n=32
#
# * HLMS, LMS, and LM-OTS are all implemented
#
# * uncommenting print statements may be useful for debugging, or
# for understanding the mechanics of
#
#
# LMOTS constants
#
D_ITER = chr(0x00) # in the iterations of the LM-OTS algorithms
D_PBLC = chr(0x01) # when computing the hash of all of the iterates in the LM-OTS algorithm
D_MESG = chr(0x02) # when computing the hash of the message in the LMOTS algorithms
D_LEAF = chr(0x03) # when computing the hash of the leaf of an LMS tree
D_INTR = chr(0x04) # when computing the hash of an interior node of an LMS tree
NULL = chr(0) # used as padding for encoding
lmots_sha256_n32_w8 = 0x08000008 # typecode for LM-OTS with n=32, w=8
lms_sha256_n32_h10 = 0x02000002 # typecode for LMS with n=32, h=10
hlms_sha256_n32_l2 = 0x01000001 # typecode for two-level HLMS with n=32
# LMOTS parameters
#
n = 32; p = 34; w = 8; ls = 0
def bytes_in_lmots_sig():
return n*(p+1)+40 # 4 + n + 31 + 1 + 4 + n*p
from Crypto.Hash import SHA256
from Crypto import Random
# SHA256 hash function
#
def H(x):
# print "hash input: " + stringToHex(x)
h = SHA256.new()
h.update(x)
return h.digest()[0:n]
def sha256_iter(x, num):
tmp = x
for j in range(0, num):
tmp = H(tmp + I + q + uint16ToString(i) + uint8ToString(j) + D_ITER)
# entropy source
#
entropySource = Random.new()
# integer to string conversion
#
def uint32ToString(x):
c4 = chr(x & 0xff)
x = x >> 8
c3 = chr(x & 0xff)
x = x >> 8
c2 = chr(x & 0xff)
x = x >> 8
c1 = chr(x & 0xff)
return c1 + c2 + c3 + c4
def uint16ToString(x):
c2 = chr(x & 0xff)
x = x >> 8
c1 = chr(x & 0xff)
return c1 + c2
def uint8ToString(x):
return chr(x)
def stringToUint(x):
sum = 0
for c in x:
sum = sum * 256 + ord(c)
return sum
# string-to-hex function needed for debugging
#
def stringToHex(x):
return "".join("{:02x}".format(ord(c)) for c in x)
# LM-OTS functions
#
def encode_lmots_sig(C, I, q, y):
result = uint32ToString(lmots_sha256_n32_w8) + C + I + NULL + q
for i, e in enumerate(y):
result = result + y[i]
return result
def decode_lmots_sig(sig):
if (len(sig) != bytes_in_lmots_sig()):
print "error decoding signature; incorrect length (" + str(len(sig)) + " bytes)"
typecode = sig[0:4]
if (typecode != uint32ToString(lmots_sha256_n32_w8)):
print "error decoding signature; got typecode " + stringToHex(typecode) + ", expected: " + stringToHex(uint32ToString(lmots_sha256_n32_w8))
return ""
C = sig[4:n+4]
I = sig[n+4:n+35]
q = sig[n+36:n+40] # note: skip over NULL
y = list()
pos = n+40
for i in range(0, p):
y.append(sig[pos:pos+n])
pos = pos + n
return C, I, q, y
def print_lmots_sig(sig):
C, I, q, y = decode_lmots_sig(sig)
print "C:\t" + stringToHex(C)
print "I:\t" + stringToHex(I)
print "q:\t" + stringToHex(q)
for i, e in enumerate(y):
print "y[" + str(i) + "]:\t" + stringToHex(e)
# Algorithm 0: Generating a Private Key
#
def lmots_gen_priv():
priv = list()
for i in range(0, p):
priv.append(entropySource.read(n))
return priv
# Algorithm 1: Generating a Public Key From a Private Key
#
def lmots_gen_pub(private_key, I, q):
hash = SHA256.new()
hash.update(I + q)
for i, x in enumerate(private_key):
tmp = x
# print "i:" + str(i) + " range: " + str(range(0, 256))
for j in range(0, 256):
tmp = H(tmp + I + q + uint16ToString(i) + uint8ToString(j) + D_ITER)
hash.update(tmp)
hash.update(D_PBLC)
return hash.digest()
# Algorithm 2: Merkle Checksum Calculation
#
def checksum(x):
sum = 0
for c in x:
sum = sum + ord(c)
# print format(sum, '04x')
c1 = chr(sum >> 8)
c2 = chr(sum & 0xff)
return c1 + c2
# Algorithm 3: Generating a Signature From a Private Key and a Message
#
def lmots_gen_sig(private_key, I, q, message):
C = entropySource.read(n)
hashQ = H(message + C + I + q + D_MESG)
V = hashQ + checksum(hashQ)
# print "V: " + stringToHex(V)
y = list()
for i, x in enumerate(private_key):
tmp = x
# print "i:" + str(i) + " range: " + str(range(0, ord(V[i])))
for j in range(0, ord(V[i])):
tmp = H(tmp + I + q + uint16ToString(i) + uint8ToString(j) + D_ITER)
y.append(tmp)
return encode_lmots_sig(C, I, q, y)
def lmots_sig_to_pub(sig, message):
C, I, q, y = decode_lmots_sig(sig)
hashQ = H(message + C + I + q + D_MESG)
V = hashQ + checksum(hashQ)
# print "V: " + stringToHex(V)
hash = SHA256.new()
hash.update(I + q)
for i, y in enumerate(y):
tmp = y
# print "i:" + str(i) + " range: " + str(range(ord(V[i]), 256))
for j in range(ord(V[i]), 256):
tmp = H(tmp + I + q + uint16ToString(i) + uint8ToString(j) + D_ITER)
hash.update(tmp)
hash.update(D_PBLC)
return hash.digest()
# Algorithm 4: Verifying a Signature and Message Using a Public Key
#
def lmots_verify_sig(public_key, sig, message):
z = lmots_sig_to_pub(sig, message)
# print "z: " + stringToHex(z)
if z == public_key:
return 1
else:
return 0
# LM-OTS test functions
#
I = entropySource.read(31)
q = uint32ToString(0)
private_key = lmots_gen_priv()
print "LMOTS private key: "
for i, x in enumerate(private_key):
print "x[" + str(i) + "]:\t" + stringToHex(x)
public_key = lmots_gen_pub(private_key, I, q)
print "LMOTS public key: "
print stringToHex(public_key)
message = "The right of the people to be secure in their persons, houses, papers, and effects, against unreasonable searches and seizures, shall not be violated, and no warrants shall issue, but upon probable cause, supported by oath or affirmation, and particularly describing the place to be searched, and the persons or things to be seized."
print "message: " + message
sig = lmots_gen_sig(private_key, I, q, message)
print "LMOTS signature byte length: " + str(len(sig))
print "LMOTS signature: "
print_lmots_sig(sig)
print "verification: "
print "true positive test: "
if (lmots_verify_sig(public_key, sig, message) == 1):
print "passed: message/signature pair is valid as expected"
else:
print "failed: message/signature pair is invalid"
print "false positive test: "
if (lmots_verify_sig(public_key, sig, "some other message") == 1):
print "failed: message/signature pair is valid (expected failure)"
else:
print "passed: message/signature pair is invalid as expected"
# LMS N-time signatures functions
#
h = 10 # height (number of levels -1) of tree
def encode_lms_sig(lmots_sig, path):
result = uint32ToString(lms_sha256_n32_h10) + lmots_sig
for i, e in enumerate(path):
result = result + path[i]
return result
def decode_lms_sig(sig):
typecode = sig[0:4]
if (typecode != uint32ToString(lms_sha256_n32_h10)):
print "error decoding signature; got typecode " + stringToHex(typecode) + ", expected: " + stringToHex(uint32ToString(lms_sha256_h10))
return ""
pos = 4 + bytes_in_lmots_sig()
lmots_sig = sig[4:pos]
path = list()
for i in range(0,h):
# print "sig[" + str(i) + "]:\t" + stringToHex(sig[pos:pos+n])
path.append(sig[pos:pos+n])
pos = pos + n
return lmots_sig, path
def print_lms_sig(sig):
lmots_sig, path = decode_lms_sig(sig)
print_lmots_sig(lmots_sig)
for i, e in enumerate(path):
print "path[" + str(i) + "]:\t" + str(stringToHex(e))
def bytes_in_lms_sig():
return bytes_in_lmots_sig() + h*n + 4
class lms_private_key(object):
# Algorithm for computing root and other nodes (alternative to Algorithm 6)
#
def T(self, j):
# print "T(" + str(j) + ")"
if (j >= 2**h):
self.nodes[j] = H(self.pub[j - 2**h] + self.I + uint32ToString(j) + D_LEAF)
return self.nodes[j]
else:
self.nodes[j] = H(self.T(2*j) + self.T(2*j+1) + self.I + uint32ToString(j) + D_INTR)
return self.nodes[j]
def __init__(self):
self.I = entropySource.read(31)
self.priv = list()
self.pub = list()
for q in range(0, 2**h):
# print "generating " + str(q) + "th OTS key"
ots_priv = lmots_gen_priv()
ots_pub = lmots_gen_pub(ots_priv, self.I, uint32ToString(q))
self.priv.append(ots_priv)
self.pub.append(ots_pub)
self.leaf_num = 0
self.nodes = {}
self.lms_public_key = self.T(1)
def num_sigs_remaining():
return 2**h - self.leaf_num
def printHex(self):
for i, p in enumerate(self.priv):
print "priv[" + str(i) + "]:"
for j, x in enumerate(p):
print "x[" + str(j) + "]:\t" + stringToHex(x)
print "pub[" + str(i) + "]:\t" + stringToHex(self.pub[i])
for t, T in self.nodes.items():
print "T(" + str(t) + "):\t" + stringToHex(T)
print "pub: \t" + stringToHex(self.lms_public_key)
def get_public_key(self):
return self.lms_public_key
def get_path(self, leaf_num):
node_num = leaf_num + 2**h
# print "signing node " + str(node_num)
path = list()
while node_num > 1:
if (node_num % 2):
# print "path" + str(node_num - 1) + ": " + stringToHex(self.nodes[node_num - 1])
path.append(self.nodes[node_num - 1])
else:
# print "path " + str(node_num + 1) + ": " + stringToHex(self.nodes[node_num + 1])
path.append(self.nodes[node_num + 1])
node_num = node_num/2
return path
def sign(self, message):
if (self.leaf_num >= 2**h):
return ""
sig = lmots_gen_sig(self.priv[self.leaf_num], self.I, uint32ToString(self.leaf_num), message)
# C, I, q, y = decode_lmots_sig(sig)
path = self.get_path(self.leaf_num)
leaf_num = self.leaf_num
self.leaf_num = self.leaf_num + 1
return encode_lms_sig(sig, path)
class lms_public_key(object):
def __init__(self, value):
self.value = value
def verify(self, message, sig):
lmots_sig, path = decode_lms_sig(sig)
C, I, q, y = decode_lmots_sig(lmots_sig) # note: only q is actually needed here
node_num = stringToUint(q) + 2**h
# print "verifying node " + str(node_num)
pathvalue = iter(path)
tmp = lmots_sig_to_pub(lmots_sig, message)
tmp = H(tmp + I + uint32ToString(node_num) + D_LEAF)
while node_num > 1:
# print "S(" + str(node_num) + "):\t" + stringToHex(tmp)
if (node_num % 2):
# print "adding node " + str(node_num - 1)
tmp = H(pathvalue.next() + tmp + I + uint32ToString(node_num/2) + D_INTR)
else:
# print "adding node " + str(node_num + 1)
tmp = H(tmp + pathvalue.next() + I + uint32ToString(node_num/2) + D_INTR)
node_num = node_num/2
# print "pubkey: " + stringToHex(tmp)
if (tmp == self.value):
return 1
else:
return 0
# test LMS signatures
#
print "LMS test"
lms_priv = lms_private_key()
lms_pub = lms_public_key(lms_priv.get_public_key())
# lms_priv.printHex()
for i in range(0, 2**h):
sig = lms_priv.sign(message)
print "LMS signature byte length: " + str(len(sig))
# print_lms_sig(sig)
print "true positive test"
if (lms_pub.verify(message, sig) == 1):
print "passed: LMS message/signature pair is valid"
else:
print "failed: LMS message/signature pair is invalid"
print "false positive test"
if (lms_pub.verify("other message", sig) == 1):
print "failed: LMS message/signature pair is valid (expected failure)"
else:
print "passed: LMS message/signature pair is invalid as expected"
# Hierarchical LMS signatures (HLMS)
def encode_hlms_sig(pub2, sig1, lms_sig):
result = uint32ToString(hlms_sha256_n32_l2)
result = result + pub2
result = result + sig1
result = result + lms_sig
return result
def decode_hlms_sig(sig):
typecode = sig[0:4]
if (typecode != uint32ToString(hlms_sha256_n32_l2)):
print "error decoding signature; got typecode " + stringToHex(typecode) + ", expected: " + stringToHex(uint32ToString(hlms_sha256_n32_l2))
return ""
pub2 = sig[4:36]
lms_sig_len = bytes_in_lms_sig()
sig1 = sig[36:36+lms_sig_len]
lms_sig = sig[36+lms_sig_len:36+2*lms_sig_len]
return pub2, sig1, lms_sig
def print_hlms_sig(sig):
pub2, sig1, lms_sig = decode_hlms_sig(sig)
print "pub2:\t" + stringToHex(pub2)
print "sig1: "
print_lms_sig(sig1)
print "sig2: "
print_lms_sig(lms_sig)
class hlms_private_key(object):
def __init__(self):
self.prv1 = lms_private_key()
self.init_level_2()
def init_level_2(self):
self.prv2 = lms_private_key()
self.sig1 = self.prv1.sign(self.prv2.get_public_key())
def get_public_key(self):
return self.prv1.get_public_key()
def sign(self, message):
lms_sig = self.prv2.sign(message)
if (lms_sig == ""):
print "refreshing level 2 public/private key pair"
self.init_level_2()
lms_sig = self.prv2.sign(message)
return encode_hlms_sig(self.prv2.get_public_key(), self.sig1, lms_sig)
class hlms_public_key(object):
def __init__(self, value):
self.pub1 = lms_public_key(value)
def verify(self, message, sig):
pub2, sig1, lms_sig = decode_hlms_sig(sig)
if (self.pub1.verify(pub2, sig1) == 1):
if (lms_public_key(pub2).verify(message, lms_sig) == 1):
return 1
else:
print "pub2 verification of lms_sig did not pass"
else:
print "pub1 verification of sig1 did not pass"
return 0
print "HLMS testing"
hlms_prv = hlms_private_key()
hlms_pub = hlms_public_key(hlms_prv.get_public_key())
for i in range(0, 4096):
sig = hlms_prv.sign(message)
# print_hlms_sig(sig)
print "HLMS signature byte length: " + str(len(sig))
print "testing verification (" + str(i) + "th iteration)"
print "true positive test"
if (hlms_pub.verify(message, sig) == 1):
print "passed; HLMS message/signature pair is valid"
else:
print "failed; HLMS message/signature pair is invalid"
print "false positive test"
if (hlms_pub.verify("other message", sig) == 1):
print "failed; HLMS message/signature pair is valid (expected failure)"
else:
print "passed; HLMS message/signature pair is invalid as expected"
]]>
</artwork>
</figure>
</section>
<!--
<section title="Example Data for Testing" anchor="testing">
<t>
As with all criticism's, implementations of LDWM signatures and
Merkle signatures need to be tested before they are used. This section contains
sample data generated from the signing and verification operations of software
that implements the algorithms described in this document.
</t>
<section title='Parameters' anchor='test_params'>
<t>
The example contained in this section demonstrates the calculations of LMOTS_SHA256_M20_W4
using a Merkle Tree Signature of degree 4 and height 2. This corresponds to the following
parameter values:
</t>
<texttable anchor='tbl_test_params'>
<ttcol align='center'>m</ttcol>
<ttcol align='center'>n</ttcol>
<ttcol align='center'>w</ttcol>
<ttcol align='center'>p</ttcol>
<ttcol align='center'>ls</ttcol>
<ttcol align='center'>k</ttcol>
<ttcol align='center'>h</ttcol>
<c>20</c> <c>32</c> <c>4</c> <c>67</c> <c>4</c> <c>4</c> <c>2</c>
</texttable>
<t>
The non-standard size of the Merkle tree (h = 2) has been selected specifically
for this example to reduce the amount of data presented.
</t>
</section>
<section title='Key Generation' anchor='test_key_gen'>
<t>The LDWM algorithm does not define a required method of key
generation. This is left to the implementer. The selected method,
however, must satisfy the requirement that the private keys of the
one-time signatures are uniformly random, independent, and
unpredicable. In addition, all LDWM key pairs must be generated in
advance in order to calculate the value of the Merkle public key.
</t>
<t>
For the test data presented here, a summary of the key generation method is as follows:
<list style='numbers'>
<t>MTS Private Key - Set mts_private_key to a pseudorandomly generated n-byte value.</t>
<t>OTS Private Keys - Use the mts_private_key as a key derivation key input to some key
derivation function, thereby producing n^k derived keys. Then use each derived key as an
input to the same function again to further derive p elements of n-bytes each.
This accomplishes the result of Algorithm 0 of <xref target='ldwm_prv_key' /> for each
leaf of the Merkle tree.</t>
<t>OTS Public Keys - For each OTS private key, calculate the corresponding OTS public key
as in Algorithm 1 of <xref target='ldwm_pub_key' />.</t>
<t>MTS Public Key - Each OTS public key is the value of a leaf on the
Merkle tree. Calculate the MTS public key using the pseudocode
algorithm of <xref target='mts_alg' /> or some equivalent implementation.</t>
</list>
</t>
<t>
The above steps result in the following data values associated with the first leaf of the
Merkle tree, leaf 0.
</t>
<texttable anchor='tbl_mts_priv_key'>
<ttcol align='center'>MTS Private Key</ttcol>
<c>0x0f677ff1b4cbf10baec89959f051f203 3371492da02f62dd61d6fbd1cee1bd14</c>
</texttable>
<texttable anchor='tbl_ots_priv_key'>
<ttcol align='center'>Key Element Index (i)</ttcol>
<ttcol align='center'>OTS Private Key 0 Element (x[i])</ttcol>
<c>0</c> <c>0xbfb757383fb08d324629115a84daf00b 188d5695303c83c184e1ec7a501c431f</c>
<c>1</c> <c>0x7ce628fb82003a2829aab708432787d0 fc735a29d671c7d790068b453dc8c913</c>
<c>2</c> <c>0x8174929461329d15068a4645a34412bd 446d4c9e757463a7d5164efd50e05c93</c>
<c>3</c> <c>0xf283f3480df668de4daa74bb0e4c5531 5bc00f7d008bb6311e59a5bbca910fd7</c>
<c>4</c> <c>0xe62708eaf9c13801622563780302a068 0ba9d39c078daa5ebc3160e1d80a1ea7</c>
<c>5</c> <c>0x1f002efad2bfb4275e376af7138129e3 3e88cf7512ec1dcdc7df8d5270bc0fd7</c>
<c>6</c> <c>0x8ed5a703e9200658d18bc4c05dd0ca8a 356448a26f3f4fe4e0418b52bd6750a2</c>
<c>7</c> <c>0xc74e56d61450c5387e86ddad5a8121c8 8b1bc463e64f248a1f1d91d950957726</c>
<c>8</c> <c>0x629f18b6a2a4ea65fff4cf758b57333f e1d34af05b1cd7763696899c9869595f</c>
<c>9</c> <c>0x1741c31fdbb4864712f6b17fadc05d45 926c831c7a755b7d7af57ac316ba6c2a</c>
<c>10</c> <c>0xe59a7b81490c5d1333a9cdd48b9cb364 56821517a3a13cb7a8ed381d4d5f3545</c>
<c>11</c> <c>0x3ba97fe8b2967dd74c8b10f31fc5f527 a23b89c1266202a4d7c281e1f41fa020</c>
<c>12</c> <c>0xa262a9287cc979aaa59225d75df51b82 57b92e780d1ab14c4ac3ecdac58f1280</c>
<c>13</c> <c>0x9dfe0af1a3d9064338d96cb8eae88baa 6a69265538873b4c17265fa9d573bcff</c>
<c>14</c> <c>0xde9c5c6a5c6a274eabe90ed2a8e6148c 720196d237a839aaf5868af8da4d0829</c>
<c>15</c> <c>0x5de81ec17090a82cb722f616362d3808 30f04841191e44f1f81b9880164b14cd</c>
<c>16</c> <c>0xc0d047000604105bad657d9fa2f9ef10 1cfd9490f4668b700d738f2fa9e1d11a</c>
<c>17</c> <c>0xf45297ef310941e1e855f97968129bb1 73379193919f7b0fee9c037ae507c2d2</c>
<c>18</c> <c>0x46ef43a877f023e5e66bbcd4f06b839f 3bfb2b64de25cd67d1946b0711989129</c>
<c>19</c> <c>0x46e2a599861bd9e8722ad1b55b8f0139 305fcf8b6077d545d4488c4bcb652f29</c>
<c>20</c> <c>0xe1ad4d2d296971e4b0b7a57de305779e 82319587b58d3ef4daeb08f630bd5684</c>
<c>21</c> <c>0x7a07fa7aed97cb54ae420a0e6a58a153 38110f7743cab8353371f8ca710a4409</c>
<c>22</c> <c>0x40601f6c4b35362dd4948d5687b5cb6b 5ec8b2ec59c2f06fd50f8919ebeaae92</c>
<c>23</c> <c>0xa061b0ba9f493c4991be5cd3a9d15360 a9eb94f6f7adc28dddf174074f3df3c4</c>
<c>24</c> <c>0xcf1546a814ff16099cebf1fe0db1ace5 1c272fda9846fbb535815924b0077fa4</c>
<c>25</c> <c>0xcbb06f13155ce4e56c85a32661c90142 8b630a4c37ea5c7062156f07f6b3efff</c>
<c>26</c> <c>0x1181ee7fc03342415094e36191eb450a 11cdea9c6f6cdc34de79cee0ba5bf230</c>
<c>27</c> <c>0xe9f1d429b343bb897881d2a19ef363cd 1ab4117cbaad54dc292b74b8af9f5cf2</c>
<c>28</c> <c>0x87f34b2551ef542f579fa65535c5036f 80eb83be4c898266ffc531da2e1a9122</c>
<c>29</c> <c>0x9b4b467852fe33a03a872572707342fd ddeae64841225186babf353fa2a0cd09</c>
<c>30</c> <c>0x19d58cd240ab5c80be6ddf5f60d18159 2dca2be40118c1fdd46e0f14dffbcc7d</c>
<c>31</c> <c>0x5c9ad386547ba82939e49c9c74a8eccf 1cea60aa327b5d2d0a66b1ca48912d6d</c>
<c>32</c> <c>0xf49083e502400ffae9273c6de92a301e 7bda1537cab085e5adfa9eb746e8eca9</c>
<c>33</c> <c>0x4074e1812d69543ce3c1ce706f6e0b45 f5f26f4ef39b34caa709335fd71e8fc0</c>
<c>34</c> <c>0x1256612b0ca8398e97b247ae564b74b1 3839b3b1cf0a0dd8ba629a2c58355f84</c>
<c>35</c> <c>0xbab3989f00fd2c327bbfb35a218cc3ce 49d6b34cbf8b6e8919e90c4eff400ca9</c>
<c>36</c> <c>0x96b52a5d395a5615b73dae65586ac5c8 7f9dd3b9b3f82dbf509b5881f0643fa8</c>
<c>37</c> <c>0x5d05ca4c644e1c41ccdaedbd2415d4f0 9b4a1b940b51fe823dff7617b8ee8304</c>
<c>38</c> <c>0xd96aab95ef6248e235d91d0f23b64727 a6675adfc64efea72f6f8b4a47996c0d</c>
<c>39</c> <c>0xfd9c384d52d3ac27c4f4898fcc15e83a c182f97ea63f7d489283e2cc7e6ed180</c>
<c>40</c> <c>0xc86eaed6a9e3fbe5b262c1fa1f099f7c 35ece71d9e467fab7a371dbcf400b544</c>
<c>41</c> <c>0xf462b3719a2ed8778155638ff814dbf4 2b107bb5246ee3dd82abf97787e6a69e</c>
<c>42</c> <c>0x014670912e3eb74936ebb64168b447e4 2522b57c2540ac4b49b9ae356c01eca6</c>
<c>43</c> <c>0x2b411096e0ca16587830d3acd673e858 863fedc4cea046587cba0556d2bf9884</c>
<c>44</c> <c>0xa73917c74730582e8e1815b8a07b1896 2ac05e500e045676be3f1495fcfa18ca</c>
<c>45</c> <c>0xa4ab61e6962fe39a255dbf8a46d25110 0d127fab08db59512653607bda24302c</c>
<c>46</c> <c>0x9b910ca516413f376b9eba4b0d571b22 253c2a9646131ac9a2af5f615f7322b8</c>
<c>47</c> <c>0xfc1b4ce627c77ad35a21ea9ded2cce91 b3758a758224e35cf2918153a513d64c</c>
<c>48</c> <c>0xc1902d8e8c02d9442581d7e053a2798a a84d77a74b6e7f2cc5096d50646c890f</c>
<c>49</c> <c>0xb3f47e2e8e2dcdd890ea00934b9d8234 830dbc4a30ac996b144f12b3e463c77f</c>
<c>50</c> <c>0x8188d1ecfc6ae6118911f2b9b3a6c7a1 e5f909aa8b5c0aab8c69f1a7d436c307</c>
<c>51</c> <c>0xca42d985974c7b870bc76494604eff49 2676c942c6cb7c75d4938805885dd054</c>
<c>52</c> <c>0xbe58851ebe566057e1ee16b8c604a473 4c373af622660b2a82357ac6effb4566</c>
<c>53</c> <c>0xc22d493f7a5642fceba2404dbefa8f95 6323fac87fac425f6de8d23c9e8b20ca</c>
<c>54</c> <c>0x1a76c1ffa467906173fd0245b0cd6639 e6013ca79c4ed92426ee69ff5beeac0b</c>
<c>55</c> <c>0xbc6c0cb7808f379af1b7b7327436ad65 c05458f2d0a6923c333e5129c4c99671</c>
<c>56</c> <c>0xfbb04488c3c088dc5e63d13e6a701036 6109ca4c5f4b0a8d37780187e2e9930e</c>
<c>57</c> <c>0xaec10811569d4d72e3a1baf71a886b75 eba6dc07ed027af0b2beffa71f9b43c8</c>
<c>58</c> <c>0xf5529be3b7a19212e8baa970d2420bf4 123f678267f96c1c3ef26ab610cb0061</c>
<c>59</c> <c>0x172ba1ba0b701eeafe00692d1eb90181 8ccaefaeb8f799395da81711766d1f43</c>
<c>60</c> <c>0xfe1f8c15825208f3a21346b894b3d94e 4f3aa29cbc194a7b2c8a810c4c509042</c>
<c>61</c> <c>0x2e81c66cc914ea1b0fa5942fe9780d54 8c0b330e3bf73f0cb0bda4bc9c9e6ff4</c>
<c>62</c> <c>0xfc3453aec5cc19a6a4bda4bc25931604 704bf4386cd65780c6e73214c1da85ba</c>
<c>63</c> <c>0x4e8000c587dc917888e7e3d817672c0a ef812788cc8579afa7e9b2e566309003</c>
<c>64</c> <c>0xba667ca0e44a8601a0fde825d4d2cf1b b9cf467041e04af84c9d0cd9fd8dc784</c>
<c>65</c> <c>0x4965db75f81c8a596680753ce70a94c6 156253bb426947de1d7662dd7e05e9a8</c>
<c>66</c> <c>0x2c23cc3e5ca37dec279c506101a3d8d9 f1e4f99b2a33741b59f8bddba7455419</c>
</texttable>
<t>
Using the value of the OTS private key above, the corresponding public key is given below.
Intermediate values of the SHA256-20 function F^(2^w - 1)(x[i]) are provided in
<xref target='tbl_sha_256_20' />.
</t>
<texttable anchor='tbl_ots_pub_key'>
<ttcol align='center'>OTS Public Key 0</ttcol>
<c>0x2db55a72075fcfab5aedbef77bf6b371 dfb489d6e61ad2884a248345e6910618</c>
</texttable>
<t>
Following the creation of all OTS public/private key pairs, the OTS public keys in
<xref target='tbl_ots_pub_keys' /> are used to determine the MTS public key below. Intermediate
values of the interior nodes of the Merkle tree are provided in <xref target='tbl_mts_int_nodes' />.
</t>
<texttable anchor='tbl_mts_pub_key'>
<ttcol align='center'>MTS Public Key</ttcol>
<c>0x6610803d9a3546fb0a7895f6a4a0cfed 3a07d45e51d096e204b018e677453235</c>
</texttable>
</section>
<section title='Signature Generation' anchor='test_sig_gen'>
<t>
In order to test signature generation, a text file containing the content "Hello world!\n",
where '\n' represents the ASCII line feed character, was created and signed. A raw hex dump
of the file contents is shown in the table below.
</t>
<texttable anchor='tbl_hex_msg'>
<ttcol align='center'>Hexadecimal Byte Values</ttcol>
<ttcol align='center'>ASCII Representation ('.' is substituted for non-printing characters)</ttcol>
<c>0x48 0x65 0x6c 0x6c 0x6f 0x20 0x77 0x6f 0x72 0x6c 0x64 0x21 0x0a</c> <c>Hello world!.</c>
</texttable>
<t>
The SHA256 hash of the text file is provided below.
</t>
<texttable anchor='tbl_sha_256_msg'>
<ttcol align='center'>SHA256 Hash of Signed File (H("Hello world!\n"))</ttcol>
<c>0x0ba904eae8773b70c75333db4de2f3ac 45a8ad4ddba1b242f0b3cfc199391dd8</c>
</texttable>
<t>
This value was subsequently used in Algorithm 3 of <xref target='ldwm_sig_gen' /> to
create the one-time signature of the message. Algorithm 2 of
<xref target='ldwm_msg_chksum' /> was applied to calculate a checksum of 0x1cc. The
resulting signature is shown in the following table.
</t>
<texttable anchor='tbl_ots'>
<ttcol align='center'>OTS Element Index (i)</ttcol>
<ttcol align='center'>Function Iteration Count (a = coef( H(msg) || C(H(msg)), i, w ))</ttcol>
<ttcol align='center'>OTS Element (y[i] = F^a(x[i]))</ttcol>
<c>0</c> <c>0</c> <c>0xbfb757383fb08d324629115a84daf00b188d5695</c>
<c>1</c> <c>11</c> <c>0x4af079e885ddfd3245f29778d265e868a3bfeaa4</c>
<c>2</c> <c>10</c> <c>0xfbad1928bfc57b22bcd949192452293d07d6b9ad</c>
<c>3</c> <c>9</c> <c>0xb98063e184b4cb949a51e1bb76d99d4249c0b448</c>
<c>4</c> <c>0</c> <c>0xe62708eaf9c13801622563780302a0680ba9d39c</c>
<c>5</c> <c>4</c> <c>0x39343cba3ffa6d75074ce89831b3f3436108318c</c>
<c>6</c> <c>14</c> <c>0xfe08aa73607aec5664188a9dacdc34a295588c9a</c>
<c>7</c> <c>10</c> <c>0xd3346382119552d1ceb92a78597a00c956372bf0</c>
<c>8</c> <c>14</c> <c>0xf1dd245ec587c0a7a1b754cc327b27c839a6e46a</c>
<c>9</c> <c>8</c> <c>0xa5f158adc1decaf0c1edc1a3a5d8958d726627b5</c>
<c>10</c> <c>7</c> <c>0x06d2990f62f22f0c943a418473678e3ffdbff482</c>
<c>11</c> <c>7</c> <c>0xf3390b8d6e5229ae9c5d4c3f45e10455d8241a49</c>
<c>12</c> <c>3</c> <c>0x22dd5f9d3c89180caa0f695203d8cf90f3c359be</c>
<c>13</c> <c>11</c> <c>0x67999c4043f95de5f07d82b741347a3eb6ac0c25</c>
<c>14</c> <c>7</c> <c>0xc4ffe472d48adeb37c7360da70711462013b7a4e</c>
<c>15</c> <c>0</c> <c>0x5de81ec17090a82cb722f616362d380830f04841</c>
<c>16</c> <c>12</c> <c>0x2f892c824af65cc749f912a36dfa8ade2e4c3fd1</c>
<c>17</c> <c>7</c> <c>0xb644393e8030924403b594fb5cacd8b2d28862e2</c>
<c>18</c> <c>5</c> <c>0x31b8d2908911dbbf5ba1f479a854808945d9e948</c>
<c>19</c> <c>3</c> <c>0xa9a02269d24eb8fed6fb86101cbd0d8977219fb1</c>
<c>20</c> <c>3</c> <c>0xe4aae6e6a9fe1b0d5099513f170c111dee95714d</c>
<c>21</c> <c>3</c> <c>0xd79c16e7f2d4dd790e28bab0d562298c864e31e9</c>
<c>22</c> <c>13</c> <c>0xc29678f0bb4744597e04156f532646c98a0b42e8</c>
<c>23</c> <c>11</c> <c>0x57b31d75743ff0f9bcf2db39d9b6224110b8d27b</c>
<c>24</c> <c>4</c> <c>0x0a336d93aac081a2d849c612368b8cbb2fa9563a</c>
<c>25</c> <c>13</c> <c>0x917be0c94770a7bb12713a4bae801fb3c1c43002</c>
<c>26</c> <c>14</c> <c>0x91586feaadcf691b6cb07c16c8a2ed0884666e84</c>
<c>27</c> <c>2</c> <c>0xdd4e4b720fb2517c4bc6f91ccb8725118e5770c6</c>
<c>28</c> <c>15</c> <c>0x491f6ec665f54c4b3cffaa02ec594d31e6e26c0e</c>
<c>29</c> <c>3</c> <c>0x4f5a082c9d9c9714701de0bf426e9f893484618c</c>
<c>30</c> <c>10</c> <c>0x11f7017313f0c9549c5d415a8abc25243028514d</c>
<c>31</c> <c>12</c> <c>0x6839a994fccb9cb76241d809146906a3d13f89f1</c>
<c>32</c> <c>4</c> <c>0x71cd1d9163d7cd563936837c61d97bb1a5337cc0</c>
<c>33</c> <c>5</c> <c>0x77c9034ffc0f9219841aa8e1edbfb62017ef9fd1</c>
<c>34</c> <c>10</c> <c>0xad9f6034017d35c338ac35778dd6c4c1abe4472a</c>
<c>35</c> <c>8</c> <c>0x4a1c396b22e4f5cc2428045b36d13737c4007515</c>
<c>36</c> <c>10</c> <c>0x98cb57b779c5fd3f361cd5debc243303ae5baefd</c>
<c>37</c> <c>13</c> <c>0x29857298f274d6bf595eadc89e5464ccf9608a6c</c>
<c>38</c> <c>4</c> <c>0x95e35a26815a3ae9ad84a24464b174a29364da18</c>
<c>39</c> <c>13</c> <c>0x4afeb3b95b5b333759c0acdd96ce3f26314bb22b</c>
<c>40</c> <c>13</c> <c>0x325a37ee5e349b22b13b54b24be5145344e7b8f3</c>
<c>41</c> <c>11</c> <c>0x4f772c93f56fd6958ce135f02847996c67e1f2ef</c>
<c>42</c> <c>10</c> <c>0xd4f6d91c577594060be328b013c9e9b0e8a2e5d8</c>
<c>43</c> <c>1</c> <c>0x717e1a81c325cdccacb6e9fd9e92dd3e1bb84ae8</c>
<c>44</c> <c>11</c> <c>0x1dd363724ec66c090a1228dfa1cd3d9cc806f346</c>
<c>45</c> <c>2</c> <c>0x64b4110476dd0beea78714c5ab71278818792cfa</c>
<c>46</c> <c>4</c> <c>0xe22290e740056a144af50f0b10962b5bcc18fc82</c>
<c>47</c> <c>2</c> <c>0x34fd87046a183f4732a52bb7805ce207eebdafc5</c>
<c>48</c> <c>15</c> <c>0xbd2fdc5e4e8d0ed7c48c1bad9c2f7793fc2c9303</c>
<c>49</c> <c>0</c> <c>0xb3f47e2e8e2dcdd890ea00934b9d8234830dbc4a</c>
<c>50</c> <c>11</c> <c>0xcd29719c56cdb507030e6132132179e5807e1d3b</c>
<c>51</c> <c>3</c> <c>0xf9edb9b301916217de0d746a0542316bebe9e806</c>
<c>52</c> <c>12</c> <c>0x7a3801cbfe0cafed863d81210c1ec721eede49e5</c>
<c>53</c> <c>15</c> <c>0x5caba3ec960efa210f5f3e1c22c567ca475ef3ec</c>
<c>54</c> <c>12</c> <c>0xf911b5d148e1b03fe6983c53411f76ea78772379</c>
<c>55</c> <c>1</c> <c>0x06da2baa75c6ef752bf59f3812fa042ff8181209</c>
<c>56</c> <c>9</c> <c>0x2b29f5aa2f34af51a78a5fac586004f749c6e6dc</c>
<c>57</c> <c>9</c> <c>0x55e033ababac0845cc9142e24f9ef0a641c51cbe</c>
<c>58</c> <c>3</c> <c>0xb62d207bb700071fba8a68312ca204ce4d994c33</c>
<c>59</c> <c>9</c> <c>0x551d5c00fad905bdb99c4f70ec7590a10d3ff8ca</c>
<c>60</c> <c>1</c> <c>0x0d03b1845b5f8838d735142f185f9cf8f8d2db6c</c>
<c>61</c> <c>13</c> <c>0x3b5d9e49e7ede41cd9aa5a09f72a0384fd4ff511</c>
<c>62</c> <c>13</c> <c>0xa766b0278d14a9b7d32bf0307c0737a8ecf82ab1</c>
<c>63</c> <c>8</c> <c>0xca85296f354e6e3d2a96ab497c01e5ccd4530cf1</c>
<c>64</c> <c>1</c> <c>0x7bb29db7dd8aaaf1cd11487cea0d13730edb1df3</c>
<c>65</c> <c>12</c> <c>0x547ef341b3cf3208753bb1b62d85a4e3fc2cffe0</c>
<c>66</c> <c>12</c> <c>0xb890e1a99da4b2e0a9dde42f82f92d0946327cee</c>
</texttable>
<t>
Finally, based on the fact that the message is the first to be signed by the
Merkle tree (i.e. using leaf node 0), the values of the leaf and interior nodes
that compose the authentication path from leaf to root are determined as described in
<xref target='mts_sig' />. These values are marked with
an asterisk ('*') in <xref target='tbl_ots_pub_keys' /> and <xref target='tbl_mts_int_nodes' />.
</t>
</section>
<section title='Signature Verification' anchor='test_sig_vrf'>
<t>
The signature verification step was provided the following items:
<list style='numbers'>
<t>OTS = (y[0] || y[1] || ... || y[p-1]) - from <xref target='tbl_ots' />.</t>
<t>Authentication Path = concatenation of (k-1)*h Merkle tree node values -
from <xref target='tbl_ots_pub_keys' /> and <xref target='tbl_mts_int_nodes' />.</t>
<t>Message Number = leaf number of Merkle tree.</t>
<t>Merkle Public Key = root of Merkle tree - from <xref target='tbl_mts_pub_key' />.</t>
</list>
Using Algorithm 4 of <xref target='ldwmn_sig_vrf' /> as a start, the potential OTS
public key was calculated from the value of the OTS. Since the actual OTS public key was
not provided to the verifier, the calculated key was checked for validity using the
pseudocode algorithm of <xref target='mts_sig_vrf' /> and the provided values of the
Authentication Path and Message Number. Since the message was valid, the calculated value
of the root matched the Merkle public key. Otherwise, verification would have failed.
</t>
</section>
<section title='Intermediate Calculation Values'>
<texttable anchor='tbl_sha_256_20'>
<ttcol align='center'>Key Element Index (i)</ttcol>
<ttcol align='center'>SHA256-20 Result for w = 4 (F^15(x[i]))</ttcol>
<c>0</c> <c>0x6eff4b0c224874ecc4e4f4500da53dbe2a030e45</c>
<c>1</c> <c>0x58ac2c6c451c7779d67efefdb12e5c3d85475a94</c>
<c>2</c> <c>0xb1f3e42e29c710d69268eed1bbdb7f5a500b7937</c>
<c>3</c> <c>0x51d28e573aac2b84d659abb961c32c465e911b55</c>
<c>4</c> <c>0xa0ed62bccac5888f5000ca6a01e5ffefd442a1c6</c>
<c>5</c> <c>0x44da9e145666322422c1e2b5e21627e05aeb4367</c>
<c>6</c> <c>0x04e7ff9213c2655f28364f659c35d3086d7414e1</c>
<c>7</c> <c>0x414cdb3215408b9722a02577eeb71f9e016e4251</c>
<c>8</c> <c>0xa3ab06b90a2b20f631175daa9454365a4f408e9e</c>
<c>9</c> <c>0xe38acfd3c0a03faa82a0f4aeac1a7c04983fad25</c>
<c>10</c> <c>0xd95a289094ccce8ad9ff1d5f9e38297f9bb306ff</c>
<c>11</c> <c>0x593d148b22e33c32f18b66340bdaffceb3ad1a55</c>
<c>12</c> <c>0x16b53fbea11dc7ab70c8336ec3c23881ae5d51bf</c>
<c>13</c> <c>0xa639ca0cf871188cadd0020832c4f06e6ebd5f98</c>
<c>14</c> <c>0xe3ab3e0c5ad79d6c8c2a7e9a79856d4380941fe0</c>
<c>15</c> <c>0x8368c2933dabcde69c373867a9bf2dc78df97bea</c>
<c>16</c> <c>0xe3609fca11545da156a7779ae565b1e3c87902c0</c>
<c>17</c> <c>0xab029e62c7011772dc0589d79fad01aacf8d2177</c>
<c>18</c> <c>0xa8310f1c27c1aa481192de07d4397b8c4716e25f</c>
<c>19</c> <c>0xdbdbb14dbd9a5f03c1849af24b69b9e3f80faca2</c>
<c>20</c> <c>0x1a17399d555dec07d3d4f6d54b2b87d2bcaa398b</c>
<c>21</c> <c>0xf81c66cc522bfb203232e44d0003ed65d2462867</c>
<c>22</c> <c>0x202a625b8c5f22de6ea081af6da077cf5c63202f</c>
<c>23</c> <c>0x2e080f3591f5ff3d5de39c2698846cc107a09816</c>
<c>24</c> <c>0xa1d9c78c22f9810e3b7db2d59ad9f5fdd259f4d4</c>
<c>25</c> <c>0x658eeb85ebe0f4542c4d32dced2d7226929266b2</c>
<c>26</c> <c>0x67fae1a784f919577afc091504d82d31b4ba9fc7</c>
<c>27</c> <c>0xfc39fb43677fb2d433a6292f19c6e7320279655a</c>
<c>28</c> <c>0x491f6ec665f54c4b3cffaa02ec594d31e6e26c0e</c>
<c>29</c> <c>0x17cec813a5781409b11d2e4a85f62301c2fd8873</c>
<c>30</c> <c>0xc578eb105454d900c053eb55833db607aa5757e0</c>
<c>31</c> <c>0xaed094323290a41fd4b546919620e2f6b23916c8</c>
<c>32</c> <c>0x192b5a87b5124dc287e06cdd4ec7c0c11f67dda6</c>
<c>33</c> <c>0x4e9e2bdc1b0204d1ceeb68fb4159e752c40b9608</c>
<c>34</c> <c>0xf34c57ad9ce45d67fd32dc2737e6263bcc5cc61f</c>
<c>35</c> <c>0xf73bd27d376186310f83cc66e72060aeaccde371</c>
<c>36</c> <c>0xeea482511acd8be783e9be42b48799653b222db4</c>
<c>37</c> <c>0xa2e53196fec8676065b8f32b3e8498e66a4af3cf</c>
<c>38</c> <c>0x670c98185157e1b28d38f7dafb00796b434c8316</c>
<c>39</c> <c>0x441afbb265b93595389aaa66325de792f343f209</c>
<c>40</c> <c>0x7b6c50d20b5edc0bc90eb4b289770514cbc8d547</c>
<c>41</c> <c>0xfde6e862a7ba3534893a3e630e209a24be590b1e</c>
<c>42</c> <c>0xc59611200c20b2e73dfb24c84cedf4792d6daf10</c>
<c>43</c> <c>0x66e3527bee88373d18f91b230b53b569361f0a15</c>
<c>44</c> <c>0xd0fd79c7116198e689275fec9b4c46f4aac73293</c>
<c>45</c> <c>0x65f07406ad4241e7cf4174c5f284267292cdbc32</c>
<c>46</c> <c>0x7b1b5535d45f46542e2b876245b66ea83cde3d8f</c>
<c>47</c> <c>0x7a11620934eb0eb17e10e4a8bbd52aa4b020da0e</c>
<c>48</c> <c>0xbd2fdc5e4e8d0ed7c48c1bad9c2f7793fc2c9303</c>
<c>49</c> <c>0x00432602437252a0622a30676dbaaef3023328b9</c>
<c>50</c> <c>0x09a9c4b25034466a5acd7ff681af1c27e8f97577</c>
<c>51</c> <c>0x4b31481d52aa5e1a261064bbd87ea46479a6be23</c>
<c>52</c> <c>0xaca2ad4aa1264618ab633bf11cbca3cc8fa43091</c>
<c>53</c> <c>0x5caba3ec960efa210f5f3e1c22c567ca475ef3ec</c>
<c>54</c> <c>0x353e3ffcedfd9500141921cf2aebc2e111364dad</c>
<c>55</c> <c>0xe1c498c32169c869174ccf2f1e71e7202f45fba7</c>
<c>56</c> <c>0x5b8519a40d4305813936c7c00a96f5b4ceb603f1</c>
<c>57</c> <c>0x3b942ae6a6bd328d08804ade771a0775bb3ff8f8</c>
<c>58</c> <c>0x6f3be60ee1c34372599b8d634be72e168453bf10</c>
<c>59</c> <c>0xf700c70bac24db0aab1257940661f5b57da6e817</c>
<c>60</c> <c>0x85ccf60624b13663a290fa808c6bbecaf89523cd</c>
<c>61</c> <c>0xd049be55ab703c44f42167d5d9e939c830df960f</c>
<c>62</c> <c>0xd27a178ccc3b364c7e03d2266093a0d1dfdd9d51</c>
<c>63</c> <c>0xd73c53fdddbe196b9ab56fcc5c9a4a57ad868cd1</c>
<c>64</c> <c>0xb59a70a7372f0c121fa71727baaf6588eccec400</c>
<c>65</c> <c>0x9b5bf379f989f9a499799c12a3202db58b084eed</c>
<c>66</c> <c>0xccabf40f3c1dacf114b5e5f98a73103b4c1f9b55</c>
</texttable>
<texttable anchor='tbl_ots_pub_keys'>
<ttcol align='center'>MTS Leaf (Level 3) Node Number</ttcol>
<ttcol align='center'>OTS Public Key (H(x[0] || x[1] || ... || x[p-1]))</ttcol>
<ttcol align='center'>Member of Authentication Path of Message 0</ttcol>
<c>0</c> <c>0x2db55a72075fcfab5aedbef77bf6b371 dfb489d6e61ad2884a248345e6910618</c> <c> </c>
<c>1</c> <c>0x8c6c6a1215bfe7fda10b7754e73cd984 a64823b1ab9d5f50feda6b151c0fee6d</c> <c>*</c>
<c>2</c> <c>0xc1fb91de68b3059c273e53596108ec7c f39923757597fe86439e91ce1c25fc84</c> <c>*</c>
<c>3</c> <c>0x1b511189baee50251335695b74d67c40 5a04eddaa79158a9090cc7c3eb204cbf</c> <c>*</c>
<c>4</c> <c>0xf3bcf088ccf9d00338b6c87e8f822da6 8ec471f88d1561193b3c017d20b3c971</c> <c> </c>
<c>5</c> <c>0x40584c059e6cc72fb61f7bd1b9c28e73 c689551e6e7de6b0b9b730fab9237531</c> <c> </c>
<c>6</c> <c>0x1b1d09de1ca16ca890036e018d7e73de b39b07de80c19dcc5e55a699f021d880</c> <c> </c>
<c>7</c> <c>0x83a82632acaac5418716f4f357f5007f 719d604525dbe1831c09a2ead9400a52</c> <c> </c>
<c>8</c> <c>0xccb8b2a1d60f731b5f51910eb427e211 96090d5cd2a077f33968b425301e3fbd</c> <c> </c>
<c>9</c> <c>0x616767ebf3c1f3ec662d8c57c630c6ae b31853fd40a18c3d831f5490610c1f16</c> <c> </c>
<c>10</c> <c>0x5a4b3e157b66327c75d7f01304d188e2 cecd1b6168240c11a01775d581b01fb6</c> <c> </c>
<c>11</c> <c>0xf25744b8a1c2184ba38521801bf4727c 407b85eb5aef8884d8fbb1c12e2f6108</c> <c> </c>
<c>12</c> <c>0xaf8189f51874999162890f72e0ef25e6 f76b4ab94dc53569bdd66507f5ab0d8e</c> <c> </c>
<c>13</c> <c>0x96251e396756686645f35cd059da329f 7083838d56c9ccacebbaf8486af18844</c> <c> </c>
<c>14</c> <c>0x773d5206e40065d3553c3c2ed2500122 e3ee6fd2c91f35a57f084dc839aab1fc</c> <c> </c>
<c>15</c> <c>0xcda7fae67ce2c3ed29ce426fdcd3f2a8 eb699e47a67a52f1c94e89726ffe97fa</c> <c> </c>
</texttable>
<texttable anchor='tbl_mts_int_nodes'>
<ttcol align='center'>MTS Interior (Level 2) Node Number</ttcol>
<ttcol align='center'>Node Value (H(child_0 || child_1 || ... || child_k-1))</ttcol>
<ttcol align='center'>Member of Authentication Path of Message 0</ttcol>
<c>0</c> <c>0xb6a310deb55ed48004133ece2aebb25e d74defb77ebd8d63c79a42b5b4191b0c</c> <c> </c>
<c>1</c> <c>0x71a0c8b767ade2c97ebac069383e4dfb a1c06d5fd3f69a775711ea6470747664</c> <c>*</c>
<c>2</c> <c>0x91109fa97662dc88ae63037391ac2650 f6c664ac2448b54800a1df748953af31</c> <c>*</c>
<c>3</c> <c>0xd277fb8c89689525f90de567068d6c93 565df3588b97223276ef8e9495468996</c> <c>*</c>
</texttable>
</section>
</section>
-->
</back>
</rfc>| PAFTECH AB 2003-2026 | 2026-04-22 21:50:00 |