Files
GmSSL/crypto/sphincs/pors.c
2019-03-13 22:26:55 +08:00

201 lines
5.3 KiB
C

/*
* 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++;
}
}
}