mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 19:43:32 +00:00
181 lines
7.7 KiB
C
181 lines
7.7 KiB
C
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
│ Copyright 2021 Google LLC │
|
|
│ │
|
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
│ any purpose with or without fee is hereby granted, provided that the │
|
|
│ above copyright notice and this permission notice appear in all copies. │
|
|
│ │
|
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "libc/str/blake2.h"
|
|
#include "libc/assert.h"
|
|
#include "libc/macros.internal.h"
|
|
#include "libc/str/str.h"
|
|
|
|
#define ROR(v, n) (((v) >> (n)) | ((v) << (64 - (n))))
|
|
|
|
asm(".ident\t\"\\n\\n\
|
|
boringssl blake2b (ISC License)\\n\
|
|
Copyright 2021 Google LLC\"");
|
|
asm(".include \"libc/disclaimer.inc\"");
|
|
|
|
// https://tools.ietf.org/html/rfc7693#section-2.6
|
|
static const uint64_t kIV[8] = {
|
|
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b,
|
|
0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f,
|
|
0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
|
|
};
|
|
|
|
// https://tools.ietf.org/html/rfc7693#section-2.7
|
|
static const uint8_t kSigma[10][16] = {
|
|
// clang-format off
|
|
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
|
{14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
|
|
{11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
|
|
{7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
|
|
{9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
|
|
{2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
|
|
{12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
|
|
{13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
|
|
{6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
|
|
{10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
|
|
// clang-format on
|
|
};
|
|
|
|
// https://tools.ietf.org/html/rfc7693#section-3.1
|
|
static void Blake2bMix(uint64_t v[16], int a, int b, int c, int d, uint64_t x,
|
|
uint64_t y) {
|
|
v[a] = v[a] + v[b] + x;
|
|
v[d] = ROR(v[d] ^ v[a], 32);
|
|
v[c] = v[c] + v[d];
|
|
v[b] = ROR(v[b] ^ v[c], 24);
|
|
v[a] = v[a] + v[b] + y;
|
|
v[d] = ROR(v[d] ^ v[a], 16);
|
|
v[c] = v[c] + v[d];
|
|
v[b] = ROR(v[b] ^ v[c], 63);
|
|
}
|
|
|
|
static void Blake2bTransform(
|
|
struct Blake2b *b2b, const uint64_t w[BLAKE2B_CBLOCK / sizeof(uint64_t)],
|
|
size_t num_bytes, int is_final_block) {
|
|
// https://tools.ietf.org/html/rfc7693#section-3.2
|
|
uint64_t v[16];
|
|
_Static_assert(sizeof(v) == sizeof(b2b->h) + sizeof(kIV), "");
|
|
memcpy(v, b2b->h, sizeof(b2b->h));
|
|
memcpy(&v[8], kIV, sizeof(kIV));
|
|
b2b->t_low += num_bytes;
|
|
if (b2b->t_low < num_bytes) {
|
|
b2b->t_high++;
|
|
}
|
|
v[12] ^= b2b->t_low;
|
|
v[13] ^= b2b->t_high;
|
|
if (is_final_block) {
|
|
v[14] = ~v[14];
|
|
}
|
|
for (int i = 0; i < 12; i++) {
|
|
Blake2bMix(v, 0, 4, 8, 12, w[kSigma[i % 10][0]], w[kSigma[i % 10][1]]);
|
|
Blake2bMix(v, 1, 5, 9, 13, w[kSigma[i % 10][2]], w[kSigma[i % 10][3]]);
|
|
Blake2bMix(v, 2, 6, 10, 14, w[kSigma[i % 10][4]], w[kSigma[i % 10][5]]);
|
|
Blake2bMix(v, 3, 7, 11, 15, w[kSigma[i % 10][6]], w[kSigma[i % 10][7]]);
|
|
Blake2bMix(v, 0, 5, 10, 15, w[kSigma[i % 10][8]], w[kSigma[i % 10][9]]);
|
|
Blake2bMix(v, 1, 6, 11, 12, w[kSigma[i % 10][10]], w[kSigma[i % 10][11]]);
|
|
Blake2bMix(v, 2, 7, 8, 13, w[kSigma[i % 10][12]], w[kSigma[i % 10][13]]);
|
|
Blake2bMix(v, 3, 4, 9, 14, w[kSigma[i % 10][14]], w[kSigma[i % 10][15]]);
|
|
}
|
|
for (size_t i = 0; i < ARRAYLEN(b2b->h); i++) {
|
|
b2b->h[i] ^= v[i];
|
|
b2b->h[i] ^= v[i + 8];
|
|
}
|
|
}
|
|
|
|
int BLAKE2B256_Init(struct Blake2b *b2b) {
|
|
bzero(b2b, sizeof(struct Blake2b));
|
|
_Static_assert(sizeof(kIV) == sizeof(b2b->h), "");
|
|
memcpy(&b2b->h, kIV, sizeof(kIV));
|
|
// https://tools.ietf.org/html/rfc7693#section-2.5
|
|
b2b->h[0] ^= 0x01010000 | BLAKE2B256_DIGEST_LENGTH;
|
|
return 0;
|
|
}
|
|
|
|
int BLAKE2B256_Process(struct Blake2b *b2b,
|
|
const uint64_t data[BLAKE2B_CBLOCK / 8]) {
|
|
Blake2bTransform(b2b, data, BLAKE2B_CBLOCK, /*is_final_block=*/0);
|
|
return 0;
|
|
}
|
|
|
|
int BLAKE2B256_Update(struct Blake2b *b2b, const void *in_data, size_t len) {
|
|
const uint8_t *data = (const uint8_t *)in_data;
|
|
size_t todo = sizeof(b2b->block.bytes) - b2b->block_used;
|
|
if (todo > len) {
|
|
todo = len;
|
|
}
|
|
if (todo) memcpy(&b2b->block.bytes[b2b->block_used], data, todo);
|
|
b2b->block_used += todo;
|
|
data += todo;
|
|
len -= todo;
|
|
if (!len) {
|
|
return 0;
|
|
}
|
|
// More input remains therefore we must have filled |b2b->block|.
|
|
_unassert(b2b->block_used == BLAKE2B_CBLOCK);
|
|
Blake2bTransform(b2b, b2b->block.words, BLAKE2B_CBLOCK,
|
|
/*is_final_block=*/0);
|
|
b2b->block_used = 0;
|
|
while (len > BLAKE2B_CBLOCK) {
|
|
uint64_t block_words[BLAKE2B_CBLOCK / sizeof(uint64_t)];
|
|
memcpy(block_words, data, sizeof(block_words));
|
|
Blake2bTransform(b2b, block_words, BLAKE2B_CBLOCK, /*is_final_block=*/0);
|
|
data += BLAKE2B_CBLOCK;
|
|
len -= BLAKE2B_CBLOCK;
|
|
}
|
|
if (len) memcpy(b2b->block.bytes, data, len);
|
|
b2b->block_used = len;
|
|
return 0;
|
|
}
|
|
|
|
int BLAKE2B256_Final(struct Blake2b *b2b,
|
|
uint8_t out[BLAKE2B256_DIGEST_LENGTH]) {
|
|
bzero(&b2b->block.bytes[b2b->block_used],
|
|
sizeof(b2b->block.bytes) - b2b->block_used);
|
|
Blake2bTransform(b2b, b2b->block.words, b2b->block_used,
|
|
/*is_final_block=*/1);
|
|
_Static_assert(BLAKE2B256_DIGEST_LENGTH <= sizeof(b2b->h), "");
|
|
memcpy(out, b2b->h, BLAKE2B256_DIGEST_LENGTH);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Computes blake2b 256bit message digest.
|
|
*
|
|
* blake2b256 n=0 191 nanoseconds
|
|
* blake2b256 n=8 23 ns/byte 40,719 kb/s
|
|
* blake2b256 n=31 6 ns/byte 153 mb/s
|
|
* blake2b256 n=32 6 ns/byte 158 mb/s
|
|
* blake2b256 n=63 3 ns/byte 312 mb/s
|
|
* blake2b256 n=64 3 ns/byte 317 mb/s
|
|
* blake2b256 n=128 1 ns/byte 640 mb/s
|
|
* blake2b256 n=256 1 ns/byte 662 mb/s
|
|
* blake2b256 n=22851 1 ns/byte 683 mb/s
|
|
*
|
|
* @param data is binary memory to hash
|
|
* @param len is bytes in `data`
|
|
* @param out receives 32 byte binary digest
|
|
* @return 0 on success (always successful)
|
|
*/
|
|
int BLAKE2B256(const void *data, size_t len,
|
|
uint8_t out[BLAKE2B256_DIGEST_LENGTH]) {
|
|
struct Blake2b ctx;
|
|
BLAKE2B256_Init(&ctx);
|
|
BLAKE2B256_Update(&ctx, data, len);
|
|
BLAKE2B256_Final(&ctx, out);
|
|
return 0;
|
|
}
|