summaryrefslogtreecommitdiff
path: root/lib/liboqs/src/sig/sphincs/pqclean_sphincs-sha256-128f-simple_clean/sha256.c
blob: 03d0eb990e251202286c439310da3ae809222299 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/* Based on the public domain implementation in
 * crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html
 * by D. J. Bernstein */

#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include "sha2.h"
#include "sha256.h"
#include "utils.h"

/*
 * Compresses an address to a 22-byte sequence.
 * This reduces the number of required SHA256 compression calls, as the last
 * block of input is padded with at least 65 bits.
 */
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]) {
    PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(out,      1, addr[0]); /* drop 3 bytes of the layer field */
    PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(out + 1,  4, addr[2]); /* drop the highest tree address word */
    PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(out + 5,  4, addr[3]);
    PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(out + 9,  1, addr[4]); /* drop 3 bytes of the type field */
    PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(out + 10, 4, addr[5]);
    PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(out + 14, 4, addr[6]);
    PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(out + 18, 4, addr[7]);
}

/**
 * Requires 'input_plus_four_bytes' to have 'inlen' + 4 bytes, so that the last
 * four bytes can be used for the counter. Typically 'input' is merely a seed.
 * Outputs outlen number of bytes
 */
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_mgf1(
    unsigned char *out, unsigned long outlen,
    unsigned char *input_plus_four_bytes, unsigned long inlen) {
    unsigned char outbuf[PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_SHA256_OUTPUT_BYTES];
    unsigned long i;

    /* While we can fit in at least another full block of SHA256 output.. */
    for (i = 0; (i + 1)*PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_SHA256_OUTPUT_BYTES <= outlen; i++) {
        PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(input_plus_four_bytes + inlen, 4, i);
        sha256(out, input_plus_four_bytes, inlen + 4);
        out += PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_SHA256_OUTPUT_BYTES;
    }
    /* Until we cannot anymore, and we fill the remainder. */
    if (outlen > i * PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_SHA256_OUTPUT_BYTES) {
        PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(input_plus_four_bytes + inlen, 4, i);
        sha256(outbuf, input_plus_four_bytes, inlen + 4);
        memcpy(out, outbuf, outlen - i * PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_SHA256_OUTPUT_BYTES);
    }
}


/**
 * Absorb the constant pub_seed using one round of the compression function
 * This initializes hash_state_seeded, which can then be reused in thash
 **/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_seed_state(sha256ctx *hash_state_seeded, const unsigned char *pub_seed) {
    uint8_t block[PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_SHA256_BLOCK_BYTES];
    size_t i;

    for (i = 0; i < PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_N; ++i) {
        block[i] = pub_seed[i];
    }
    for (i = PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_N; i < PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_SHA256_BLOCK_BYTES; ++i) {
        block[i] = 0;
    }

    sha256_inc_init(hash_state_seeded);
    sha256_inc_blocks(hash_state_seeded, block, 1);
}