mirror of https://github.com/wolfSSL/wolfBoot.git
XMSS wolfBoot support.
parent
9b12acfed3
commit
79aadb5cc1
|
@ -0,0 +1,26 @@
|
|||
# XMSS/XMSS^MT/HSS signature example, based on sim.config example.
|
||||
#
|
||||
#
|
||||
|
||||
ARCH=sim
|
||||
TARGET=sim
|
||||
SIGN?=XMSS
|
||||
HASH?=SHA256
|
||||
XMSS_PARAMS='XMSS-SHA2_10_256'
|
||||
WOLFBOOT_SMALL_STACK=0
|
||||
SPI_FLASH=0
|
||||
DEBUG=0
|
||||
DELTA_UPDATES=0
|
||||
IMAGE_SIGNATURE_SIZE=2500
|
||||
IMAGE_HEADER_SIZE?=5000
|
||||
|
||||
# sizes should be multiple of system page size
|
||||
WOLFBOOT_PARTITION_SIZE=0x40000
|
||||
WOLFBOOT_SECTOR_SIZE=0x1000
|
||||
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x20000
|
||||
# if on external flash, it should be multiple of system page size
|
||||
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x60000
|
||||
WOLFBOOT_PARTITION_SWAP_ADDRESS=0xA0000
|
||||
|
||||
# required for keytools
|
||||
WOLFBOOT_FIXED_PARTITIONS=1
|
95
docs/PQ.md
95
docs/PQ.md
|
@ -1,17 +1,27 @@
|
|||
# Post-Quantum Signatures
|
||||
|
||||
wolfBoot is adding support for post-quantum signatures. At present, support
|
||||
for LMS/HSS signatures has been added.
|
||||
for LMS/HSS (https://www.rfc-editor.org/rfc/rfc8554.html), and XMSS/XMSS^MT
|
||||
(https://www.rfc-editor.org/rfc/rfc8391.html) has been added.
|
||||
|
||||
## LMS/HSS
|
||||
|
||||
LMS/HSS is a post-quantum stateful hash-based signature scheme (HBS). It
|
||||
is known for having small public and private keys, but larger signatures.
|
||||
The signature size is tunable via the different LMS parameters.
|
||||
LMS/HSS and XMSS/XMSS^MT are both post-quantum stateful hash-based signature
|
||||
(HBS) schemes. They are known for having small public keys, relatively fast
|
||||
signing and verifying operations, but larger signatures. Their signature sizes
|
||||
however are tunable via their different parameters, which affords a space-time
|
||||
tradeoff.
|
||||
|
||||
Stateful HBS schemes are based on the security of their underlying hash
|
||||
functions and Merkle trees, which are not expected to be broken by the advent
|
||||
of cryptographically relevant quantum computers.
|
||||
of cryptographically relevant quantum computers. For this reason they have
|
||||
been recommended by both NIST SP 800-208, and the NSA’s CNSA 2.0 suite.
|
||||
|
||||
See these links for more info on stateful HBS support and wolfSSL/wolfCrypt:
|
||||
- https://www.wolfssl.com/documentation/manuals/wolfssl/appendix07.html#post-quantum-stateful-hash-based-signatures
|
||||
- https://github.com/wolfSSL/wolfssl-examples/tree/master/pq/stateful_hash_sig
|
||||
|
||||
|
||||
## LMS/HSS
|
||||
|
||||
|
||||
### Building with LMS Support
|
||||
|
||||
|
@ -44,7 +54,7 @@ keygen, signing, and verifying functionality. However wolfBoot
|
|||
links directly with the subset of objects in the `hss_verify.a`
|
||||
build rule, as it only requires verify functionality.
|
||||
|
||||
### Config
|
||||
### LMS Config
|
||||
|
||||
A new LMS sim example has been added here:
|
||||
```
|
||||
|
@ -69,17 +79,66 @@ In LMS the signature size is a function of the parameters. Use the added helper
|
|||
script `tools/lms/lms_siglen.sh` to calculate your signature length given your
|
||||
LMS parameters:
|
||||
```
|
||||
$./tools/lms/lms_siglen.sh
|
||||
levels: 3
|
||||
height: 5
|
||||
winternitz: 8
|
||||
#
|
||||
total_len: 3992
|
||||
$ ./tools/lms/lms_siglen.sh 2 5 8
|
||||
levels: 2
|
||||
height: 5
|
||||
winternitz: 8
|
||||
signature length: 2644
|
||||
```
|
||||
|
||||
### More Info
|
||||
## XMSS/XMSS^MT
|
||||
|
||||
See these links for more info on LMS and wolfSSL/wolfCrypt:
|
||||
- https://www.wolfssl.com/documentation/manuals/wolfssl/appendix07.html#post-quantum-stateful-hash-based-signatures
|
||||
- https://github.com/wolfSSL/wolfssl-examples/tree/master/pq/stateful_hash_sig
|
||||
### Building with XMSS Support
|
||||
|
||||
XMSS/XMSS^MT support in wolfCrypt requires a patched version of the
|
||||
xmss-reference library ( https://github.com/XMSS/xmss-reference.git ).
|
||||
Use the following procedure to prepare xmss-reference for building with
|
||||
wolfBoot:
|
||||
|
||||
```
|
||||
$ cd lib
|
||||
$ git clone https://github.com/XMSS/xmss-reference.git xmss
|
||||
$ ls
|
||||
CMakeLists.txt wolfPKCS11 wolfTPM wolfssl xmss
|
||||
$ cd xmss
|
||||
$ git checkout 171ccbd26f098542a67eb5d2b128281c80bd71a6
|
||||
$ git apply ../../../tools/xmss/0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch
|
||||
```
|
||||
|
||||
The patch creates an addendum readme, `patch_readme.md`, with further comments.
|
||||
|
||||
Nothing more is needed beyond the patch step, as wolfBoot will handle building
|
||||
the xmss build artifacts it requires.
|
||||
|
||||
### XMSS Config
|
||||
A new XMSS sim example has been added here:
|
||||
```
|
||||
config/examples/sim-xmss.config
|
||||
```
|
||||
|
||||
The `XMSS_PARAMS`, `IMAGE_SIGNATURE_SIZE`, and (optionally) `IMAGE_HEADER_SIZE`
|
||||
must be set:
|
||||
|
||||
```
|
||||
SIGN?=XMSS
|
||||
...
|
||||
XMSS_PARAMS='XMSS-SHA2_10_256'
|
||||
...
|
||||
IMAGE_SIGNATURE_SIZE=2500
|
||||
IMAGE_HEADER_SIZE?=5000
|
||||
```
|
||||
|
||||
The `XMSS_PARAMS` may be any SHA256 parameter set string from Tables 10 and 11
|
||||
from NIST SP 800-208. Use the helper script `tools/xmss/xmss_siglen.sh` to
|
||||
calculate your signature length given your XMSS/XMSS^MT parameter string, e.g.:
|
||||
```
|
||||
$ ./tools/xmss/xmss_siglen.sh XMSS-SHA2_10_256
|
||||
parameter set: XMSS-SHA2_10_256
|
||||
signature length: 2500
|
||||
```
|
||||
|
||||
```
|
||||
$ ./tools/xmss/xmss_siglen.sh XMSSMT-SHA2_20/2_256
|
||||
parameter set: XMSSMT-SHA2_20/2_256
|
||||
signature length: 4963
|
||||
```
|
||||
|
|
|
@ -67,6 +67,9 @@ extern "C" {
|
|||
* options.mk from the .config file. */
|
||||
extern const unsigned char lms_pub_key[];
|
||||
extern unsigned int lms_pub_key_len;
|
||||
#elif defined(WOLFBOOT_SIGN_XMSS)
|
||||
extern const unsigned char xmss_pub_key[];
|
||||
extern unsigned int xmss_pub_key_len;
|
||||
#elif !defined(WOLFBOOT_NO_SIGN)
|
||||
# error "No public key available for given signing algorithm."
|
||||
#endif /* Algorithm selection */
|
||||
|
|
|
@ -85,6 +85,7 @@ extern "C" {
|
|||
#define AUTH_KEY_ECC521 0x07
|
||||
#define AUTH_KEY_RSA3072 0x08
|
||||
#define AUTH_KEY_LMS 0x09
|
||||
#define AUTH_KEY_XMSS 0x10
|
||||
|
||||
|
||||
|
||||
|
@ -105,6 +106,7 @@ extern "C" {
|
|||
#define HDR_IMG_TYPE_AUTH_ECC521 (AUTH_KEY_ECC521 << 8)
|
||||
#define HDR_IMG_TYPE_AUTH_RSA3072 (AUTH_KEY_RSA3072 << 8)
|
||||
#define HDR_IMG_TYPE_AUTH_LMS (AUTH_KEY_LMS << 8)
|
||||
#define HDR_IMG_TYPE_AUTH_XMSS (AUTH_KEY_XMSS << 8)
|
||||
|
||||
#define HDR_IMG_TYPE_DIFF 0x00D0
|
||||
|
||||
|
@ -122,6 +124,7 @@ extern "C" {
|
|||
#define KEYSTORE_PUBKEY_SIZE_RSA3072 448
|
||||
#define KEYSTORE_PUBKEY_SIZE_RSA4096 576
|
||||
#define KEYSTORE_PUBKEY_SIZE_LMS 60
|
||||
#define KEYSTORE_PUBKEY_SIZE_XMSS 68
|
||||
|
||||
/* Mask for key permissions */
|
||||
#define KEY_VERIFY_ALL (0xFFFFFFFFU)
|
||||
|
@ -222,6 +225,11 @@ extern "C" {
|
|||
# ifndef WOLFBOOT_UNIVERSAL_KEYSTORE
|
||||
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_LMS
|
||||
# endif
|
||||
#elif defined(WOLFBOOT_SIGN_XMSS)
|
||||
# define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_XMSS
|
||||
# ifndef WOLFBOOT_UNIVERSAL_KEYSTORE
|
||||
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_XMSS
|
||||
# endif
|
||||
#else
|
||||
# error "No valid authentication mechanism selected. " \
|
||||
"Please select a valid SIGN= option."
|
||||
|
|
40
options.mk
40
options.mk
|
@ -381,6 +381,46 @@ ifeq ($(SIGN),LMS)
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(SIGN),XMSS)
|
||||
ifndef XMSS_PARAMS
|
||||
$(error XMSS_PARAMS not set)
|
||||
endif
|
||||
|
||||
ifndef IMAGE_SIGNATURE_SIZE
|
||||
$(error IMAGE_SIGNATURE_SIZE not set)
|
||||
endif
|
||||
|
||||
ifndef IMAGE_HEADER_SIZE
|
||||
$(error IMAGE_HEADER_SIZE not set)
|
||||
endif
|
||||
|
||||
XMSSDIR = lib/xmss
|
||||
KEYGEN_OPTIONS+=--xmss
|
||||
SIGN_OPTIONS+=--xmss
|
||||
WOLFCRYPT_OBJS+= \
|
||||
./$(XMSSDIR)/params.o \
|
||||
./$(XMSSDIR)/thash.o \
|
||||
./$(XMSSDIR)/hash_address.o \
|
||||
./$(XMSSDIR)/wots.o \
|
||||
./$(XMSSDIR)/xmss.o \
|
||||
./$(XMSSDIR)/xmss_core_fast.o \
|
||||
./$(XMSSDIR)/xmss_commons.o \
|
||||
./$(XMSSDIR)/utils.o \
|
||||
./lib/wolfssl/wolfcrypt/src/ext_xmss.o \
|
||||
./lib/wolfssl/wolfcrypt/src/memory.o \
|
||||
./lib/wolfssl/wolfcrypt/src/wc_port.o \
|
||||
./lib/wolfssl/wolfcrypt/src/hash.o
|
||||
CFLAGS+=-D"WOLFBOOT_SIGN_XMSS" -D"WOLFSSL_HAVE_XMSS" -D"HAVE_LIBXMSS" \
|
||||
-DXMSS_PARAMS=\"$(XMSS_PARAMS)\" -I$(XMSSDIR) \
|
||||
-D"IMAGE_SIGNATURE_SIZE"=$(IMAGE_SIGNATURE_SIZE) \
|
||||
-D"WOLFSSL_XMSS_VERIFY_ONLY" -D"XMSS_VERIFY_ONLY"
|
||||
ifeq ($(WOLFBOOT_SMALL_STACK),1)
|
||||
$(error WOLFBOOT_SMALL_STACK with XMSS not supported)
|
||||
else
|
||||
STACK_USAGE=18064
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(RAM_CODE),1)
|
||||
CFLAGS+= -D"RAM_CODE"
|
||||
endif
|
||||
|
|
65
src/image.c
65
src/image.c
|
@ -382,6 +382,71 @@ static void wolfBoot_verify_signature(uint8_t key_slot,
|
|||
}
|
||||
#endif /* WOLFBOOT_SIGN_LMS */
|
||||
|
||||
#ifdef WOLFBOOT_SIGN_XMSS
|
||||
#include <wolfssl/wolfcrypt/xmss.h>
|
||||
#ifdef HAVE_LIBXMSS
|
||||
#include <wolfssl/wolfcrypt/ext_xmss.h>
|
||||
#endif
|
||||
|
||||
static void wolfBoot_verify_signature(uint8_t key_slot,
|
||||
struct wolfBoot_image *img, uint8_t *sig)
|
||||
{
|
||||
int ret = 0;
|
||||
XmssKey xmss;
|
||||
word32 pub_len = 0;
|
||||
uint8_t * pubkey = NULL;
|
||||
|
||||
wolfBoot_printf("info: XMSS wolfBoot_verify_signature\n");
|
||||
|
||||
pubkey = keystore_get_buffer(key_slot);
|
||||
if (pubkey == NULL) {
|
||||
wolfBoot_printf("error: Xmss pubkey not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = wc_XmssKey_Init(&xmss, NULL, INVALID_DEVID);
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("error: wc_XmssKey_Init returned %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
wolfBoot_printf("info: using XMSS parameters: %s\n", XMSS_PARAMS);
|
||||
|
||||
/* Set the XMSS parameters. */
|
||||
ret = wc_XmssKey_SetParamStr(&xmss, XMSS_PARAMS);
|
||||
if (ret != 0) {
|
||||
/* Something is wrong with the pub key or XMSS parameters. */
|
||||
wolfBoot_printf("error: wc_XmssKey_SetParamStr(%s)" \
|
||||
" returned %d\n", XMSS_PARAMS, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
wolfBoot_printf("info: using XMSS parameters: %s\n", XMSS_PARAMS);
|
||||
|
||||
/* Set the public key. */
|
||||
ret = wc_XmssKey_ImportPubRaw(&xmss, pubkey, KEYSTORE_PUBKEY_SIZE);
|
||||
if (ret != 0) {
|
||||
/* Something is wrong with the pub key or LMS parameters. */
|
||||
wolfBoot_printf("error: wc_XmssKey_ImportPubRaw" \
|
||||
" returned %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = wc_XmssKey_Verify(&xmss, sig, IMAGE_SIGNATURE_SIZE, img->sha_hash,
|
||||
WOLFBOOT_SHA_DIGEST_SIZE);
|
||||
|
||||
if (ret == 0) {
|
||||
wolfBoot_printf("info: wc_XmssKey_Verify returned OK\n");
|
||||
wolfBoot_image_confirm_signature_ok(img);
|
||||
}
|
||||
else {
|
||||
wolfBoot_printf("error: wc_XmssKey_Verify returned %d\n", ret);
|
||||
}
|
||||
|
||||
wc_XmssKey_Free(&xmss);
|
||||
}
|
||||
#endif /* WOLFBOOT_SIGN_XMSS */
|
||||
|
||||
#endif /* WOLFBOOT_TPM && WOLFBOOT_TPM_VERIFY */
|
||||
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ ifeq ($(ARCH),)
|
|||
LMS_LEVELS?=0
|
||||
LMS_HEIGHT?=0
|
||||
LMS_WINTERNITZ?=0
|
||||
XMSS_PARAMS?=XMSS-SHA2_10_256
|
||||
NO_MPU?=0
|
||||
ENCRYPT?=0
|
||||
ENCRYPT_WITH_CHACHA?=0
|
||||
|
@ -93,4 +94,5 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO
|
|||
ENCRYPT_WITH_CHACHA ENCRYPT_WITH_AES128 ENCRYPT_WITH_AES256 ARMORED \
|
||||
LMS_LEVELS LMS_HEIGHT LMS_WINTERNITZ \
|
||||
WOLFBOOT_UNIVERSAL_KEYSTORE \
|
||||
XMSS_PARAMS \
|
||||
ELF
|
||||
|
|
|
@ -25,6 +25,15 @@ ifeq ($(SIGN),LMS)
|
|||
-D"LMS_WINTERNITZ=$(LMS_WINTERNITZ)"
|
||||
endif
|
||||
|
||||
ifeq ($(SIGN),XMSS)
|
||||
$(info xmss params: $(XMSS_PARAMS))
|
||||
XMSSDIR = $(WOLFBOOTDIR)/lib/xmss
|
||||
CFLAGS +=-DWOLFBOOT_SIGN_XMSS -DWOLFSSL_HAVE_XMSS -DHAVE_LIBXMSS -I$(XMSSDIR) \
|
||||
-D"IMAGE_SIGNATURE_SIZE"=$(IMAGE_SIGNATURE_SIZE) \
|
||||
-DXMSS_PARAMS=\"$(XMSS_PARAMS)\"
|
||||
endif
|
||||
|
||||
|
||||
# option variables
|
||||
DEBUG_FLAGS = -g -DDEBUG -DDEBUG_SIGNTOOL -DDEBUG_WOLFSSL -DDEBUG_WOLFSSL_VERBOSE
|
||||
SANITIZE_FLAGS = -fsanitize=address
|
||||
|
@ -75,16 +84,33 @@ OBJS_REAL=\
|
|||
$(WOLFDIR)/wolfcrypt/src/tfm.o \
|
||||
$(WOLFDIR)/wolfcrypt/src/wc_port.o \
|
||||
$(WOLFDIR)/wolfcrypt/src/wolfmath.o \
|
||||
$(WOLFDIR)/wolfcrypt/src/ext_lms.o
|
||||
$(WOLFDIR)/wolfcrypt/src/ext_lms.o \
|
||||
$(WOLFDIR)/wolfcrypt/src/ext_xmss.o
|
||||
|
||||
OBJS_REAL+=\
|
||||
$(WOLFBOOTDIR)/src/delta.o
|
||||
|
||||
ifeq ($(SIGN),XMSS)
|
||||
OBJS_REAL+=\
|
||||
$(XMSSDIR)/params.o \
|
||||
$(XMSSDIR)/thash.o \
|
||||
$(XMSSDIR)/hash_address.o \
|
||||
$(XMSSDIR)/wots.o \
|
||||
$(XMSSDIR)/xmss.o \
|
||||
$(XMSSDIR)/xmss_core_fast.o \
|
||||
$(XMSSDIR)/xmss_commons.o \
|
||||
$(XMSSDIR)/utils.o
|
||||
endif
|
||||
|
||||
OBJS_VIRT=$(addprefix $(OBJDIR), $(notdir $(OBJS_REAL)))
|
||||
vpath %.c $(WOLFDIR)/wolfcrypt/src/
|
||||
vpath %.c $(WOLFBOOTDIR)/src/
|
||||
vpath %.c ./
|
||||
|
||||
ifeq ($(SIGN),XMSS)
|
||||
vpath %.c $(XMSSDIR)/
|
||||
endif
|
||||
|
||||
.PHONY: clean all
|
||||
|
||||
all: $(WOLFBOOTDIR)/include/target.h sign keygen
|
||||
|
@ -114,6 +140,9 @@ $(OBJDIR)/%.o: $(WOLFBOOTDIR)/src/%.c
|
|||
$(OBJDIR)/%.o: $(WOLFDIR)/wolfcrypt/src/%.c
|
||||
$(Q)$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(XMSSDIR)/src/%.o: $(XMSSDIR)/src/%.c
|
||||
$(Q)$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
# build templates
|
||||
sign: $(OBJS_VIRT) $(LIBS) sign.o
|
||||
@echo "Building signing tool"
|
||||
|
|
|
@ -68,6 +68,13 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_HAVE_XMSS)
|
||||
#include <wolfssl/wolfcrypt/xmss.h>
|
||||
#ifdef HAVE_LIBXMSS
|
||||
#include <wolfssl/wolfcrypt/ext_xmss.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <wolfssl/wolfcrypt/random.h>
|
||||
#include <wolfssl/wolfcrypt/error-crypt.h>
|
||||
#ifdef DEBUG_SIGNTOOL
|
||||
|
@ -91,6 +98,7 @@
|
|||
#define KEYGEN_ECC521 7
|
||||
#define KEYGEN_RSA3072 8
|
||||
#define KEYGEN_LMS 9
|
||||
#define KEYGEN_XMSS 10
|
||||
|
||||
/* Globals */
|
||||
static FILE *fpub, *fpub_image;
|
||||
|
@ -236,7 +244,8 @@ const char KType[][17] = {
|
|||
"AUTH_KEY_ECC384",
|
||||
"AUTH_KEY_ECC521",
|
||||
"AUTH_KEY_RSA3072",
|
||||
"AUTH_KEY_LMS"
|
||||
"AUTH_KEY_LMS",
|
||||
"AUTH_KEY_XMSS"
|
||||
};
|
||||
|
||||
const char KSize[][29] = {
|
||||
|
@ -249,7 +258,8 @@ const char KSize[][29] = {
|
|||
"KEYSTORE_PUBKEY_SIZE_ECC384",
|
||||
"KEYSTORE_PUBKEY_SIZE_ECC521",
|
||||
"KEYSTORE_PUBKEY_SIZE_RSA3072",
|
||||
"KEYSTORE_PUBKEY_SIZE_LMS"
|
||||
"KEYSTORE_PUBKEY_SIZE_LMS",
|
||||
"KEYSTORE_PUBKEY_SIZE_XMSS"
|
||||
};
|
||||
|
||||
const char KName[][8] = {
|
||||
|
@ -262,7 +272,8 @@ const char KName[][8] = {
|
|||
"ECC384",
|
||||
"ECC521",
|
||||
"RSA3072",
|
||||
"LMS"
|
||||
"LMS",
|
||||
"XMSS"
|
||||
};
|
||||
|
||||
#define MAX_PUBKEYS 64
|
||||
|
@ -306,6 +317,9 @@ static uint32_t get_pubkey_size(uint32_t keyType)
|
|||
case KEYGEN_LMS:
|
||||
size = KEYSTORE_PUBKEY_SIZE_LMS;
|
||||
break;
|
||||
case KEYGEN_XMSS:
|
||||
size = KEYSTORE_PUBKEY_SIZE_XMSS;
|
||||
break;
|
||||
default:
|
||||
size = 0;
|
||||
}
|
||||
|
@ -595,6 +609,97 @@ static void keygen_lms(const char *priv_fname, uint32_t id_mask)
|
|||
}
|
||||
#endif /* if defined(WOLFSSL_HAVE_LMS) */
|
||||
|
||||
#if defined(WOLFSSL_HAVE_XMSS)
|
||||
#include "../xmss/xmss_common.h"
|
||||
|
||||
static void keygen_xmss(const char *priv_fname, uint32_t id_mask)
|
||||
{
|
||||
FILE * fpriv;
|
||||
XmssKey key;
|
||||
int ret;
|
||||
word32 priv_sz = 0;
|
||||
byte xmss_pub[XMSS_SHA256_PUBLEN];
|
||||
word32 pub_len = sizeof(xmss_pub);
|
||||
|
||||
ret = wc_XmssKey_Init(&key, NULL, INVALID_DEVID);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "error: wc_XmssKey_Init returned %d\n", ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = wc_XmssKey_SetParamStr(&key, XMSS_PARAMS);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "error: wc_XmssKey_SetParamStr(%s)" \
|
||||
" returned %d\n", XMSS_PARAMS, ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("info: using XMSS parameters: %s\n", XMSS_PARAMS);
|
||||
|
||||
ret = wc_XmssKey_SetWriteCb(&key, xmss_write_key);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "error: wc_XmssKey_SetWriteCb returned %d\n", ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = wc_XmssKey_SetReadCb(&key, xmss_read_key);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "error: wc_XmssKey_SetReadCb returned %d\n", ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = wc_XmssKey_SetContext(&key, (void *) priv_fname);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "error: wc_XmssKey_SetContext returned %d\n", ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Make the key pair. */
|
||||
ret = wc_XmssKey_MakeKey(&key, &rng);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "error: wc_XmssKey_MakeKey returned %d\n", ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Get the XMSS/XMSS^MT secret key length. */
|
||||
ret = wc_XmssKey_GetPrivLen(&key, &priv_sz);
|
||||
if (ret != 0 || priv_sz <= 0) {
|
||||
printf("error: wc_XmssKey_GetPrivLen returned %d\n",
|
||||
ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = wc_XmssKey_ExportPubRaw(&key, xmss_pub, &pub_len);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "error: wc_XmssKey_ExportPubRaw returned %d\n", ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pub_len != sizeof(xmss_pub)) {
|
||||
fprintf(stderr, "error: wc_XmssKey_ExportPubRaw returned pub_len=%d\n" \
|
||||
", expected %zu\n", pub_len, sizeof(xmss_pub));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Append the public key to the private keyfile. */
|
||||
fpriv = fopen(priv_fname, "r+");
|
||||
if (!fpriv) {
|
||||
fprintf(stderr, "error: fopen(%s, \"r+\") returned %d\n", priv_fname,
|
||||
ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fseek(fpriv, priv_sz, SEEK_SET);
|
||||
fwrite(xmss_pub, KEYSTORE_PUBKEY_SIZE_XMSS, 1, fpriv);
|
||||
fclose(fpriv);
|
||||
|
||||
keystore_add(KEYGEN_XMSS, xmss_pub, KEYSTORE_PUBKEY_SIZE_XMSS, priv_fname, id_mask);
|
||||
|
||||
wc_XmssKey_Free(&key);
|
||||
}
|
||||
#endif /* if defined(WOLFSSL_HAVE_XMSS) */
|
||||
|
||||
|
||||
static void key_gen_check(const char *kfilename)
|
||||
{
|
||||
FILE *f;
|
||||
|
@ -663,6 +768,12 @@ static void key_generate(uint32_t ktype, const char *kfilename, uint32_t id_mask
|
|||
keygen_lms(kfilename, id_mask);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_HAVE_XMSS
|
||||
case KEYGEN_XMSS:
|
||||
keygen_xmss(kfilename, id_mask);
|
||||
break;
|
||||
#endif
|
||||
} /* end switch */
|
||||
}
|
||||
|
||||
|
@ -815,6 +926,11 @@ int main(int argc, char** argv)
|
|||
else if (strcmp(argv[i], "--lms") == 0) {
|
||||
keytype = KEYGEN_LMS;
|
||||
}
|
||||
#endif
|
||||
#if defined(WOLFSSL_HAVE_XMSS)
|
||||
else if (strcmp(argv[i], "--xmss") == 0) {
|
||||
keytype = KEYGEN_XMSS;
|
||||
}
|
||||
#endif
|
||||
else if (strcmp(argv[i], "--force") == 0) {
|
||||
force = 1;
|
||||
|
|
|
@ -108,6 +108,13 @@ static inline int fp_truncate(FILE *f, size_t len)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_HAVE_XMSS)
|
||||
#include <wolfssl/wolfcrypt/xmss.h>
|
||||
#ifdef HAVE_LIBXMSS
|
||||
#include <wolfssl/wolfcrypt/ext_xmss.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_SIGNTOOL
|
||||
#include <wolfssl/wolfcrypt/logging.h>
|
||||
#endif
|
||||
|
@ -169,6 +176,7 @@ static inline int fp_truncate(FILE *f, size_t len)
|
|||
#define SIGN_ECC384 HDR_IMG_TYPE_AUTH_ECC384
|
||||
#define SIGN_ECC521 HDR_IMG_TYPE_AUTH_ECC521
|
||||
#define SIGN_LMS HDR_IMG_TYPE_AUTH_LMS
|
||||
#define SIGN_XMSS HDR_IMG_TYPE_AUTH_XMSS
|
||||
|
||||
|
||||
#define ENC_OFF 0
|
||||
|
@ -203,6 +211,10 @@ static void header_append_tag(uint8_t* header, uint32_t* idx, uint16_t tag,
|
|||
#include "../lms/lms_common.h"
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_HAVE_XMSS
|
||||
#include "../xmss/xmss_common.h"
|
||||
#endif
|
||||
|
||||
/* Globals */
|
||||
static const char wolfboot_delta_file[] = "/tmp/wolfboot-delta.bin";
|
||||
|
||||
|
@ -222,6 +234,9 @@ static union {
|
|||
#ifdef WOLFSSL_HAVE_LMS
|
||||
LmsKey lms;
|
||||
#endif
|
||||
#ifdef WOLFSSL_HAVE_XMSS
|
||||
XmssKey xmss;
|
||||
#endif
|
||||
} key;
|
||||
|
||||
struct cmd_options {
|
||||
|
@ -736,6 +751,57 @@ static uint8_t *load_key(uint8_t **key_buffer, uint32_t *key_buffer_sz,
|
|||
}
|
||||
}
|
||||
#endif /* WOLFSSL_HAVE_LMS */
|
||||
|
||||
#ifdef WOLFSSL_HAVE_XMSS
|
||||
FALL_THROUGH;
|
||||
case SIGN_XMSS:
|
||||
ret = -1;
|
||||
|
||||
if (CMD.sign == SIGN_AUTO) {
|
||||
/* XMSS is stateful and requires additional config, and is not
|
||||
* compatible with SIGN_AUTO. */
|
||||
printf("error: SIGN_AUTO with XMSS is not supported\n");
|
||||
}
|
||||
else {
|
||||
/* The XMSS file callbacks will handle writing and reading the
|
||||
* private key. We only need to set the public key here.
|
||||
*
|
||||
* If both priv/pub are present:
|
||||
* - The first ?? bytes is the private key.
|
||||
* - The next 60 bytes is the public key. */
|
||||
word32 priv_sz = 0;
|
||||
int xmss_ret = 0;
|
||||
|
||||
xmss_ret = wc_XmssKey_GetPrivLen(&key.xmss, &priv_sz);
|
||||
if (xmss_ret != 0 || priv_sz <= 0) {
|
||||
printf("error: wc_XmssKey_GetPrivLen returned %d\n",
|
||||
xmss_ret);
|
||||
break;
|
||||
}
|
||||
|
||||
printf("info: xmss sk len: %d\n", priv_sz);
|
||||
printf("info: xmss pk len: %d\n", KEYSTORE_PUBKEY_SIZE_XMSS);
|
||||
|
||||
if (*key_buffer_sz == (priv_sz + KEYSTORE_PUBKEY_SIZE_XMSS)) {
|
||||
/* priv + pub */
|
||||
*pubkey = (*key_buffer) + priv_sz;
|
||||
*pubkey_sz = (*key_buffer_sz) - priv_sz;
|
||||
ret = 0;
|
||||
}
|
||||
else if (*key_buffer_sz == KEYSTORE_PUBKEY_SIZE_XMSS) {
|
||||
/* pub only. */
|
||||
*pubkey = (*key_buffer);
|
||||
*pubkey_sz = KEYSTORE_PUBKEY_SIZE_XMSS;
|
||||
ret = 0;
|
||||
}
|
||||
else {
|
||||
/* We don't recognize this as an XMSS pub or private key. */
|
||||
printf("error: unrecognized XMSS key size: %d\n",
|
||||
*key_buffer_sz );
|
||||
}
|
||||
}
|
||||
#endif /* WOLFSSL_HAVE_XMSS */
|
||||
|
||||
break;
|
||||
} /* end switch (CMD.sign) */
|
||||
|
||||
|
@ -868,6 +934,35 @@ static int sign_digest(int sign, int hash_algo,
|
|||
}
|
||||
else
|
||||
#endif /* WOLFSSL_HAVE_LMS */
|
||||
#ifdef WOLFSSL_HAVE_XMSS
|
||||
if (sign == SIGN_XMSS) {
|
||||
ret = wc_XmssKey_Init(&key.xmss, NULL, INVALID_DEVID);
|
||||
/* Set the callbacks, so XMSS can update the private key while signing */
|
||||
if (ret == 0) {
|
||||
ret = wc_XmssKey_SetWriteCb(&key.xmss, xmss_write_key);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_XmssKey_SetReadCb(&key.xmss, xmss_read_key);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_XmssKey_SetContext(&key.xmss, (void*)CMD.key_file);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_XmssKey_SetParamStr(&key.xmss, XMSS_PARAMS);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_XmssKey_Reload(&key.xmss);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_XmssKey_Sign(&key.xmss, signature, signature_sz, digest,
|
||||
digest_sz);
|
||||
}
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "error signing with XMSS: %d\n", ret);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* WOLFSSL_HAVE_XMSS */
|
||||
{
|
||||
ret = NOT_COMPILED_IN;
|
||||
}
|
||||
|
@ -1769,6 +1864,12 @@ int main(int argc, char** argv)
|
|||
CMD.sign = SIGN_LMS;
|
||||
sign_str = "LMS";
|
||||
}
|
||||
#endif
|
||||
#ifdef WOLFSSL_HAVE_XMSS
|
||||
else if (strcmp(argv[i], "--xmss") == 0) {
|
||||
CMD.sign = SIGN_XMSS;
|
||||
sign_str = "XMSS";
|
||||
}
|
||||
#endif
|
||||
else if (strcmp(argv[i], "--sha256") == 0) {
|
||||
CMD.hash_algo = HASH_SHA256;
|
||||
|
@ -1980,6 +2081,39 @@ int main(int argc, char** argv)
|
|||
CMD.signature_sz = sig_sz;
|
||||
}
|
||||
#endif /* WOLFSSL_HAVE_LMS */
|
||||
#ifdef WOLFSSL_HAVE_XMSS
|
||||
else if (CMD.sign == SIGN_XMSS) {
|
||||
int xmss_ret = 0;
|
||||
word32 sig_sz = 0;
|
||||
|
||||
xmss_ret = wc_XmssKey_Init(&key.xmss, NULL, INVALID_DEVID);
|
||||
if (xmss_ret != 0) {
|
||||
fprintf(stderr, "error: wc_XmssKey_Init returned %d\n", xmss_ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
xmss_ret = wc_XmssKey_SetParamStr(&key.xmss, XMSS_PARAMS);
|
||||
if (xmss_ret != 0) {
|
||||
fprintf(stderr, "error: wc_XmssKey_SetParamStr(%s)" \
|
||||
" returned %d\n", XMSS_PARAMS, ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("info: using XMSS parameters: %s\n", XMSS_PARAMS);
|
||||
|
||||
xmss_ret = wc_XmssKey_GetSigLen(&key.xmss, &sig_sz);
|
||||
if (xmss_ret != 0) {
|
||||
fprintf(stderr, "error: wc_XmssKey_GetSigLen returned %d\n",
|
||||
xmss_ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("info: XMSS signature size: %d\n", sig_sz);
|
||||
|
||||
CMD.header_sz = 2 * sig_sz;
|
||||
CMD.signature_sz = sig_sz;
|
||||
}
|
||||
#endif /* WOLFSSL_HAVE_XMSS */
|
||||
|
||||
if (((CMD.sign != NO_SIGN) && (CMD.signature_sz == 0)) ||
|
||||
CMD.header_sz == 0) {
|
||||
|
|
|
@ -53,6 +53,9 @@ endif
|
|||
ifeq ($(SIGN),LMS)
|
||||
SIGN_ARGS+= --lms
|
||||
endif
|
||||
ifeq ($(SIGN),XMSS)
|
||||
SIGN_ARGS+= --xmss
|
||||
endif
|
||||
|
||||
# Make sign hash argument
|
||||
ifeq ($(HASH),SHA256)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,146 @@
|
|||
/* xmss_common.h
|
||||
*
|
||||
* Common callback functions used by XMSS to write/read the private
|
||||
* key file.
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2023 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot 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.
|
||||
*
|
||||
* wolfBoot 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 XMSS_COMMON_H
|
||||
#define XMSS_COMMON_H
|
||||
static enum wc_XmssRc xmss_write_key(const byte * priv, word32 privSz, void * context)
|
||||
{
|
||||
FILE * file = NULL;
|
||||
const char * filename = NULL;
|
||||
int n_cmp = 0;
|
||||
size_t n_read = 0;
|
||||
size_t n_write = 0;
|
||||
byte * buff = NULL;
|
||||
int err = 0;
|
||||
|
||||
if (priv == NULL || context == NULL || privSz == 0) {
|
||||
fprintf(stderr, "error: invalid write args\n");
|
||||
return WC_XMSS_RC_BAD_ARG;
|
||||
}
|
||||
|
||||
filename = context;
|
||||
|
||||
/* Open file for read and write. */
|
||||
file = fopen(filename, "r+");
|
||||
if (!file) {
|
||||
/* Create the file if it didn't exist. */
|
||||
file = fopen(filename, "w+");
|
||||
if (!file) {
|
||||
fprintf(stderr, "error: fopen(%s, \"w+\") failed: %d\n", filename,
|
||||
ferror(file));
|
||||
return WC_XMSS_RC_WRITE_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
n_write = fwrite(priv, 1, privSz, file);
|
||||
|
||||
if (n_write != privSz) {
|
||||
fprintf(stderr, "error: wrote %zu, expected %d: %d\n", n_write, privSz,
|
||||
ferror(file));
|
||||
return WC_XMSS_RC_WRITE_FAIL;
|
||||
}
|
||||
|
||||
err = fclose(file);
|
||||
if (err) {
|
||||
fprintf(stderr, "error: fclose returned %d\n", err);
|
||||
return WC_XMSS_RC_WRITE_FAIL;
|
||||
}
|
||||
|
||||
/* Verify private key data has actually been written to persistent
|
||||
* storage correctly. */
|
||||
file = fopen(filename, "r+");
|
||||
if (!file) {
|
||||
fprintf(stderr, "error: fopen(%s, \"r+\") failed: %d\n", filename,
|
||||
ferror(file));
|
||||
return WC_XMSS_RC_WRITE_FAIL;
|
||||
}
|
||||
|
||||
buff = malloc(privSz);
|
||||
if (buff == NULL) {
|
||||
fprintf(stderr, "error: malloc(%d) failed\n", privSz);
|
||||
return WC_XMSS_RC_WRITE_FAIL;
|
||||
}
|
||||
|
||||
XMEMSET(buff, 0, n_write);
|
||||
|
||||
n_read = fread(buff, 1, n_write, file);
|
||||
|
||||
if (n_read != n_write) {
|
||||
fprintf(stderr, "error: read %zu, expected %zu: %d\n", n_read, n_write,
|
||||
ferror(file));
|
||||
free(buff);
|
||||
return WC_XMSS_RC_WRITE_FAIL;
|
||||
}
|
||||
|
||||
n_cmp = XMEMCMP(buff, priv, n_write);
|
||||
free(buff);
|
||||
buff = NULL;
|
||||
|
||||
if (n_cmp != 0) {
|
||||
fprintf(stderr, "error: write data was corrupted: %d\n", n_cmp);
|
||||
return WC_XMSS_RC_WRITE_FAIL;
|
||||
}
|
||||
|
||||
err = fclose(file);
|
||||
if (err) {
|
||||
fprintf(stderr, "error: fclose returned %d\n", err);
|
||||
return WC_XMSS_RC_WRITE_FAIL;
|
||||
}
|
||||
|
||||
return WC_XMSS_RC_SAVED_TO_NV_MEMORY;
|
||||
}
|
||||
|
||||
static enum wc_XmssRc xmss_read_key(byte * priv, word32 privSz, void * context)
|
||||
{
|
||||
FILE * file = NULL;
|
||||
const char * filename = NULL;
|
||||
size_t n_read = 0;
|
||||
|
||||
if (priv == NULL || context == NULL || privSz == 0) {
|
||||
fprintf(stderr, "error: invalid read args\n");
|
||||
return WC_XMSS_RC_BAD_ARG;
|
||||
}
|
||||
|
||||
filename = context;
|
||||
|
||||
file = fopen(filename, "rb");
|
||||
if (!file) {
|
||||
fprintf(stderr, "error: fopen(%s, \"rb\") failed\n", filename);
|
||||
return WC_XMSS_RC_READ_FAIL;
|
||||
}
|
||||
|
||||
n_read = fread(priv, 1, privSz, file);
|
||||
|
||||
if (n_read != privSz) {
|
||||
fprintf(stderr, "error: read %zu, expected %d: %d\n", n_read, privSz,
|
||||
ferror(file));
|
||||
return WC_XMSS_RC_READ_FAIL;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return WC_XMSS_RC_READ_TO_MEMORY;
|
||||
}
|
||||
#endif /* XMSS_COMMON_H */
|
|
@ -0,0 +1,93 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Prints the XMSS/XMSS^MT signature length given a parameter set string.
|
||||
#
|
||||
# References:
|
||||
# - https://www.rfc-editor.org/rfc/rfc8391.html
|
||||
# - https://eprint.iacr.org/2017/349.pdf
|
||||
|
||||
print_usage_and_exit() {
|
||||
echo "usage:"
|
||||
echo " ./xmss_siglen.sh <parameter string>"
|
||||
echo ""
|
||||
echo "examples:"
|
||||
echo " ./xmss_siglen.sh XMSS-SHA2_10_256"
|
||||
echo " ./xmss_siglen.sh XMSS-SHA2_16_256"
|
||||
echo " ./xmss_siglen.sh XMSS-SHA2_20_256"
|
||||
echo " ./xmss_siglen.sh XMSSMT-SHA2_20/2_256"
|
||||
echo " ./xmss_siglen.sh XMSSMT-SHA2_20/4_256"
|
||||
echo " ./xmss_siglen.sh XMSSMT-SHA2_40/2_256"
|
||||
echo " ./xmss_siglen.sh XMSSMT-SHA2_40/4_256"
|
||||
echo " ./xmss_siglen.sh XMSSMT-SHA2_40/8_256"
|
||||
echo " ./xmss_siglen.sh XMSSMT-SHA2_60/3_256"
|
||||
echo " ./xmss_siglen.sh XMSSMT-SHA2_60/6_256"
|
||||
echo " ./xmss_siglen.sh XMSSMT-SHA2_60/12_256"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
print_usage_and_exit
|
||||
fi
|
||||
|
||||
param=$1
|
||||
len=${#param}
|
||||
|
||||
n=32
|
||||
p=67
|
||||
h=0
|
||||
d=1
|
||||
|
||||
if [[ "$len" != @("16"|"20"|"21") ]]; then
|
||||
echo "error: invalid len: $len"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $len == 16 ]]; then
|
||||
# Must be one of these three:
|
||||
# - "XMSS-SHA2_10_256"
|
||||
# - "XMSS-SHA2_16_256"
|
||||
# - "XMSS-SHA2_20_256"
|
||||
if [[ $param =~ "XMSS-SHA2_" && $param =~ "_256" ]]; then
|
||||
h=$(echo $param | cut -c 11-12)
|
||||
else
|
||||
echo "error: invalid param string: $param"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# In XMSS the signature length is:
|
||||
# siglen = 4 + n(p + h + 1)
|
||||
siglen=$((4 + n * (p + h + 1)))
|
||||
else
|
||||
# Must be one of these 8:
|
||||
# - "XMSSMT-SHA2_20/2_256"
|
||||
# - "XMSSMT-SHA2_20/4_256"
|
||||
# - "XMSSMT-SHA2_40/2_256"
|
||||
# - "XMSSMT-SHA2_40/4_256"
|
||||
# - "XMSSMT-SHA2_40/8_256"
|
||||
# - "XMSSMT-SHA2_60/3_256"
|
||||
# - "XMSSMT-SHA2_60/6_256"
|
||||
# - "XMSSMT-SHA2_60/12_256"
|
||||
#
|
||||
if [[ $param =~ "XMSSMT-SHA2_" && $param =~ "_256" ]]; then
|
||||
h=$(echo $param | cut -c 13-14)
|
||||
else
|
||||
echo "error: invalid param string: $param"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $len == 20 ]]; then
|
||||
d=$(echo $param | cut -c 16-16)
|
||||
else
|
||||
d=$(echo $param | cut -c 16-17)
|
||||
fi
|
||||
|
||||
# In XMSS^MT the signature length is:
|
||||
# siglen = Sum[h]/8 + n (Sum[p] + Sum[h] + 1)
|
||||
#
|
||||
# Where Sum[h] means the total height of the hyper-tree.
|
||||
# Note: The Sum[h]/8 must be rounded up.
|
||||
siglen=$((((h + 7) / 8) + n * ((d * p) + h + 1)))
|
||||
fi
|
||||
|
||||
echo "parameter set: $param"
|
||||
echo "signature length: $siglen"
|
Loading…
Reference in New Issue