mirror of
https://github.com/guanzhi/GmSSL.git
synced 2026-05-07 08:56:17 +08:00
add sphincs
This commit is contained in:
46
crypto/sphincs/.clang-format
Normal file
46
crypto/sphincs/.clang-format
Normal file
@@ -0,0 +1,46 @@
|
||||
AccessModifierOffset: 0
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortFunctionsOnASingleLine: true
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
BinPackParameters: false
|
||||
BreakBeforeBinaryOperators: false
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: ''
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 0
|
||||
ContinuationIndentWidth: 0
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerBinding: false
|
||||
IndentCaseLabels: false
|
||||
IndentFunctionDeclarationAfterType: false
|
||||
IndentWidth: 4
|
||||
Language: Cpp
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: None
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakBeforeFirstCallParameter: 100
|
||||
PenaltyBreakComment: 100
|
||||
PenaltyBreakFirstLessLess: 0
|
||||
PenaltyBreakString: 100
|
||||
PenaltyExcessCharacter: 1
|
||||
PenaltyReturnTypeOnItsOwnLine: 20
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: Always
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
3
crypto/sphincs/.gitignore
vendored
Normal file
3
crypto/sphincs/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
bench
|
||||
*.o
|
||||
*.dSYM
|
||||
13
crypto/sphincs/LICENSE
Normal file
13
crypto/sphincs/LICENSE
Normal file
@@ -0,0 +1,13 @@
|
||||
Copyright 2017 Nagravision S.A.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
52
crypto/sphincs/Makefile
Normal file
52
crypto/sphincs/Makefile
Normal file
@@ -0,0 +1,52 @@
|
||||
SRC=$(wildcard *.c) $(wildcard primitives/*.c)
|
||||
OBJ=$(patsubst %.c, %.o, $(SRC))
|
||||
|
||||
CFLAGS_COMMON=-std=c89 -pedantic -Wall -Wextra -Wno-long-long -march=native
|
||||
LDFLAGS=-lcrypto
|
||||
|
||||
VERSION_S= -DPORS_k=24 -DMERKLE_h=5 -DGRAVITY_d=1 -DGRAVITY_c=10
|
||||
VERSION_M= -DPORS_k=32 -DMERKLE_h=5 -DGRAVITY_d=7 -DGRAVITY_c=15
|
||||
VERSION_L= -DPORS_k=28 -DMERKLE_h=5 -DGRAVITY_d=10 -DGRAVITY_c=14
|
||||
|
||||
VERSION=$(VERSION_S)
|
||||
|
||||
CFLAGS_COMMON+=$(VERSION)
|
||||
CFLAGS=$(CFLAGS_COMMON) -O3 -fomit-frame-pointer
|
||||
CFLAGS_SANITIZED=$(CFLAGS_COMMON) -fsanitize=address,undefined -g
|
||||
|
||||
KERNEL_NAME := $(shell uname -s)
|
||||
ifeq ($(KERNEL_NAME), Darwin)
|
||||
CFLAGS += -I/usr/local/opt/openssl/include
|
||||
LDFLAGS += -L/usr/local/opt/openssl/lib
|
||||
endif
|
||||
|
||||
all: help
|
||||
|
||||
help:
|
||||
@echo "Please choose a target:"
|
||||
@echo "\tanalyze\t\t runs static analyzers"
|
||||
@echo "\tbench\t\t runs speed benchmarks"
|
||||
@echo "\tclean\t\t cleans up"
|
||||
@echo "\tformat\t\t formats the code using .clang-format rules"
|
||||
|
||||
bench: $(SRC)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o bench
|
||||
./bench
|
||||
|
||||
format:
|
||||
clang-format -i *.c *.h
|
||||
|
||||
analyze:
|
||||
cppcheck . --std=c89
|
||||
scan-build gcc -c $(CFLAGS_SANITIZED) *.c
|
||||
cppclean .
|
||||
rm -f *.o
|
||||
|
||||
cloc:
|
||||
cloc $(wildcard *.c) $(wildcard *.h)
|
||||
|
||||
clean:
|
||||
rm -f bench *.dSYM *.o
|
||||
|
||||
.PHONY: clean format analyze cloc bench
|
||||
|
||||
10
crypto/sphincs/aes.h
Normal file
10
crypto/sphincs/aes.h
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int aesctr256 (uint8_t *out, const uint8_t *sk, const void *counter, int bytes);
|
||||
|
||||
int aesctr256_zeroiv (uint8_t *out, const uint8_t *sk, int bytes);
|
||||
41
crypto/sphincs/api.h
Normal file
41
crypto/sphincs/api.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef CRYPTO_BYTES
|
||||
|
||||
/* setting CRYPTO_BYTES to the static structure size, for simplicity,
|
||||
as opposed to the actual message-dependent signature size */
|
||||
|
||||
#define CRYPTO_ALGNAME "Gravity-SPHINCS S"
|
||||
#define CRYPTO_SECRETKEYBYTES 65568
|
||||
#define CRYPTO_PUBLICKEYBYTES 32
|
||||
#define CRYPTO_BYTES 15728 // 12640
|
||||
|
||||
#if 0
|
||||
#define CRYPTO_ALGNAME "Gravity-SPHINCS M"
|
||||
#define CRYPTO_SECRETKEYBYTES 2097184
|
||||
#define CRYPTO_PUBLICKEYBYTES 32
|
||||
#define CRYPTO_BYTES 34064 // 28929
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define CRYPTO_ALGNAME "Gravity-SPHINCS L"
|
||||
#define CRYPTO_SECRETKEYBYTES 1048608
|
||||
#define CRYPTO_PUBLICKEYBYTES 32
|
||||
#define CRYPTO_BYTES 38768 // 35168
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
int crypto_sign_keypair (unsigned char *pk, unsigned char *sk);
|
||||
|
||||
int crypto_sign (unsigned char *sm,
|
||||
unsigned long long *smlen,
|
||||
const unsigned char *m,
|
||||
unsigned long long mlen,
|
||||
const unsigned char *sk);
|
||||
|
||||
int crypto_sign_open (unsigned char *m,
|
||||
unsigned long long *mlen,
|
||||
const unsigned char *sm,
|
||||
unsigned long long smlen,
|
||||
const unsigned char *pk);
|
||||
93
crypto/sphincs/batch.c
Normal file
93
crypto/sphincs/batch.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#include "batch.h"
|
||||
|
||||
#include "merkle.h"
|
||||
|
||||
int batch_init (struct batch_buf *buf) {
|
||||
buf->count = 0;
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
int batch_append (struct batch_buf *buf, const uint8_t *msg, uint64_t len, uint32_t *index) {
|
||||
if (buf->count == MAX_BATCH_COUNT) return GRAVITY_ERR_BATCH;
|
||||
|
||||
/* TODO: randomize this hash? */
|
||||
hash_to_N (&buf->buf[buf->count], msg, len);
|
||||
|
||||
*index = buf->count;
|
||||
++buf->count;
|
||||
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
int batch_group (struct batch_group *group, struct batch_buf *buf) {
|
||||
int height = LOG_MAX_BATCH_COUNT;
|
||||
int n = 1 << height;
|
||||
int offset = n - 1;
|
||||
|
||||
struct hash *src;
|
||||
struct hash *dst;
|
||||
uint32_t count;
|
||||
int i;
|
||||
|
||||
/* Check batch count */
|
||||
count = buf->count;
|
||||
if (count == 0) return GRAVITY_ERR_BATCH;
|
||||
group->count = count;
|
||||
|
||||
/* Leaves */
|
||||
dst = &group->tree[offset];
|
||||
|
||||
hashcpyN (dst, buf->buf, count);
|
||||
for (i = count; i < n; ++i) hashcpy (&dst[i], &buf->buf[0]);
|
||||
|
||||
/* Compress until root */
|
||||
while (height > 0) {
|
||||
offset >>= 1;
|
||||
--height;
|
||||
|
||||
src = dst;
|
||||
dst = &group->tree[offset];
|
||||
hash_compress_pairs (dst, src, 1 << height);
|
||||
}
|
||||
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
int batch_extract (const struct batch_group *group, struct batch_auth *auth, uint32_t index) {
|
||||
int height = LOG_MAX_BATCH_COUNT;
|
||||
int n = 1 << height;
|
||||
int offset = n - 1;
|
||||
|
||||
uint32_t count;
|
||||
int i, sibling;
|
||||
|
||||
/* Check batch count */
|
||||
count = group->count;
|
||||
if (index >= count) return GRAVITY_ERR_BATCH;
|
||||
|
||||
/* Convert row index into tree index */
|
||||
auth->index = offset + index;
|
||||
|
||||
/* Copy auth path */
|
||||
for (i = 0; i < height; ++i) {
|
||||
sibling = index ^ 1;
|
||||
hashcpy (&auth->auth[i], &group->tree[offset + sibling]);
|
||||
index >>= 1;
|
||||
offset >>= 1;
|
||||
}
|
||||
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
void batch_compress_auth (struct hash *node,
|
||||
const struct batch_auth *auth,
|
||||
const uint8_t *msg,
|
||||
uint64_t len) {
|
||||
/* Compute Merkle tree root */
|
||||
int height = LOG_MAX_BATCH_COUNT;
|
||||
hash_to_N (node, msg, len);
|
||||
merkle_compress_auth (node, auth->index, auth->auth, height);
|
||||
}
|
||||
34
crypto/sphincs/batch.h
Normal file
34
crypto/sphincs/batch.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
struct batch_buf {
|
||||
struct hash buf[MAX_BATCH_COUNT];
|
||||
uint32_t count;
|
||||
};
|
||||
|
||||
struct batch_group {
|
||||
struct hash tree[2 * MAX_BATCH_COUNT - 1];
|
||||
uint32_t count;
|
||||
};
|
||||
|
||||
struct batch_auth {
|
||||
struct hash auth[LOG_MAX_BATCH_COUNT];
|
||||
uint32_t index;
|
||||
};
|
||||
|
||||
int batch_init (struct batch_buf *buf);
|
||||
|
||||
int batch_append (struct batch_buf *buf, const uint8_t *msg, uint64_t len, uint32_t *index);
|
||||
|
||||
int batch_group (struct batch_group *group, struct batch_buf *buf);
|
||||
|
||||
int batch_extract (const struct batch_group *group, struct batch_auth *auth, uint32_t index);
|
||||
|
||||
void batch_compress_auth (struct hash *node,
|
||||
const struct batch_auth *auth,
|
||||
const uint8_t *msg,
|
||||
uint64_t len);
|
||||
97
crypto/sphincs/bench.c
Normal file
97
crypto/sphincs/bench.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
|
||||
#include "gravity.h"
|
||||
#include "randombytes.h"
|
||||
#include "sign.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define SKLEN sizeof (struct gravity_sk)
|
||||
#define PKLEN sizeof (struct gravity_pk)
|
||||
#define SIGLEN sizeof (struct gravity_sign)
|
||||
#define N 32
|
||||
#define ROUNDS 3
|
||||
|
||||
|
||||
int main () {
|
||||
|
||||
unsigned long long smlen;
|
||||
unsigned long long mlen = N;
|
||||
uint8_t sk[SKLEN];
|
||||
uint8_t pk[PKLEN];
|
||||
uint8_t m[N];
|
||||
uint8_t *sm = malloc (N + SIGLEN);
|
||||
struct timeval tm1, tm2;
|
||||
unsigned long long usecs;
|
||||
int ret = -1;
|
||||
int i;
|
||||
|
||||
if (!sm) {
|
||||
fprintf (stderr, "error: sm malloc failed\n");
|
||||
ret = 1;
|
||||
goto label_exit_0;
|
||||
}
|
||||
|
||||
printf ("k\t%d\n", PORS_k);
|
||||
printf ("h\t%d\n", MERKLE_h);
|
||||
printf ("d\t%d\n", GRAVITY_d);
|
||||
printf ("c\t%d\n", GRAVITY_c);
|
||||
printf ("sk len\t%d\n", (int)SKLEN);
|
||||
printf ("pk len\t%d\n", (int)PKLEN);
|
||||
printf ("sig len\t%d\n", (int)SIGLEN);
|
||||
|
||||
#define MEASURE(s) \
|
||||
do { \
|
||||
gettimeofday (&tm2, NULL); \
|
||||
usecs = 1000000 * (tm2.tv_sec - tm1.tv_sec) + (tm2.tv_usec - tm1.tv_usec); \
|
||||
printf ("\n# %s\n", s); \
|
||||
printf ("%.2f usec\n", (double)usecs); \
|
||||
} while (0)
|
||||
|
||||
randombytes (m, N);
|
||||
|
||||
gettimeofday (&tm1, NULL);
|
||||
|
||||
if (crypto_sign_keypair (pk, sk)) {
|
||||
fprintf (stderr, "error: crypto_sign_keypair failed\n");
|
||||
ret = 1;
|
||||
goto label_exit_2;
|
||||
}
|
||||
|
||||
MEASURE ("crypto_sign_keypair");
|
||||
|
||||
for (i = 0; i < ROUNDS; ++i) {
|
||||
|
||||
gettimeofday (&tm1, NULL);
|
||||
|
||||
if (crypto_sign (sm, &smlen, m, mlen, sk)) {
|
||||
fprintf (stderr, "error: crypto_sign failed\n");
|
||||
ret = 1;
|
||||
goto label_exit_2;
|
||||
}
|
||||
|
||||
MEASURE ("crypto_sign");
|
||||
gettimeofday (&tm1, NULL);
|
||||
|
||||
|
||||
if (crypto_sign_open (m, &mlen, sm, smlen, pk)) {
|
||||
fprintf (stderr, "error: crypto_sign_open failed\n");
|
||||
ret = 1;
|
||||
goto label_exit_2;
|
||||
}
|
||||
|
||||
m[0] ^= sm[33];
|
||||
|
||||
MEASURE ("crypto_sign_open");
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
label_exit_2:
|
||||
free (sm);
|
||||
label_exit_0:
|
||||
return ret;
|
||||
}
|
||||
47
crypto/sphincs/common.h
Normal file
47
crypto/sphincs/common.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#define HASH_SIZE 32
|
||||
|
||||
#define WOTS_LOG_ell1 6
|
||||
#define WOTS_ell1 (1 << (WOTS_LOG_ell1))
|
||||
#define WOTS_chksum 3
|
||||
#define WOTS_ell ((WOTS_ell1) + (WOTS_chksum))
|
||||
#define WOTS_w 16
|
||||
|
||||
/* set by compile flags */
|
||||
#if 0
|
||||
#define PORS_k 28
|
||||
#define MERKLE_h 5
|
||||
#define GRAVITY_d 10
|
||||
#define GRAVITY_c 14
|
||||
#endif
|
||||
|
||||
#define PORS_tau 16
|
||||
#define PORS_t (1 << (PORS_tau))
|
||||
|
||||
#define MERKLE_hhh (1 << (MERKLE_h))
|
||||
|
||||
#define GRAVITY_ccc (1 << (GRAVITY_c))
|
||||
#define GRAVITY_h ((MERKLE_h) * (GRAVITY_d) + (GRAVITY_c))
|
||||
|
||||
#if GRAVITY_h < 64
|
||||
#define GRAVITY_mask ~(0xFFFFFFFFFFFFFFFFull << (GRAVITY_h))
|
||||
#else
|
||||
#define GRAVITY_mask 0xFFFFFFFFFFFFFFFFull
|
||||
#endif
|
||||
|
||||
#define LOG_MAX_BATCH_COUNT 10
|
||||
#define MAX_BATCH_COUNT (1 << (LOG_MAX_BATCH_COUNT))
|
||||
|
||||
|
||||
#define GRAVITY_OK 0
|
||||
#define GRAVITY_ERR_VERIF 1
|
||||
#define GRAVITY_ERR_ALLOC 2
|
||||
#define GRAVITY_ERR_BATCH 3
|
||||
|
||||
#define U8TO32(p) \
|
||||
(((uint32_t) ((p)[0]) << 24) | ((uint32_t) ((p)[1]) << 16) | \
|
||||
((uint32_t) ((p)[2]) << 8) | ((uint32_t) ((p)[3])))
|
||||
196
crypto/sphincs/gravity.c
Normal file
196
crypto/sphincs/gravity.c
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
|
||||
#include "gravity.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
int gravity_gensk (struct gravity_sk *sk) {
|
||||
int n = GRAVITY_ccc;
|
||||
struct hash *src;
|
||||
struct hash *dst = sk->cache;
|
||||
struct merkle_pk mpk;
|
||||
struct address address;
|
||||
int i;
|
||||
int res;
|
||||
|
||||
/* Create sub Merkle trees */
|
||||
address.layer = 0;
|
||||
for (i = 0; i < n; ++i) {
|
||||
address.index = i * MERKLE_hhh;
|
||||
res = merkle_genpk (&sk->seed, &address, &mpk);
|
||||
if (res != GRAVITY_OK) return res;
|
||||
|
||||
hashcpy (&dst[i], &mpk.k);
|
||||
}
|
||||
|
||||
/* Cache layers of Merkle tree */
|
||||
for (i = 0; i < GRAVITY_c; ++i) {
|
||||
src = dst;
|
||||
dst += n;
|
||||
n >>= 1;
|
||||
|
||||
hash_compress_pairs (dst, src, n);
|
||||
}
|
||||
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
int gravity_genpk (const struct gravity_sk *sk, struct gravity_pk *pk) {
|
||||
hashcpy (&pk->k, &sk->cache[2 * GRAVITY_ccc - 2]);
|
||||
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
int gravity_sign (const struct gravity_sk *sk, struct gravity_sign *sign, const struct hash *msg) {
|
||||
struct hash buf[2];
|
||||
struct address address;
|
||||
struct pors_subset subset;
|
||||
struct pors_sk *psk;
|
||||
struct porst_pk ppk;
|
||||
struct merkle_pk mpk;
|
||||
struct hash h;
|
||||
int layer;
|
||||
int res;
|
||||
#if GRAVITY_c > 0
|
||||
int offset;
|
||||
int n = GRAVITY_ccc;
|
||||
int i, sibling;
|
||||
#endif
|
||||
|
||||
/* Generate "randomness" from message and secret salt */
|
||||
hashcpy (&buf[0], &sk->salt);
|
||||
hashcpy (&buf[1], msg);
|
||||
hash_2N_to_N (&sign->rand, buf);
|
||||
|
||||
/* Generate address and PORST indices */
|
||||
pors_randsubset (&sign->rand, msg, &address.index, &subset);
|
||||
|
||||
/* PORST */
|
||||
psk = malloc (sizeof (struct pors_sk));
|
||||
if (psk == NULL) return GRAVITY_ERR_ALLOC;
|
||||
|
||||
address.layer = GRAVITY_d;
|
||||
pors_gensk (&sk->seed, &address, psk);
|
||||
|
||||
res = octoporst_sign (psk, &sign->op_sign, &ppk, &subset);
|
||||
/* TODO: wipe key */
|
||||
free (psk);
|
||||
|
||||
if (res != GRAVITY_OK) return res;
|
||||
|
||||
/* Store PORST pubkey into h */
|
||||
hashcpy (&h, &ppk.k);
|
||||
|
||||
/* Hyper tree */
|
||||
for (layer = 0; layer < GRAVITY_d; ++layer) {
|
||||
/* Sign h with Merkle tree and obtain public key */
|
||||
--address.layer;
|
||||
res = merkle_sign (&sk->seed, &address, &sign->merkle[layer], &h, &mpk);
|
||||
if (res != GRAVITY_OK) return res;
|
||||
hashcpy (&h, &mpk.k);
|
||||
|
||||
/* Reduce address for next layer */
|
||||
address.index >>= MERKLE_h;
|
||||
}
|
||||
|
||||
#if GRAVITY_c > 0
|
||||
/* Cached Merkle tree */
|
||||
offset = 0;
|
||||
for (i = 0; i < GRAVITY_c; ++i) {
|
||||
sibling = address.index ^ 1;
|
||||
hashcpy (&sign->auth[i], &sk->cache[offset + sibling]);
|
||||
|
||||
address.index >>= 1;
|
||||
offset += n;
|
||||
n >>= 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
int gravity_verify (const struct gravity_pk *pk,
|
||||
const struct gravity_sign *sign,
|
||||
const struct hash *msg) {
|
||||
struct address address;
|
||||
struct pors_subset subset;
|
||||
struct porst_pk ppk;
|
||||
struct merkle_pk mpk;
|
||||
struct hash h;
|
||||
int layer;
|
||||
int res;
|
||||
|
||||
/* Generate address and PORST indices */
|
||||
pors_randsubset (&sign->rand, msg, &address.index, &subset);
|
||||
|
||||
/* PORST */
|
||||
res = octoporst_extract (&ppk, &sign->op_sign, &subset);
|
||||
if (res != GRAVITY_OK) return res;
|
||||
|
||||
/* Store PORST pubkey into h */
|
||||
hashcpy (&h, &ppk.k);
|
||||
|
||||
/* Hyper tree */
|
||||
address.layer = GRAVITY_d;
|
||||
for (layer = 0; layer < GRAVITY_d; ++layer) {
|
||||
/* Obtain Merkle tree root */
|
||||
--address.layer;
|
||||
merkle_extract (&mpk, &address, &sign->merkle[layer], &h);
|
||||
hashcpy (&h, &mpk.k);
|
||||
|
||||
/* Reduce address for next layer */
|
||||
address.index >>= MERKLE_h;
|
||||
}
|
||||
|
||||
#if GRAVITY_c > 0
|
||||
/* Cached Merkle tree */
|
||||
merkle_compress_auth (&h, address.index, sign->auth, GRAVITY_c);
|
||||
#endif
|
||||
|
||||
if (hashcmp (&h, &pk->k)) return GRAVITY_ERR_VERIF;
|
||||
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
int gravity_loadsign (struct gravity_sign *sign, const uint8_t *_sign, size_t _len) {
|
||||
size_t baselen = HASH_SIZE + GRAVITY_d * sizeof (struct merkle_sign)
|
||||
#if GRAVITY_c > 0
|
||||
+ GRAVITY_c * HASH_SIZE
|
||||
#endif
|
||||
;
|
||||
|
||||
if (_len < baselen) return GRAVITY_ERR_VERIF;
|
||||
_len -= baselen;
|
||||
|
||||
memcpy (&sign->rand, _sign, HASH_SIZE);
|
||||
_sign += HASH_SIZE;
|
||||
|
||||
if (octoporst_loadsign (&sign->op_sign, _sign, _len) != GRAVITY_OK)
|
||||
return GRAVITY_ERR_VERIF;
|
||||
_sign += _len;
|
||||
|
||||
memcpy (sign->merkle, _sign, GRAVITY_d * sizeof (struct merkle_sign));
|
||||
|
||||
#if GRAVITY_c > 0
|
||||
_sign += GRAVITY_d * sizeof (struct merkle_sign);
|
||||
memcpy (sign->auth, _sign, GRAVITY_c * HASH_SIZE);
|
||||
#endif
|
||||
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
int gravity_signcmp (const struct gravity_sign *sign1, const struct gravity_sign *sign2) {
|
||||
if (hashcmp (&sign1->rand, &sign2->rand)) return 1;
|
||||
if (octoporst_signcmp (&sign1->op_sign, &sign2->op_sign)) return 1;
|
||||
if (memcmp (&sign1->merkle, &sign2->merkle, GRAVITY_d * sizeof (struct merkle_sign)))
|
||||
return 1;
|
||||
#if GRAVITY_c > 0
|
||||
if (hashcmpN (sign1->auth, sign2->auth, GRAVITY_c)) return 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
41
crypto/sphincs/gravity.h
Normal file
41
crypto/sphincs/gravity.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "merkle.h"
|
||||
#include "pors.h"
|
||||
|
||||
struct gravity_sk {
|
||||
struct hash seed;
|
||||
struct hash salt;
|
||||
struct hash cache[2 * GRAVITY_ccc - 1];
|
||||
};
|
||||
|
||||
struct gravity_pk {
|
||||
struct hash k;
|
||||
};
|
||||
|
||||
struct gravity_sign {
|
||||
struct hash rand;
|
||||
struct octoporst_sign op_sign;
|
||||
struct merkle_sign merkle[GRAVITY_d];
|
||||
#if GRAVITY_c > 0
|
||||
struct hash auth[GRAVITY_c];
|
||||
#endif
|
||||
};
|
||||
|
||||
int gravity_gensk (struct gravity_sk *sk);
|
||||
|
||||
int gravity_genpk (const struct gravity_sk *sk, struct gravity_pk *pk);
|
||||
|
||||
int gravity_sign (const struct gravity_sk *sk, struct gravity_sign *sign, const struct hash *msg);
|
||||
|
||||
int gravity_verify (const struct gravity_pk *pk,
|
||||
const struct gravity_sign *sign,
|
||||
const struct hash *msg);
|
||||
|
||||
/* Serialization */
|
||||
int gravity_loadsign (struct gravity_sign *sign, const uint8_t *_sign, size_t _len);
|
||||
|
||||
int gravity_signcmp (const struct gravity_sign *sign1, const struct gravity_sign *sign2);
|
||||
53
crypto/sphincs/hash.h
Normal file
53
crypto/sphincs/hash.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* TODO: portable alignment */
|
||||
struct hash {
|
||||
uint8_t h[HASH_SIZE];
|
||||
} __attribute__ ((aligned (16)));
|
||||
|
||||
struct address {
|
||||
uint64_t index;
|
||||
uint32_t layer;
|
||||
};
|
||||
|
||||
|
||||
void hash_N_to_N (struct hash *dst, const struct hash *src);
|
||||
void hash_N_to_N_chain (struct hash *dst, const struct hash *src, int chainlen);
|
||||
void hash_2N_to_N (struct hash *dst, const struct hash *src);
|
||||
void hash_to_N (struct hash *dst, const uint8_t *src, uint64_t srclen);
|
||||
|
||||
/* Compress 2*count input hashes into count output hashes, pairwise */
|
||||
void hash_compress_pairs (struct hash *dst, const struct hash *src, int count);
|
||||
/* Compress count hashes into a single hash */
|
||||
void hash_compress_all (struct hash *dst, const struct hash *src, int count);
|
||||
/* Compute count hashes in parallel */
|
||||
void hash_parallel (struct hash *dst, const struct hash *src, int count);
|
||||
/* Compute count hash chains of length chainlen in parallel */
|
||||
void hash_parallel_chains (struct hash *dst, const struct hash *src, int count, int chainlen);
|
||||
|
||||
|
||||
/* int hashcmp(const struct hash *a, const struct hash *b); */
|
||||
#define hashcmp(a, b) memcmp ((a)->h, (b)->h, HASH_SIZE)
|
||||
/* int hashcmpN(const struct hash *a, const struct hash *b, size_t count); */
|
||||
#define hashcmpN(a, b, N) memcmp ((a)->h, (b)->h, (N)*HASH_SIZE)
|
||||
/* void hashcpy(struct hash *dst, const struct hash *src); */
|
||||
#define hashcpy(a, b) memcpy ((a)->h, (b)->h, HASH_SIZE)
|
||||
/* void hashcpyN(struct hash *dst, const struct hash *src, size_t count); */
|
||||
#define hashcpyN(a, b, N) memcpy ((a)->h, (b)->h, (N)*HASH_SIZE)
|
||||
/* void hashzero(struct hash *dst); */
|
||||
#define hashzero(a) memset ((a)->h, 0, HASH_SIZE)
|
||||
/* void swap(struct hash *a, struct hash *b, struct hash *tmp); */
|
||||
#define hashswap(a, b, tmp) \
|
||||
do { \
|
||||
(tmp) = (a); \
|
||||
(a) = (b); \
|
||||
(b) = (tmp); \
|
||||
} while (0);
|
||||
28
crypto/sphincs/ltree.c
Normal file
28
crypto/sphincs/ltree.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#include "ltree.h"
|
||||
|
||||
void ltree (struct hash *buf, int count, struct hash *root) {
|
||||
struct hash *src = &buf[count];
|
||||
struct hash *dst = &buf[0];
|
||||
struct hash *tmp;
|
||||
int newcount;
|
||||
|
||||
while (count > 1) {
|
||||
/* Swap buffers */
|
||||
hashswap (src, dst, tmp);
|
||||
|
||||
/* Compute all hashes at current layer */
|
||||
newcount = count >> 1;
|
||||
hash_compress_pairs (dst, src, newcount);
|
||||
if (count & 1) {
|
||||
hashcpy (&dst[newcount], &src[count - 1]);
|
||||
++newcount;
|
||||
}
|
||||
|
||||
count = newcount;
|
||||
}
|
||||
|
||||
hashcpy (root, dst);
|
||||
}
|
||||
8
crypto/sphincs/ltree.h
Normal file
8
crypto/sphincs/ltree.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
void ltree (struct hash *buf, int count, struct hash *root);
|
||||
266
crypto/sphincs/merkle.c
Normal file
266
crypto/sphincs/merkle.c
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#include "merkle.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int merkle_base_address (const struct address *address, struct address *base_address) {
|
||||
int index = address->index & (MERKLE_hhh - 1);
|
||||
if (base_address != NULL) {
|
||||
base_address->layer = address->layer;
|
||||
base_address->index = address->index - index;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
int merkle_genpk (const struct hash *key, const struct address *address, struct merkle_pk *pk) {
|
||||
struct address base_address;
|
||||
struct hash *buf;
|
||||
struct wots_sk wsk;
|
||||
struct lwots_pk wpk;
|
||||
int j;
|
||||
|
||||
merkle_base_address (address, &base_address);
|
||||
|
||||
buf = merkle_alloc_buf (MERKLE_h);
|
||||
if (buf == NULL) return GRAVITY_ERR_ALLOC;
|
||||
|
||||
/* Leaves */
|
||||
for (j = 0; j < MERKLE_hhh; ++j) {
|
||||
wots_gensk (key, &base_address, &wsk);
|
||||
lwots_genpk (&wsk, &wpk);
|
||||
hashcpy (&buf[j], &wpk.k);
|
||||
|
||||
++base_address.index;
|
||||
}
|
||||
|
||||
/* Merkle tree */
|
||||
merkle_compress_all (buf, MERKLE_h, &pk->k);
|
||||
|
||||
merkle_free_buf (buf);
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
int merkle_sign (const struct hash *key,
|
||||
const struct address *address,
|
||||
struct merkle_sign *sign,
|
||||
const struct hash *msg,
|
||||
struct merkle_pk *pk) {
|
||||
struct address base_address;
|
||||
struct hash *buf;
|
||||
struct wots_sk wsk;
|
||||
struct lwots_pk wpk;
|
||||
int index;
|
||||
int j;
|
||||
|
||||
index = merkle_base_address (address, &base_address);
|
||||
|
||||
buf = merkle_alloc_buf (MERKLE_h);
|
||||
if (buf == NULL) return GRAVITY_ERR_ALLOC;
|
||||
|
||||
/* Leaves */
|
||||
for (j = 0; j < MERKLE_hhh; ++j) {
|
||||
wots_gensk (key, &base_address, &wsk);
|
||||
lwots_genpk (&wsk, &wpk);
|
||||
hashcpy (&buf[j], &wpk.k);
|
||||
|
||||
++base_address.index;
|
||||
|
||||
/* WOTS */
|
||||
if (j == index) wots_sign (&wsk, &sign->wots, msg);
|
||||
}
|
||||
|
||||
/* Merkle tree */
|
||||
merkle_gen_auth (buf, MERKLE_h, sign->auth, index, pk == NULL ? NULL : &pk->k);
|
||||
|
||||
merkle_free_buf (buf);
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
void merkle_extract (struct merkle_pk *pk,
|
||||
const struct address *address,
|
||||
const struct merkle_sign *sign,
|
||||
const struct hash *msg) {
|
||||
struct lwots_pk wpk;
|
||||
int index = merkle_base_address (address, NULL);
|
||||
|
||||
/* WOTS */
|
||||
lwots_extract (&wpk, &sign->wots, msg);
|
||||
|
||||
/* Auth path */
|
||||
merkle_compress_auth (&wpk.k, index, sign->auth, MERKLE_h);
|
||||
hashcpy (&pk->k, &wpk.k);
|
||||
}
|
||||
|
||||
|
||||
/* Helper functions */
|
||||
/* Alloc/free a buffer large enough to store leaves and compress them */
|
||||
struct hash *merkle_alloc_buf (int height) {
|
||||
int n = 1 << height;
|
||||
return malloc (2 * n * HASH_SIZE);
|
||||
}
|
||||
|
||||
void merkle_free_buf (struct hash *buf) {
|
||||
/* TODO: wipe buffer? */
|
||||
free (buf);
|
||||
}
|
||||
|
||||
/* Compress leaves from level height until root */
|
||||
void merkle_compress_all (struct hash *buf, int height, struct hash *root) {
|
||||
int n = 1 << height;
|
||||
struct hash *src = &buf[n];
|
||||
struct hash *dst = &buf[0];
|
||||
struct hash *tmp;
|
||||
int l;
|
||||
|
||||
for (l = 0; l < height; ++l) {
|
||||
/* Swap buffers */
|
||||
hashswap (src, dst, tmp);
|
||||
n >>= 1;
|
||||
|
||||
/* Compute all hashes at current layer */
|
||||
hash_compress_pairs (dst, src, n);
|
||||
}
|
||||
|
||||
hashcpy (root, dst);
|
||||
}
|
||||
|
||||
/* Compute authentication path */
|
||||
void merkle_gen_auth (struct hash *buf, int height, struct hash *auth, int index, struct hash *root) {
|
||||
int n = 1 << height;
|
||||
struct hash *src = &buf[n];
|
||||
struct hash *dst = &buf[0];
|
||||
struct hash *tmp;
|
||||
int l, sibling;
|
||||
|
||||
for (l = 0; l < height; ++l) {
|
||||
/* Copy auth path */
|
||||
sibling = index ^ 1;
|
||||
hashcpy (&auth[l], &dst[sibling]);
|
||||
index >>= 1;
|
||||
|
||||
/* Swap buffers */
|
||||
hashswap (src, dst, tmp);
|
||||
n >>= 1;
|
||||
|
||||
/* Compute all hashes at current layer */
|
||||
hash_compress_pairs (dst, src, n);
|
||||
}
|
||||
|
||||
/* Public key */
|
||||
if (root != NULL) hashcpy (root, dst);
|
||||
}
|
||||
|
||||
/* Compress node with its auth path on height_diff levels */
|
||||
int merkle_compress_auth (struct hash *node, int index, const struct hash *auth, int height_diff) {
|
||||
struct hash buf[2];
|
||||
int l;
|
||||
|
||||
for (l = 0; l < height_diff; ++l) {
|
||||
if (index % 2 == 0) {
|
||||
hashcpy (&buf[0], node);
|
||||
hashcpy (&buf[1], &auth[l]);
|
||||
} else {
|
||||
hashcpy (&buf[0], &auth[l]);
|
||||
hashcpy (&buf[1], node);
|
||||
}
|
||||
|
||||
hash_2N_to_N (node, buf);
|
||||
|
||||
index >>= 1;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void merkle_gen_octopus (struct hash *buf,
|
||||
int height,
|
||||
struct hash *octopus,
|
||||
int *octolen,
|
||||
struct hash *root,
|
||||
int *indices,
|
||||
int count) {
|
||||
int n = 1 << height;
|
||||
struct hash *src = &buf[n];
|
||||
struct hash *dst = &buf[0];
|
||||
struct hash *tmp;
|
||||
int i, j, l;
|
||||
int len = 0;
|
||||
int index, sibling;
|
||||
|
||||
for (l = 0; l < height; ++l) {
|
||||
/* Copy auth octopus */
|
||||
for (i = 0, j = 0; i < count; ++i, ++j) {
|
||||
index = indices[i];
|
||||
sibling = index ^ 1;
|
||||
|
||||
/* Check redundancy with sibling */
|
||||
if (i + 1 < count && indices[i + 1] == sibling)
|
||||
++i;
|
||||
else
|
||||
hashcpy (&octopus[len++], &dst[sibling]);
|
||||
|
||||
indices[j] = indices[i] >> 1;
|
||||
}
|
||||
/* Update count of non-redundant nodes */
|
||||
count = j;
|
||||
|
||||
/* Swap buffers */
|
||||
hashswap (src, dst, tmp);
|
||||
n >>= 1;
|
||||
|
||||
/* Compute all hashes at current layer */
|
||||
hash_compress_pairs (dst, src, n);
|
||||
}
|
||||
|
||||
hashcpy (root, dst);
|
||||
*octolen = len;
|
||||
}
|
||||
|
||||
int merkle_compress_octopus (struct hash *nodes,
|
||||
int height,
|
||||
const struct hash *octopus,
|
||||
int octolen,
|
||||
int *indices,
|
||||
int count) {
|
||||
struct hash buf[2];
|
||||
int i, j, l;
|
||||
int len = 0;
|
||||
int index;
|
||||
|
||||
for (l = 0; l < height; ++l) {
|
||||
for (i = 0, j = 0; i < count; ++i, ++j) {
|
||||
/* Select 2 values to merge */
|
||||
index = indices[i];
|
||||
if (index % 2 == 0) {
|
||||
hashcpy (&buf[0], &nodes[i]);
|
||||
|
||||
if (i + 1 < count && indices[i + 1] == index + 1) {
|
||||
++i;
|
||||
hashcpy (&buf[1], &nodes[i]);
|
||||
} else {
|
||||
if (len == octolen) return GRAVITY_ERR_VERIF;
|
||||
hashcpy (&buf[1], &octopus[len++]);
|
||||
}
|
||||
} else {
|
||||
if (len == octolen) return GRAVITY_ERR_VERIF;
|
||||
hashcpy (&buf[0], &octopus[len++]);
|
||||
hashcpy (&buf[1], &nodes[i]);
|
||||
}
|
||||
|
||||
/* Hash values */
|
||||
hash_2N_to_N (&nodes[j], buf);
|
||||
|
||||
indices[j] = indices[i] >> 1;
|
||||
}
|
||||
|
||||
/* Update count of non-redundant nodes */
|
||||
count = j;
|
||||
}
|
||||
|
||||
/* Check len */
|
||||
if (len != octolen) return GRAVITY_ERR_VERIF;
|
||||
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
62
crypto/sphincs/merkle.h
Normal file
62
crypto/sphincs/merkle.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "wots.h"
|
||||
|
||||
struct merkle_pk {
|
||||
struct hash k;
|
||||
};
|
||||
|
||||
struct merkle_sign {
|
||||
struct wots_sign wots;
|
||||
struct hash auth[MERKLE_h];
|
||||
};
|
||||
|
||||
int merkle_genpk (const struct hash *key, const struct address *address, struct merkle_pk *pk);
|
||||
|
||||
int merkle_sign (const struct hash *key,
|
||||
const struct address *address,
|
||||
struct merkle_sign *sign,
|
||||
const struct hash *msg,
|
||||
struct merkle_pk *pk);
|
||||
|
||||
void merkle_extract (struct merkle_pk *pk,
|
||||
const struct address *address,
|
||||
const struct merkle_sign *sign,
|
||||
const struct hash *msg);
|
||||
|
||||
|
||||
/* Helper functions */
|
||||
/* Alloc/free a buffer large enough to store leaves and compress them */
|
||||
struct hash *merkle_alloc_buf (int height);
|
||||
|
||||
void merkle_free_buf (struct hash *buf);
|
||||
|
||||
/* Compress leaves from level height to root */
|
||||
void merkle_compress_all (struct hash *buf, int height, struct hash *root);
|
||||
|
||||
/* Compute authentication path */
|
||||
void merkle_gen_auth (struct hash *buf, int height, struct hash *auth, int index, struct hash *root);
|
||||
|
||||
/* Compress node with its auth path on height_diff levels */
|
||||
int merkle_compress_auth (struct hash *node, int index, const struct hash *auth, int height_diff);
|
||||
|
||||
/* "indices" must be sorted */
|
||||
void merkle_gen_octopus (struct hash *buf,
|
||||
int height,
|
||||
struct hash *octopus,
|
||||
int *octolen,
|
||||
struct hash *root,
|
||||
int *indices,
|
||||
int count);
|
||||
|
||||
/* Compress a set of leaves with their auth path */
|
||||
/* "indices" must be sorted */
|
||||
int merkle_compress_octopus (struct hash *nodes,
|
||||
int height,
|
||||
const struct hash *octopus,
|
||||
int octolen,
|
||||
int *indices,
|
||||
int count);
|
||||
200
crypto/sphincs/pors.c
Normal file
200
crypto/sphincs/pors.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#include "pors.h"
|
||||
|
||||
#include "aes.h"
|
||||
#include "merkle.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Naive PORS without Merkle tree */
|
||||
void pors_gensk (const struct hash *key, const struct address *address, struct pors_sk *sk) {
|
||||
uint8_t iv[16];
|
||||
|
||||
iv[0] = (address->index >> 56) & 0xFF;
|
||||
iv[1] = (address->index >> 48) & 0xFF;
|
||||
iv[2] = (address->index >> 40) & 0xFF;
|
||||
iv[3] = (address->index >> 32) & 0xFF;
|
||||
iv[4] = (address->index >> 24) & 0xFF;
|
||||
iv[5] = (address->index >> 16) & 0xFF;
|
||||
iv[6] = (address->index >> 8) & 0xFF;
|
||||
iv[7] = address->index & 0xFF;
|
||||
|
||||
iv[8] = (address->layer >> 24) & 0xFF;
|
||||
iv[9] = (address->layer >> 16) & 0xFF;
|
||||
iv[10] = (address->layer >> 8) & 0xFF;
|
||||
iv[11] = address->layer & 0xFF;
|
||||
|
||||
/* Counter */
|
||||
iv[12] = 0;
|
||||
iv[13] = 0;
|
||||
iv[14] = 0;
|
||||
iv[15] = 0;
|
||||
aesctr256 (sk->k->h, key->h, iv, PORS_t * HASH_SIZE);
|
||||
}
|
||||
|
||||
void pors_sign (const struct pors_sk *sk, struct pors_sign *sign, const struct pors_subset *subset) {
|
||||
int i;
|
||||
int index;
|
||||
|
||||
for (i = 0; i < PORS_k; ++i) {
|
||||
index = subset->s[i];
|
||||
hashcpy (&sign->s[i], &sk->k[index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Naive PORST without merging of authentication paths */
|
||||
int porst_genpk (const struct pors_sk *sk, struct porst_pk *pk) {
|
||||
struct hash *buf = merkle_alloc_buf (PORS_tau);
|
||||
if (buf == NULL) return GRAVITY_ERR_ALLOC;
|
||||
|
||||
/* Leaves */
|
||||
hash_parallel (buf, sk->k, PORS_t);
|
||||
|
||||
/* Merkle tree */
|
||||
merkle_compress_all (buf, PORS_tau, &pk->k);
|
||||
|
||||
merkle_free_buf (buf);
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
|
||||
/* PORST with authentication octopus */
|
||||
void sort_subset (struct pors_subset *subset) {
|
||||
/* Selection sort */
|
||||
int i, j, k, tmp;
|
||||
for (i = 0; i + 1 < PORS_k; ++i) {
|
||||
k = i;
|
||||
tmp = subset->s[k];
|
||||
for (j = i + 1; j < PORS_k; ++j) {
|
||||
if (subset->s[j] < tmp) {
|
||||
k = j;
|
||||
tmp = subset->s[k];
|
||||
}
|
||||
}
|
||||
|
||||
subset->s[k] = subset->s[i];
|
||||
subset->s[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
int octoporst_sign (const struct pors_sk *sk,
|
||||
struct octoporst_sign *sign,
|
||||
struct porst_pk *pk,
|
||||
struct pors_subset *subset) {
|
||||
struct hash *buf;
|
||||
|
||||
/* Sort subset */
|
||||
sort_subset (subset);
|
||||
|
||||
/* Values */
|
||||
pors_sign (sk, &sign->s, subset);
|
||||
|
||||
/* Authentication paths */
|
||||
buf = merkle_alloc_buf (PORS_tau);
|
||||
if (buf == NULL) return GRAVITY_ERR_ALLOC;
|
||||
|
||||
/* Leaves */
|
||||
hash_parallel (buf, sk->k, PORS_t);
|
||||
|
||||
/* Merkle tree */
|
||||
merkle_gen_octopus (buf, PORS_tau, sign->octopus, &sign->octolen, &pk->k,
|
||||
subset->s, PORS_k);
|
||||
|
||||
merkle_free_buf (buf);
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
int octoporst_extract (struct porst_pk *pk,
|
||||
const struct octoporst_sign *sign,
|
||||
struct pors_subset *subset) {
|
||||
struct hash tmp[PORS_k];
|
||||
int res;
|
||||
|
||||
/* Sort subset */
|
||||
sort_subset (subset);
|
||||
|
||||
/* Compute leaves */
|
||||
hash_parallel (tmp, sign->s.s, PORS_k);
|
||||
|
||||
/* Auth octopus */
|
||||
res = merkle_compress_octopus (tmp, PORS_tau, sign->octopus, sign->octolen,
|
||||
subset->s, PORS_k);
|
||||
if (res != GRAVITY_OK) return res;
|
||||
|
||||
hashcpy (&pk->k, &tmp[0]);
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
|
||||
int octoporst_loadsign (struct octoporst_sign *sign, const uint8_t *_sign, size_t _len) {
|
||||
if (_len < sizeof (struct pors_sign)) return GRAVITY_ERR_VERIF;
|
||||
_len -= sizeof (struct pors_sign);
|
||||
|
||||
if (_len % HASH_SIZE != 0) return GRAVITY_ERR_VERIF;
|
||||
_len /= HASH_SIZE;
|
||||
|
||||
if (_len > PORS_k * PORS_tau) return GRAVITY_ERR_VERIF;
|
||||
|
||||
memcpy (&sign->s, _sign, sizeof (struct pors_sign));
|
||||
_sign += sizeof (struct pors_sign);
|
||||
memcpy (sign->octopus, _sign, _len * HASH_SIZE);
|
||||
sign->octolen = _len;
|
||||
|
||||
return GRAVITY_OK;
|
||||
}
|
||||
|
||||
int octoporst_signcmp (const struct octoporst_sign *sign1,
|
||||
const struct octoporst_sign *sign2) {
|
||||
if (sign1->octolen != sign2->octolen) return 1;
|
||||
if (hashcmpN (sign1->s.s, sign2->s.s, PORS_k)) return 1;
|
||||
if (hashcmpN (sign1->octopus, sign2->octopus, sign1->octolen)) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void pors_randsubset (const struct hash *rand,
|
||||
const struct hash *msg,
|
||||
uint64_t *address,
|
||||
struct pors_subset *subset) {
|
||||
#define BYTES_PER_INDEX 4
|
||||
#define STREAMLEN \
|
||||
((8 * (PORS_k)) + HASH_SIZE) /* count twice as many indexes as needed */
|
||||
uint8_t randstream[STREAMLEN];
|
||||
int index, duplicate, i, count = 0;
|
||||
size_t offset = 0;
|
||||
struct hash seed;
|
||||
struct hash buf[2];
|
||||
uint64_t addr;
|
||||
uint8_t byte;
|
||||
|
||||
hashcpy (&buf[0], rand);
|
||||
hashcpy (&buf[1], msg);
|
||||
hash_2N_to_N (&seed, buf);
|
||||
|
||||
aesctr256_zeroiv (randstream, seed.h, STREAMLEN);
|
||||
|
||||
/* compute address */
|
||||
addr = 0;
|
||||
for (i = 0; i < HASH_SIZE; ++i) {
|
||||
byte = randstream[i];
|
||||
addr = (addr << 8) | byte;
|
||||
addr &= GRAVITY_mask;
|
||||
}
|
||||
*address = addr;
|
||||
|
||||
while (count < PORS_k) {
|
||||
/* ok to take mod since T is a power of 2 */
|
||||
index = U8TO32 (randstream + HASH_SIZE + offset) % PORS_t;
|
||||
offset += BYTES_PER_INDEX;
|
||||
duplicate = 0;
|
||||
for (i = 0; i < count; ++i)
|
||||
if (subset->s[i] == index) duplicate++;
|
||||
if (!duplicate) {
|
||||
subset->s[count] = index;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
74
crypto/sphincs/pors.h
Normal file
74
crypto/sphincs/pors.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
/* PRNG to obtain a random subset */
|
||||
struct pors_subset {
|
||||
int s[PORS_k];
|
||||
};
|
||||
|
||||
void pors_randsubset (const struct hash *rand,
|
||||
const struct hash *msg,
|
||||
uint64_t *address,
|
||||
struct pors_subset *subset);
|
||||
|
||||
|
||||
/* Naive PORS without Merkle tree */
|
||||
struct pors_sk {
|
||||
struct hash k[PORS_t];
|
||||
};
|
||||
|
||||
struct pors_pk {
|
||||
struct hash k[PORS_t];
|
||||
};
|
||||
|
||||
struct pors_keypair {
|
||||
struct pors_sk sk;
|
||||
struct pors_pk pk;
|
||||
};
|
||||
|
||||
struct pors_sign {
|
||||
struct hash s[PORS_k];
|
||||
};
|
||||
|
||||
void pors_gensk (const struct hash *key, const struct address *address, struct pors_sk *sk);
|
||||
|
||||
void pors_sign (const struct pors_sk *sk, struct pors_sign *sign, const struct pors_subset *subset);
|
||||
|
||||
|
||||
/* Naive PORST without merging of authentication paths */
|
||||
struct porst_pk {
|
||||
struct hash k;
|
||||
};
|
||||
|
||||
struct porst_keypair {
|
||||
struct pors_sk sk;
|
||||
struct porst_pk pk;
|
||||
};
|
||||
|
||||
int porst_genpk (const struct pors_sk *sk, struct porst_pk *pk);
|
||||
|
||||
|
||||
/* PORST with authentication octopus */
|
||||
struct octoporst_sign {
|
||||
struct pors_sign s;
|
||||
struct hash octopus[PORS_k * PORS_tau]; /* Large enough buffer */
|
||||
int octolen; /* Number of elements in the octopus */
|
||||
};
|
||||
|
||||
int octoporst_sign (const struct pors_sk *sk,
|
||||
struct octoporst_sign *sign,
|
||||
struct porst_pk *pk,
|
||||
struct pors_subset *subset);
|
||||
|
||||
int octoporst_extract (struct porst_pk *pk,
|
||||
const struct octoporst_sign *sign,
|
||||
struct pors_subset *subset);
|
||||
|
||||
/* Serialization */
|
||||
int octoporst_loadsign (struct octoporst_sign *sign, const uint8_t *_sign, size_t _len);
|
||||
|
||||
int octoporst_signcmp (const struct octoporst_sign *sign1, const struct octoporst_sign *sign2);
|
||||
61
crypto/sphincs/primitives/aes.c
Normal file
61
crypto/sphincs/primitives/aes.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
|
||||
#include "../aes.h"
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
int aesctr256 (uint8_t *out, const uint8_t *sk, const void *counter, int bytes) {
|
||||
static const uint8_t buffer[4096] = { 0 };
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
int len = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (bytes == 0) return 0;
|
||||
|
||||
if (!(ctx = EVP_CIPHER_CTX_new ())) {
|
||||
ret = -2;
|
||||
goto label_exit_0;
|
||||
}
|
||||
|
||||
if (1 != EVP_EncryptInit_ex (ctx, EVP_aes_256_ctr (), NULL, sk, counter)) {
|
||||
ret = -3;
|
||||
goto label_exit_1;
|
||||
}
|
||||
|
||||
while (bytes >= (int)sizeof (buffer)) {
|
||||
if (1 != EVP_EncryptUpdate (ctx, out, &len, buffer, sizeof (buffer))) {
|
||||
ret = -4;
|
||||
goto label_exit_1;
|
||||
}
|
||||
out += sizeof (buffer);
|
||||
bytes -= sizeof (buffer);
|
||||
}
|
||||
if (bytes) {
|
||||
if (1 != EVP_EncryptUpdate (ctx, out, &len, buffer, bytes)) {
|
||||
ret = -4;
|
||||
goto label_exit_1;
|
||||
}
|
||||
}
|
||||
|
||||
if (1 != EVP_EncryptFinal_ex (ctx, out + len, &len)) {
|
||||
ret = -5;
|
||||
goto label_exit_1;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
label_exit_1:
|
||||
EVP_CIPHER_CTX_free (ctx);
|
||||
label_exit_0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int aesctr256_zeroiv (uint8_t *out, const uint8_t *sk, int bytes) {
|
||||
uint8_t counter[16] = {0};
|
||||
return aesctr256(out, sk, counter, bytes);
|
||||
}
|
||||
125
crypto/sphincs/primitives/haraka.c
Normal file
125
crypto/sphincs/primitives/haraka.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
|
||||
#include "haraka.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
void aesenc (uint8_t *s, const uint8_t *rk) {
|
||||
uint8_t i, t, u, v[4][4];
|
||||
for (i = 0; i < 16; ++i) v[((i / 4) + 4 - (i % 4)) % 4][i % 4] = sbox[s[i]];
|
||||
for (i = 0; i < 4; ++i) {
|
||||
t = v[i][0];
|
||||
u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3];
|
||||
v[i][0] ^= u ^ XT (v[i][0] ^ v[i][1]);
|
||||
v[i][1] ^= u ^ XT (v[i][1] ^ v[i][2]);
|
||||
v[i][2] ^= u ^ XT (v[i][2] ^ v[i][3]);
|
||||
v[i][3] ^= u ^ XT (v[i][3] ^ t);
|
||||
}
|
||||
for (i = 0; i < 16; ++i) s[i] = v[i / 4][i % 4] ^ rk[i];
|
||||
}
|
||||
|
||||
|
||||
void haraka256_256 (uint8_t *out, const uint8_t *in) {
|
||||
|
||||
uint8_t s0[16], s1[16];
|
||||
uint32_t tmp[4];
|
||||
int i;
|
||||
|
||||
memcpy (s0, in, 16);
|
||||
memcpy (s1, in + 16, 16);
|
||||
|
||||
AES2 (0);
|
||||
MIX2;
|
||||
AES2 (4);
|
||||
MIX2;
|
||||
AES2 (8);
|
||||
MIX2;
|
||||
AES2 (12);
|
||||
MIX2;
|
||||
AES2 (16);
|
||||
MIX2;
|
||||
AES2 (20);
|
||||
MIX2;
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
out[i] = in[i] ^ s0[i];
|
||||
out[i + 16] = in[i + 16] ^ s1[i];
|
||||
}
|
||||
}
|
||||
|
||||
void haraka256_256_chain (uint8_t *out, const uint8_t *in, int chainlen) {
|
||||
|
||||
uint8_t s0[16], s1[16];
|
||||
uint8_t t0[16], t1[16];
|
||||
uint32_t tmp[4];
|
||||
int i, j;
|
||||
|
||||
memcpy (s0, in, 16);
|
||||
memcpy (s1, in + 16, 16);
|
||||
memcpy (t0, in, 16);
|
||||
memcpy (t1, in + 16, 16);
|
||||
|
||||
for (j = 0; j < chainlen; ++j) {
|
||||
|
||||
AES2 (0);
|
||||
MIX2;
|
||||
AES2 (4);
|
||||
MIX2;
|
||||
AES2 (8);
|
||||
MIX2;
|
||||
AES2 (12);
|
||||
MIX2;
|
||||
AES2 (16);
|
||||
MIX2;
|
||||
AES2 (20);
|
||||
MIX2;
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
s0[i] = t0[i] = t0[i] ^ s0[i];
|
||||
s1[i] = t1[i] = t1[i] ^ s1[i];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 16; ++i) {
|
||||
out[i] = s0[i];
|
||||
out[i + 16] = s1[i];
|
||||
}
|
||||
}
|
||||
|
||||
void haraka512_256 (uint8_t *out, const uint8_t *in) {
|
||||
|
||||
uint8_t s0[16], s1[16], s2[16], s3[16];
|
||||
uint32_t tmp[5];
|
||||
int i;
|
||||
|
||||
memcpy (s0, in, 16);
|
||||
memcpy (s1, in + 16, 16);
|
||||
memcpy (s2, in + 32, 16);
|
||||
memcpy (s3, in + 48, 16);
|
||||
|
||||
AES4 (0);
|
||||
MIX4;
|
||||
AES4 (8);
|
||||
MIX4;
|
||||
AES4 (16);
|
||||
MIX4;
|
||||
AES4 (24);
|
||||
MIX4;
|
||||
AES4 (32);
|
||||
MIX4;
|
||||
AES4 (40);
|
||||
MIX4;
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
s0[i] = in[i] ^ s0[i];
|
||||
s1[i] = in[i + 16] ^ s1[i];
|
||||
s2[i] = in[i + 32] ^ s2[i];
|
||||
s3[i] = in[i + 48] ^ s3[i];
|
||||
}
|
||||
|
||||
((uint64_t *)out)[0] = ((uint64_t *)s0)[1];
|
||||
((uint64_t *)out)[1] = ((uint64_t *)s1)[1];
|
||||
((uint64_t *)out)[2] = ((uint64_t *)s2)[0];
|
||||
((uint64_t *)out)[3] = ((uint64_t *)s3)[0];
|
||||
}
|
||||
160
crypto/sphincs/primitives/haraka.h
Normal file
160
crypto/sphincs/primitives/haraka.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Stefan Kölbl
|
||||
original Haraka implementations
|
||||
|
||||
Copyright (c) 2017 Nagravision S.A.
|
||||
changes by JP Aumasson, Guillaume Endignoux, 2017: improvements, non-ni versions
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
static const uint32_t rc[48 * 4] = {
|
||||
0x75817b9d, 0xb2c5fef0, 0xe620c00a, 0x0684704c, 0x2f08f717, 0x640f6ba4,
|
||||
0x88f3a06b, 0x8b66b4e1, 0x9f029114, 0xcf029d60, 0x53f28498, 0x3402de2d,
|
||||
0xfd5b4f79, 0xbbf3bcaf, 0x2e7b4f08, 0x0ed6eae6, 0xbe397044, 0x79eecd1c,
|
||||
0x4872448b, 0xcbcfb0cb, 0x2b8a057b, 0x8d5335ed, 0x6e9032b7, 0x7eeacdee,
|
||||
0xda4fef1b, 0xe2412761, 0x5e2e7cd0, 0x67c28f43, 0x1fc70b3b, 0x675ffde2,
|
||||
0xafcacc07, 0x2924d9b0, 0xb9d465ee, 0xecdb8fca, 0xe6867fe9, 0xab4d63f1,
|
||||
0xad037e33, 0x5b2a404f, 0xd4b7cd64, 0x1c30bf84, 0x8df69800, 0x69028b2e,
|
||||
0x941723bf, 0xb2cc0bb9, 0x5c9d2d8a, 0x4aaa9ec8, 0xde6f5572, 0xfa0478a6,
|
||||
0x29129fd4, 0x0efa4f2e, 0x6b772a12, 0xdfb49f2b, 0xbb6a12ee, 0x32d611ae,
|
||||
0xf449a236, 0x1ea10344, 0x9ca8eca6, 0x5f9600c9, 0x4b050084, 0xaf044988,
|
||||
0x27e593ec, 0x78a2c7e3, 0x9d199c4f, 0x21025ed8, 0x82d40173, 0xb9282ecd,
|
||||
0xa759c9b7, 0xbf3aaaf8, 0x10307d6b, 0x37f2efd9, 0x6186b017, 0x6260700d,
|
||||
0xf6fc9ac6, 0x81c29153, 0x21300443, 0x5aca45c2, 0x36d1943a, 0x2caf92e8,
|
||||
0x226b68bb, 0x9223973c, 0xe51071b4, 0x6cbab958, 0x225886eb, 0xd3bf9238,
|
||||
0x24e1128d, 0x933dfddd, 0xaef0c677, 0xdb863ce5, 0xcb2212b1, 0x83e48de3,
|
||||
0xffeba09c, 0xbb606268, 0xc72bf77d, 0x2db91a4e, 0xe2e4d19c, 0x734bd3dc,
|
||||
0x2cb3924e, 0x4b1415c4, 0x61301b43, 0x43bb47c3, 0x16eb6899, 0x03b231dd,
|
||||
0xe707eff6, 0xdba775a8, 0x7eca472c, 0x8e5e2302, 0x3c755977, 0x6df3614b,
|
||||
0xb88617f9, 0x6d1be5b9, 0xd6de7d77, 0xcda75a17, 0xa946ee5d, 0x9d6c069d,
|
||||
0x6ba8e9aa, 0xec6b43f0, 0x3bf327c1, 0xa2531159, 0xf957332b, 0xcb1e6950,
|
||||
0x600ed0d9, 0xe4ed0353, 0x00da619c, 0x2cee0c75, 0x63a4a350, 0x80bbbabc,
|
||||
0x96e90cab, 0xf0b1a5a1, 0x938dca39, 0xab0dde30, 0x5e962988, 0xae3db102,
|
||||
0x2e75b442, 0x8814f3a8, 0xd554a40b, 0x17bb8f38, 0x360a16f6, 0xaeb6b779,
|
||||
0x5f427fd7, 0x34bb8a5b, 0xffbaafde, 0x43ce5918, 0xcbe55438, 0x26f65241,
|
||||
0x839ec978, 0xa2ca9cf7, 0xb9f3026a, 0x4ce99a54, 0x22901235, 0x40c06e28,
|
||||
0x1bdff7be, 0xae51a51a, 0x48a659cf, 0xc173bc0f, 0xba7ed22b, 0xa0c1613c,
|
||||
0xe9c59da1, 0x4ad6bdfd, 0x02288288, 0x756acc03, 0x848f2ad2, 0x367e4778,
|
||||
0x0de7d31e, 0x2ff37238, 0xb73bd58f, 0xee36b135, 0xcf74be8b, 0x08d95c6a,
|
||||
0xa3743e4a, 0x66ae1838, 0xc9d6ee98, 0x5880f434, 0x9a9369bd, 0xd0fdf4c7,
|
||||
0xaefabd99, 0x593023f0, 0x6f1ecb2a, 0xa5cc637b, 0xeb606e6f, 0x329ae3d1,
|
||||
0xcb7594ab, 0xa4dc93d6, 0x49e01594, 0xe00207eb, 0x65208ef8, 0x942366a6,
|
||||
0xf751c880, 0x1caa0c4f, 0xe3e67e4a, 0xbd03239f, 0xdb2dc1dd, 0x02f7f57f,
|
||||
};
|
||||
|
||||
static const uint8_t sbox[256] =
|
||||
{ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe,
|
||||
0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4,
|
||||
0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7,
|
||||
0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3,
|
||||
0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09,
|
||||
0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3,
|
||||
0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe,
|
||||
0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
|
||||
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92,
|
||||
0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c,
|
||||
0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19,
|
||||
0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
|
||||
0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2,
|
||||
0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5,
|
||||
0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25,
|
||||
0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86,
|
||||
0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e,
|
||||
0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42,
|
||||
0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
|
||||
|
||||
#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b))
|
||||
|
||||
#define AES2(rci) \
|
||||
aesenc (s0, ((uint8_t *)rc) + 16 * (rci + 0)); \
|
||||
aesenc (s1, ((uint8_t *)rc) + 16 * (rci + 1)); \
|
||||
aesenc (s0, ((uint8_t *)rc) + 16 * (rci + 2)); \
|
||||
aesenc (s1, ((uint8_t *)rc) + 16 * (rci + 3));
|
||||
|
||||
#define MIX2 \
|
||||
tmp[0] = ((uint32_t *)s0)[0]; \
|
||||
tmp[1] = ((uint32_t *)s1)[0]; \
|
||||
tmp[2] = ((uint32_t *)s0)[1]; \
|
||||
tmp[3] = ((uint32_t *)s1)[1]; \
|
||||
((uint32_t *)s1)[0] = ((uint32_t *)s0)[2]; \
|
||||
((uint32_t *)s1)[1] = ((uint32_t *)s1)[2]; \
|
||||
((uint32_t *)s1)[2] = ((uint32_t *)s0)[3]; \
|
||||
((uint32_t *)s0)[0] = tmp[0]; \
|
||||
((uint32_t *)s0)[1] = tmp[1]; \
|
||||
((uint32_t *)s0)[2] = tmp[2]; \
|
||||
((uint32_t *)s0)[3] = tmp[3];
|
||||
|
||||
#define AES4(rci) \
|
||||
aesenc (s0, ((uint8_t *)rc) + 16 * (rci + 0)); \
|
||||
aesenc (s1, ((uint8_t *)rc) + 16 * (rci + 1)); \
|
||||
aesenc (s2, ((uint8_t *)rc) + 16 * (rci + 2)); \
|
||||
aesenc (s3, ((uint8_t *)rc) + 16 * (rci + 3)); \
|
||||
aesenc (s0, ((uint8_t *)rc) + 16 * (rci + 4)); \
|
||||
aesenc (s1, ((uint8_t *)rc) + 16 * (rci + 5)); \
|
||||
aesenc (s2, ((uint8_t *)rc) + 16 * (rci + 6)); \
|
||||
aesenc (s3, ((uint8_t *)rc) + 16 * (rci + 7));
|
||||
|
||||
#define MIX4 \
|
||||
tmp[0] = ((uint32_t *)s0)[0]; \
|
||||
tmp[1] = ((uint32_t *)s1)[0]; \
|
||||
tmp[2] = ((uint32_t *)s0)[1]; \
|
||||
tmp[3] = ((uint32_t *)s1)[1]; \
|
||||
tmp[4] = ((uint32_t *)s3)[0]; \
|
||||
((uint32_t *)s0)[0] = ((uint32_t *)s0)[2]; \
|
||||
((uint32_t *)s0)[1] = ((uint32_t *)s1)[2]; \
|
||||
((uint32_t *)s0)[2] = ((uint32_t *)s0)[3]; \
|
||||
((uint32_t *)s0)[3] = ((uint32_t *)s1)[3]; \
|
||||
((uint32_t *)s1)[0] = ((uint32_t *)s2)[0]; \
|
||||
((uint32_t *)s1)[1] = ((uint32_t *)s3)[0]; \
|
||||
((uint32_t *)s1)[2] = ((uint32_t *)s2)[1]; \
|
||||
((uint32_t *)s1)[3] = ((uint32_t *)s3)[1]; \
|
||||
((uint32_t *)s2)[0] = ((uint32_t *)s2)[2]; \
|
||||
((uint32_t *)s2)[1] = ((uint32_t *)s3)[2]; \
|
||||
((uint32_t *)s2)[2] = ((uint32_t *)s2)[3]; \
|
||||
((uint32_t *)s2)[3] = ((uint32_t *)s3)[3]; \
|
||||
((uint32_t *)s3)[0] = ((uint32_t *)s0)[0]; \
|
||||
((uint32_t *)s3)[1] = ((uint32_t *)s2)[0]; \
|
||||
((uint32_t *)s3)[2] = ((uint32_t *)s0)[1]; \
|
||||
((uint32_t *)s3)[3] = ((uint32_t *)s2)[1]; \
|
||||
((uint32_t *)s0)[0] = ((uint32_t *)s0)[2]; \
|
||||
((uint32_t *)s0)[1] = ((uint32_t *)s2)[2]; \
|
||||
((uint32_t *)s0)[2] = ((uint32_t *)s0)[3]; \
|
||||
((uint32_t *)s0)[3] = ((uint32_t *)s2)[3]; \
|
||||
((uint32_t *)s2)[0] = ((uint32_t *)s1)[2]; \
|
||||
((uint32_t *)s2)[1] = tmp[2]; \
|
||||
((uint32_t *)s2)[2] = ((uint32_t *)s1)[3]; \
|
||||
((uint32_t *)s2)[3] = tmp[3]; \
|
||||
((uint32_t *)s1)[0] = ((uint32_t *)s1)[0]; \
|
||||
((uint32_t *)s1)[1] = tmp[0]; \
|
||||
((uint32_t *)s1)[2] = tmp[4]; \
|
||||
((uint32_t *)s1)[3] = tmp[1];
|
||||
|
||||
|
||||
void haraka256_256(unsigned char *out, const unsigned char *in);
|
||||
void haraka256_256_chain(unsigned char *out, const unsigned char *in, int chainlen);
|
||||
void haraka512_256(unsigned char *out, const unsigned char *in);
|
||||
56
crypto/sphincs/primitives/hash.c
Normal file
56
crypto/sphincs/primitives/hash.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#include "../hash.h"
|
||||
|
||||
#include "haraka.h"
|
||||
#include <openssl/sha.h>
|
||||
|
||||
void hash_N_to_N(struct hash *dst, const struct hash *src)
|
||||
{
|
||||
haraka256_256(dst->h, src->h);
|
||||
}
|
||||
|
||||
void hash_N_to_N_chain(struct hash *dst, const struct hash *src, int chainlen)
|
||||
{
|
||||
haraka256_256_chain(dst->h, src->h, chainlen);
|
||||
}
|
||||
|
||||
void hash_2N_to_N(struct hash *dst, const struct hash *src)
|
||||
{
|
||||
haraka512_256(dst->h, src->h);
|
||||
}
|
||||
|
||||
void hash_to_N(struct hash *dst, const uint8_t *src, uint64_t srclen)
|
||||
{
|
||||
SHA256(src, srclen, dst->h);
|
||||
}
|
||||
|
||||
void hash_compress_pairs(struct hash *dst, const struct hash *src, int count)
|
||||
{
|
||||
int i = 0;
|
||||
for (; i < count; ++i)
|
||||
hash_2N_to_N(&dst[i], &src[2*i]);
|
||||
}
|
||||
|
||||
void hash_compress_all(struct hash *dst, const struct hash *src, int count)
|
||||
{
|
||||
/* Fast implementation with a single call to a large input hash function */
|
||||
hash_to_N(dst, src->h, count * HASH_SIZE);
|
||||
/* TODO: implement a real L-tree with 2N->N compression function */
|
||||
}
|
||||
|
||||
void hash_parallel(struct hash *dst, const struct hash *src, int count)
|
||||
{
|
||||
int i = 0;
|
||||
for (; i < count; ++i)
|
||||
hash_N_to_N(&dst[i], &src[i]);
|
||||
}
|
||||
|
||||
void hash_parallel_chains(struct hash *dst, const struct hash *src, int count, int chainlen)
|
||||
{
|
||||
int i = 0;
|
||||
for (; i < count; ++i)
|
||||
hash_N_to_N_chain(&dst[i], &src[i], chainlen);
|
||||
}
|
||||
|
||||
13
crypto/sphincs/randombytes.c
Normal file
13
crypto/sphincs/randombytes.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "randombytes.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* lazy unsafe emulation of SUPERCOP's randombytes() */
|
||||
void randombytes (unsigned char *x, unsigned long long xlen) {
|
||||
static int fd = -1;
|
||||
if (fd == -1) fd = open ("/dev/urandom", O_RDONLY);
|
||||
read (fd, x, xlen);
|
||||
}
|
||||
4
crypto/sphincs/randombytes.h
Normal file
4
crypto/sphincs/randombytes.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
void randombytes (unsigned char *x, unsigned long long xlen);
|
||||
|
||||
85
crypto/sphincs/sign.c
Normal file
85
crypto/sphincs/sign.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#include "gravity.h"
|
||||
#include "randombytes.h"
|
||||
|
||||
|
||||
int crypto_sign_keypair (unsigned char *pk, unsigned char *sk) {
|
||||
|
||||
struct gravity_sk sk_str;
|
||||
struct gravity_pk pk_str;
|
||||
|
||||
if (!pk || !sk) return -1;
|
||||
|
||||
randombytes (sk_str.seed.h, HASH_SIZE);
|
||||
randombytes (sk_str.salt.h, HASH_SIZE);
|
||||
|
||||
gravity_gensk (&sk_str);
|
||||
|
||||
memcpy (sk, (void *)&sk_str, sizeof (struct gravity_sk));
|
||||
|
||||
gravity_genpk (&sk_str, &pk_str);
|
||||
|
||||
memcpy (pk, pk_str.k.h, HASH_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypto_sign (unsigned char *sm,
|
||||
unsigned long long *smlen,
|
||||
const unsigned char *m,
|
||||
unsigned long long mlen,
|
||||
const unsigned char *sk) {
|
||||
|
||||
struct gravity_sk sk_str;
|
||||
struct hash msg;
|
||||
struct gravity_sign sig;
|
||||
int ret;
|
||||
|
||||
if (!sm || !smlen || !m || !sk) return -1;
|
||||
|
||||
hash_to_N (&msg, m, mlen);
|
||||
|
||||
memcpy ((void *)&sk_str, sk, sizeof (struct gravity_sk));
|
||||
|
||||
memset ((uint8_t *)(&sig), 0, sizeof (struct gravity_sign));
|
||||
|
||||
ret = gravity_sign (&sk_str, &sig, &msg);
|
||||
|
||||
if (ret != GRAVITY_OK) return ret;
|
||||
|
||||
memcpy (sm + mlen, (uint8_t *)(&sig), sizeof (struct gravity_sign));
|
||||
|
||||
memmove (sm, m, mlen);
|
||||
*smlen = mlen + sizeof (struct gravity_sign);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypto_sign_open (unsigned char *m,
|
||||
unsigned long long *mlen,
|
||||
const unsigned char *sm,
|
||||
unsigned long long smlen,
|
||||
const unsigned char *pk) {
|
||||
|
||||
struct gravity_pk pk_str;
|
||||
struct hash msg;
|
||||
struct gravity_sign sig;
|
||||
|
||||
if (!m || !mlen || !sm || !pk) return -1;
|
||||
|
||||
if (smlen < sizeof (struct gravity_sign)) return -2;
|
||||
|
||||
*mlen = smlen - sizeof (struct gravity_sign);
|
||||
|
||||
memcpy ((void *)(&pk_str), pk, HASH_SIZE);
|
||||
|
||||
memcpy ((void *)&sig, sm + *mlen, sizeof (struct gravity_sign));
|
||||
|
||||
memcpy (m, sm, *mlen);
|
||||
|
||||
hash_to_N (&msg, m, *mlen);
|
||||
|
||||
return gravity_verify (&pk_str, &sig, &msg);
|
||||
}
|
||||
18
crypto/sphincs/sign.h
Normal file
18
crypto/sphincs/sign.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
int crypto_sign_keypair (unsigned char *pk, unsigned char *sk);
|
||||
|
||||
int crypto_sign (unsigned char *sm,
|
||||
unsigned long long *smlen,
|
||||
const unsigned char *m,
|
||||
unsigned long long mlen,
|
||||
const unsigned char *sk);
|
||||
|
||||
int crypto_sign_open (unsigned char *m,
|
||||
unsigned long long *mlen,
|
||||
const unsigned char *sm,
|
||||
unsigned long long smlen,
|
||||
const unsigned char *pk);
|
||||
101
crypto/sphincs/wots.c
Normal file
101
crypto/sphincs/wots.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#include "wots.h"
|
||||
#include "aes.h"
|
||||
|
||||
#include "ltree.h"
|
||||
|
||||
void wots_chain (const struct hash *src, struct hash *dst, int count) {
|
||||
hash_N_to_N_chain (dst, src, count);
|
||||
}
|
||||
|
||||
/* Naive WOTS without L-tree nor masks */
|
||||
void wots_gensk (const struct hash *key, const struct address *address, struct wots_sk *sk) {
|
||||
uint8_t iv[16];
|
||||
|
||||
iv[0] = (address->index >> 56) & 0xFF;
|
||||
iv[1] = (address->index >> 48) & 0xFF;
|
||||
iv[2] = (address->index >> 40) & 0xFF;
|
||||
iv[3] = (address->index >> 32) & 0xFF;
|
||||
iv[4] = (address->index >> 24) & 0xFF;
|
||||
iv[5] = (address->index >> 16) & 0xFF;
|
||||
iv[6] = (address->index >> 8) & 0xFF;
|
||||
iv[7] = address->index & 0xFF;
|
||||
|
||||
iv[8] = (address->layer >> 24) & 0xFF;
|
||||
iv[9] = (address->layer >> 16) & 0xFF;
|
||||
iv[10] = (address->layer >> 8) & 0xFF;
|
||||
iv[11] = address->layer & 0xFF;
|
||||
|
||||
/* Counter */
|
||||
iv[12] = 0;
|
||||
iv[13] = 0;
|
||||
iv[14] = 0;
|
||||
iv[15] = 0;
|
||||
aesctr256 (sk->k->h, key->h, iv, WOTS_ell * HASH_SIZE);
|
||||
}
|
||||
|
||||
void wots_sign (const struct wots_sk *sk, struct wots_sign *sign, const struct hash *msg) {
|
||||
int checksum = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < WOTS_ell1; ++i) {
|
||||
uint8_t v = msg->h[i / 2];
|
||||
int a = (v >> 4) & 15;
|
||||
int b = v & 15;
|
||||
checksum += (WOTS_w - 1 - a) + (WOTS_w - 1 - b);
|
||||
|
||||
wots_chain (&sk->k[i], &sign->s[i], a);
|
||||
++i;
|
||||
wots_chain (&sk->k[i], &sign->s[i], b);
|
||||
}
|
||||
|
||||
/* Checksum values */
|
||||
for (i = WOTS_ell1; i < WOTS_ell; ++i) {
|
||||
wots_chain (&sk->k[i], &sign->s[i], checksum & 15);
|
||||
checksum >>= 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* WOTS with L-tree and without masks */
|
||||
void lwots_ltree (const struct wots_pk *pk, struct lwots_pk *root) {
|
||||
struct hash buf[2 * WOTS_ell];
|
||||
|
||||
hashcpyN (buf, pk->k, WOTS_ell);
|
||||
ltree (buf, WOTS_ell, &root->k);
|
||||
}
|
||||
|
||||
void lwots_genpk (const struct wots_sk *sk, struct lwots_pk *pk) {
|
||||
struct wots_pk tmp;
|
||||
|
||||
hash_parallel_chains (tmp.k, sk->k, WOTS_ell, WOTS_w - 1);
|
||||
lwots_ltree (&tmp, pk);
|
||||
}
|
||||
|
||||
void lwots_extract (struct lwots_pk *pk, const struct wots_sign *sign, const struct hash *msg) {
|
||||
struct wots_pk tmp;
|
||||
int i;
|
||||
int checksum = 0;
|
||||
|
||||
for (i = 0; i < WOTS_ell1; ++i) {
|
||||
uint8_t v = msg->h[i / 2];
|
||||
int a = (v >> 4) & 15;
|
||||
int b = v & 15;
|
||||
checksum += (WOTS_w - 1 - a) + (WOTS_w - 1 - b);
|
||||
|
||||
wots_chain (&sign->s[i], &tmp.k[i], WOTS_w - 1 - a);
|
||||
++i;
|
||||
wots_chain (&sign->s[i], &tmp.k[i], WOTS_w - 1 - b);
|
||||
}
|
||||
|
||||
/* Checksum values */
|
||||
for (i = WOTS_ell1; i < WOTS_ell; ++i) {
|
||||
wots_chain (&sign->s[i], &tmp.k[i], WOTS_w - 1 - (checksum & 15));
|
||||
checksum >>= 4;
|
||||
}
|
||||
|
||||
/* L-tree */
|
||||
lwots_ltree (&tmp, pk);
|
||||
}
|
||||
34
crypto/sphincs/wots.h
Normal file
34
crypto/sphincs/wots.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Nagravision S.A.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "hash.h"
|
||||
|
||||
/* Naive WOTS without L-tree nor masks */
|
||||
struct wots_sk {
|
||||
struct hash k[WOTS_ell];
|
||||
};
|
||||
|
||||
struct wots_pk {
|
||||
struct hash k[WOTS_ell];
|
||||
};
|
||||
|
||||
struct wots_sign {
|
||||
struct hash s[WOTS_ell];
|
||||
};
|
||||
|
||||
void wots_gensk (const struct hash *key, const struct address *address, struct wots_sk *sk);
|
||||
|
||||
void wots_sign (const struct wots_sk *sk, struct wots_sign *sign, const struct hash *msg);
|
||||
|
||||
|
||||
/* WOTS with L-tree and without masks */
|
||||
struct lwots_pk {
|
||||
struct hash k;
|
||||
};
|
||||
|
||||
void lwots_genpk (const struct wots_sk *sk, struct lwots_pk *pk);
|
||||
|
||||
void lwots_extract (struct lwots_pk *pk, const struct wots_sign *sign, const struct hash *msg);
|
||||
Reference in New Issue
Block a user