Merge pull request #5 from guanzhi/master

update 4-2
This commit is contained in:
Gorachya
2019-04-02 11:35:00 +08:00
committed by GitHub
30 changed files with 2022 additions and 1 deletions

View File

@@ -1,3 +1,3 @@
LIBS=../../libcrypto
SOURCE[../../libcrypto]=sm2_err.c sm2_asn1.c sm2_id.c sm2_sign.c sm2_enc.c \
sm2_oct.c sm2_exch.c sm2_kmeth.c
sm2_oct.c sm2_exch.c sm2_kmeth.c sm2_cosign.c

View 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
View File

@@ -0,0 +1,3 @@
bench
*.o
*.dSYM

13
crypto/sphincs/LICENSE Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);

View 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);
}

View 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];
}

View 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);

View 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);
}

View 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);
}

View File

@@ -0,0 +1,4 @@
#pragma once
void randombytes (unsigned char *x, unsigned long long xlen);

85
crypto/sphincs/sign.c Normal file
View 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
View 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
View 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
View 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);