From 0a967ccf9ac868ddaf5f8da3cd4ab3a0119d81af Mon Sep 17 00:00:00 2001 From: Raef Coles Date: Fri, 2 Sep 2022 17:46:15 +0100 Subject: [PATCH] Document LMS and LMOTS internal functions Signed-off-by: Raef Coles --- library/lmots.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ library/lms.c | 69 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 146 insertions(+), 1 deletion(-) diff --git a/library/lmots.c b/library/lmots.c index 7dbf8a206b..fe01bf6721 100644 --- a/library/lmots.c +++ b/library/lmots.c @@ -99,6 +99,17 @@ unsigned int network_bytes_to_unsigned_int( size_t len, return val; } +/* Calculate the checksum digits that are appended to the end of the LMOTS digit + * string. See NIST SP800-208 section 3.1 or RFC8554 Algorithm 2 for details of + * the checksum algorithm. + * + * \param params The LMOTS parameter set, I and q values which + * describe the key being used. + * + * \param digest The digit string to create the digest from. As + * this does not contain a checksum, it is the same + * size as a hash output. + */ static unsigned short lmots_checksum_calculate( const mbedtls_lmots_parameters_t *params, const unsigned char* digest ) { @@ -113,6 +124,29 @@ static unsigned short lmots_checksum_calculate( const mbedtls_lmots_parameters_t return sum; } +/* Create the string of digest digits (in the base determined by the Winternitz + * parameter with the checksum appended to the end (Q || cksm(Q)). See NIST + * SP800-208 section 3.1 or RFC8554 Algorithm 3 step 5 (also used in Algorithm + * 4b step 3) for details. + * + * \param params The LMOTS parameter set, I and q values which + * describe the key being used. + * + * \param msg The message that will be hashed to create the + * digest. + * + * \param msg_size The size of the message. + * + * \param C_random_value The random value that will be combined with the + * message digest. This is always the same size as a + * hash output for whichever hash algorithm is + * determined by the parameter set. + * + * \param output An output containing the digit string (+ + * checksum) of length P digits (in the case of + * MBEDTLS_LMOTS_SHA256_N32_W8, this means it is of + * size P bytes). + */ static int create_digit_array_with_checksum( const mbedtls_lmots_parameters_t *params, const unsigned char *msg, size_t msg_len, @@ -176,6 +210,35 @@ exit: return( ret ); } +/* Hash each element of the string of digits (+ checksum), producing a hash + * output for each element. This is used in several places (by varying the + * hash_idx_min/max_values) in order to calculate a public key from a private + * key (RFC8554 Algorithm 1 step 4), in order to sign a message (RFC8554 + * Algorithm 3 step 5), and to calculate a public key candidate from a + * signature and message (RFC8554 Algorithm 4b step 3). + * + * \param params The LMOTS parameter set, I and q values which + * describe the key being used. + * + * \param x_digit_array The array of digits (of size P, 34 in the case of + * MBEDTLS_LMOTS_SHA256_N32_W8). + * + * \param hash_idx_min_values An array of the starting values of the j iterator + * for each of the members of the digit array. If + * this value in NULL, then all iterators will start + * at 0. + * + * \param hash_idx_max_values An array of the upper bound values of the j + * iterator for each of the members of the digit + * array. If this value in NULL, then iterator is + * bounded to be less than 2^w - 1 (255 in the case + * of MBEDTLS_LMOTS_SHA256_N32_W8) + * + * \param output An array containing a hash output for each member + * of the digit string P. In the case of + * MBEDTLS_LMOTS_SHA256_N32_W8, this is of size 32 * + * 34. + */ static int hash_digit_array( const mbedtls_lmots_parameters_t *params, const unsigned char *x_digit_array, const unsigned char *hash_idx_min_values, @@ -278,6 +341,21 @@ exit: return ret; } +/* Combine the hashes of the digit array into a public key. This is used in + * in order to calculate a public key from a private key (RFC8554 Algorithm 1 + * step 4), and to calculate a public key candidate from a signature and message + * (RFC8554 Algorithm 4b step 3). + * + * \param params The LMOTS parameter set, I and q values which describe + * the key being used. + * \param y_hashed_digits The array of hashes, one hash for each digit of the + * symbol array (which is of size P, 34 in the case of + * MBEDTLS_LMOTS_SHA256_N32_W8) + * + * \param pub_key The output public key (or candidate public key in + * case this is being run as part of signature + * verification), in the form of a hash output. + */ static int public_key_from_hashed_digit_array( const mbedtls_lmots_parameters_t *params, const unsigned char *y_hashed_digits, unsigned char *pub_key ) diff --git a/library/lms.c b/library/lms.c index 72f93192bf..e0f5946efb 100644 --- a/library/lms.c +++ b/library/lms.c @@ -80,8 +80,27 @@ #define D_CONST_LEN (2) static const unsigned char D_LEAF_CONSTANT_BYTES[D_CONST_LEN] = {0x82, 0x82}; -static const unsigned char D_INTERNAL_CONSTANT_BYTES[D_CONST_LEN] = {0x83, 0x83}; +static const unsigned char D_INTR_CONSTANT_BYTES[D_CONST_LEN] = {0x83, 0x83}; + +/* Calculate the value of a leaf node of the merkle tree (which is a hash of a + * public key and some other parameters like the leaf index). This function + * implements RFC8554 section 5.3, in the case where r >= 2^h. + * + * \param params The LMS parameter set, the underlying LMOTS + * parameter set, and I value which describe the key + * being used. + * + * \param pub_key The public key of the private whose index + * corresponds to the index of this leaf node. This + * is a hash output. + * + * \param r_node_idx The index of this node in the merkle tree. Note + * that the root node of the merkle tree is + * 1-indexed. + * + * \param out The output node value, which is a hash output. + */ static int create_merkle_leaf_value( const mbedtls_lms_parameters_t *params, unsigned char *pub_key, unsigned int r_node_idx, @@ -134,6 +153,28 @@ exit: return( ret ); } +/* Calculate the value of an internal node of the merkle tree (which is a hash + * of a public key and some other parameters like the node index). This function + * implements RFC8554 section 5.3, in the case where r < 2^h. + * + * \param params The LMS parameter set, the underlying LMOTS + * parameter set, and I value which describe the key + * being used. + * + * \param left_node The value of the child of this node which is on + * the left-hand side. As with all nodes on the + * merkle tree, this is a hash output. + * + * \param right_node The value of the child of this node which is on + * the right-hand side. As with all nodes on the + * merkle tree, this is a hash output. + * + * \param r_node_idx The index of this node in the merkle tree. Note + * that the root node of the merkle tree is + * 1-indexed. + * + * \param out The output node value, which is a hash output. + */ static int create_merkle_internal_value( const mbedtls_lms_parameters_t *params, const unsigned char *left_node, const unsigned char *right_node, @@ -363,6 +404,20 @@ int mbedtls_lms_verify( const mbedtls_lms_public_t *ctx, #ifdef MBEDTLS_LMS_PRIVATE +/* Calculate a full merkle tree based on a private key. This function + * implements RFC8554 section 5.3, and is used to generate a public key (as the + * public key is the root node of the merkle tree). + * + * \param ctx The LMS private context, containing a parameter + * set and private key material consisting of both + * public and private OTS. + * + * \param tree The output tree, which is 2^(H + 1) hash outputs. + * In the case of H=10 we have 2048 tree nodes (of + * which 1024 of them are leaf nodes). Note that + * because the merkle tree root is 1-indexed, the 0 + * index tree node is never used. + */ static int calculate_merkle_tree( mbedtls_lms_private_t *ctx, unsigned char *tree ) { @@ -406,6 +461,18 @@ static int calculate_merkle_tree( mbedtls_lms_private_t *ctx, return( 0 ); } +/* Calculate a path from a leaf node of the merkle tree to the root of the tree, + * and return the full path. This function implements RFC8554 section 5.4.1, as + * the merkle path is the main component of an LMS signature. + * + * \param ctx The LMS private context, containing a parameter + * set and private key material consisting of both + * public and private OTS. + * + * \param leaf_node_id Which leaf node to calculate the path from. + * + * \param tree The output path, which is H hash outputs. + */ static int get_merkle_path( mbedtls_lms_private_t *ctx, unsigned int leaf_node_id, unsigned char *path )