Merge pull request #6564 from philljj/add_lms_hooks

Add LMS/HSS wolfCrypt hooks.
This commit is contained in:
JacobBarthelmeh 2023-07-14 14:33:25 -06:00 committed by GitHub
commit a026d843cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1813 additions and 1 deletions

55
INSTALL
View File

@ -254,3 +254,58 @@
The wolfssl port in vcpkg is kept up to date by wolfSSL.
We also have vcpkg ports for wolftpm, wolfmqtt and curl.
17. Building with hash-sigs lib for LMS/HSS support [EXPERIMENTAL]
Using LMS/HSS requires that the hash-sigs lib has been built on
your system. We support hash-sigs lib at this git commit:
b0631b8891295bf2929e68761205337b7c031726
At the time of writing this, this is the HEAD of the master
branch of the hash-sigs project.
Currently the hash-sigs project only builds static libraries:
- hss_lib.a: a single-threaded static lib.
- hss_lib_thread.a: a multi-threaded static lib.
The multi-threaded version will mainly have speedups for key
generation and signing.
Additionally, the hash-sigs project can be modified to build
and install a shared library in /usr/local with either single
or multi-threaded versions. If the shared version has been
built, libhss.so is the assumed name.
wolfSSL supports either option, and by default will look for
hss_lib.a first, and hss_lib_thread.a second, and libhss.so
lastly, in a specified hash-sigs dir.
How to get and build the hash-sigs library:
$ mkdir ~/hash_sigs
$ cd ~/hash_sigs
$ git clone https://github.com/cisco/hash-sigs.git src
$ cd src
$ git checkout b0631b8891295bf2929e68761205337b7c031726
In sha256.h, set USE_OPENSSL to 0:
#define USE_OPENSSL 0
To build the single-threaded version:
$ make hss_lib.a
$ ls *.a
hss_lib.a
To build multi-threaded:
$ make hss_lib_thread.a
$ ls *.a
hss_lib_thread.a
Build wolfSSL with
$ ./configure \
--enable-static \
--disable-shared \
--enable-lms=yes \
--with-liblms=<path to dir containing hss_lib_thread.a>
$ make
Run the benchmark against LMS/HSS with:
$ ./wolfcrypt/benchmark/benchmark -lms_hss

View File

@ -1144,6 +1144,109 @@ then
fi
# liblms
# Get the path to the hash-sigs LMS HSS lib.
ENABLED_LIBLMS="no"
tryliblmsdir=""
AC_ARG_WITH([liblms],
[AS_HELP_STRING([--with-liblms=PATH],[PATH to hash-sigs LMS/HSS install (default /usr/local) EXPERIMENTAL!])],
[
AC_MSG_CHECKING([for liblms])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <hss.h>]], [[ param_set_t lm_type; param_set_t lm_ots_type; hss_get_public_key_len(4, &lm_type, &lm_ots_type); ]])], [ liblms_linked=yes ],[ liblms_linked=no ])
if test "x$liblms_linked" = "xno" ; then
if test "x$withval" != "xno" ; then
tryliblmsdir=$withval
fi
if test "x$withval" = "xyes" ; then
tryliblmsdir="/usr/local"
fi
# 1. By default use the hash-sigs single-threaded static library.
# 2. If 1 not found, then use the multi-threaded static lib.
# 3. If 2 not found, then use the multi-threaded dynamic lib.
if test -e $tryliblmsdir/hss_lib.a; then
CPPFLAGS="$AM_CPPFLAGS -DHAVE_LIBLMS -I$tryliblmsdir"
LIB_STATIC_ADD="$LIB_STATIC_ADD $tryliblmsdir/hss_lib.a"
enable_shared=no
enable_static=yes
liblms_linked=yes
elif test -e $tryliblmsdir/hss_lib_thread.a; then
CPPFLAGS="$AM_CPPFLAGS -DHAVE_LIBLMS -I$tryliblmsdir"
LIB_STATIC_ADD="$LIB_STATIC_ADD $tryliblmsdir/hss_lib_thread.a"
enable_shared=no
enable_static=yes
liblms_linked=yes
elif test -e $tryliblmsdir/lib/libhss.so; then
LIBS="$LIBS -lhss"
CPPFLAGS="$AM_CPPFLAGS -DHAVE_LIBLMS -I$tryliblmsdir/include/hss"
LDFLAGS="$AM_LDFLAGS $LDFLAGS -L$tryliblmsdir/lib"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <hss.h>]], [[ param_set_t lm_type; param_set_t lm_ots_type; hss_get_public_key_len(4, &lm_type, &lm_ots_type); ]])], [ liblms_linked=yes ],[ liblms_linked=no ])
else
AC_MSG_ERROR([liblms isn't found.
If it's already installed, specify its path using --with-liblms=/dir/])
fi
if test "x$liblms_linked" = "xno" ; then
AC_MSG_ERROR([liblms isn't found.
If it's already installed, specify its path using --with-liblms=/dir/])
fi
AC_MSG_RESULT([yes])
AM_CPPFLAGS="$CPPFLAGS"
AM_LDFLAGS="$LDFLAGS"
else
AC_MSG_RESULT([yes])
fi
AM_CFLAGS="$AM_CFLAGS -DHAVE_LIBLMS"
ENABLED_LIBLMS="yes"
]
)
# LMS
AC_ARG_ENABLE([lms],
[AS_HELP_STRING([--enable-lms],[Enable stateful LMS/HSS signatures (default: disabled)])],
[ ENABLED_LMS=$enableval ],
[ ENABLED_LMS=no ]
)
ENABLED_WC_LMS=no
for v in `echo $ENABLED_LMS | tr "," " "`
do
case $v in
yes)
;;
no)
;;
wolfssl)
ENABLED_WC_LMS=yes
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_LMS"
;;
*)
AC_MSG_ERROR([Invalid choice for LMS []: $ENABLED_LMS.])
break;;
esac
done
if test "$ENABLED_LMS" != "no"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_LMS"
if test "$ENABLED_WC_LMS" = "no";
then
# Default is to use hash-sigs LMS lib. Make sure it's enabled.
if test "$ENABLED_LIBLMS" = "no"; then
AC_MSG_ERROR([The default implementation for LMS is the hash-sigs LMS/HSS lib.
Please use --with-liblms.])
fi
fi
fi
# SINGLE THREADED
AC_ARG_ENABLE([singlethreaded],
[AS_HELP_STRING([--enable-singlethreaded],[Enable wolfSSL single threaded (default: disabled)])],
@ -8753,6 +8856,7 @@ AM_CONDITIONAL([BUILD_FE448], [test "x$ENABLED_FE448" = "xyes" || test "x$ENABLE
AM_CONDITIONAL([BUILD_GE448], [test "x$ENABLED_GE448" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_CURVE448],[test "x$ENABLED_CURVE448" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_CURVE448_SMALL],[test "x$ENABLED_CURVE448_SMALL" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_WC_LMS],[test "x$ENABLED_WC_LMS" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_WC_KYBER],[test "x$ENABLED_WC_KYBER" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_ECCSI],[test "x$ENABLED_ECCSI" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_SAKKE],[test "x$ENABLED_SAKKE" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
@ -8792,6 +8896,7 @@ AM_CONDITIONAL([BUILD_CRL],[test "x$ENABLED_CRL" != "xno" || test "x$ENABLED_USE
AM_CONDITIONAL([BUILD_CRL_MONITOR],[test "x$ENABLED_CRL_MONITOR" = "xyes"])
AM_CONDITIONAL([BUILD_USER_RSA],[test "x$ENABLED_USER_RSA" = "xyes"] )
AM_CONDITIONAL([BUILD_USER_CRYPTO],[test "x$ENABLED_USER_CRYPTO" = "xyes"])
AM_CONDITIONAL([BUILD_LIBLMS],[test "x$ENABLED_LIBLMS" = "xyes"])
AM_CONDITIONAL([BUILD_LIBOQS],[test "x$ENABLED_LIBOQS" = "xyes"])
AM_CONDITIONAL([BUILD_WNR],[test "x$ENABLED_WNR" = "xyes"])
AM_CONDITIONAL([BUILD_SRP],[test "x$ENABLED_SRP" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
@ -9242,6 +9347,8 @@ echo " * ED25519 streaming: $ENABLED_ED25519_STREAM"
echo " * CURVE448: $ENABLED_CURVE448"
echo " * ED448: $ENABLED_ED448"
echo " * ED448 streaming: $ENABLED_ED448_STREAM"
echo " * LMS: $ENABLED_LMS"
echo " * LMS wolfSSL impl: $ENABLED_WC_LMS"
echo " * KYBER: $ENABLED_KYBER"
echo " * KYBER wolfSSL impl: $ENABLED_WC_KYBER"
echo " * ECCSI $ENABLED_ECCSI"
@ -9297,6 +9404,7 @@ echo " * Persistent session cache: $ENABLED_SAVESESSION"
echo " * Persistent cert cache: $ENABLED_SAVECERT"
echo " * Atomic User Record Layer: $ENABLED_ATOMICUSER"
echo " * Public Key Callbacks: $ENABLED_PKCALLBACKS"
echo " * liblms: $ENABLED_LIBLMS"
echo " * liboqs: $ENABLED_LIBOQS"
echo " * Whitewood netRandom: $ENABLED_WNR"
echo " * Server Name Indication: $ENABLED_SNI"

View File

@ -655,6 +655,10 @@ endif
endif
endif
if BUILD_WC_LMS
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_lms.c
endif
if BUILD_CURVE25519
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/curve25519.c
endif
@ -734,6 +738,10 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sphincs.c
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ext_kyber.c
endif
if BUILD_LIBLMS
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ext_lms.c
endif
if BUILD_LIBZ
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/compress.c
endif

View File

@ -154,6 +154,12 @@
#include <wolfssl/wolfcrypt/ext_kyber.h>
#endif
#endif
#ifdef WOLFSSL_HAVE_LMS
#include <wolfssl/wolfcrypt/lms.h>
#ifdef HAVE_LIBLMS
#include <wolfssl/wolfcrypt/ext_lms.h>
#endif
#endif
#ifdef WOLFCRYPT_HAVE_ECCSI
#include <wolfssl/wolfcrypt/eccsi.h>
#endif
@ -565,6 +571,9 @@
#define BENCH_SPHINCS_SMALL_LEVEL3_SIGN 0x00000010
#define BENCH_SPHINCS_SMALL_LEVEL5_SIGN 0x00000020
/* Post-Quantum Stateful Hash-Based sig algorithms. */
#define BENCH_LMS_HSS 0x00000001
/* Other */
#define BENCH_RNG 0x00000001
#define BENCH_SCRYPT 0x00000002
@ -603,6 +612,8 @@ static word32 bench_pq_asym_algs = 0;
static word32 bench_pq_asym_algs2 = 0;
/* Other cryptographic algorithms to benchmark. */
static word32 bench_other_algs = 0;
/* Post-Quantum Stateful Hash-Based sig algorithms to benchmark. */
static word32 bench_pq_hash_sig_algs = 0;
#if !defined(WOLFSSL_BENCHMARK_ALL) && !defined(NO_MAIN_DRIVER)
@ -856,6 +867,21 @@ static const bench_alg bench_other_opt[] = {
#endif /* !WOLFSSL_BENCHMARK_ALL && !NO_MAIN_DRIVER */
#if defined(WOLFSSL_HAVE_LMS)
typedef struct bench_pq_hash_sig_alg {
/* Command line option string. */
const char* str;
/* Bit values to set. */
word32 val;
} bench_pq_hash_sig_alg;
static const bench_pq_hash_sig_alg bench_pq_hash_sig_opt[] = {
{ "-pq_hash_sig", 0xffffffff},
{ "-lms_hss", BENCH_LMS_HSS},
{ NULL, 0}
};
#endif /* if defined(WOLFSSL_HAVE_LMS) */
#if defined(HAVE_PQC) && defined(HAVE_LIBOQS)
/* The post-quantum-specific mapping of command line option to bit values and
* OQS name. */
@ -1592,6 +1618,7 @@ static void benchmark_static_init(int force)
bench_asym_algs = 0;
bench_pq_asym_algs = 0;
bench_other_algs = 0;
bench_pq_hash_sig_algs = 0;
csv_format = 0;
}
}
@ -2798,6 +2825,12 @@ static void* benchmarks_do(void* args)
}
#endif
#ifdef WOLFSSL_HAVE_LMS
if (bench_all || (bench_pq_hash_sig_algs & BENCH_LMS_HSS)) {
bench_lms();
}
#endif
#ifdef HAVE_ECC
if (bench_all || (bench_asym_algs & BENCH_ECC_MAKEKEY) ||
(bench_asym_algs & BENCH_ECC) ||
@ -7624,6 +7657,375 @@ void bench_kyber(int type)
}
#endif
#ifdef WOLFSSL_HAVE_LMS
/* WC_LMS_PARM_L2_H10_W2
* signature length: 9300 */
static const byte lms_priv_L2_H10_W2[64] =
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x62,0x62,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xC7,0x74,0x25,0x5B,0x2C,0xE8,0xDA,0x53,
0xF0,0x7C,0x04,0x3F,0x64,0x2D,0x26,0x2C,
0x46,0x1D,0xC8,0x90,0x77,0x59,0xD6,0xC0,
0x56,0x46,0x7D,0x97,0x64,0xF2,0xA3,0xA1,
0xF8,0xD0,0x3B,0x5F,0xAC,0x40,0xB9,0x9E,
0x83,0x67,0xBF,0x92,0x8D,0xFE,0x45,0x79
};
static const byte lms_pub_L2_H10_W2[60] =
{
0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x06,
0x00,0x00,0x00,0x02,0xF8,0xD0,0x3B,0x5F,
0xAC,0x40,0xB9,0x9E,0x83,0x67,0xBF,0x92,
0x8D,0xFE,0x45,0x79,0x41,0xBC,0x2A,0x3B,
0x9F,0xC0,0x11,0x12,0x93,0xF0,0x5A,0xA5,
0xC1,0x88,0x29,0x79,0x6C,0x3E,0x0A,0x0F,
0xEC,0x3B,0x3E,0xE4,0x38,0xD3,0xD2,0x34,
0x7F,0xC8,0x91,0xB0
};
/* WC_LMS_PARM_L2_H10_W4
* signature length: 5076 */
static const byte lms_priv_L2_H10_W4[64] =
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x63,0x63,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xAE,0x28,0x87,0x19,0x4F,0x4B,0x68,0x61,
0x93,0x9A,0xC7,0x0E,0x33,0xB8,0xCE,0x96,
0x66,0x0D,0xC7,0xB1,0xFA,0x94,0x80,0xA2,
0x28,0x9B,0xCF,0xE2,0x08,0xB5,0x25,0xAC,
0xFB,0xB8,0x65,0x5E,0xD1,0xCC,0x31,0xDA,
0x2E,0x49,0x3A,0xEE,0xAF,0x63,0x70,0x5E
};
static const byte lms_pub_L2_H10_W4[60] =
{
0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x06,
0x00,0x00,0x00,0x03,0xFB,0xB8,0x65,0x5E,
0xD1,0xCC,0x31,0xDA,0x2E,0x49,0x3A,0xEE,
0xAF,0x63,0x70,0x5E,0xA2,0xD5,0xB6,0x15,
0x33,0x8C,0x9B,0xE9,0xE1,0x91,0x40,0x1A,
0x12,0xE0,0xD7,0xBD,0xE4,0xE0,0x76,0xF5,
0x04,0x90,0x76,0xA5,0x9A,0xA7,0x4E,0xFE,
0x6B,0x9A,0xD3,0x14
};
/* WC_LMS_PARM_L3_H5_W4
* signature length: 7160 */
static const byte lms_priv_L3_H5_W4[64] =
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x53,0x53,0x53,0xFF,0xFF,0xFF,0xFF,0xFF,
0x38,0xD1,0xBE,0x68,0xD1,0x93,0xE1,0x14,
0x6C,0x8B,0xED,0xE2,0x25,0x88,0xED,0xAC,
0x57,0xBD,0x87,0x9F,0x54,0xF3,0x58,0xD9,
0x4D,0xF5,0x6A,0xBD,0x71,0x99,0x6A,0x28,
0x2F,0xE1,0xFC,0xD1,0xD1,0x0C,0x7C,0xF8,
0xB4,0xDC,0xDF,0x7F,0x14,0x1A,0x7B,0x50
};
static const byte lms_pub_L3_H5_W4[60] =
{
0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x05,
0x00,0x00,0x00,0x03,0x2F,0xE1,0xFC,0xD1,
0xD1,0x0C,0x7C,0xF8,0xB4,0xDC,0xDF,0x7F,
0x14,0x1A,0x7B,0x50,0x8E,0x3A,0xD4,0x05,
0x0C,0x95,0x59,0xA0,0xCA,0x7A,0xD8,0xD6,
0x5D,0xBD,0x42,0xBB,0xD5,0x82,0xB8,0x9C,
0x52,0x37,0xB7,0x45,0x03,0xC2,0x06,0xCE,
0xAB,0x4B,0x51,0x39
};
/* WC_LMS_PARM_L3_H5_W8
* signature length: 3992 */
static const byte lms_priv_L3_H5_W8[64] =
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x54,0x54,0x54,0xFF,0xFF,0xFF,0xFF,0xFF,
0xA5,0x46,0x97,0x0C,0xA1,0x3C,0xEA,0x17,
0x5C,0x9D,0x59,0xF4,0x0E,0x27,0x37,0xF3,
0x6A,0x1C,0xF7,0x29,0x4A,0xCC,0xCD,0x7B,
0x4F,0xE7,0x37,0x6E,0xEF,0xC1,0xBD,0xBD,
0x04,0x5D,0x8E,0xDD,0xAA,0x47,0xCC,0xE6,
0xCE,0x78,0x46,0x20,0x41,0x87,0xE0,0x85
};
static const byte lms_pub_L3_H5_W8[60] =
{
0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x05,
0x00,0x00,0x00,0x04,0x04,0x5D,0x8E,0xDD,
0xAA,0x47,0xCC,0xE6,0xCE,0x78,0x46,0x20,
0x41,0x87,0xE0,0x85,0x0D,0x2C,0x46,0xB9,
0x39,0x8C,0xA3,0x92,0x4F,0xCE,0x50,0x96,
0x90,0x9C,0xF3,0x36,0x2E,0x09,0x15,0x3B,
0x4B,0x34,0x17,0xE7,0xE2,0x55,0xFC,0x5B,
0x83,0xAB,0x43,0xAF
};
/* WC_LMS_PARM_L3_H10_W4
* signature length: 7640 */
static const byte lms_priv_L3_H10_W4[64] =
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x63,0x63,0x63,0xFF,0xFF,0xFF,0xFF,0xFF,
0xDF,0x98,0xAB,0xEC,0xFE,0x13,0x9F,0xF8,
0xD7,0x2B,0x4F,0x4C,0x79,0x34,0xB8,0x89,
0x24,0x6B,0x26,0x7D,0x7A,0x2E,0xA2,0xCB,
0x82,0x75,0x4E,0x96,0x54,0x49,0xED,0xA0,
0xAF,0xC7,0xA5,0xEE,0x8A,0xA2,0x83,0x99,
0x4B,0x18,0x59,0x2B,0x66,0xC0,0x32,0xDB
};
static const byte lms_pub_L3_H10_W4[60] =
{
0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x06,
0x00,0x00,0x00,0x03,0xAF,0xC7,0xA5,0xEE,
0x8A,0xA2,0x83,0x99,0x4B,0x18,0x59,0x2B,
0x66,0xC0,0x32,0xDB,0xC4,0x18,0xEB,0x11,
0x17,0x7D,0xAA,0x93,0xFD,0xA0,0x70,0x4D,
0x68,0x4B,0x63,0x8F,0xC2,0xE7,0xCA,0x34,
0x14,0x31,0x0D,0xAA,0x18,0xBF,0x9B,0x32,
0x8D,0x78,0xD5,0xA8
};
/* WC_LMS_PARM_L4_H5_W8
* signature length: 5340 */
static const byte lms_priv_L4_H5_W8[64] =
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x54,0x54,0x54,0x54,0xFF,0xFF,0xFF,0xFF,
0x46,0x8F,0x2A,0x4A,0x14,0x26,0xF0,0x89,
0xFE,0xED,0x66,0x0F,0x73,0x69,0xB1,0x4C,
0x47,0xA1,0x35,0x9F,0x7B,0xBA,0x08,0x03,
0xEE,0xA2,0xEB,0xAD,0xB4,0x82,0x52,0x1F,
0xFD,0x9B,0x22,0x82,0x42,0x1A,0x96,0x1E,
0xE4,0xA1,0x9C,0x33,0xED,0xE6,0x9F,0xAB
};
static const byte lms_pub_L4_H5_W8[60] =
{
0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x05,
0x00,0x00,0x00,0x04,0xFD,0x9B,0x22,0x82,
0x42,0x1A,0x96,0x1E,0xE4,0xA1,0x9C,0x33,
0xED,0xE6,0x9F,0xAB,0x6B,0x47,0x05,0x5B,
0xA7,0xAD,0xF6,0x88,0xA5,0x4F,0xCD,0xF1,
0xDA,0x29,0x67,0xC3,0x7F,0x2C,0x11,0xFE,
0x85,0x1A,0x7A,0xD8,0xD5,0x46,0x74,0x3B,
0x74,0x24,0x12,0xC8
};
static int lms_write_key_mem(const byte * priv, word32 privSz, void *context)
{
/* WARNING: THIS IS AN INSECURE WRITE CALLBACK THAT SHOULD ONLY
* BE USED FOR TESTING PURPOSES! Production applications should
* write only to non-volatile storage. */
XMEMCPY(context, priv, privSz);
return WC_LMS_RC_SAVED_TO_NV_MEMORY;
}
static int lms_read_key_mem(byte * priv, word32 privSz, void *context)
{
/* WARNING: THIS IS AN INSECURE READ CALLBACK THAT SHOULD ONLY
* BE USED FOR TESTING PURPOSES! */
XMEMCPY(priv, context, privSz);
return WC_LMS_RC_READ_TO_MEMORY;
}
static void bench_lms_sign_verify(enum wc_LmsParm parm)
{
LmsKey key;
int ret = 0;
const char * msg = TEST_STRING;
word32 msgSz = TEST_STRING_SZ;
byte * sig = NULL;
word32 sigSz = 0;
word32 privLen = 0;
int loaded = 0;
int times = 0;
int count = 0;
double start = 0.0F;
byte priv[HSS_MAX_PRIVATE_KEY_LEN];
const char * str = wc_LmsKey_ParmToStr(parm);
ret = wc_LmsKey_Init(&key, NULL, INVALID_DEVID);
if (ret) {
printf("wc_LmsKey_Init failed: %d\n", ret);
goto exit_lms_sign_verify;
}
ret = wc_LmsKey_SetLmsParm(&key, parm);
if (ret) {
printf("wc_LmsKey_SetLmsParm failed: %d\n", ret);
goto exit_lms_sign_verify;
}
switch (parm) {
case WC_LMS_PARM_L2_H10_W2:
XMEMCPY(priv, lms_priv_L2_H10_W2, sizeof(lms_priv_L2_H10_W2));
XMEMCPY(key.pub, lms_pub_L2_H10_W2, sizeof(lms_pub_L2_H10_W2));
break;
case WC_LMS_PARM_L2_H10_W4:
XMEMCPY(priv, lms_priv_L2_H10_W4, sizeof(lms_priv_L2_H10_W4));
XMEMCPY(key.pub, lms_pub_L2_H10_W4, sizeof(lms_pub_L2_H10_W4));
break;
case WC_LMS_PARM_L3_H5_W4:
XMEMCPY(priv, lms_priv_L3_H5_W4, sizeof(lms_priv_L3_H5_W4));
XMEMCPY(key.pub, lms_pub_L3_H5_W4, sizeof(lms_pub_L3_H5_W4));
break;
case WC_LMS_PARM_L3_H5_W8:
XMEMCPY(priv, lms_priv_L3_H5_W8, sizeof(lms_priv_L3_H5_W8));
XMEMCPY(key.pub, lms_pub_L3_H5_W8, sizeof(lms_pub_L3_H5_W8));
break;
case WC_LMS_PARM_L3_H10_W4:
XMEMCPY(priv, lms_priv_L3_H10_W4, sizeof(lms_priv_L3_H10_W4));
XMEMCPY(key.pub, lms_pub_L3_H10_W4, sizeof(lms_pub_L3_H10_W4));
break;
case WC_LMS_PARM_L4_H5_W8:
XMEMCPY(priv, lms_priv_L4_H5_W8, sizeof(lms_priv_L4_H5_W8));
XMEMCPY(key.pub, lms_pub_L4_H5_W8, sizeof(lms_pub_L4_H5_W8));
break;
case WC_LMS_PARM_NONE:
case WC_LMS_PARM_L1_H15_W2:
case WC_LMS_PARM_L1_H15_W4:
case WC_LMS_PARM_L2_H10_W8:
case WC_LMS_PARM_L3_H5_W2:
printf("bench_lms_sign_verify: unsupported benchmark option: %d\n",
parm);
goto exit_lms_sign_verify;
}
ret = wc_LmsKey_SetWriteCb(&key, lms_write_key_mem);
if (ret) {
fprintf(stderr, "error: wc_LmsKey_SetWriteCb failed: %d\n", ret);
goto exit_lms_sign_verify;
}
ret = wc_LmsKey_SetReadCb(&key, lms_read_key_mem);
if (ret) {
fprintf(stderr, "error: wc_LmsKey_SetReadCb failed: %d\n", ret);
goto exit_lms_sign_verify;
}
ret = wc_LmsKey_SetContext(&key, (void *) priv);
if (ret) {
fprintf(stderr, "error: wc_LmsKey_SetContext failed: %d\n", ret);
goto exit_lms_sign_verify;
}
/* Even with saved priv/pub keys, we must still reload the private
* key before using it. Reloading the private key is the bottleneck
* for larger heights. Only print load time in debug builds. */
#if defined(DEBUG_WOLFSSL)
bench_stats_start(&count, &start);
#endif /* if defined DEBUG_WOLFSSL*/
ret = wc_LmsKey_Reload(&key);
if (ret) {
printf("wc_LmsKey_Reload failed: %d\n", ret);
goto exit_lms_sign_verify;
}
count +=1;
ret = wc_LmsKey_GetSigLen(&key, &sigSz);
if (ret) {
printf("wc_LmsKey_GetSigLen failed: %d\n", ret);
goto exit_lms_sign_verify;
}
ret = wc_LmsKey_GetPrivLen(&key, &privLen);
if (ret) {
printf("wc_LmsKey_GetPrivLen failed: %d\n", ret);
goto exit_lms_sign_verify;
}
#if defined(DEBUG_WOLFSSL)
bench_stats_check(start);
bench_stats_asym_finish(str, (int)privLen, "load", 0,
count, start, ret);
#endif /* if defined DEBUG_WOLFSSL*/
loaded = 1;
sig = XMALLOC(sigSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
if (sig == NULL) {
printf("bench_lms_sign_verify malloc failed\n");
goto exit_lms_sign_verify;
}
count = 0;
bench_stats_start(&count, &start);
do {
/* LMS is stateful. Async queuing not practical. */
for (times = 0; times < ntimes; ++times) {
ret = wc_LmsKey_Sign(&key, sig, &sigSz, (byte *) msg, msgSz);
if (ret) {
printf("wc_LmsKey_Sign failed: %d\n", ret);
goto exit_lms_sign_verify;
}
}
count += times;
} while (bench_stats_check(start));
bench_stats_asym_finish(str, (int)sigSz, "sign", 0,
count, start, ret);
count = 0;
bench_stats_start(&count, &start);
do {
/* LMS is stateful. Async queuing not practical. */
for (times = 0; times < ntimes; ++times) {
ret = wc_LmsKey_Verify(&key, sig, sigSz, (byte *) msg, msgSz);
if (ret) {
printf("wc_LmsKey_Verify failed: %d\n", ret);
goto exit_lms_sign_verify;
}
}
count += times;
} while (bench_stats_check(start));
exit_lms_sign_verify:
bench_stats_asym_finish(str, (int)sigSz, "verify", 0,
count, start, ret);
if (loaded) {
wc_LmsKey_Free(&key);
loaded = 0;
}
if (sig != NULL) {
XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
sig = NULL;
}
return;
}
void bench_lms(void)
{
bench_lms_sign_verify(WC_LMS_PARM_L2_H10_W2);
bench_lms_sign_verify(WC_LMS_PARM_L2_H10_W4);
bench_lms_sign_verify(WC_LMS_PARM_L3_H5_W4);
bench_lms_sign_verify(WC_LMS_PARM_L3_H5_W8);
bench_lms_sign_verify(WC_LMS_PARM_L3_H10_W4);
bench_lms_sign_verify(WC_LMS_PARM_L4_H5_W8);
return;
}
#endif /* ifdef WOLFSSL_HAVE_LMS */
#ifdef HAVE_ECC
/* Maximum ECC name plus null terminator:
@ -9952,6 +10354,10 @@ static void Usage(void)
print_alg(bench_pq_asym_opt2[i].str, &line);
#endif /* HAVE_LIBOQS */
#endif /* HAVE_PQC */
#if defined(WOLFSSL_HAVE_LMS)
for (i=0; bench_pq_hash_sig_opt[i].str != NULL; i++)
print_alg(bench_pq_hash_sig_opt[i].str, &line);
#endif /* if defined(WOLFSSL_HAVE_LMS) */
printf("\n");
#endif /* !WOLFSSL_BENCHMARK_ALL */
e++;
@ -10211,6 +10617,17 @@ int wolfcrypt_benchmark_main(int argc, char** argv)
optMatched = 1;
}
}
#if defined(WOLFSSL_HAVE_LMS)
/* post-quantum stateful hash-based signatures */
for (i=0; !optMatched && bench_pq_hash_sig_opt[i].str != NULL; i++) {
if (string_matches(argv[1], bench_pq_hash_sig_opt[i].str)) {
bench_pq_hash_sig_algs |= bench_pq_hash_sig_opt[i].val;
bench_all = 0;
optMatched = 1;
}
}
#endif /* if defined(WOLFSSL_HAVE_LMS) */
#endif
if (!optMatched) {
printf("Option not recognized: %s\n", argv[1]);

View File

@ -101,6 +101,7 @@ void bench_rsa(int useDeviceID);
void bench_rsa_key(int useDeviceID, word32 keySz);
void bench_dh(int useDeviceID);
void bench_kyber(int type);
void bench_lms(void);
void bench_ecc_curve(int curveId);
void bench_eccMakeKey(int useDeviceID, int curveId);
void bench_ecc(int useDeviceID, int curveId);

818
wolfcrypt/src/ext_lms.c Normal file
View File

@ -0,0 +1,818 @@
/* ext_lms.c
*
* Copyright (C) 2006-2023 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/logging.h>
#ifdef WOLFSSL_HAVE_LMS
#include <wolfssl/wolfcrypt/ext_lms.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
/* If built against hss_lib_thread.a, the hash-sigs lib will spawn
* worker threads to parallelize cpu intensive tasks. This will mainly
* speedup key generation and signing, and to a lesser extent
* verifying for larger levels values.
*
* Their default max is 16 worker threads, but can be capped with
* hss_extra_info_set_threads(). To be safe we are capping at 4 here.
* */
#define EXT_LMS_MAX_THREADS (4)
/* The hash-sigs hss_generate_private_key API requires a generate_random
* callback that only has output and length args. The RNG struct must be global
* to the function. Maybe there should be a wc_LmsKey_SetRngCb. */
static THREAD_LS_T WC_RNG * LmsRng = NULL;
static bool LmsGenerateRand(void * output, size_t length)
{
int ret = 0;
if (output == NULL || LmsRng == NULL) {
return false;
}
if (length == 0) {
return true;
}
ret = wc_RNG_GenerateBlock(LmsRng, output, (word32) length);
if (ret) {
WOLFSSL_MSG("error: LmsGenerateRand failed");
return false;
}
return true;
}
/* Write callback passed into hash-sigs hss lib.
*
* Returns true on success. */
static bool LmsWritePrivKey(unsigned char *private_key,
size_t len_private_key, void *lmsKey)
{
LmsKey * key = (LmsKey *) lmsKey;
enum wc_LmsRc ret = WC_LMS_RC_NONE;
if (private_key == NULL || key == NULL || len_private_key <= 0) {
WOLFSSL_MSG("error: LmsWritePrivKey: invalid args");
return false;
}
if (key->state != WC_LMS_STATE_PARMSET && key->state != WC_LMS_STATE_OK) {
/* The LmsKey is not ready for writing. */
WOLFSSL_MSG("error: LmsWritePrivKey: LMS key not in writeable state");
return false;
}
if (key->write_private_key == NULL) {
WOLFSSL_MSG("error: LmsWritePrivKey: LMS key write callback not set");
key->state = WC_LMS_STATE_BAD;
return false;
}
/* Use write callback that saves private key to non-volatile storage. */
ret = key->write_private_key(private_key, len_private_key, key->context);
if (ret != WC_LMS_RC_SAVED_TO_NV_MEMORY) {
WOLFSSL_MSG("error: LmsKey write_private_key failed");
WOLFSSL_MSG(wc_LmsKey_RcToStr(ret));
key->state = WC_LMS_STATE_BAD;
return false;
}
return true;
}
/* Read callback passed into hash-sigs hss lib.
*
* Returns true on success. */
static bool LmsReadPrivKey(unsigned char *private_key,
size_t len_private_key, void *lmsKey)
{
LmsKey * key = (LmsKey *) lmsKey;
enum wc_LmsRc ret = WC_LMS_RC_NONE;
if (private_key == NULL || key == NULL || len_private_key <= 0) {
WOLFSSL_MSG("error: LmsReadPrivKey: invalid args");
return false;
}
if (key->state != WC_LMS_STATE_PARMSET && key->state != WC_LMS_STATE_OK) {
/* The LmsKey is not ready for reading. */
WOLFSSL_MSG("error: LmsReadPrivKey: LMS key not in readable state");
return false;
}
if (key->read_private_key == NULL) {
WOLFSSL_MSG("error: LmsReadPrivKey: LMS key read callback not set");
key->state = WC_LMS_STATE_BAD;
return false;
}
/* Use read callback that reads private key from non-volatile storage. */
ret = key->read_private_key(private_key, len_private_key, key->context);
if (ret != WC_LMS_RC_READ_TO_MEMORY) {
WOLFSSL_MSG("error: LmsKey read_private_key failed");
WOLFSSL_MSG(wc_LmsKey_RcToStr(ret));
key->state = WC_LMS_STATE_BAD;
return false;
}
return true;
}
const char * wc_LmsKey_ParmToStr(enum wc_LmsParm lmsParm)
{
switch (lmsParm) {
case WC_LMS_PARM_NONE:
return "LMS_NONE";
case WC_LMS_PARM_L1_H15_W2:
return "LMS/HSS L1_H15_W2";
case WC_LMS_PARM_L1_H15_W4:
return "LMS/HSS L1_H15_W4";
case WC_LMS_PARM_L2_H10_W2:
return "LMS/HSS L2_H10_W2";
case WC_LMS_PARM_L2_H10_W4:
return "LMS/HSS L2_H10_W4";
case WC_LMS_PARM_L2_H10_W8:
return "LMS/HSS L2_H10_W8";
case WC_LMS_PARM_L3_H5_W2:
return "LMS/HSS L3_H5_W2";
case WC_LMS_PARM_L3_H5_W4:
return "LMS/HSS L3_H5_W4";
case WC_LMS_PARM_L3_H5_W8:
return "LMS/HSS L3_H5_W8";
case WC_LMS_PARM_L3_H10_W4:
return "LMS/HSS L3_H10_W4";
case WC_LMS_PARM_L4_H5_W8:
return "LMS/HSS L4_H5_W8";
default:
WOLFSSL_MSG("error: invalid LMS parameter");
break;
}
return "LMS_INVALID";
}
const char * wc_LmsKey_RcToStr(enum wc_LmsRc lmsEc)
{
switch (lmsEc) {
case WC_LMS_RC_NONE:
return "LMS_RC_NONE";
case WC_LMS_RC_BAD_ARG:
return "LMS_RC_BAD_ARG";
case WC_LMS_RC_WRITE_FAIL:
return "LMS_RC_WRITE_FAIL";
case WC_LMS_RC_READ_FAIL:
return "LMS_RC_READ_FAIL";
case WC_LMS_RC_SAVED_TO_NV_MEMORY:
return "LMS_RC_SAVED_TO_NV_MEMORY";
case WC_LMS_RC_READ_TO_MEMORY:
return "LMS_RC_READ_TO_MEMORY";
default:
WOLFSSL_MSG("error: invalid LMS error code");
break;
}
return "LMS_RC_INVALID";
}
/* Init an LMS key.
*
* Call this before setting the parms of an LMS key.
*
* Returns 0 on success.
* */
int wc_LmsKey_Init(LmsKey * key, void * heap, int devId)
{
if (key == NULL) {
return BAD_FUNC_ARG;
}
(void) heap;
(void) devId;
ForceZero(key, sizeof(LmsKey));
/* Set the max number of worker threads that hash-sigs can spawn. */
hss_init_extra_info(&key->info);
hss_extra_info_set_threads(&key->info, EXT_LMS_MAX_THREADS);
key->working_key = NULL;
key->write_private_key = NULL;
key->read_private_key = NULL;
key->context = NULL;
key->state = WC_LMS_STATE_INITED;
return 0;
}
/* Set the wc_LmsParm of an LMS key.
*
* Use this if you wish to set a key with a predefined parameter set,
* such as WC_LMS_PARM_L2_H10_W8.
*
* Key must be inited before calling this.
*
* Returns 0 on success.
* */
int wc_LmsKey_SetLmsParm(LmsKey * key, enum wc_LmsParm lmsParm)
{
if (key == NULL) {
return BAD_FUNC_ARG;
}
/* If NONE is passed, default to the lowest predefined set. */
switch (lmsParm) {
case WC_LMS_PARM_NONE:
case WC_LMS_PARM_L1_H15_W2:
return wc_LmsKey_SetParameters(key, 1, 15, 2);
case WC_LMS_PARM_L1_H15_W4:
return wc_LmsKey_SetParameters(key, 1, 15, 4);
case WC_LMS_PARM_L2_H10_W2:
return wc_LmsKey_SetParameters(key, 2, 10, 2);
case WC_LMS_PARM_L2_H10_W4:
return wc_LmsKey_SetParameters(key, 2, 10, 4);
case WC_LMS_PARM_L2_H10_W8:
return wc_LmsKey_SetParameters(key, 2, 10, 8);
case WC_LMS_PARM_L3_H5_W2:
return wc_LmsKey_SetParameters(key, 3, 5, 2);
case WC_LMS_PARM_L3_H5_W4:
return wc_LmsKey_SetParameters(key, 3, 5, 4);
case WC_LMS_PARM_L3_H5_W8:
return wc_LmsKey_SetParameters(key, 3, 5, 8);
case WC_LMS_PARM_L3_H10_W4:
return wc_LmsKey_SetParameters(key, 3, 10, 4);
case WC_LMS_PARM_L4_H5_W8:
return wc_LmsKey_SetParameters(key, 4, 5, 8);
default:
WOLFSSL_MSG("error: invalid LMS parameter set");
break;
}
return BAD_FUNC_ARG;
}
/* Set the parameters of an LMS key.
*
* Use this if you wish to set specific parameters not found in the
* wc_LmsParm predefined sets. See comments in lms.h for allowed
* parameters.
*
* Key must be inited before calling this.
*
* Returns 0 on success.
* */
int wc_LmsKey_SetParameters(LmsKey * key, int levels, int height,
int winternitz)
{
int i = 0;
param_set_t lm = LMS_SHA256_N32_H5;
param_set_t ots = LMOTS_SHA256_N32_W1;
if (key == NULL) {
return BAD_FUNC_ARG;
}
if (key->state != WC_LMS_STATE_INITED) {
WOLFSSL_MSG("error: LmsKey needs init");
return -1;
}
/* Verify inputs make sense.
*
* Note: there does not seem to be a define for min or
* max Winternitz integer in hash-sigs lib or RFC8554. */
if (levels < MIN_HSS_LEVELS || levels > MAX_HSS_LEVELS) {
WOLFSSL_MSG("error: invalid level parameter");
return BAD_FUNC_ARG;
}
if (height < MIN_MERKLE_HEIGHT || height > MAX_MERKLE_HEIGHT) {
WOLFSSL_MSG("error: invalid height parameter");
return BAD_FUNC_ARG;
}
switch (height) {
case 5:
lm = LMS_SHA256_N32_H5;
break;
case 10:
lm = LMS_SHA256_N32_H10;
break;
case 15:
lm = LMS_SHA256_N32_H15;
break;
case 20:
lm = LMS_SHA256_N32_H20;
break;
case 25:
lm = LMS_SHA256_N32_H25;
break;
default:
WOLFSSL_MSG("error: invalid height parameter");
return BAD_FUNC_ARG;
}
switch (winternitz) {
case 1:
ots = LMOTS_SHA256_N32_W1;
break;
case 2:
ots = LMOTS_SHA256_N32_W2;
break;
case 4:
ots = LMOTS_SHA256_N32_W4;
break;
case 8:
ots = LMOTS_SHA256_N32_W8;
break;
default:
WOLFSSL_MSG("error: invalid winternitz parameter");
return BAD_FUNC_ARG;
}
key->levels = levels;
for (i = 0; i < levels; ++i) {
key->lm_type[i] = lm;
key->lm_ots_type[i] = ots;
}
/* Move the state to parms set.
* Key is ready for MakeKey or Reload. */
key->state = WC_LMS_STATE_PARMSET;
return 0;
}
/* Frees the LMS key from memory.
*
* This does not affect the private key saved to non-volatile storage.
* */
void wc_LmsKey_Free(LmsKey* key)
{
if (key == NULL) {
return;
}
if (key->working_key != NULL) {
hss_free_working_key(key->working_key);
key->working_key = NULL;
}
ForceZero(key, sizeof(LmsKey));
key->state = WC_LMS_STATE_FREED;
return;
}
/* Set the write private key callback to the LMS key structure.
*
* The callback must be able to write/update the private key to
* non-volatile storage.
*
* Returns 0 on success.
* */
int wc_LmsKey_SetWriteCb(LmsKey * key, write_private_key_cb write_cb)
{
if (key == NULL || write_cb == NULL) {
return BAD_FUNC_ARG;
}
/* Changing the write callback of an already working key is forbidden. */
if (key->state == WC_LMS_STATE_OK) {
WOLFSSL_MSG("error: wc_LmsKey_SetWriteCb: key in use");
return -1;
}
key->write_private_key = write_cb;
return 0;
}
/* Set the read private key callback to the LMS key structure.
*
* The callback must be able to read the private key from
* non-volatile storage.
*
* Returns 0 on success.
* */
int wc_LmsKey_SetReadCb(LmsKey * key, read_private_key_cb read_cb)
{
if (key == NULL || read_cb == NULL) {
return BAD_FUNC_ARG;
}
/* Changing the read callback of an already working key is forbidden. */
if (key->state == WC_LMS_STATE_OK) {
WOLFSSL_MSG("error: wc_LmsKey_SetReadCb: key in use");
return -1;
}
key->read_private_key = read_cb;
return 0;
}
/* Sets the context to be used by write and read callbacks.
*
* E.g. this could be a filename if the callbacks write/read to file.
*
* Returns 0 on success.
* */
int wc_LmsKey_SetContext(LmsKey * key, void * context)
{
if (key == NULL || context == NULL) {
return BAD_FUNC_ARG;
}
/* Setting context of an already working key is forbidden. */
if (key->state == WC_LMS_STATE_OK) {
WOLFSSL_MSG("error: wc_LmsKey_SetContext: key in use");
return -1;
}
key->context = context;
return 0;
}
/* Make the LMS private/public key pair. The key must have its parameters
* set before calling this.
*
* Write/read callbacks, and context data, must be set prior.
* Key must have parameters set.
*
* Returns 0 on success.
* */
int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG * rng)
{
bool result = true;
if (key == NULL || rng == NULL) {
return BAD_FUNC_ARG;
}
if (key->state != WC_LMS_STATE_PARMSET) {
WOLFSSL_MSG("error: LmsKey not ready for generation");
return -1;
}
if (key->write_private_key == NULL || key->read_private_key == NULL) {
WOLFSSL_MSG("error: LmsKey write/read callbacks are not set");
return -1;
}
if (key->context == NULL) {
WOLFSSL_MSG("error: LmsKey context is not set");
return -1;
}
LmsRng = rng;
/* TODO: The hash-sigs lib allows you to save variable length auxiliary
* data, which can be used to speed up key reloading when signing. The
* aux data can be 300B - 1KB in size.
*
* Not implemented at the moment.
*
* key->aux_data_len = hss_get_aux_data_len(AUX_DATA_MAX_LEN, key->levels,
* key->lm_type,
* key->lm_ots_type);
*
* key->aux_data = XMALLOC(key->aux_data_len, NULL,
* DYNAMIC_TYPE_TMP_BUFFER);
*/
/* First generate the private key using the parameters and callbacks.
* If successful, private key will be saved to non-volatile storage,
* and the public key will be in memory. */
result = hss_generate_private_key(LmsGenerateRand, key->levels,
key->lm_type, key->lm_ots_type,
LmsWritePrivKey, key,
key->pub, sizeof(key->pub),
NULL, 0, &key->info);
if (!result) {
WOLFSSL_MSG("error: hss_generate_private_key failed");
key->state = WC_LMS_STATE_BAD;
return -1;
}
/* Once generated, now we must load the private key so we have
* an hss working key for signing operations. */
key->working_key = hss_load_private_key(LmsReadPrivKey, key,
0, NULL, 0, &key->info);
if (key->working_key == NULL) {
WOLFSSL_MSG("error: hss_load_private_key failed");
key->state = WC_LMS_STATE_BAD;
return -1;
}
/* This should not happen, but check just in case. */
if (wc_LmsKey_SigsLeft(key) == 0) {
WOLFSSL_MSG("error: generated LMS key signatures exhausted");
key->state = WC_LMS_STATE_NOSIGS;
return -1;
}
key->state = WC_LMS_STATE_OK;
return 0;
}
/* Reload a key that has been prepared with the appropriate parms and
* data. Use this if you wish to resume signing with an existing key.
*
* Write/read callbacks, and context data, must be set prior.
* Key must have parameters set.
*
* Returns 0 on success. */
int wc_LmsKey_Reload(LmsKey * key)
{
bool result = true;
if (key == NULL) {
return BAD_FUNC_ARG;
}
if (key->state != WC_LMS_STATE_PARMSET) {
WOLFSSL_MSG("error: LmsKey not ready for reload");
return -1;
}
if (key->write_private_key == NULL || key->read_private_key == NULL) {
WOLFSSL_MSG("error: LmsKey write/read callbacks are not set");
return -1;
}
if (key->context == NULL) {
WOLFSSL_MSG("error: LmsKey context is not set");
return -1;
}
key->working_key = hss_load_private_key(LmsReadPrivKey, key,
0, NULL, 0, &key->info);
if (key->working_key == NULL) {
WOLFSSL_MSG("error: hss_load_private_key failed");
key->state = WC_LMS_STATE_BAD;
return -1;
}
result = hss_get_parameter_set(&key->levels, key->lm_type,
key->lm_ots_type, LmsReadPrivKey, key);
if (!result) {
WOLFSSL_MSG("error: hss_get_parameter_set failed");
key->state = WC_LMS_STATE_BAD;
hss_free_working_key(key->working_key);
key->working_key = NULL;
return -1;
}
/* Double check the key actually has signatures left. */
if (wc_LmsKey_SigsLeft(key) == 0) {
WOLFSSL_MSG("error: reloaded LMS key signatures exhausted");
key->state = WC_LMS_STATE_NOSIGS;
return -1;
}
key->state = WC_LMS_STATE_OK;
return 0;
}
/* Given a levels, height, winternitz parameter set, determine
* the private key length */
int wc_LmsKey_GetPrivLen(LmsKey * key, word32 * len)
{
if (key == NULL || len == NULL) {
return BAD_FUNC_ARG;
}
*len = (word32) hss_get_private_key_len(key->levels, key->lm_type,
key->lm_ots_type);
return 0;
}
/* Given a levels, height, winternitz parameter set, determine
* the public key length */
int wc_LmsKey_GetPubLen(LmsKey * key, word32 * len)
{
if (key == NULL || len == NULL) {
return BAD_FUNC_ARG;
}
*len = (word32) hss_get_public_key_len(key->levels, key->lm_type,
key->lm_ots_type);
return 0;
}
/* Export a generated public key and parameter set from one LmsKey
* to another. Use this to prepare a signature verification LmsKey
* that is pub only.
*
* Though the public key is all that is used to verify signatures,
* the parameter set is needed to calculate the signature length
* before hand. */
int wc_LmsKey_ExportPub(LmsKey * keyDst, const LmsKey * keySrc)
{
if (keyDst == NULL || keySrc == NULL) {
return BAD_FUNC_ARG;
}
ForceZero(keyDst, sizeof(LmsKey));
XMEMCPY(keyDst->pub, keySrc->pub, sizeof(keySrc->pub));
XMEMCPY(keyDst->lm_type, keySrc->lm_type, sizeof(keySrc->lm_type));
XMEMCPY(keyDst->lm_ots_type, keySrc->lm_ots_type,
sizeof(keySrc->lm_ots_type));
keyDst->levels = keySrc->levels;
/* Mark this key as verify only, to prevent misuse. */
keyDst->state = WC_LMS_STATE_VERIFYONLY;
return 0;
}
/* Given a levels, height, winternitz parameter set, determine
* the signature length.
*
* Call this before wc_LmsKey_Sign so you know the length of
* the required signature buffer. */
int wc_LmsKey_GetSigLen(LmsKey * key, word32 * len)
{
if (key == NULL || len == NULL) {
return BAD_FUNC_ARG;
}
*len = (word32) hss_get_signature_len(key->levels, key->lm_type,
key->lm_ots_type);
return 0;
}
int wc_LmsKey_Sign(LmsKey* key, byte * sig, word32 * sigSz, const byte * msg,
int msgSz)
{
bool result = true;
size_t len = 0;
if (key == NULL || sig == NULL || sigSz == NULL || msg == NULL) {
return BAD_FUNC_ARG;
}
if (msgSz <= 0) {
return BAD_FUNC_ARG;
}
if (key->state == WC_LMS_STATE_NOSIGS) {
WOLFSSL_MSG("error: LMS signatures exhausted");
return -1;
}
else if (key->state != WC_LMS_STATE_OK) {
/* The key had an error the last time it was used, and we
* can't guarantee its state. */
WOLFSSL_MSG("error: can't sign, LMS key not in good state");
return -1;
}
len = hss_get_signature_len(key->levels, key->lm_type, key->lm_ots_type);
if (len == 0) {
/* Key parameters are invalid. */
WOLFSSL_MSG("error: hss_get_signature_len failed");
key->state = WC_LMS_STATE_BAD;
return -1;
}
result = hss_generate_signature(key->working_key, LmsWritePrivKey,
key, (const void *) msg, msgSz,
sig, len, &key->info);
if (!result) {
if (wc_LmsKey_SigsLeft(key) == 0) {
WOLFSSL_MSG("error: LMS signatures exhausted");
key->state = WC_LMS_STATE_NOSIGS;
return -1;
}
WOLFSSL_MSG("error: hss_generate_signature failed");
key->state = WC_LMS_STATE_BAD;
return -1;
}
*sigSz = (word32) len;
return 0;
}
int wc_LmsKey_Verify(LmsKey * key, const byte * sig, word32 sigSz,
const byte * msg, int msgSz)
{
bool result = true;
if (key == NULL || sig == NULL || msg == NULL) {
return BAD_FUNC_ARG;
}
result = hss_validate_signature(key->pub, (const void *) msg, msgSz, sig,
sigSz, &key->info);
if (!result) {
WOLFSSL_MSG("error: hss_validate_signature failed");
return -1;
}
return 0;
}
/* Returns 1 if there are signatures remaining.
* Returns 0 if available signatures are exhausted.
*
* Note: the number of remaining signatures is hidden behind an opaque
* pointer in the hash-sigs lib. We could add a counter here that is
* decremented on every signature. The number of available signatures
* grows as
* N = 2 ** (levels * height)
* so it would need to be a big integer. */
int wc_LmsKey_SigsLeft(LmsKey * key)
{
if (key == NULL) {
return BAD_FUNC_ARG;
}
if (hss_extra_info_test_last_signature(&key->info)) {
return 0;
}
return 1;
}
#endif /* WOLFSSL_HAVE_LMS */

26
wolfcrypt/src/wc_lms.c Normal file
View File

@ -0,0 +1,26 @@
/* wc_lms.c
*
* Copyright (C) 2006-2023 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <wolfssl/wolfcrypt/settings.h>
#ifdef WOLFSSL_HAVE_LMS
#error "Contact wolfSSL to get the implementation of this file"
#endif

View File

@ -284,6 +284,12 @@ const byte const_byte_array[] = "A+Gd\0\0\0";
#include <wolfssl/wolfcrypt/ext_kyber.h>
#endif
#endif
#ifdef WOLFSSL_HAVE_LMS
#include <wolfssl/wolfcrypt/lms.h>
#ifdef HAVE_LIBLMS
#include <wolfssl/wolfcrypt/ext_lms.h>
#endif
#endif
#ifdef WOLFCRYPT_HAVE_ECCSI
#include <wolfssl/wolfcrypt/eccsi.h>
#endif
@ -555,6 +561,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t scrypt_test(void);
#ifdef WOLFSSL_HAVE_KYBER
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t kyber_test(void);
#endif
#ifdef WOLFSSL_HAVE_LMS
WOLFSSL_TEST_SUBROUTINE int lms_test(void);
#endif
#ifdef WOLFCRYPT_HAVE_ECCSI
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t eccsi_test(void);
#endif
@ -1580,6 +1589,13 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\
TEST_PASS("KYBER test passed!\n");
#endif
#ifdef WOLFSSL_HAVE_LMS
if ( (ret = lms_test()) != 0)
TEST_FAIL("LMS test failed!\n", ret);
else
TEST_PASS("LMS test passed!\n");
#endif
#ifdef WOLFCRYPT_HAVE_ECCSI
if ( (ret = eccsi_test()) != 0)
TEST_FAIL("ECCSI test failed!\n", ret);
@ -34908,6 +34924,144 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t kyber_test(void)
}
#endif /* WOLFSSL_HAVE_KYBER */
#ifdef WOLFSSL_HAVE_LMS
static int lms_write_key_mem(const byte * priv, word32 privSz, void *context)
{
/* WARNING: THIS IS AN INSECURE WRITE CALLBACK THAT SHOULD ONLY
* BE USED FOR TESTING PURPOSES! Production applications should
* write only to non-volatile storage. */
XMEMCPY(context, priv, privSz);
return WC_LMS_RC_SAVED_TO_NV_MEMORY;
}
static int lms_read_key_mem(byte * priv, word32 privSz, void *context)
{
/* WARNING: THIS IS AN INSECURE READ CALLBACK THAT SHOULD ONLY
* BE USED FOR TESTING PURPOSES! */
XMEMCPY(priv, context, privSz);
return WC_LMS_RC_READ_TO_MEMORY;
}
/* LMS signature sizes are a function of their parameters. This
* test has a signature of 8688 bytes. */
#define WC_TEST_LMS_SIG_LEN (8688)
WOLFSSL_TEST_SUBROUTINE int lms_test(void)
{
int ret;
int sigsLeft = 0;
LmsKey signingKey;
LmsKey verifyKey;
WC_RNG rng;
word32 sigSz = 0;
const char * msg = "LMS HSS post quantum signature test";
word32 msgSz = (word32) XSTRLEN(msg);
unsigned char priv[HSS_MAX_PRIVATE_KEY_LEN];
unsigned char old_priv[HSS_MAX_PRIVATE_KEY_LEN];
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
byte * sig = XMALLOC(WC_TEST_LMS_SIG_LEN, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER);
if (sig == NULL) {
return WC_TEST_RET_ENC_ERRNO;
}
#else
byte sig[WC_TEST_LMS_SIG_LEN];
#endif
XMEMSET(priv, 0, sizeof(priv));
XMEMSET(old_priv, 0, sizeof(old_priv));
#ifndef HAVE_FIPS
ret = wc_InitRng_ex(&rng, HEAP_HINT, INVALID_DEVID);
#else
ret = wc_InitRng(&rng);
#endif
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
/* This test:
* levels: 1
* height: 5
* winternitz: 1
*
* max sigs: 2 ** (1 * 5) = 32
* signature length: 8688
*/
ret = wc_LmsKey_Init(&signingKey, NULL, INVALID_DEVID);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_LmsKey_Init(&verifyKey, NULL, INVALID_DEVID);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_LmsKey_SetParameters(&signingKey, 1, 5, 1);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_LmsKey_SetWriteCb(&signingKey, lms_write_key_mem);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_LmsKey_SetReadCb(&signingKey, lms_read_key_mem);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_LmsKey_SetContext(&signingKey, (void *) priv);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_LmsKey_MakeKey(&signingKey, &rng);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
XMEMCPY(old_priv, priv, sizeof(priv));
ret = wc_LmsKey_ExportPub(&verifyKey, &signingKey);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_LmsKey_GetSigLen(&verifyKey, &sigSz);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
if (sigSz != WC_TEST_LMS_SIG_LEN) {
printf("error: got %d, expected %d\n", sigSz, WC_TEST_LMS_SIG_LEN);
return WC_TEST_RET_ENC_EC(sigSz);
}
/* 2 ** 5 should be the max number of signatures */
for (size_t i = 0; i < 32; ++i) {
/* We should have remaining signstures. */
sigsLeft = wc_LmsKey_SigsLeft(&signingKey);
if (sigsLeft == 0) {
return WC_TEST_RET_ENC_EC(sigsLeft);
}
/* Sign with key. The private key will be updated on every signature. */
ret = wc_LmsKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz);
if (ret != 0) { return WC_TEST_RET_ENC_I(i); }
/* The updated private key should not match the old one. */
if (XMEMCMP(old_priv, priv, sizeof(priv)) == 0) {
printf("error: current priv key should not match old: %zu\n", i);
return WC_TEST_RET_ENC_I(i);
}
XMEMCPY(old_priv, priv, sizeof(priv));
ret = wc_LmsKey_Verify(&verifyKey, sig, sigSz, (byte *) msg, msgSz);
if (ret != 0) { return WC_TEST_RET_ENC_I(i); }
}
/* This should be the last signature. */
sigsLeft = wc_LmsKey_SigsLeft(&signingKey);
if (sigsLeft != 0) {
return WC_TEST_RET_ENC_EC(sigsLeft);
}
wc_LmsKey_Free(&signingKey);
wc_LmsKey_Free(&verifyKey);
wc_FreeRng(&rng);
return ret;
}
#endif /* WOLFSSL_HAVE_LMS */
static const int fiducial3 = WC_TEST_RET_LN; /* source code reference point --
* see print_fiducials() below.
*/

View File

@ -0,0 +1,63 @@
/* ext_lms.h
*
* Copyright (C) 2006-2023 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef EXT_LMS_H
#define EXT_LMS_H
#ifdef WOLFSSL_HAVE_LMS
#include <wolfssl/wolfcrypt/lms.h>
#if !defined(HAVE_LIBLMS)
#error "This code requires liblms"
#endif
/* hash-sigs LMS HSS includes */
#include <hss.h>
#if defined(WOLFSSL_WC_LMS)
#error "This code is incompatible with wolfCrypt's implementation of LMS."
#endif
/*
* The hash-sigs LMS lib supports from MIN_HSS_LEVELS to MAX_HSS_LEVELS
* number of levels of Merkle trees. It allows for the tree height and
* winternitz parameter to be unique per level.
*/
/* hss structs */
typedef struct hss_working_key hss_working_key;
typedef struct hss_extra_info hss_extra_info;
struct LmsKey {
unsigned levels; /* Number of tree levels. */
param_set_t lm_type[MAX_HSS_LEVELS]; /* Height parm per level. */
param_set_t lm_ots_type[MAX_HSS_LEVELS]; /* Winternitz parm per level. */
unsigned char pub[HSS_MAX_PUBLIC_KEY_LEN];
hss_working_key * working_key;
write_private_key_cb write_private_key; /* Callback to write/update key. */
read_private_key_cb read_private_key; /* Callback to read key. */
void * context; /* Context arg passed to callbacks. */
hss_extra_info info;
enum wc_LmsState state;
};
#endif /* WOLFSSL_HAVE_LMS */
#endif /* EXT_LMS_H */

View File

@ -78,7 +78,10 @@ nobase_include_HEADERS+= \
wolfssl/wolfcrypt/ext_kyber.h \
wolfssl/wolfcrypt/sm2.h \
wolfssl/wolfcrypt/sm3.h \
wolfssl/wolfcrypt/sm4.h
wolfssl/wolfcrypt/sm4.h \
wolfssl/wolfcrypt/lms.h \
wolfssl/wolfcrypt/wc_lms.h \
wolfssl/wolfcrypt/ext_lms.h
noinst_HEADERS+= \
wolfssl/wolfcrypt/port/aria/aria-crypt.h \

136
wolfssl/wolfcrypt/lms.h Normal file
View File

@ -0,0 +1,136 @@
/* lms.h
*
* Copyright (C) 2006-2023 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/*!
\file wolfssl/wolfcrypt/lms.h
*/
#ifndef WOLF_CRYPT_LMS_H
#define WOLF_CRYPT_LMS_H
#include <wolfssl/wolfcrypt/types.h>
#include <wolfssl/wolfcrypt/random.h>
#ifdef WOLFSSL_HAVE_LMS
typedef struct LmsKey LmsKey;
/* Private key write and read callbacks. */
typedef int (*write_private_key_cb)(const byte * priv, word32 privSz, void *context);
typedef int (*read_private_key_cb)(byte * priv, word32 privSz, void *context);
/* Return codes returned by private key callbacks. */
enum wc_LmsRc {
WC_LMS_RC_NONE,
WC_LMS_RC_BAD_ARG, /* Bad arg in read or write callback. */
WC_LMS_RC_WRITE_FAIL, /* Write or update private key failed. */
WC_LMS_RC_READ_FAIL, /* Read private key failed. */
WC_LMS_RC_SAVED_TO_NV_MEMORY, /* Wrote private key to nonvolatile storage. */
WC_LMS_RC_READ_TO_MEMORY /* Read private key from storage. */
};
/* LMS/HSS signatures are defined by 3 parameters:
* levels: number of levels of Merkle trees.
* height: height of an individual Merkle tree.
* winternitz: number of bits from hash used in a Winternitz chain.
*
* The acceptable parameter values are those in RFC8554:
* levels = {1..8}
* height = {5, 10, 15, 20, 25}
* winternitz = {1, 2, 4, 8}
*
* The number of available signatures is:
* N = 2 ** (levels * height)
*
* Signature sizes are determined by levels and winternitz
* parameters primarily, and height to a lesser extent:
* - Larger levels values increase signature size significantly.
* - Larger height values increase signature size moderately.
* - Larger winternitz values will reduce the signature size, at
* the expense of longer key generation and sign/verify times.
*
* Key generation time is strongly determined by the height of
* the first level tree. A 3 level, 5 height tree is much faster
* than 1 level, 15 height at initial key gen, even if the number
* of available signatures is the same.
* */
/* Predefined LMS/HSS parameter sets for convenience.
*
* Not predefining a set with Winternitz=1, because the signatures
* will be large. */
enum wc_LmsParm {
WC_LMS_PARM_NONE = 0,
WC_LMS_PARM_L1_H15_W2 = 1, /* 1 level Merkle tree of 15 height. */
WC_LMS_PARM_L1_H15_W4 = 2,
WC_LMS_PARM_L2_H10_W2 = 3, /* 2 level Merkle tree of 10 height. */
WC_LMS_PARM_L2_H10_W4 = 4,
WC_LMS_PARM_L2_H10_W8 = 5,
WC_LMS_PARM_L3_H5_W2 = 6, /* 3 level Merkle tree of 5 height. */
WC_LMS_PARM_L3_H5_W4 = 7,
WC_LMS_PARM_L3_H5_W8 = 8,
WC_LMS_PARM_L3_H10_W4 = 9, /* 3 level Merkle tree of 10 height. */
WC_LMS_PARM_L4_H5_W8 = 10, /* 4 level Merkle tree of 5 height. */
};
/* enum wc_LmsState is to help track the state of an LMS/HSS Key. */
enum wc_LmsState {
WC_LMS_STATE_FREED, /* Key has been freed from memory. */
WC_LMS_STATE_INITED, /* Key has been inited, ready to set parms.*/
WC_LMS_STATE_PARMSET, /* Parms are set, ready to MakeKey or Reload. */
WC_LMS_STATE_OK, /* Able to sign signatures and verify. */
WC_LMS_STATE_VERIFYONLY, /* A public only LmsKey. */
WC_LMS_STATE_BAD, /* Can't guarantee key's state. */
WC_LMS_STATE_NOSIGS /* Signatures exhausted. */
};
#ifdef __cplusplus
extern "C" {
#endif
WOLFSSL_API int wc_LmsKey_Init(LmsKey * key, void * heap, int devId);
WOLFSSL_API int wc_LmsKey_SetLmsParm(LmsKey * key, enum wc_LmsParm lmsParm);
WOLFSSL_API int wc_LmsKey_SetParameters(LmsKey * key, int levels,
int height, int winternitz);
WOLFSSL_API int wc_LmsKey_SetWriteCb(LmsKey * key,
write_private_key_cb write_cb);
WOLFSSL_API int wc_LmsKey_SetReadCb(LmsKey * key,
read_private_key_cb read_cb);
WOLFSSL_API int wc_LmsKey_SetContext(LmsKey * key, void * context);
WOLFSSL_API void wc_LmsKey_Free(LmsKey * key);
WOLFSSL_API int wc_LmsKey_MakeKey(LmsKey * key, WC_RNG * rng);
WOLFSSL_API int wc_LmsKey_Reload(LmsKey * key);
WOLFSSL_API int wc_LmsKey_GetSigLen(LmsKey * key, word32 * len);
WOLFSSL_API int wc_LmsKey_GetPrivLen(LmsKey * key, word32 * len);
WOLFSSL_API int wc_LmsKey_GetPubLen(LmsKey * key, word32 * len);
WOLFSSL_API int wc_LmsKey_ExportPub(LmsKey * keyDst, const LmsKey * keySrc);
WOLFSSL_API int wc_LmsKey_Sign(LmsKey * key, byte * sig, word32 * sigSz,
const byte * msg, int msgSz);
WOLFSSL_API int wc_LmsKey_Verify(LmsKey * key, const byte * sig, word32 sigSz,
const byte * msg, int msgSz);
WOLFSSL_API int wc_LmsKey_SigsLeft(LmsKey * key);
WOLFSSL_API const char * wc_LmsKey_ParmToStr(enum wc_LmsParm lmsParm);
WOLFSSL_API const char * wc_LmsKey_RcToStr(enum wc_LmsRc lmsRc);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* WOLFSSL_HAVE_LMS */
#endif /* WOLF_CRYPT_LMS_H */

View File

@ -0,0 +1,23 @@
/* wc_lms.h
*
* Copyright (C) 2006-2023 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#error "Contact wolfSSL to get the implementation of this file"