Skip to content

Commit d05790e

Browse files
committed
LMS: Allow state to be saved with private key
Defining WOLFSSL_WC_LMS_SERIALIZE_STATE will have the state serialized before the private key data. Lots of memory used but means fast reload times. That means that the key can be reloaded for each sign.
1 parent 978a29d commit d05790e

5 files changed

Lines changed: 130 additions & 39 deletions

File tree

.wolfssl_known_macro_extras

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,8 @@ WOLFSSL_USE_FLASHMEM
863863
WOLFSSL_USE_OPTIONS_H
864864
WOLFSSL_USE_POPEN_HOST
865865
WOLFSSL_VALIDATE_DH_KEYGEN
866+
WOLFSSL_WC_LMS_SERIALIZE_STATE
867+
WOLFSSL_WC_MLKEM
866868
WOLFSSL_WC_XMSS_NO_SHA256
867869
WOLFSSL_WC_XMSS_NO_SHAKE256
868870
WOLFSSL_WICED_PSEUDO_UNIX_EPOCH_TIME

wolfcrypt/benchmark/benchmark.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9876,6 +9876,7 @@ void bench_mlkem(int type)
98769876
#endif
98779877

98789878
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
9879+
#ifndef WOLFSSL_WC_LMS_SERIALIZE_STATE
98799880
#ifndef WOLFSSL_NO_LMS_SHA256_256
98809881
/* WC_LMS_PARM_L2_H10_W2
98819882
* signature length: 9300 */
@@ -10033,6 +10034,7 @@ static const byte lms_pub_L4_H5_W8[60] =
1003310034
0x74,0x24,0x12,0xC8
1003410035
};
1003510036
#endif
10037+
#endif /* WOLFSSL_WC_LMS_SERIALIZE_STATE */
1003610038

1003710039
static int lms_write_key_mem(const byte* priv, word32 privSz, void* context)
1003810040
{
@@ -10050,7 +10052,11 @@ static int lms_read_key_mem(byte* priv, word32 privSz, void* context)
1005010052
XMEMCPY(priv, context, privSz);
1005110053
return WC_LMS_RC_READ_TO_MEMORY;
1005210054
}
10055+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
10056+
static byte lms_priv[64*1024 + HSS_MAX_PRIVATE_KEY_LEN];
10057+
#else
1005310058
static byte lms_priv[HSS_MAX_PRIVATE_KEY_LEN];
10059+
#endif
1005410060

1005510061
static void bench_lms_keygen(enum wc_LmsParm parm, byte* pub)
1005610062
{
@@ -10192,6 +10198,7 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm, byte* pub)
1019210198
goto exit_lms_sign_verify;
1019310199
}
1019410200

10201+
#ifndef WOLFSSL_WC_LMS_SERIALIZE_STATE
1019510202
switch (parm) {
1019610203
#ifndef WOLFSSL_NO_LMS_SHA256_256
1019710204
case WC_LMS_PARM_L2_H10_W2:
@@ -10283,6 +10290,9 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm, byte* pub)
1028310290
XMEMCPY(key.pub, pub, HSS_MAX_PUBLIC_KEY_LEN);
1028410291
break;
1028510292
}
10293+
#else
10294+
XMEMCPY(key.pub, pub, HSS_MAX_PUBLIC_KEY_LEN);
10295+
#endif
1028610296

1028710297
ret = wc_LmsKey_SetWriteCb(&key, lms_write_key_mem);
1028810298
if (ret) {

wolfcrypt/src/wc_lms.c

Lines changed: 81 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -586,11 +586,14 @@ void wc_LmsKey_Free(LmsKey* key)
586586
#ifndef WOLFSSL_LMS_VERIFY_ONLY
587587
if (key->priv_data != NULL) {
588588
const LmsParams* params = key->params;
589-
590-
ForceZero(key->priv_data, LMS_PRIV_DATA_LEN(params->levels,
589+
int priv_data_len = LMS_PRIV_DATA_LEN(params->levels,
591590
params->height, params->p, params->rootLevels,
592-
params->cacheBits, params->hash_len));
591+
params->cacheBits, params->hash_len);
593592

593+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
594+
priv_data_len += HSS_PRIVATE_KEY_LEN(key->params->hash_len);
595+
#endif
596+
ForceZero(key->priv_data, priv_data_len);
594597
XFREE(key->priv_data, key->heap, DYNAMIC_TYPE_LMS);
595598
}
596599
#endif
@@ -717,6 +720,7 @@ int wc_LmsKey_SetContext(LmsKey* key, void* context)
717720
int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng)
718721
{
719722
int ret = 0;
723+
int priv_data_len = 0;
720724

721725
/* Validate parameters. */
722726
if ((key == NULL) || (rng == NULL)) {
@@ -738,17 +742,26 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng)
738742
ret = BAD_FUNC_ARG;
739743
}
740744

741-
if ((ret == 0) && (key->priv_data == NULL)) {
745+
if (ret == 0) {
742746
const LmsParams* params = key->params;
747+
priv_data_len = LMS_PRIV_DATA_LEN(params->levels, params->height,
748+
params->p, params->rootLevels, params->cacheBits, params->hash_len);
743749

750+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
751+
priv_data_len += HSS_PRIVATE_KEY_LEN(key->params->hash_len);
752+
#endif
753+
}
754+
if ((ret == 0) && (key->priv_data == NULL)) {
744755
/* Allocate memory for the private key data. */
745-
key->priv_data = (byte *)XMALLOC(LMS_PRIV_DATA_LEN(params->levels,
746-
params->height, params->p, params->rootLevels, params->cacheBits,
747-
params->hash_len), key->heap, DYNAMIC_TYPE_LMS);
756+
key->priv_data = (byte *)XMALLOC(priv_data_len, key->heap,
757+
DYNAMIC_TYPE_LMS);
748758
/* Check pointer is valid. */
749759
if (key->priv_data == NULL) {
750760
ret = MEMORY_E;
751761
}
762+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
763+
XMEMSET(key->priv_data, 0, priv_data_len);
764+
#endif
752765
}
753766
if (ret == 0) {
754767
#ifdef WOLFSSL_SMALL_STACK
@@ -759,7 +772,8 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng)
759772

760773
#ifdef WOLFSSL_SMALL_STACK
761774
/* Allocate memory for working state. */
762-
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL, DYNAMIC_TYPE_TMP_BUFFER);
775+
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL,
776+
DYNAMIC_TYPE_TMP_BUFFER);
763777
if (state == NULL) {
764778
ret = MEMORY_E;
765779
}
@@ -781,9 +795,18 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng)
781795
}
782796
}
783797
if (ret == 0) {
798+
int rv;
784799
/* Write private key to storage. */
785-
int rv = key->write_private_key(key->priv_raw,
800+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
801+
XMEMCPY(key->priv_data + priv_data_len -
802+
HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->priv_raw,
803+
HSS_PRIVATE_KEY_LEN(key->params->hash_len));
804+
rv = key->write_private_key(key->priv_data, priv_data_len,
805+
key->context);
806+
#else
807+
rv = key->write_private_key(key->priv_raw,
786808
HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->context);
809+
#endif
787810
if (rv != WC_LMS_RC_SAVED_TO_NV_MEMORY) {
788811
ret = IO_FAILED_E;
789812
}
@@ -816,6 +839,7 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng)
816839
int wc_LmsKey_Reload(LmsKey* key)
817840
{
818841
int ret = 0;
842+
int priv_data_len = 0;
819843

820844
/* Validate parameter. */
821845
if (key == NULL) {
@@ -837,25 +861,46 @@ int wc_LmsKey_Reload(LmsKey* key)
837861
ret = BAD_FUNC_ARG;
838862
}
839863

840-
if ((ret == 0) && (key->priv_data == NULL)) {
864+
if (ret == 0) {
841865
const LmsParams* params = key->params;
866+
priv_data_len = LMS_PRIV_DATA_LEN(params->levels, params->height,
867+
params->p, params->rootLevels, params->cacheBits, params->hash_len);
842868

869+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
870+
priv_data_len += HSS_PRIVATE_KEY_LEN(params->hash_len);
871+
#endif
872+
}
873+
if ((ret == 0) && (key->priv_data == NULL)) {
843874
/* Allocate memory for the private key data. */
844-
key->priv_data = (byte *)XMALLOC(LMS_PRIV_DATA_LEN(params->levels,
845-
params->height, params->p, params->rootLevels, params->cacheBits,
846-
params->hash_len), key->heap, DYNAMIC_TYPE_LMS);
875+
key->priv_data = (byte *)XMALLOC(priv_data_len, key->heap,
876+
DYNAMIC_TYPE_LMS);
847877
/* Check pointer is valid. */
848878
if (key->priv_data == NULL) {
849879
ret = MEMORY_E;
850880
}
851881
}
852882
if (ret == 0) {
883+
int rv;
884+
853885
/* Load private key. */
854-
int rv = key->read_private_key(key->priv_raw,
886+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
887+
const LmsParams* params = key->params;
888+
889+
rv = key->read_private_key(key->priv_data, priv_data_len, key->context);
890+
#else
891+
rv = key->read_private_key(key->priv_raw,
855892
HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->context);
893+
#endif
856894
if (rv != WC_LMS_RC_READ_TO_MEMORY) {
857895
ret = IO_FAILED_E;
858896
}
897+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
898+
if (ret == 0) {
899+
XMEMCPY(key->priv_raw, key->priv_data + priv_data_len -
900+
HSS_PRIVATE_KEY_LEN(params->hash_len),
901+
HSS_PRIVATE_KEY_LEN(params->hash_len));
902+
}
903+
#endif
859904
}
860905

861906
/* Double check the key actually has signatures left. */
@@ -874,7 +919,8 @@ int wc_LmsKey_Reload(LmsKey* key)
874919

875920
#ifdef WOLFSSL_SMALL_STACK
876921
/* Allocate memory for working state. */
877-
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL, DYNAMIC_TYPE_TMP_BUFFER);
922+
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL,
923+
DYNAMIC_TYPE_TMP_BUFFER);
878924
if (state == NULL) {
879925
ret = MEMORY_E;
880926
}
@@ -972,7 +1018,8 @@ int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg,
9721018

9731019
#ifdef WOLFSSL_SMALL_STACK
9741020
/* Allocate memory for working state. */
975-
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL, DYNAMIC_TYPE_TMP_BUFFER);
1021+
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL,
1022+
DYNAMIC_TYPE_TMP_BUFFER);
9761023
if (state == NULL) {
9771024
ret = MEMORY_E;
9781025
}
@@ -997,9 +1044,24 @@ int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg,
9971044
*sigSz = (word32)key->params->sig_len;
9981045
}
9991046
if (ret == 0) {
1047+
int rv;
1048+
10001049
/* Write private key to storage. */
1001-
int rv = key->write_private_key(key->priv_raw,
1050+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
1051+
const LmsParams* params = key->params;
1052+
int priv_data_len = LMS_PRIV_DATA_LEN(params->levels, params->height,
1053+
params->p, params->rootLevels, params->cacheBits,
1054+
params->hash_len) + HSS_PRIVATE_KEY_LEN(key->params->hash_len);
1055+
1056+
XMEMCPY(key->priv_data + priv_data_len -
1057+
HSS_PRIVATE_KEY_LEN(params->hash_len), key->priv_raw,
1058+
HSS_PRIVATE_KEY_LEN(params->hash_len));
1059+
rv = key->write_private_key(key->priv_data, priv_data_len,
1060+
key->context);
1061+
#else
1062+
rv = key->write_private_key(key->priv_raw,
10021063
HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->context);
1064+
#endif
10031065
if (rv != WC_LMS_RC_SAVED_TO_NV_MEMORY) {
10041066
ret = IO_FAILED_E;
10051067
}
@@ -1234,7 +1296,8 @@ int wc_LmsKey_Verify(LmsKey* key, const byte* sig, word32 sigSz,
12341296

12351297
#ifdef WOLFSSL_SMALL_STACK
12361298
/* Allocate memory for working state. */
1237-
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL, DYNAMIC_TYPE_TMP_BUFFER);
1299+
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL,
1300+
DYNAMIC_TYPE_TMP_BUFFER);
12381301
if (state == NULL) {
12391302
ret = MEMORY_E;
12401303
}

wolfcrypt/src/wc_lms_impl.c

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3208,7 +3208,7 @@ static void wc_hss_priv_data_store(const LmsParams* params, HssPrivKey* key,
32083208
int wc_hss_reload_key(LmsState* state, const byte* priv_raw,
32093209
HssPrivKey* priv_key, byte* priv_data, byte* pub_root)
32103210
{
3211-
int ret;
3211+
int ret = 0;
32123212

32133213
(void)pub_root;
32143214

@@ -3217,27 +3217,34 @@ int wc_hss_reload_key(LmsState* state, const byte* priv_raw,
32173217
priv_key->inited = 0;
32183218
#endif
32193219

3220-
/* Expand the raw private key into the private key data. */
3221-
ret = wc_hss_expand_private_key(state, priv_key->priv, priv_raw, 0);
3222-
#ifndef WOLFSSL_WC_LMS_SMALL
3223-
if ((ret == 0) && (!priv_key->inited)) {
3224-
/* Initialize the authentication paths and caches for all trees. */
3225-
ret = wc_hss_init_auth_path(state, priv_key, pub_root);
3226-
#ifndef WOLFSSL_LMS_NO_SIGN_SMOOTHING
3227-
if (ret == 0) {
3228-
ret = wc_hss_next_subtrees_init(state, priv_key);
3229-
}
3230-
#endif
3231-
#if !defined(WOLFSSL_LMS_NO_SIG_CACHE) && (LMS_MAX_LEVELS > 1)
3232-
if (ret == 0) {
3233-
/* Calculate signatures for trees not at bottom. */
3234-
ret = wc_hss_presign(state, priv_key);
3220+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
3221+
if (pub_root != NULL)
3222+
#endif
3223+
{
3224+
/* Expand the raw private key into the private key data. */
3225+
ret = wc_hss_expand_private_key(state, priv_key->priv, priv_raw, 0);
3226+
#ifndef WOLFSSL_WC_LMS_SMALL
3227+
if ((ret == 0) && (!priv_key->inited)) {
3228+
/* Initialize the authentication paths and caches for all trees. */
3229+
ret = wc_hss_init_auth_path(state, priv_key, pub_root);
3230+
#ifndef WOLFSSL_LMS_NO_SIGN_SMOOTHING
3231+
if (ret == 0) {
3232+
ret = wc_hss_next_subtrees_init(state, priv_key);
3233+
}
3234+
#endif
3235+
#if !defined(WOLFSSL_LMS_NO_SIG_CACHE) && (LMS_MAX_LEVELS > 1)
3236+
if (ret == 0) {
3237+
/* Calculate signatures for trees not at bottom. */
3238+
ret = wc_hss_presign(state, priv_key);
3239+
}
3240+
#endif /* !WOLFSSL_LMS_NO_SIG_CACHE */
32353241
}
3236-
#endif /* !WOLFSSL_LMS_NO_SIG_CACHE */
3237-
/* Set initialized flag. */
3238-
priv_key->inited = (ret == 0);
3242+
#endif /* WOLFSSL_WC_LMS_SMALL */
32393243
}
3240-
#endif /* WOLFSSL_WC_LMS_SMALL */
3244+
#ifndef WOLFSSL_WC_LMS_SMALL
3245+
/* Set initialized flag. */
3246+
priv_key->inited = (ret == 0);
3247+
#endif
32413248

32423249
return ret;
32433250
}
@@ -3301,6 +3308,10 @@ int wc_hss_make_key(LmsState* state, WC_RNG* rng, byte* priv_raw,
33013308
wc_lmots_public_key_encode(params, priv_key->priv, pub);
33023309
}
33033310

3311+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
3312+
wc_hss_priv_data_store(state->params, priv_key, priv_data);
3313+
#endif
3314+
33043315
return ret;
33053316
}
33063317

@@ -3581,7 +3592,7 @@ static int wc_hss_sign_build_sig(LmsState* state, byte* priv_raw,
35813592
*
35823593
* @param [in, out] state LMS state.
35833594
* @param [in, out] priv_raw Raw private key bytes.
3584-
* @param [in, out] priv_key Private key data.
3595+
* @param [in, out] priv_key Private key.
35853596
* @param [in, out] priv_data Private key data.
35863597
* @param [in] msg Message to sign.
35873598
* @param [in] msgSz Length of message in bytes.

wolfcrypt/test/test.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47911,8 +47911,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
4791147911
word32 sigSz = 0;
4791247912
const char * msg = "LMS HSS post quantum signature test";
4791347913
word32 msgSz = (word32) XSTRLEN(msg);
47914+
#ifndef WOLFSSL_WC_LMS_SERIALIZE_STATE
4791447915
unsigned char priv[HSS_MAX_PRIVATE_KEY_LEN];
4791547916
unsigned char old_priv[HSS_MAX_PRIVATE_KEY_LEN];
47917+
#else
47918+
static unsigned char priv[64 * 1024 + HSS_MAX_PRIVATE_KEY_LEN];
47919+
static unsigned char old_priv[64 * 1024 + HSS_MAX_PRIVATE_KEY_LEN];
47920+
#endif
4791647921
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
4791747922
byte * sig = (byte*)XMALLOC(WC_TEST_LMS_SIG_LEN, HEAP_HINT,
4791847923
DYNAMIC_TYPE_TMP_BUFFER);

0 commit comments

Comments
 (0)