Commit 1ea09eb5 authored by Beniamino Galvani's avatar Beniamino Galvani

Squashed 'shared/c-siphash/' content from commit 24e301e32

git-subtree-dir: shared/c-siphash
git-subtree-split: 24e301e32939be88744a9d0f81d18d9b7b8f4e37
parents
#!/bin/bash
set -e
rm -Rf "./ci-build"
mkdir "./ci-build"
cd "./ci-build"
${CHERRY_LIB_MESONSETUP} . "${CHERRY_LIB_SRCDIR}"
${CHERRY_LIB_NINJABUILD}
${CHERRY_LIB_MESONTEST}
(( ! CHERRY_LIB_VALGRIND )) || ${CHERRY_LIB_MESONTEST} "--wrapper=${CHERRY_LIB_VALGRINDWRAP}"
root = true
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
[*.{c,h}]
indent_style = space
indent_size = 8
services:
- docker
before_install:
- curl -O -L "https://raw.githubusercontent.com/cherry-pick/cherry-images/v1/scripts/vmrun"
- curl -O -L "https://raw.githubusercontent.com/cherry-pick/cherry-ci/v1/scripts/cherryci"
- chmod +x "./vmrun" "./cherryci"
jobs:
include:
- stage: test
script:
- ./vmrun -- ../src/cherryci -d ../src/.cherryci -s c-util -m
- script:
- ./vmrun -T armv7hl -- ../src/cherryci -d ../src/.cherryci -s c-util -m
- script:
- ./vmrun -T i686 -- ../src/cherryci -d ../src/.cherryci -s c-util -m
LICENSE:
This project is dual-licensed under both the Apache License, Version
2.0, and the GNU Lesser General Public License, Version 2.1+.
AUTHORS-ASL:
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.
AUTHORS-LGPL:
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.
COPYRIGHT: (ordered alphabetically)
Copyright (C) 2015-2018 Red Hat, Inc.
AUTHORS: (ordered alphabetically)
David Herrmann <dh.herrmann@gmail.com>
Tom Gundersen <teg@jklm.no>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
c-siphash - Streaming-capable SipHash Implementation
ABOUT:
The c-siphash project is a standalone implementation of SipHash in
Standard ISO-C11. It provides a streaming-capable API to compute data
hashes according to the SipHash algorithm.
For API documentation, see the c-siphash.h header file, as well as the
docbook comments for each function.
DETAILS:
https://c-util.github.io/c-siphash
BUG REPORTS:
https://github.com/c-util/c-siphash/issues
GIT:
git@github.com:c-util/c-siphash.git
https://github.com/c-util/c-siphash.git
GITWEB:
https://github.com/c-util/c-siphash
LICENSE:
Apache Software License 2.0
Lesser General Public License 2.1+
See AUTHORS for details.
REQUIREMENTS:
The requirements for c-siphash are:
libc (e.g., glibc >= 2.16)
At build-time, the following software is required:
meson >= 0.41
pkg-config >= 0.29
INSTALL:
The meson build-system is used for c-siphash. Contact upstream
documentation for detailed help. In most situations the following
commands are sufficient to build and install c-siphash from source:
$ mkdir build
$ cd build
$ meson setup ..
$ ninja
$ meson test
# ninja install
No custom configuration options are available.
project(
'c-siphash',
'c',
version: '1',
license: 'Apache',
default_options: [
'c_std=c11'
]
)
add_project_arguments('-D_GNU_SOURCE', language: 'c')
mod_pkgconfig = import('pkgconfig')
subdir('src')
/*
* SipHash Implementation
*
* For highlevel documentation of the API see the header file and the docbook
* comments. This implementation is based on the reference implementation of
* SipHash, written by Jean-Philippe Aumasson and Daniel J. Bernstein, and
* released to the Public Domain.
*
* So far, only SipHash24 is implemented, since there was no need for other
* parameters. However, adjusted c_siphash_append_X() and
* C_siphash_finalize_Y() can be easily provided, if required.
*/
#include <stddef.h>
#include <stdint.h>
#include "c-siphash.h"
#define _public_ __attribute__((__visibility__("default")))
static inline uint64_t c_siphash_read_le64(const uint8_t bytes[8]) {
return ((uint64_t) bytes[0]) |
(((uint64_t) bytes[1]) << 8) |
(((uint64_t) bytes[2]) << 16) |
(((uint64_t) bytes[3]) << 24) |
(((uint64_t) bytes[4]) << 32) |
(((uint64_t) bytes[5]) << 40) |
(((uint64_t) bytes[6]) << 48) |
(((uint64_t) bytes[7]) << 56);
}
static inline uint64_t c_siphash_rotate_left(uint64_t x, uint8_t b) {
return (x << b) | (x >> (64 - b));
}
static inline void c_siphash_sipround(CSipHash *state) {
state->v0 += state->v1;
state->v1 = c_siphash_rotate_left(state->v1, 13);
state->v1 ^= state->v0;
state->v0 = c_siphash_rotate_left(state->v0, 32);
state->v2 += state->v3;
state->v3 = c_siphash_rotate_left(state->v3, 16);
state->v3 ^= state->v2;
state->v0 += state->v3;
state->v3 = c_siphash_rotate_left(state->v3, 21);
state->v3 ^= state->v0;
state->v2 += state->v1;
state->v1 = c_siphash_rotate_left(state->v1, 17);
state->v1 ^= state->v2;
state->v2 = c_siphash_rotate_left(state->v2, 32);
}
/**
* c_siphash_init() - initialize siphash context
* @state: context object
* @seed: 128bit seed
*
* This initializes the siphash state context. Once initialized, it can be used
* to hash arbitary input. To feed data into it, use c_siphash_append(). To get
* the final hash, use c_siphash_finalize().
*
* Note that the siphash context does not allocate state. There is no need to
* deserialize it before releasing its backing memory.
*
* The hashes generated by this context change depending on the seed. Every
* user is highly inclined to provide their unique seed. If no stable hashes
* are needed, a random seed will do fine.
*
* Right now, only SipHash24 is supported. Other SipHash parameters can be
* easily added if required.
*/
_public_ void c_siphash_init(CSipHash *state, const uint8_t seed[16]) {
uint64_t k0, k1;
k0 = c_siphash_read_le64(seed);
k1 = c_siphash_read_le64(seed + 8);
*state = (CSipHash) {
/*
* Default seed is taken from the reference implementation
* of SipHash24 ("somepseudorandomlygeneratedbytes"). Callers
* are still recommended to provide proper seeds themselves.
*/
.v0 = 0x736f6d6570736575ULL ^ k0,
.v1 = 0x646f72616e646f6dULL ^ k1,
.v2 = 0x6c7967656e657261ULL ^ k0,
.v3 = 0x7465646279746573ULL ^ k1,
.padding = 0,
.n_bytes = 0,
};
}
/**
* c_siphash_append() - hash stream of data
* @state: context object
* @bytes: array of input bytes
* @n_bytes: number of input bytes
*
* This feeds an array of bytes into the SipHash state machine. This is a
* streaming-capable API. That is, the resulting hash is the same, regardless
* of the way you chunk the input.
* This function simply feeds the given bytes into the SipHash state machine.
* It does not produce a final hash. You can call this function many times to
* append more data. To retrieve the final hash, call c_siphash_finalize().
*
* Note that this implementation works best when used with chunk-sizes of
* multiples of 64bit (8-bytes). This is not a requirement, though.
*/
_public_ void c_siphash_append(CSipHash *state, const uint8_t *bytes, size_t n_bytes) {
const uint8_t *end = bytes + n_bytes;
size_t left = state->n_bytes & 7;
uint64_t m;
state->n_bytes += n_bytes;
/*
* SipHash operates on 64bit chunks. If the previous blob was not a
* multiple of 64bit in length, we must operate on single bytes.
*/
if (left > 0) {
for ( ; bytes < end && left < 8; ++bytes, ++left)
state->padding |= ((uint64_t) *bytes) << (left * 8);
if (bytes == end && left < 8)
return;
state->v3 ^= state->padding;
c_siphash_sipround(state);
c_siphash_sipround(state);
state->v0 ^= state->padding;
state->padding = 0;
}
end -= (state->n_bytes % sizeof(uint64_t));
/*
* We are now guaranteed to be at a 64bit state boudary. Hence, we can
* operate in 64bit chunks on all input. This is much faster than the
* one-byte-at-a-time loop.
*/
for ( ; bytes < end; bytes += 8) {
m = c_siphash_read_le64(bytes);
state->v3 ^= m;
c_siphash_sipround(state);
c_siphash_sipround(state);
state->v0 ^= m;
}
/*
* Now that we hashed as much 64bit chunks as possible, we need to
* remember the remaining trailing bytes. Keep them in @padding so the
* next round (or the finalizer) get access to them.
*/
left = state->n_bytes & 7;
switch (left) {
case 7:
state->padding |= ((uint64_t) bytes[6]) << 48;
/* fallthrough */
case 6:
state->padding |= ((uint64_t) bytes[5]) << 40;
/* fallthrough */
case 5:
state->padding |= ((uint64_t) bytes[4]) << 32;
/* fallthrough */
case 4:
state->padding |= ((uint64_t) bytes[3]) << 24;
/* fallthrough */
case 3:
state->padding |= ((uint64_t) bytes[2]) << 16;
/* fallthrough */
case 2:
state->padding |= ((uint64_t) bytes[1]) << 8;
/* fallthrough */
case 1:
state->padding |= ((uint64_t) bytes[0]);
/* fallthrough */
case 0:
break;
}
}
/**
* c_siphash_finalize() - finalize hash
* @state: context object
*
* This produces the final SipHash24 hash value for the given SipHash state.
* That is, it produces a hash value corresponding to the SipHash24 hash value
* of the concatenated byte-array passed into @state via c_siphash_append().
*
* Note that @state has an invalid state after this function returns. To reuse
* it for another hash, you must call c_siphash_init() again. If you don't need
* the object, anymore, you can release it any time. There is no need to
* destroy the object explicitly.
*
* Return: 64bit hash value
*/
_public_ uint64_t c_siphash_finalize(CSipHash *state) {
uint64_t b;
b = state->padding | (((uint64_t) state->n_bytes) << 56);
state->v3 ^= b;
c_siphash_sipround(state);
c_siphash_sipround(state);
state->v0 ^= b;
state->v2 ^= 0xff;
c_siphash_sipround(state);
c_siphash_sipround(state);
c_siphash_sipround(state);
c_siphash_sipround(state);
return state->v0 ^ state->v1 ^ state->v2 ^ state->v3;
}
/**
* c_siphash_hash() - hash data blob
* @seed: 128bit seed
* @bytes: byte array to hash
* @n_bytes: number of bytes to hash
*
* This produces the SipHash24 hash value for the input @bytes / @n_bytes,
* using the seed provided as @seed.
*
* This is functionally equivalent to:
*
* CSipHash state;
* c_siphash_init(&state, seed);
* c_siphash_apend(&state, bytes, n_bytes);
* return c_siphash_finalize(&state);
*
* Unlike the streaming API, this is a one-shot call suitable for any data that
* is available in-memory at the same time.
*
* Return: 64bit hash value
*/
_public_ uint64_t c_siphash_hash(const uint8_t seed[16], const uint8_t *bytes, size_t n_bytes) {
CSipHash state;
c_siphash_init(&state, seed);
c_siphash_append(&state, bytes, n_bytes);
return c_siphash_finalize(&state);
}
#pragma once
/**
* Streaming-capable SipHash Implementation
*
* This library provides a SipHash API, that is fully implemented in ISO-C11
* and has no external dependencies. The library performs no memory allocation,
* and provides a streaming API where data to be hashed can be appended
* piecemeal.
*
* A streaming-capable hash state is represented by the "CSipHash" structure,
* which should be initialized with a unique seed before use. If streaming
* capabilities are not required, c_siphash_hash() provides a simple one-shot
* API.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
typedef struct CSipHash CSipHash;
/**
* struct CSipHash - SipHash state object
* @v0-@v3: internal state
* @padding: pending bytes that were not a multiple of 8
* @n_bytes: number of hashed bytes
*
* The state of an inflight hash is represenetd by a CSipHash object. Before
* hashing, it must be initialized with c_siphash_init(), providing a unique
* random hash seed. Data is hashed by appending it to the state object, using
* c_siphash_append(). Finally, the hash is read out by calling
* c_siphash_finalize().
*
* This state object has no allocated resources. It is safe to release its
* backing memory without any further action.
*/
struct CSipHash {
uint64_t v0;
uint64_t v1;
uint64_t v2;
uint64_t v3;
uint64_t padding;
size_t n_bytes;
};
#define C_SIPHASH_NULL {}
void c_siphash_init(CSipHash *state, const uint8_t seed[16]);
void c_siphash_append(CSipHash *state, const uint8_t *bytes, size_t n_bytes);
uint64_t c_siphash_finalize(CSipHash *state);
uint64_t c_siphash_hash(const uint8_t seed[16], const uint8_t *bytes, size_t n_bytes);
#ifdef __cplusplus
}
#endif
LIBCSIPHASH_1 {
global:
c_siphash_init;
c_siphash_append;
c_siphash_finalize;
c_siphash_hash;
local:
*;
};
#
# target: libcsiphash.so
#
libcsiphash_symfile = join_paths(meson.current_source_dir(), 'libcsiphash.sym')
libcsiphash_private = static_library(
'csiphash-private',
[
'c-siphash.c',
],
c_args: [
'-fvisibility=hidden',
'-fno-common',
],
pic: true,
)
libcsiphash_shared = shared_library(
'csiphash',
objects: libcsiphash_private.extract_all_objects(),
install: not meson.is_subproject(),
soversion: 0,
link_depends: libcsiphash_symfile,
link_args: [
'-Wl,--no-undefined',
'-Wl,--version-script=@0@'.format(libcsiphash_symfile),
],
)
libcsiphash_dep = declare_dependency(
include_directories: include_directories('.'),
link_with: libcsiphash_private,
version: meson.project_version()
)
if not meson.is_subproject()
install_headers('c-siphash.h')
mod_pkgconfig.generate(
libraries: libcsiphash_shared,
version: meson.project_version(),
name: 'libcsiphash',
filebase: 'libcsiphash',
description: 'Streaming-capable SipHash Implementation',
)
endif
#
# target: test-*
#
test_api = executable('test-api', ['test-api.c'], link_with: libcsiphash_shared)
test('API Symbol Visibility', test_api)
test_basic = executable('test-basic', ['test-basic.c'], link_with: libcsiphash_private)
test('Basic API Behavior', test_basic)
/*
* Tests for Public API
* This test, unlikely the others, is linked against the real, distributed,
* shared library. Its sole purpose is to test for symbol availability.
*/
#undef NDEBUG
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "c-siphash.h"
static void test_api(void) {
CSipHash state = C_SIPHASH_NULL;
uint8_t seed[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
uint64_t hash1, hash2;
c_siphash_init(&state, seed);
c_siphash_append(&state, NULL, 0);
hash1 = c_siphash_finalize(&state);
assert(hash1 == 12552310112479190712ULL);
hash2 = c_siphash_hash(seed, NULL, 0);
assert(hash1 == hash2);
}
int main(int argc, char **argv) {
test_api();
return 0;
}
/*
* Tests for Basic Hash Operations
* This test does some basic hash operations and verifies their correctness. It
* breaks up the data to be hashed in various ways to make sure it is stable.
*/
#undef NDEBUG
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "c-siphash.h"
/* See https://131002.net/siphash/siphash.pdf, Appendix A. */
static void do_reference_test(const uint8_t *in, size_t len, const uint8_t *key) {
CSipHash state = {};
uint64_t out;
unsigned i, j;
/* verify the internal state as given in the above paper */
c_siphash_init(&state, key);
assert(state.v0 == 0x7469686173716475);
assert(state.v1 == 0x6b617f6d656e6665);
assert(state.v2 == 0x6b7f62616d677361);
assert(state.v3 == 0x7b6b696e727e6c7b);
c_siphash_append(&state, in, len);
assert(state.v0 == 0x4a017198de0a59e0);
assert(state.v1 == 0x0d52f6f62a4f59a4);
assert(state.v2 == 0x634cb3577b01fd3d);
assert(state.v3 == 0xa5224d6f55c7d9c8);
out = c_siphash_finalize(&state);
assert(out == 0xa129ca6149be45e5);
assert(state.v0 == 0xf6bcd53893fecff1);
assert(state.v1 == 0x54b9964c7ea0d937);
assert(state.v2 == 0x1b38329c099bb55a);
assert(state.v3 == 0x1814bb89ad7be679);
/* verify that decomposing the input in three chunks gives the
same result */
for (i = 0; i < len; i++) {
for (j = i; j < len; j++) {
c_siphash_init(&state, key);
c_siphash_append(&state, in, i);
c_siphash_append(&state, &in[i], j - i);
c_siphash_append(&state, &in[j], len - j);
out = c_siphash_finalize(&state);
assert(out == 0xa129ca6149be45e5);
}
}
/* verify c_siphash_hash() produces the same result */
assert(out == c_siphash_hash(key, in, len));
}
static void test_reference(void) {
const uint8_t in[15] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e };
const uint8_t key[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
uint8_t in_buf[20];
/* Test with same input but different alignments. */
memcpy(in_buf, in, sizeof(in));
do_reference_test(in_buf, sizeof(in), key);
memcpy(in_buf + 1, in, sizeof(in));
do_reference_test(in_buf + 1, sizeof(in), key);
memcpy(in_buf + 2, in, sizeof(in));
do_reference_test(in_buf + 2, sizeof(in), key);
memcpy(in_buf + 4, in, sizeof(in));
do_reference_test(in_buf + 4, sizeof(in), key);
}
static void test_short_hashes(void) {
const uint8_t one[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };
const uint8_t key[16] = { 0x22, 0x24, 0x41, 0x22, 0x55, 0x77, 0x88, 0x07,
0x23, 0x09, 0x23, 0x14, 0x0c, 0x33, 0x0e, 0x0f};
uint8_t two[sizeof one] = {};
CSipHash state1 = {}, state2 = {};
unsigned i, j;
c_siphash_init(&state1, key);
c_siphash_init(&state2, key);
/* hashing 1, 2, 3, 4, 5, ..., 16 bytes, with the byte after the buffer different */
for (i = 1; i <= sizeof one; i++) {
c_siphash_append(&state1, one, i);
two[i-1] = one[i-1];
c_siphash_append(&state2, two, i);
assert(memcmp(&state1, &state2, sizeof state1) == 0);
}
/* hashing n and 1, n and 2, n and 3, ..., n-1 and 1, n-2 and 2, ... */
for (i = sizeof one; i > 0; i--) {
memset(two, 0, sizeof(two));
for (j = 1; j <= sizeof one; j++) {
c_siphash_append(&state1, one, i);
c_siphash_append(&state1, one, j);
c_siphash_append(&state2, one, i);
two[j-1] = one[j-1];
c_siphash_append(&state2, two, j);
assert(memcmp(&state1, &state2, sizeof state1) == 0);
}
}
}
int main(int argc, char *argv[]) {
test_reference();
test_short_hashes();
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment