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
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. 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. 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 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 # 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)])],
@ -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_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"])
@ -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_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"])
@ -9242,6 +9347,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"
@ -9297,6 +9404,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

@ -655,6 +655,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
@ -734,6 +738,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
@ -565,6 +571,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
@ -603,6 +612,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)
@ -856,6 +867,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. */
@ -1592,6 +1618,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;
} }
} }
@ -2798,6 +2825,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) ||
@ -7624,6 +7657,375 @@ 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 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 #ifdef HAVE_ECC
/* Maximum ECC name plus null terminator: /* Maximum ECC name plus null terminator:
@ -9952,6 +10354,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++;
@ -10211,6 +10617,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);

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> #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
@ -1580,6 +1589,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);
@ -34908,6 +34924,144 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t kyber_test(void)
} }
#endif /* WOLFSSL_HAVE_KYBER */ #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 -- 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,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/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/aria/aria-crypt.h \ 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"