Add LMS/HSS wolfCrypt hooks.

This commit is contained in:
jordan
2023-07-06 10:55:53 -05:00
parent 794425c431
commit 67bef21185
12 changed files with 1554 additions and 1 deletions

40
INSTALL
View File

@@ -254,3 +254,43 @@
The wolfssl port in vcpkg is kept up to date by wolfSSL. The wolfssl port in vcpkg is kept up to date by wolfSSL.
We also have vcpkg ports for wolftpm, wolfmqtt and curl. 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. At present we support the current master branch of
the hash-sigs project.
At present the hash-sigs project only builds static libraries.
It can be modified though to build and install a shared library
in /usr/local.
wolfSSL supports either option, and by default will look for
hss_lib_thread.a in a specified hash-sigs dir. If hash-sigs has
been built as a shared lib and installed in /usr/local/ , then
wolfSSL will look for libhss.so there.
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
In sha256.h, set USE_OPENSSl to 0:
#define USE_OPENSSL 0
Now build:
$ make
$ ls *.a
hss_lib.a hss_lib_thread.a hss_verify.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

@@ -1141,6 +1141,100 @@ then
fi 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
if 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 # SINGLE THREADED
AC_ARG_ENABLE([singlethreaded], AC_ARG_ENABLE([singlethreaded],
[AS_HELP_STRING([--enable-singlethreaded],[Enable wolfSSL single threaded (default: disabled)])], [AS_HELP_STRING([--enable-singlethreaded],[Enable wolfSSL single threaded (default: disabled)])],
@@ -8665,6 +8759,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_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],[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_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_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_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"]) AM_CONDITIONAL([BUILD_SAKKE],[test "x$ENABLED_SAKKE" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
@@ -8704,6 +8799,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_CRL_MONITOR],[test "x$ENABLED_CRL_MONITOR" = "xyes"])
AM_CONDITIONAL([BUILD_USER_RSA],[test "x$ENABLED_USER_RSA" = "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_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_LIBOQS],[test "x$ENABLED_LIBOQS" = "xyes"])
AM_CONDITIONAL([BUILD_WNR],[test "x$ENABLED_WNR" = "xyes"]) AM_CONDITIONAL([BUILD_WNR],[test "x$ENABLED_WNR" = "xyes"])
AM_CONDITIONAL([BUILD_SRP],[test "x$ENABLED_SRP" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SRP],[test "x$ENABLED_SRP" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
@@ -9150,6 +9246,8 @@ echo " * ED25519 streaming: $ENABLED_ED25519_STREAM"
echo " * CURVE448: $ENABLED_CURVE448" echo " * CURVE448: $ENABLED_CURVE448"
echo " * ED448: $ENABLED_ED448" echo " * ED448: $ENABLED_ED448"
echo " * ED448 streaming: $ENABLED_ED448_STREAM" echo " * ED448 streaming: $ENABLED_ED448_STREAM"
echo " * LMS: $ENABLED_LMS"
echo " * LMS wolfSSL impl: $ENABLED_WC_LMS"
echo " * KYBER: $ENABLED_KYBER" echo " * KYBER: $ENABLED_KYBER"
echo " * KYBER wolfSSL impl: $ENABLED_WC_KYBER" echo " * KYBER wolfSSL impl: $ENABLED_WC_KYBER"
echo " * ECCSI $ENABLED_ECCSI" echo " * ECCSI $ENABLED_ECCSI"
@@ -9204,6 +9302,7 @@ echo " * Persistent session cache: $ENABLED_SAVESESSION"
echo " * Persistent cert cache: $ENABLED_SAVECERT" echo " * Persistent cert cache: $ENABLED_SAVECERT"
echo " * Atomic User Record Layer: $ENABLED_ATOMICUSER" echo " * Atomic User Record Layer: $ENABLED_ATOMICUSER"
echo " * Public Key Callbacks: $ENABLED_PKCALLBACKS" echo " * Public Key Callbacks: $ENABLED_PKCALLBACKS"
echo " * liblms: $ENABLED_LIBLMS"
echo " * liboqs: $ENABLED_LIBOQS" echo " * liboqs: $ENABLED_LIBOQS"
echo " * Whitewood netRandom: $ENABLED_WNR" echo " * Whitewood netRandom: $ENABLED_WNR"
echo " * Server Name Indication: $ENABLED_SNI" echo " * Server Name Indication: $ENABLED_SNI"

View File

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

View File

@@ -154,6 +154,12 @@
#include <wolfssl/wolfcrypt/ext_kyber.h> #include <wolfssl/wolfcrypt/ext_kyber.h>
#endif #endif
#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 #ifdef WOLFCRYPT_HAVE_ECCSI
#include <wolfssl/wolfcrypt/eccsi.h> #include <wolfssl/wolfcrypt/eccsi.h>
#endif #endif
@@ -569,6 +575,9 @@
#define BENCH_SPHINCS_SMALL_LEVEL3_SIGN 0x00000010 #define BENCH_SPHINCS_SMALL_LEVEL3_SIGN 0x00000010
#define BENCH_SPHINCS_SMALL_LEVEL5_SIGN 0x00000020 #define BENCH_SPHINCS_SMALL_LEVEL5_SIGN 0x00000020
/* Post-Quantum Stateful Hash-Based sig algorithms. */
#define BENCH_LMS_HSS 0x00000001
/* Other */ /* Other */
#define BENCH_RNG 0x00000001 #define BENCH_RNG 0x00000001
#define BENCH_SCRYPT 0x00000002 #define BENCH_SCRYPT 0x00000002
@@ -607,6 +616,8 @@ static word32 bench_pq_asym_algs = 0;
static word32 bench_pq_asym_algs2 = 0; static word32 bench_pq_asym_algs2 = 0;
/* Other cryptographic algorithms to benchmark. */ /* Other cryptographic algorithms to benchmark. */
static word32 bench_other_algs = 0; 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) #if !defined(WOLFSSL_BENCHMARK_ALL) && !defined(NO_MAIN_DRIVER)
@@ -860,6 +871,21 @@ static const bench_alg bench_other_opt[] = {
#endif /* !WOLFSSL_BENCHMARK_ALL && !NO_MAIN_DRIVER */ #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) #if defined(HAVE_PQC) && defined(HAVE_LIBOQS)
/* The post-quantum-specific mapping of command line option to bit values and /* The post-quantum-specific mapping of command line option to bit values and
* OQS name. */ * OQS name. */
@@ -1596,6 +1622,7 @@ static void benchmark_static_init(int force)
bench_asym_algs = 0; bench_asym_algs = 0;
bench_pq_asym_algs = 0; bench_pq_asym_algs = 0;
bench_other_algs = 0; bench_other_algs = 0;
bench_pq_hash_sig_algs = 0;
csv_format = 0; csv_format = 0;
} }
} }
@@ -2802,6 +2829,12 @@ static void* benchmarks_do(void* args)
} }
#endif #endif
#ifdef WOLFSSL_HAVE_LMS
if (bench_all || (bench_pq_hash_sig_algs & BENCH_LMS_HSS)) {
bench_lms();
}
#endif
#ifdef HAVE_ECC #ifdef HAVE_ECC
if (bench_all || (bench_asym_algs & BENCH_ECC_MAKEKEY) || if (bench_all || (bench_asym_algs & BENCH_ECC_MAKEKEY) ||
(bench_asym_algs & BENCH_ECC) || (bench_asym_algs & BENCH_ECC) ||
@@ -7628,6 +7661,339 @@ void bench_kyber(int type)
} }
#endif #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 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;
const char * str = wc_LmsKey_ParmToStr(parm);
ret = wc_LmsKey_Init(&key, parm);
if (ret) {
printf("wc_LmsKey_Init failed: %d\n", ret);
goto exit_lms_sign_verify;
}
switch (parm) {
case WC_LMS_PARM_L2_H10_W2:
XMEMCPY(key.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(key.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(key.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(key.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(key.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(key.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;
}
/* 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;
}
/*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));
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 #ifdef HAVE_ECC
/* Maximum ECC name plus null terminator: /* Maximum ECC name plus null terminator:
@@ -9956,6 +10322,10 @@ static void Usage(void)
print_alg(bench_pq_asym_opt2[i].str, &line); print_alg(bench_pq_asym_opt2[i].str, &line);
#endif /* HAVE_LIBOQS */ #endif /* HAVE_LIBOQS */
#endif /* HAVE_PQC */ #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"); printf("\n");
#endif /* !WOLFSSL_BENCHMARK_ALL */ #endif /* !WOLFSSL_BENCHMARK_ALL */
e++; e++;
@@ -10215,6 +10585,17 @@ int wolfcrypt_benchmark_main(int argc, char** argv)
optMatched = 1; 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 #endif
if (!optMatched) { if (!optMatched) {
printf("Option not recognized: %s\n", argv[1]); 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_rsa_key(int useDeviceID, word32 keySz);
void bench_dh(int useDeviceID); void bench_dh(int useDeviceID);
void bench_kyber(int type); void bench_kyber(int type);
void bench_lms(void);
void bench_ecc_curve(int curveId); void bench_ecc_curve(int curveId);
void bench_eccMakeKey(int useDeviceID, int curveId); void bench_eccMakeKey(int useDeviceID, int curveId);
void bench_ecc(int useDeviceID, int curveId); void bench_ecc(int useDeviceID, int curveId);

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

@@ -0,0 +1,690 @@
/* 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
/* 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. */
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_INITED && 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: LmsWritePrivKey: LMS key not in good state");
return false;
}
if (key->write_private_key != NULL) {
/* Use write callback. */
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;
}
}
else {
/* Save to memory. */
if (len_private_key > sizeof(key->priv)) {
WOLFSSL_MSG("error: LmsWritePrivKey: private key too large");
key->state = WC_LMS_STATE_BAD;
return false;
}
XMEMSET(key->priv, 0, sizeof(key->priv));
XMEMCPY(key->priv, private_key, len_private_key);
}
return true;
}
/* Read callback passed into hash-sigs hss lib. */
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_INITED && 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: LmsReadPrivKey: LMS key not in good state");
return false;
}
if (key->read_private_key != NULL) {
/* Use read callback. */
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;
}
}
else {
/* Read from memory. */
if (len_private_key > sizeof(key->priv)) {
WOLFSSL_MSG("error: LmsReadPrivKey: private key too large");
key->state = WC_LMS_STATE_BAD;
return false;
}
XMEMCPY(private_key, key->priv, len_private_key);
}
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";
}
int wc_LmsKey_Init(LmsKey * key, enum wc_LmsParm lmsParm)
{
if (key == NULL) {
return BAD_FUNC_ARG;
}
switch (lmsParm) {
case WC_LMS_PARM_NONE:
return wc_LmsKey_Init_ex(key, 1, 15, 2, NULL, INVALID_DEVID);
case WC_LMS_PARM_L1_H15_W2:
return wc_LmsKey_Init_ex(key, 1, 15, 2, NULL, INVALID_DEVID);
case WC_LMS_PARM_L1_H15_W4:
return wc_LmsKey_Init_ex(key, 1, 15, 4, NULL, INVALID_DEVID);
case WC_LMS_PARM_L2_H10_W2:
return wc_LmsKey_Init_ex(key, 2, 10, 2, NULL, INVALID_DEVID);
case WC_LMS_PARM_L2_H10_W4:
return wc_LmsKey_Init_ex(key, 2, 10, 4, NULL, INVALID_DEVID);
case WC_LMS_PARM_L2_H10_W8:
return wc_LmsKey_Init_ex(key, 2, 10, 8, NULL, INVALID_DEVID);
case WC_LMS_PARM_L3_H5_W2:
return wc_LmsKey_Init_ex(key, 3, 5, 2, NULL, INVALID_DEVID);
case WC_LMS_PARM_L3_H5_W4:
return wc_LmsKey_Init_ex(key, 3, 5, 4, NULL, INVALID_DEVID);
case WC_LMS_PARM_L3_H5_W8:
return wc_LmsKey_Init_ex(key, 3, 5, 8, NULL, INVALID_DEVID);
case WC_LMS_PARM_L3_H10_W4:
return wc_LmsKey_Init_ex(key, 3, 10, 4, NULL, INVALID_DEVID);
case WC_LMS_PARM_L4_H5_W8:
return wc_LmsKey_Init_ex(key, 4, 5, 8, NULL, INVALID_DEVID);
default:
WOLFSSL_MSG("error: invalid LMS parameter set");
break;
}
return BAD_FUNC_ARG;
}
int wc_LmsKey_Init_ex(LmsKey * key, int levels, int height,
int winternitz, void* heap, int devId)
{
int ret = 0;
int i = 0;
param_set_t lm = LMS_SHA256_N32_H5;
param_set_t ots = LMOTS_SHA256_N32_W8;
(void) heap;
(void) devId;
key->state = WC_LMS_STATE_NOT_INITED;
if (key == NULL) {
return BAD_FUNC_ARG;
}
ForceZero(key, sizeof(LmsKey));
/* Verify inputs make sense. Values of 0 may be passed to signify
* using minimum defaults. */
if (levels == 0) {
levels = MIN_HSS_LEVELS;
}
else if (levels < MIN_HSS_LEVELS || levels > MAX_HSS_LEVELS) {
WOLFSSL_MSG("error: invalid level parameter");
return BAD_FUNC_ARG;
}
if (height == 0) {
height = MIN_MERKLE_HEIGHT;
}
else if (height < MIN_MERKLE_HEIGHT || height > MAX_MERKLE_HEIGHT) {
WOLFSSL_MSG("error: invalid height parameter");
return BAD_FUNC_ARG;
}
if (winternitz == 0) {
winternitz = 2;
}
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;
}
hss_init_extra_info(&key->info);
/* The hash-sigs lib API will accept either:
* 1. private key callbacks with context pointer, or
* 2. context that points at private key.
* Do the 2nd by default, unless user sets the callbacks through API. */
key->working_key = NULL;
key->write_private_key = NULL;
key->read_private_key = NULL;
key->context = NULL;
key->state = WC_LMS_STATE_INITED;
return ret;
}
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_NOT_INITED;
return;
}
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_INITED) {
WOLFSSL_MSG("error: LmsKey not ready for generation");
return -1;
}
LmsRng = rng;
/* todo: The has-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);
*/
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;
}
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;
}
key->state = WC_LMS_STATE_OK;
return 0;
}
int wc_LmsKey_SetWriteCb(LmsKey * key, write_private_key_cb wf)
{
if (key == NULL || wf == NULL) {
return BAD_FUNC_ARG;
}
key->write_private_key = wf;
return 0;
}
int wc_LmsKey_SetReadCb(LmsKey * key, read_private_key_cb rf)
{
if (key == NULL || rf == NULL) {
return BAD_FUNC_ARG;
}
key->read_private_key = rf;
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. */
int wc_LmsKey_SetContext(LmsKey * key, void * context)
{
if (key == NULL || context == NULL) {
return BAD_FUNC_ARG;
}
key->context = context;
return 0;
}
/* Reload a key that has been prepared with the appropriate read callbacks
* or data. */
int wc_LmsKey_Reload(LmsKey * key)
{
bool result = true;
if (key == NULL) {
return BAD_FUNC_ARG;
}
if (key->state != WC_LMS_STATE_INITED) {
WOLFSSL_MSG("error: LmsKey not ready for reload");
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;
}
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. Use this to prepare a signature verification
* key that is pub only. */
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;
keyDst->state = keySrc->state;
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 sig 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;
}
int wc_LmsKey_SigsLeft(LmsKey * key)
{
/* 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. */
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> #include <wolfssl/wolfcrypt/ext_kyber.h>
#endif #endif
#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 #ifdef WOLFCRYPT_HAVE_ECCSI
#include <wolfssl/wolfcrypt/eccsi.h> #include <wolfssl/wolfcrypt/eccsi.h>
#endif #endif
@@ -555,6 +561,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t scrypt_test(void);
#ifdef WOLFSSL_HAVE_KYBER #ifdef WOLFSSL_HAVE_KYBER
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t kyber_test(void); WOLFSSL_TEST_SUBROUTINE wc_test_ret_t kyber_test(void);
#endif #endif
#ifdef WOLFSSL_HAVE_LMS
WOLFSSL_TEST_SUBROUTINE int lms_test(void);
#endif
#ifdef WOLFCRYPT_HAVE_ECCSI #ifdef WOLFCRYPT_HAVE_ECCSI
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t eccsi_test(void); WOLFSSL_TEST_SUBROUTINE wc_test_ret_t eccsi_test(void);
#endif #endif
@@ -1558,6 +1567,13 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\
TEST_PASS("KYBER test passed!\n"); TEST_PASS("KYBER test passed!\n");
#endif #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 #ifdef WOLFCRYPT_HAVE_ECCSI
if ( (ret = eccsi_test()) != 0) if ( (ret = eccsi_test()) != 0)
TEST_FAIL("ECCSI test failed!\n", ret); TEST_FAIL("ECCSI test failed!\n", ret);
@@ -34805,6 +34821,97 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t kyber_test(void)
} }
#endif /* WOLFSSL_HAVE_KYBER */ #endif /* WOLFSSL_HAVE_KYBER */
#ifdef WOLFSSL_HAVE_LMS
WOLFSSL_TEST_SUBROUTINE int lms_test(void)
{
int ret;
int sigsLeft = 0;
LmsKey signingKey;
LmsKey verifyKey;
WC_RNG rng;
byte sig[8688];
word32 sigSz = 0;
const char * msg = "LMS HSS post quantum signature test";
word32 msgSz = (word32) XSTRLEN(msg);
unsigned char old_priv[HSS_MAX_PRIVATE_KEY_LEN];
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); }
/*
* levels: 1
* height: 5
* winternitz: 1
*
* max sigs: 2 ** (1 * 5) = 32
* signature length: 8688
*/
ret = wc_LmsKey_Init_ex(&signingKey, 1, 5, 1, NULL, INVALID_DEVID);
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, signingKey.priv, sizeof(signingKey.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 != sizeof(sig)) {
printf("error: got %d, expected %zu\n", sigSz, sizeof(sig));
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, signingKey.priv, sizeof(signingKey.priv)) == 0) {
printf("error: current priv key should not match old: %zu\n", i);
return WC_TEST_RET_ENC_I(i);
}
XMEMCPY(old_priv, signingKey.priv, sizeof(signingKey.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 -- static const int fiducial3 = WC_TEST_RET_LN; /* source code reference point --
* see print_fiducials() below. * see print_fiducials() below.
*/ */

View File

@@ -0,0 +1,64 @@
/* 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 priv[HSS_MAX_PRIVATE_KEY_LEN];
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/ext_kyber.h \
wolfssl/wolfcrypt/sm2.h \ wolfssl/wolfcrypt/sm2.h \
wolfssl/wolfcrypt/sm3.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+= \ noinst_HEADERS+= \
wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h \ wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h \

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

@@ -0,0 +1,131 @@
/* 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. */
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 {
WC_LMS_STATE_OK = 0,
WC_LMS_STATE_NOT_INITED = 1,
WC_LMS_STATE_INITED = 2,
WC_LMS_STATE_BAD = 3, /* Can't guarantee key's state. */
WC_LMS_STATE_NOSIGS = 4, /* Signatures exhausted. */
};
#ifdef __cplusplus
extern "C" {
#endif
/* Need an update_key_cb setting function.
* Also maybe a generate rand cb setter. */
WOLFSSL_API int wc_LmsKey_Init(LmsKey * key, enum wc_LmsParm lmsParm);
WOLFSSL_API int wc_LmsKey_Init_ex(LmsKey * key, int levels,
int height, int winternitz, void* heap, int devId);
WOLFSSL_API int wc_LmsKey_SetWriteCb(LmsKey * key, write_private_key_cb wf);
WOLFSSL_API int wc_LmsKey_SetReadCb(LmsKey * key, read_private_key_cb rf);
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,3 @@
#error "Contact wolfSSL to get the implementation of this file"