diff --git a/.gitignore b/.gitignore index c6432ad..f77ab37 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,9 @@ test/test_xmssmt_core_XMSSMT* test/test_xmssmt_core_fast_XMSSMT* test/speed test/gen_testvectors +test/xmss_keypair +test/xmss_open +test/xmss_sign +test/xmssmt_keypair +test/xmssmt_open +test/xmssmt_sign diff --git a/Makefile b/Makefile index b0e9571..3ce49a3 100644 --- a/Makefile +++ b/Makefile @@ -1,42 +1,41 @@ CC = /usr/bin/gcc CFLAGS = -Wall -g -O3 -Wextra +LDLIBS = -lcrypto -lm -all: test/test_wots \ -test/test_xmss_core \ -test/test_xmss_core_fast \ -test/test_xmss \ -test/test_xmssmt_core_fast \ -test/test_xmssmt_core \ -test/test_xmssmt +SOURCES = params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss.c xmss_core.c xmss_commons.c +HEADERS = params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss.h xmss_core.h xmss_commons.h -.PHONY: clean +SOURCES_FAST = $(subst core,core_fast,$(SOURCES)) +HEADERS_FAST = $(subst core,core_fast,$(HEADERS)) -test/test_wots: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_commons.c test/test_wots.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_commons.h - $(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_commons.c test/test_wots.c -o $@ -lcrypto -lm +TESTS = test/test_wots \ + test/test_xmss_core \ + test/test_xmss_core_fast \ + test/test_xmss \ + test/test_xmssmt_core_fast \ + test/test_xmssmt_core \ + test/test_xmssmt \ -test/test_xmss_core: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c test/test_xmss_core.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core.h xmss_commons.h - $(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c test/test_xmss_core.c -o $@ -lcrypto -lm +UI = test/xmss_keypair \ + test/xmss_sign \ + test/xmss_open \ + test/xmssmt_keypair \ + test/xmssmt_sign \ + test/xmssmt_open \ -test/test_xmss_core_fast: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core_fast.c xmss_commons.c test/test_xmss_core_fast.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core_fast.h xmss_commons.h - $(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core_fast.c xmss_commons.c test/test_xmss_core_fast.c -o $@ -lcrypto -lm +all: $(TESTS) $(UI) -test/test_xmssmt_core: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c test/test_xmssmt_core.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core.h xmss_commons.h - $(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c test/test_xmssmt_core.c -o $@ -lcrypto -lm +.PHONY: clean -test/test_xmssmt_core_fast: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core_fast.c xmss_commons.c test/test_xmssmt_core_fast.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core_fast.h xmss_commons.h - $(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core_fast.c xmss_commons.c test/test_xmssmt_core_fast.c -o $@ -lcrypto -lm +test/%_fast: test/%_fast.c $(SOURCES_FAST) $(OBJS) $(HEADERS_FAST) + $(CC) $(CFLAGS) -o $@ $(SOURCES_FAST) $< $(LDLIBS) -test/test_xmss: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c xmss.c test/test_xmss.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core.h xmss_commons.h xmss.h - $(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c xmss.c test/test_xmss.c -o $@ -lcrypto -lm +test/%: test/%.c $(SOURCES) $(OBJS) $(HEADERS) + $(CC) $(CFLAGS) -o $@ $(SOURCES) $< $(LDLIBS) -test/test_xmssmt: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c xmss.c test/test_xmssmt.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core.h xmss_commons.h xmss.h - $(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c xmss.c test/test_xmssmt.c -o $@ -lcrypto -lm +test/test_wots: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_commons.c test/test_wots.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_commons.h + $(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_commons.c test/test_wots.c -o $@ -lcrypto -lm clean: - -rm test/test_wots - -rm test/test_xmss_core - -rm test/test_xmss_core_fast - -rm test/test_xmss - -rm test/test_xmssmt_core - -rm test/test_xmssmt_core_fast - -rm test/test_xmssmt + -$(RM) $(TESTS) + -$(RM) $(UI) diff --git a/params.c b/params.c index 1282de4..f947e70 100644 --- a/params.c +++ b/params.c @@ -1,6 +1,155 @@ #include +#include #include "params.h" +int xmss_str_to_oid(uint32_t *oid, const char *s) +{ + if (!strcmp(s, "XMSS-SHA2_10_256")) { + *oid = 0x01000001; + } + else if (!strcmp(s, "XMSS-SHA2_16_256")) { + *oid = 0x02000002; + } + else if (!strcmp(s, "XMSS-SHA2_20_256")) { + *oid = 0x03000003; + } + else if (!strcmp(s, "XMSS-SHA2_10_512")) { + *oid = 0x04000004; + } + else if (!strcmp(s, "XMSS-SHA2_16_512")) { + *oid = 0x05000005; + } + else if (!strcmp(s, "XMSS-SHA2_20_512")) { + *oid = 0x06000006; + } + else if (!strcmp(s, "XMSS-SHAKE_10_256")) { + *oid = 0x07000007; + } + else if (!strcmp(s, "XMSS-SHAKE_16_256")) { + *oid = 0x08000008; + } + else if (!strcmp(s, "XMSS-SHAKE_20_256")) { + *oid = 0x09000009; + } + else if (!strcmp(s, "XMSS-SHAKE_10_512")) { + *oid = 0x0a00000a; + } + else if (!strcmp(s, "XMSS-SHAKE_16_512")) { + *oid = 0x0b00000b; + } + else if (!strcmp(s, "XMSS-SHAKE_20_512")) { + *oid = 0x0c00000c; + } + else { + return -1; + } + return 0; +} + +int xmssmt_str_to_oid(uint32_t *oid, const char *s) +{ + if (!strcmp(s, "XMSSMT-SHA2_20/2_256")) { + *oid = 0x01000001; + } + else if (!strcmp(s, "XMSSMT-SHA2_20/4_256")) { + *oid = 0x02000002; + } + else if (!strcmp(s, "XMSSMT-SHA2_40/2_256")) { + *oid = 0x03000003; + } + else if (!strcmp(s, "XMSSMT-SHA2_40/4_256")) { + *oid = 0x04000004; + } + else if (!strcmp(s, "XMSSMT-SHA2_40/8_256")) { + *oid = 0x05000005; + } + else if (!strcmp(s, "XMSSMT-SHA2_60/3_256")) { + *oid = 0x06000006; + } + else if (!strcmp(s, "XMSSMT-SHA2_60/6_256")) { + *oid = 0x07000007; + } + else if (!strcmp(s, "XMSSMT-SHA2_60/12_256")) { + *oid = 0x08000008; + } + else if (!strcmp(s, "XMSSMT-SHA2_20/2_512")) { + *oid = 0x09000009; + } + else if (!strcmp(s, "XMSSMT-SHA2_20/4_512")) { + *oid = 0x0a00000a; + } + else if (!strcmp(s, "XMSSMT-SHA2_40/2_512")) { + *oid = 0x0b00000b; + } + else if (!strcmp(s, "XMSSMT-SHA2_40/4_512")) { + *oid = 0x0c00000c; + } + else if (!strcmp(s, "XMSSMT-SHA2_40/8_512")) { + *oid = 0x0d00000d; + } + else if (!strcmp(s, "XMSSMT-SHA2_60/3_512")) { + *oid = 0x0e00000e; + } + else if (!strcmp(s, "XMSSMT-SHA2_60/6_512")) { + *oid = 0x0f00000f; + } + else if (!strcmp(s, "XMSSMT-SHA2_60/12_512")) { + *oid = 0x01010101; + } + else if (!strcmp(s, "XMSSMT-SHAKE_20/2_256")) { + *oid = 0x02010102; + } + else if (!strcmp(s, "XMSSMT-SHAKE_20/4_256")) { + *oid = 0x03010103; + } + else if (!strcmp(s, "XMSSMT-SHAKE_40/2_256")) { + *oid = 0x04010104; + } + else if (!strcmp(s, "XMSSMT-SHAKE_40/4_256")) { + *oid = 0x05010105; + } + else if (!strcmp(s, "XMSSMT-SHAKE_40/8_256")) { + *oid = 0x06010106; + } + else if (!strcmp(s, "XMSSMT-SHAKE_60/3_256")) { + *oid = 0x07010107; + } + else if (!strcmp(s, "XMSSMT-SHAKE_60/6_256")) { + *oid = 0x08010108; + } + else if (!strcmp(s, "XMSSMT-SHAKE_60/12_256")) { + *oid = 0x09010109; + } + else if (!strcmp(s, "XMSSMT-SHAKE_20/2_512")) { + *oid = 0x0a01010a; + } + else if (!strcmp(s, "XMSSMT-SHAKE_20/4_512")) { + *oid = 0x0b01010b; + } + else if (!strcmp(s, "XMSSMT-SHAKE_40/2_512")) { + *oid = 0x0c01010c; + } + else if (!strcmp(s, "XMSSMT-SHAKE_40/4_512")) { + *oid = 0x0d01010d; + } + else if (!strcmp(s, "XMSSMT-SHAKE_40/8_512")) { + *oid = 0x0e01010e; + } + else if (!strcmp(s, "XMSSMT-SHAKE_60/3_512")) { + *oid = 0x0f01010f; + } + else if (!strcmp(s, "XMSSMT-SHAKE_60/6_512")) { + *oid = 0x01020201; + } + else if (!strcmp(s, "XMSSMT-SHAKE_60/12_512")) { + *oid = 0x02020202; + } + else { + return -1; + } + return 0; +} + int xmss_parse_oid(xmss_params *params, const uint32_t oid) { switch (oid) { diff --git a/params.h b/params.h index 7b6f82c..c15a80d 100644 --- a/params.h +++ b/params.h @@ -30,6 +30,9 @@ typedef struct { unsigned int bds_k; } xmss_params; +int xmss_str_to_oid(uint32_t *oid, const char* s); +int xmssmt_str_to_oid(uint32_t *oid, const char* s); + int xmss_parse_oid(xmss_params *params, const uint32_t oid); int xmssmt_parse_oid(xmss_params *params, const uint32_t oid); diff --git a/test/xmss_keypair.c b/test/xmss_keypair.c new file mode 100644 index 0000000..d36c5ba --- /dev/null +++ b/test/xmss_keypair.c @@ -0,0 +1,30 @@ +#include "../params.h" +#include "../xmss.h" +#include +#include + +int main(int argc, char **argv) +{ + xmss_params params; + uint32_t oid; + + if (argc != 2) { + fprintf(stderr, "Expected parameter string (e.g. 'XMSS-SHA2_10_256')" + " as only parameter.\n" + "The keypair is written to stdout.\n"); + return -1; + } + + xmss_str_to_oid(&oid, argv[1]); + xmss_parse_oid(¶ms, oid); + + unsigned char pk[XMSS_OID_LEN + params.publickey_bytes]; + unsigned char sk[XMSS_OID_LEN + params.privatekey_bytes]; + + xmss_keypair(pk, sk, oid); + + fwrite(pk, 1, XMSS_OID_LEN + params.publickey_bytes, stdout); + fwrite(sk, 1, XMSS_OID_LEN + params.privatekey_bytes, stdout); + + fclose(stdout); +} diff --git a/test/xmss_open.c b/test/xmss_open.c new file mode 100644 index 0000000..05ec8fe --- /dev/null +++ b/test/xmss_open.c @@ -0,0 +1,47 @@ +#include "../params.h" +#include "../xmss_core.h" +#include + +#define MLEN 32 + +int main(int argc, char **argv) { + FILE *keypair; + xmss_params params; + uint32_t oid; + int ret; + + if (argc != 2) { + fprintf(stderr, "Expected keypair filename as only parameter, " + "and the message + signature via stdin.\n" + "Keypair file needs only to contain the public key.\n" + "The return code 0 indicates verification success.\n"); + return -1; + } + + keypair = fopen(argv[1], "rb"); + if (keypair == NULL) { + return -1; + } + + fread(&oid, 1, XMSS_OID_LEN, keypair); + xmss_parse_oid(¶ms, oid); + + unsigned char pk[params.publickey_bytes]; + unsigned char sm[params.bytes + MLEN]; + unsigned char m[params.bytes + MLEN]; + unsigned long long mlen; + + fread(pk, 1, params.publickey_bytes, keypair); + fread(sm, 1, params.bytes + MLEN, stdin); + + ret = xmss_core_sign_open(¶ms, m, &mlen, sm, params.bytes + MLEN, pk); + + if (ret) { + printf("Verification failed!\n"); + } + else { + printf("Verification succeeded.\n"); + } + + return ret; +} diff --git a/test/xmss_sign.c b/test/xmss_sign.c new file mode 100644 index 0000000..13c0615 --- /dev/null +++ b/test/xmss_sign.c @@ -0,0 +1,52 @@ +#include "../params.h" +#include "../xmss_core.h" +#include + +#define MLEN 32 + +int main(int argc, char **argv) { + FILE *keypair; + xmss_params params; + uint32_t oid_pk; + uint32_t oid_sk; + + if (argc != 2) { + fprintf(stderr, "Expected keypair filename as only parameter, " + "and the message via stdin.\n" + "The keypair is updated with the changed state, " + "and the message + signature is output via stdout.\n"); + return -1; + } + + keypair = fopen(argv[1], "rb"); + if (keypair == NULL) { + fprintf(stderr, "Could not open keypair file.\n"); + return -1; + } + + // Read the OID from the public key, as we need its length to seek past it + fread(&oid_pk, 1, XMSS_OID_LEN, keypair); + xmss_parse_oid(¶ms, oid_pk); + + // fseek past the public key + fseek(keypair, params.publickey_bytes, SEEK_CUR); + // This is the OID we're actually going to use. Likely the same, but still. + fread(&oid_sk, 1, XMSS_OID_LEN, keypair); + xmss_parse_oid(¶ms, oid_sk); + + unsigned char sk[params.privatekey_bytes]; + unsigned char m[MLEN]; + unsigned char sm[params.bytes + MLEN]; + unsigned long long smlen; + + fread(sk, 1, params.privatekey_bytes, keypair); + fread(m, 1, MLEN, stdin); + xmss_core_sign(¶ms, sk, sm, &smlen, m, MLEN); + + fseek(keypair, -params.privatekey_bytes, SEEK_CUR); + fwrite(sk, 1, params.privatekey_bytes, keypair); + fwrite(sm, 1, params.bytes + MLEN, stdout); + + fclose(keypair); + fclose(stdout); +} diff --git a/test/xmssmt_keypair.c b/test/xmssmt_keypair.c new file mode 100644 index 0000000..6e2982f --- /dev/null +++ b/test/xmssmt_keypair.c @@ -0,0 +1,30 @@ +#include "../params.h" +#include "../xmss.h" +#include +#include + +int main(int argc, char **argv) +{ + xmss_params params; + uint32_t oid; + + if (argc != 2) { + fprintf(stderr, "Expected parameter string (e.g. 'XMSS-SHA2_10_256')" + " as only parameter.\n" + "The keypair is written to stdout.\n"); + return -1; + } + + xmssmt_str_to_oid(&oid, argv[1]); + xmssmt_parse_oid(¶ms, oid); + + unsigned char pk[XMSS_OID_LEN + params.publickey_bytes]; + unsigned char sk[XMSS_OID_LEN + params.privatekey_bytes]; + + xmssmt_keypair(pk, sk, oid); + + fwrite(pk, 1, XMSS_OID_LEN + params.publickey_bytes, stdout); + fwrite(sk, 1, XMSS_OID_LEN + params.privatekey_bytes, stdout); + + fclose(stdout); +} diff --git a/test/xmssmt_open.c b/test/xmssmt_open.c new file mode 100644 index 0000000..2636f95 --- /dev/null +++ b/test/xmssmt_open.c @@ -0,0 +1,47 @@ +#include "../params.h" +#include "../xmss_core.h" +#include + +#define MLEN 32 + +int main(int argc, char **argv) { + FILE *keypair; + xmss_params params; + uint32_t oid; + int ret; + + if (argc != 2) { + fprintf(stderr, "Expected keypair filename as only parameter, " + "and the message + signature via stdin.\n" + "Keypair file needs only to contain the public key.\n" + "The return code 0 indicates verification success.\n"); + return -1; + } + + keypair = fopen(argv[1], "rb"); + if (keypair == NULL) { + return -1; + } + + fread(&oid, 1, XMSS_OID_LEN, keypair); + xmssmt_parse_oid(¶ms, oid); + + unsigned char pk[params.publickey_bytes]; + unsigned char sm[params.bytes + MLEN]; + unsigned char m[params.bytes + MLEN]; + unsigned long long mlen; + + fread(pk, 1, params.publickey_bytes, keypair); + fread(sm, 1, params.bytes + MLEN, stdin); + + ret = xmssmt_core_sign_open(¶ms, m, &mlen, sm, params.bytes + MLEN, pk); + + if (ret) { + printf("Verification failed!\n"); + } + else { + printf("Verification succeeded.\n"); + } + + return ret; +} diff --git a/test/xmssmt_sign.c b/test/xmssmt_sign.c new file mode 100644 index 0000000..f709366 --- /dev/null +++ b/test/xmssmt_sign.c @@ -0,0 +1,52 @@ +#include "../params.h" +#include "../xmss_core.h" +#include + +#define MLEN 32 + +int main(int argc, char **argv) { + FILE *keypair; + xmss_params params; + uint32_t oid_pk; + uint32_t oid_sk; + + if (argc != 2) { + fprintf(stderr, "Expected keypair filename as only parameter, " + "and the message via stdin.\n" + "The keypair is updated with the changed state, " + "and the message + signature is output via stdout.\n"); + return -1; + } + + keypair = fopen(argv[1], "rb"); + if (keypair == NULL) { + fprintf(stderr, "Could not open keypair file.\n"); + return -1; + } + + // Read the OID from the public key, as we need its length to seek past it + fread(&oid_pk, 1, XMSS_OID_LEN, keypair); + xmssmt_parse_oid(¶ms, oid_pk); + + // fseek past the public key + fseek(keypair, params.publickey_bytes, SEEK_CUR); + // This is the OID we're actually going to use. Likely the same, but still. + fread(&oid_sk, 1, XMSS_OID_LEN, keypair); + xmssmt_parse_oid(¶ms, oid_sk); + + unsigned char sk[params.privatekey_bytes]; + unsigned char m[MLEN]; + unsigned char sm[params.bytes + MLEN]; + unsigned long long smlen; + + fread(sk, 1, params.privatekey_bytes, keypair); + fread(m, 1, MLEN, stdin); + xmssmt_core_sign(¶ms, sk, sm, &smlen, m, MLEN); + + fseek(keypair, -params.privatekey_bytes, SEEK_CUR); + fwrite(sk, 1, params.privatekey_bytes, keypair); + fwrite(sm, 1, params.bytes + MLEN, stdout); + + fclose(keypair); + fclose(stdout); +}