Rusty Russell
9 years ago
20 changed files with 979 additions and 32 deletions
@ -1,3 +1,3 @@ |
|||
CCAN imported from http://ccodearchive.net. |
|||
|
|||
CCAN version: init-2181-g2953f51 |
|||
CCAN version: init-2207-ge0b86f0 |
|||
|
@ -0,0 +1 @@ |
|||
../../../licenses/CC0 |
@ -0,0 +1,60 @@ |
|||
#include "config.h" |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
|
|||
/** |
|||
* crypto/siphash24 - implementation of SipHash-2-4. |
|||
* |
|||
* SipHash was designed as a mitigation to hash-flooding DoS |
|||
* attacks. It is now used in the hash tables implementation of |
|||
* Python, Ruby, Perl 5, etc. |
|||
* |
|||
* SipHash was designed by Jean-Philippe Aumasson and Daniel J. Bernstein. |
|||
* |
|||
* License: CC0 |
|||
* Maintainer: Rusty Russell <rusty@rustcorp.com.au> |
|||
* |
|||
* Example: |
|||
* // Dumb example to print siphash of words, and all strung together. |
|||
* #include <ccan/crypto/siphash24/siphash24.h> |
|||
* #include <stdio.h> |
|||
* #include <stdlib.h> |
|||
* #include <string.h> |
|||
* #include <inttypes.h> |
|||
* |
|||
* int main(int argc, char *argv[]) |
|||
* { |
|||
* struct siphash_seed seed; |
|||
* struct siphash24_ctx ctx; |
|||
* int i; |
|||
* |
|||
* if (argc < 3) { |
|||
* fprintf(stderr, "Need at least seed1 and seed2 arguments"); |
|||
* exit(1); |
|||
* } |
|||
* |
|||
* seed.u.u64[0] = atoi(argv[1]); |
|||
* seed.u.u64[1] = atoi(argv[2]); |
|||
* siphash24_init(&ctx, &seed); |
|||
* for (i = 3; i < argc; i++) { |
|||
* printf("Hash of '%s' = %"PRIu64, |
|||
* argv[i], siphash24(&seed, argv[i], strlen(argv[i]))); |
|||
* siphash24_update(&ctx, argv[i], strlen(argv[i])); |
|||
* } |
|||
* printf("Hash of concatenated args = %"PRIu64, siphash24_done(&ctx)); |
|||
* return 0; |
|||
* } |
|||
*/ |
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
/* Expect exactly one argument */ |
|||
if (argc != 2) |
|||
return 1; |
|||
|
|||
if (strcmp(argv[1], "depends") == 0) { |
|||
printf("ccan/endian\n"); |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
@ -0,0 +1,228 @@ |
|||
/* CC0 license (public domain) - see LICENSE file for details */ |
|||
/* Based on CC0 reference implementation:
|
|||
* https://github.com/veorq/SipHash c03e6bbf6613243bc30788912ad4afbc0b992d47
|
|||
*/ |
|||
#include <ccan/crypto/siphash24/siphash24.h> |
|||
#include <ccan/endian/endian.h> |
|||
#include <stdbool.h> |
|||
#include <assert.h> |
|||
#include <string.h> |
|||
|
|||
/* default: SipHash-2-4 */ |
|||
#define cROUNDS 2 |
|||
#define dROUNDS 4 |
|||
|
|||
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) |
|||
|
|||
#define SIPROUND(v) \ |
|||
do { \ |
|||
v[0] += v[1]; \ |
|||
v[1] = ROTL(v[1], 13); \ |
|||
v[1] ^= v[0]; \ |
|||
v[0] = ROTL(v[0], 32); \ |
|||
v[2] += v[3]; \ |
|||
v[3] = ROTL(v[3], 16); \ |
|||
v[3] ^= v[2]; \ |
|||
v[0] += v[3]; \ |
|||
v[3] = ROTL(v[3], 21); \ |
|||
v[3] ^= v[0]; \ |
|||
v[2] += v[1]; \ |
|||
v[1] = ROTL(v[1], 17); \ |
|||
v[1] ^= v[2]; \ |
|||
v[2] = ROTL(v[2], 32); \ |
|||
} while (0) |
|||
|
|||
static void invalidate_siphash24(struct siphash24_ctx *ctx) |
|||
{ |
|||
ctx->bytes = -1ULL; |
|||
} |
|||
|
|||
static void check_siphash24(struct siphash24_ctx *ctx) |
|||
{ |
|||
assert(ctx->bytes != -1ULL); |
|||
} |
|||
|
|||
static bool alignment_ok(const void *p, size_t n) |
|||
{ |
|||
#if HAVE_UNALIGNED_ACCESS |
|||
return true; |
|||
#else |
|||
return ((size_t)p % n == 0); |
|||
#endif |
|||
} |
|||
|
|||
static void add_64bits(uint64_t v[4], uint64_t in) |
|||
{ |
|||
int i; |
|||
uint64_t m = cpu_to_le64(in); |
|||
v[3] ^= m; |
|||
|
|||
for (i = 0; i < cROUNDS; ++i) |
|||
SIPROUND(v); |
|||
|
|||
v[0] ^= m; |
|||
} |
|||
|
|||
static void add(struct siphash24_ctx *ctx, const void *p, size_t len) |
|||
{ |
|||
const unsigned char *data = p; |
|||
size_t bufsize = ctx->bytes % sizeof(ctx->buf.u8); |
|||
|
|||
if (bufsize + len >= sizeof(ctx->buf.u8)) { |
|||
// Fill the buffer, and process it.
|
|||
memcpy(ctx->buf.u8 + bufsize, data, |
|||
sizeof(ctx->buf.u8) - bufsize); |
|||
ctx->bytes += sizeof(ctx->buf.u8) - bufsize; |
|||
data += sizeof(ctx->buf.u8) - bufsize; |
|||
len -= sizeof(ctx->buf.u8) - bufsize; |
|||
add_64bits(ctx->v, ctx->buf.u64); |
|||
bufsize = 0; |
|||
} |
|||
|
|||
while (len >= sizeof(ctx->buf.u8)) { |
|||
// Process full chunks directly from the source.
|
|||
if (alignment_ok(data, sizeof(uint64_t))) |
|||
add_64bits(ctx->v, *(const uint64_t *)data); |
|||
else { |
|||
memcpy(ctx->buf.u8, data, sizeof(ctx->buf)); |
|||
add_64bits(ctx->v, ctx->buf.u64); |
|||
} |
|||
ctx->bytes += sizeof(ctx->buf.u8); |
|||
data += sizeof(ctx->buf.u8); |
|||
len -= sizeof(ctx->buf.u8); |
|||
} |
|||
|
|||
if (len) { |
|||
// Fill the buffer with what remains.
|
|||
memcpy(ctx->buf.u8 + bufsize, data, len); |
|||
ctx->bytes += len; |
|||
} |
|||
} |
|||
|
|||
void siphash24_init(struct siphash24_ctx *ctx, const struct siphash_seed *seed) |
|||
{ |
|||
struct siphash24_ctx init = SIPHASH24_INIT(0, 0); |
|||
*ctx = init; |
|||
ctx->v[0] ^= seed->u.u64[0]; |
|||
ctx->v[1] ^= seed->u.u64[1]; |
|||
ctx->v[2] ^= seed->u.u64[0]; |
|||
ctx->v[3] ^= seed->u.u64[1]; |
|||
} |
|||
|
|||
void siphash24_update(struct siphash24_ctx *ctx, const void *p, size_t size) |
|||
{ |
|||
check_siphash24(ctx); |
|||
add(ctx, p, size); |
|||
} |
|||
|
|||
uint64_t siphash24_done(struct siphash24_ctx *ctx) |
|||
{ |
|||
uint64_t b; |
|||
int i; |
|||
|
|||
b = ctx->bytes << 56; |
|||
|
|||
switch (ctx->bytes % 8) { |
|||
case 7: |
|||
b |= ((uint64_t)ctx->buf.u8[6]) << 48; |
|||
case 6: |
|||
b |= ((uint64_t)ctx->buf.u8[5]) << 40; |
|||
case 5: |
|||
b |= ((uint64_t)ctx->buf.u8[4]) << 32; |
|||
case 4: |
|||
b |= ((uint64_t)ctx->buf.u8[3]) << 24; |
|||
case 3: |
|||
b |= ((uint64_t)ctx->buf.u8[2]) << 16; |
|||
case 2: |
|||
b |= ((uint64_t)ctx->buf.u8[1]) << 8; |
|||
case 1: |
|||
b |= ((uint64_t)ctx->buf.u8[0]); |
|||
break; |
|||
case 0: |
|||
break; |
|||
} |
|||
|
|||
ctx->v[3] ^= b; |
|||
|
|||
for (i = 0; i < cROUNDS; ++i) |
|||
SIPROUND(ctx->v); |
|||
|
|||
ctx->v[0] ^= b; |
|||
|
|||
ctx->v[2] ^= 0xff; |
|||
|
|||
for (i = 0; i < dROUNDS; ++i) |
|||
SIPROUND(ctx->v); |
|||
|
|||
b = ctx->v[0] ^ ctx->v[1] ^ ctx->v[2] ^ ctx->v[3]; |
|||
|
|||
invalidate_siphash24(ctx); |
|||
return cpu_to_le64(b); |
|||
} |
|||
|
|||
uint64_t siphash24(const struct siphash_seed *seed, const void *p, size_t size) |
|||
{ |
|||
struct siphash24_ctx ctx; |
|||
|
|||
siphash24_init(&ctx, seed); |
|||
siphash24_update(&ctx, p, size); |
|||
return siphash24_done(&ctx); |
|||
} |
|||
|
|||
void siphash24_u8(struct siphash24_ctx *ctx, uint8_t v) |
|||
{ |
|||
siphash24_update(ctx, &v, sizeof(v)); |
|||
} |
|||
|
|||
void siphash24_u16(struct siphash24_ctx *ctx, uint16_t v) |
|||
{ |
|||
siphash24_update(ctx, &v, sizeof(v)); |
|||
} |
|||
|
|||
void siphash24_u32(struct siphash24_ctx *ctx, uint32_t v) |
|||
{ |
|||
siphash24_update(ctx, &v, sizeof(v)); |
|||
} |
|||
|
|||
void siphash24_u64(struct siphash24_ctx *ctx, uint64_t v) |
|||
{ |
|||
siphash24_update(ctx, &v, sizeof(v)); |
|||
} |
|||
|
|||
/* Add as little-endian */ |
|||
void siphash24_le16(struct siphash24_ctx *ctx, uint16_t v) |
|||
{ |
|||
leint16_t lev = cpu_to_le16(v); |
|||
siphash24_update(ctx, &lev, sizeof(lev)); |
|||
} |
|||
|
|||
void siphash24_le32(struct siphash24_ctx *ctx, uint32_t v) |
|||
{ |
|||
leint32_t lev = cpu_to_le32(v); |
|||
siphash24_update(ctx, &lev, sizeof(lev)); |
|||
} |
|||
|
|||
void siphash24_le64(struct siphash24_ctx *ctx, uint64_t v) |
|||
{ |
|||
leint64_t lev = cpu_to_le64(v); |
|||
siphash24_update(ctx, &lev, sizeof(lev)); |
|||
} |
|||
|
|||
/* Add as big-endian */ |
|||
void siphash24_be16(struct siphash24_ctx *ctx, uint16_t v) |
|||
{ |
|||
beint16_t bev = cpu_to_be16(v); |
|||
siphash24_update(ctx, &bev, sizeof(bev)); |
|||
} |
|||
|
|||
void siphash24_be32(struct siphash24_ctx *ctx, uint32_t v) |
|||
{ |
|||
beint32_t bev = cpu_to_be32(v); |
|||
siphash24_update(ctx, &bev, sizeof(bev)); |
|||
} |
|||
|
|||
void siphash24_be64(struct siphash24_ctx *ctx, uint64_t v) |
|||
{ |
|||
beint64_t bev = cpu_to_be64(v); |
|||
siphash24_update(ctx, &bev, sizeof(bev)); |
|||
} |
@ -0,0 +1,139 @@ |
|||
/* CC0 license (public domain) - see LICENSE file for details */ |
|||
#ifndef CCAN_CRYPTO_SIPHASH24_H |
|||
#define CCAN_CRYPTO_SIPHASH24_H |
|||
/* Public domain - see LICENSE file for details */ |
|||
#include "config.h" |
|||
#include <stdint.h> |
|||
#include <stdlib.h> |
|||
|
|||
/**
|
|||
* struct siphash_seed - random bytes to seed the siphash |
|||
* @u.u8: an unsigned char array. |
|||
* @u.u32: a 32-bit integer array. |
|||
* |
|||
* Other fields may be added to the union in future. |
|||
*/ |
|||
struct siphash_seed { |
|||
union { |
|||
/* Array of chars */ |
|||
unsigned char u8[16]; |
|||
/* Array of uint32_t */ |
|||
uint32_t u32[4]; |
|||
/* Array of uint64_t */ |
|||
uint64_t u64[2]; |
|||
} u; |
|||
}; |
|||
|
|||
/**
|
|||
* siphash24 - return SipHash-2-4 of an object. |
|||
* @seed: the seed for the hash. |
|||
* @p: pointer to memory, |
|||
* @size: the number of bytes pointed to by @p |
|||
* |
|||
* The bytes pointed to by @p is SIPHASH24 hashed into @siphash24, |
|||
* using seed @seed. This is equivalent to siphash24_init(), |
|||
* siphash24_update() then siphash24_done(). |
|||
*/ |
|||
uint64_t siphash24(const struct siphash_seed *seed, const void *p, size_t size); |
|||
|
|||
/**
|
|||
* struct siphash24_ctx - structure to store running context for siphash24 |
|||
*/ |
|||
struct siphash24_ctx { |
|||
uint64_t v[4]; |
|||
uint64_t bytes; |
|||
union { |
|||
uint64_t u64; |
|||
unsigned char u8[8]; |
|||
} buf; |
|||
}; |
|||
|
|||
/**
|
|||
* siphash24_init - initialize an SIPHASH24 context. |
|||
* @ctx: the siphash24_ctx to initialize |
|||
* @seed: the siphash_seed. |
|||
* |
|||
* This must be called before siphash24_update or siphash24_done, or |
|||
* alternately you can assign SIPHASH24_INIT. |
|||
* |
|||
* If it was already initialized, this forgets anything which was |
|||
* hashed before. |
|||
* |
|||
* Example: |
|||
* static void hash_all(const char **arr, uint64_t *hash) |
|||
* { |
|||
* size_t i; |
|||
* struct siphash24_ctx ctx; |
|||
* struct siphash_seed seed; |
|||
* |
|||
* // Use a random seed, not this!
|
|||
* memset(seed.u.u64, 7, sizeof(seed.u.u64)); |
|||
* siphash24_init(&ctx, &seed); |
|||
* for (i = 0; arr[i]; i++) |
|||
* siphash24_update(&ctx, arr[i], strlen(arr[i])); |
|||
* *hash = siphash24_done(&ctx); |
|||
* } |
|||
*/ |
|||
void siphash24_init(struct siphash24_ctx *ctx, const struct siphash_seed *seed); |
|||
|
|||
/**
|
|||
* SIPHASH24_INIT - initializer for an SIPHASH24 context. |
|||
* @seed1, @seed2: two 64-bit words for seed. |
|||
* |
|||
* This can be used to staticly initialize an SIPHASH24 context (instead |
|||
* of siphash24_init()). |
|||
* |
|||
* Example: |
|||
* static uint64_t hash_all(const char **arr) |
|||
* { |
|||
* size_t i; |
|||
* struct siphash24_ctx ctx = SIPHASH24_INIT(0x0707070707070707ULL, |
|||
* 0x0707070707070707ULL); |
|||
* |
|||
* for (i = 0; arr[i]; i++) |
|||
* siphash24_update(&ctx, arr[i], strlen(arr[i])); |
|||
* return siphash24_done(&ctx); |
|||
* } |
|||
*/ |
|||
#define SIPHASH24_INIT(seed1, seed2) \ |
|||
{ { 0x736f6d6570736575ULL ^ (seed1), \ |
|||
0x646f72616e646f6dULL ^ (seed2), \ |
|||
0x6c7967656e657261ULL ^ (seed1), \ |
|||
0x7465646279746573ULL ^ (seed2) } } |
|||
|
|||
/**
|
|||
* siphash24_update - include some memory in the hash. |
|||
* @ctx: the siphash24_ctx to use |
|||
* @p: pointer to memory, |
|||
* @size: the number of bytes pointed to by @p |
|||
* |
|||
* You can call this multiple times to hash more data, before calling |
|||
* siphash24_done(). |
|||
*/ |
|||
void siphash24_update(struct siphash24_ctx *ctx, const void *p, size_t size); |
|||
|
|||
/**
|
|||
* siphash24_done - finish SIPHASH24 and return the hash |
|||
* @ctx: the siphash24_ctx to complete |
|||
* |
|||
* Note that @ctx is *destroyed* by this, and must be reinitialized. |
|||
* To avoid that, pass a copy instead. |
|||
*/ |
|||
uint64_t siphash24_done(struct siphash24_ctx *siphash24); |
|||
|
|||
/* Add various types to an SIPHASH24 hash */ |
|||
void siphash24_u8(struct siphash24_ctx *ctx, uint8_t v); |
|||
void siphash24_u16(struct siphash24_ctx *ctx, uint16_t v); |
|||
void siphash24_u32(struct siphash24_ctx *ctx, uint32_t v); |
|||
void siphash24_u64(struct siphash24_ctx *ctx, uint64_t v); |
|||
|
|||
/* Add as little-endian */ |
|||
void siphash24_le16(struct siphash24_ctx *ctx, uint16_t v); |
|||
void siphash24_le32(struct siphash24_ctx *ctx, uint32_t v); |
|||
void siphash24_le64(struct siphash24_ctx *ctx, uint64_t v); |
|||
|
|||
/* Add as big-endian */ |
|||
void siphash24_be16(struct siphash24_ctx *ctx, uint16_t v); |
|||
void siphash24_be32(struct siphash24_ctx *ctx, uint32_t v); |
|||
void siphash24_be64(struct siphash24_ctx *ctx, uint64_t v); |
|||
#endif /* CCAN_CRYPTO_SIPHASH24_H */ |
@ -0,0 +1,126 @@ |
|||
#include <ccan/crypto/siphash24/siphash24.h> |
|||
/* Include the C files directly. */ |
|||
#include <ccan/crypto/siphash24/siphash24.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
/* Taken from SipHash/main.c */ |
|||
/*
|
|||
SipHash-2-4 output with |
|||
k = 00 01 02 ... |
|||
and |
|||
in = (empty string) |
|||
in = 00 (1 byte) |
|||
in = 00 01 (2 bytes) |
|||
in = 00 01 02 (3 bytes) |
|||
... |
|||
in = 00 01 02 ... 3e (63 bytes) |
|||
*/ |
|||
static const uint8_t vectors[][sizeof(uint64_t)] = |
|||
{ |
|||
{ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, }, |
|||
{ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, }, |
|||
{ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, }, |
|||
{ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, }, |
|||
{ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, }, |
|||
{ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, }, |
|||
{ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, }, |
|||
{ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, }, |
|||
{ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, }, |
|||
{ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, }, |
|||
{ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, }, |
|||
{ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, }, |
|||
{ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, }, |
|||
{ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, }, |
|||
{ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, }, |
|||
{ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, }, |
|||
{ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, }, |
|||
{ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, }, |
|||
{ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, }, |
|||
{ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, }, |
|||
{ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, }, |
|||
{ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, }, |
|||
{ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, }, |
|||
{ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, }, |
|||
{ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, }, |
|||
{ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, }, |
|||
{ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, }, |
|||
{ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, }, |
|||
{ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, }, |
|||
{ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, }, |
|||
{ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, }, |
|||
{ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, }, |
|||
{ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, }, |
|||
{ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, }, |
|||
{ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, }, |
|||
{ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, }, |
|||
{ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, }, |
|||
{ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, }, |
|||
{ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, }, |
|||
{ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, }, |
|||
{ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, }, |
|||
{ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, }, |
|||
{ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, }, |
|||
{ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, }, |
|||
{ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, }, |
|||
{ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, }, |
|||
{ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, }, |
|||
{ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, }, |
|||
{ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, }, |
|||
{ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, }, |
|||
{ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, }, |
|||
{ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, }, |
|||
{ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, }, |
|||
{ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, }, |
|||
{ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, }, |
|||
{ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, }, |
|||
{ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, }, |
|||
{ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, }, |
|||
{ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, }, |
|||
{ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, }, |
|||
{ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, }, |
|||
{ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, }, |
|||
{ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, }, |
|||
{ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, } |
|||
}; |
|||
|
|||
#define MAXLEN (sizeof(vectors)/sizeof(vectors[0])) |
|||
|
|||
int main(void) |
|||
{ |
|||
struct siphash24_ctx ctx1 = SIPHASH24_INIT(0x0706050403020100ULL, |
|||
0x0f0e0d0c0b0a0908ULL); |
|||
struct siphash24_ctx ctx2; |
|||
struct siphash_seed seed; |
|||
leint64_t v; |
|||
uint8_t in[MAXLEN]; |
|||
int i; |
|||
|
|||
/* This is how many tests you plan to run */ |
|||
plan_tests(1 + MAXLEN * 2); |
|||
|
|||
/* Initialzed an manually created should give same results. */ |
|||
for (i = 0; i < sizeof(seed.u.u8); i++) |
|||
seed.u.u8[i] = i; |
|||
siphash24_init(&ctx2, &seed); |
|||
ok1(memcmp(&ctx1, &ctx2, sizeof(ctx1)) == 0); |
|||
|
|||
for (i = 0; i < MAXLEN; ++i) { |
|||
memcpy(&v, vectors[i], sizeof(v)); |
|||
in[i] = i; |
|||
ok1(siphash24(&seed, in, i) == v); |
|||
} |
|||
|
|||
|
|||
/* Now try splitting last one along all possible lines. */ |
|||
memcpy(&v, vectors[MAXLEN-1], sizeof(v)); |
|||
for (i = 0; i < MAXLEN; ++i) { |
|||
struct siphash24_ctx ctx = SIPHASH24_INIT(0x0706050403020100ULL, |
|||
0x0f0e0d0c0b0a0908ULL); |
|||
siphash24_update(&ctx, in, i); |
|||
siphash24_update(&ctx, in + i, MAXLEN - i - 1); |
|||
ok1(siphash24_done(&ctx) == v); |
|||
} |
|||
|
|||
/* This exits depending on whether all tests passed */ |
|||
return exit_status(); |
|||
} |
@ -0,0 +1,44 @@ |
|||
#include <ccan/htable/htable.h> |
|||
#include <ccan/htable/htable.c> |
|||
#include <ccan/tap/tap.h> |
|||
#include <stdbool.h> |
|||
#include <string.h> |
|||
|
|||
#define NUM_VALS 512 |
|||
|
|||
static size_t hash(const void *elem, void *unused) |
|||
{ |
|||
size_t h = *(uint64_t *)elem / 2; |
|||
return h; |
|||
} |
|||
|
|||
static bool cmp(const void *candidate, void *ptr) |
|||
{ |
|||
return *(const uint64_t *)candidate == *(const uint64_t *)ptr; |
|||
} |
|||
|
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
struct htable ht, ht2; |
|||
uint64_t val[NUM_VALS], i; |
|||
|
|||
plan_tests((NUM_VALS) * 3); |
|||
for (i = 0; i < NUM_VALS; i++) |
|||
val[i] = i; |
|||
|
|||
htable_init(&ht, hash, NULL); |
|||
for (i = 0; i < NUM_VALS; i++) { |
|||
ok1(ht.max >= i); |
|||
ok1(ht.max <= i * 2); |
|||
htable_add(&ht, hash(&val[i], NULL), &val[i]); |
|||
} |
|||
|
|||
htable_copy(&ht2, &ht); |
|||
htable_clear(&ht); |
|||
|
|||
for (i = 0; i < NUM_VALS; i++) |
|||
ok1(htable_get(&ht2, hash(&i, NULL), cmp, &i) == &val[i]); |
|||
htable_clear(&ht2); |
|||
|
|||
return exit_status(); |
|||
} |
@ -0,0 +1,215 @@ |
|||
/* Key is an unsigned int, not a pointer. */ |
|||
#include "config.h" |
|||
#if !defined(HAVE_TYPEOF) || !HAVE_TYPEOF |
|||
#define HTABLE_KTYPE(keyof, type) unsigned int |
|||
#endif |
|||
#include <ccan/htable/htable_type.h> |
|||
#include <ccan/htable/htable.c> |
|||
#include <ccan/tap/tap.h> |
|||
#include <stdbool.h> |
|||
#include <string.h> |
|||
|
|||
#define NUM_BITS 7 |
|||
#define NUM_VALS (1 << NUM_BITS) |
|||
|
|||
struct obj { |
|||
/* Makes sure we don't try to treat and obj as a key or vice versa */ |
|||
unsigned char unused; |
|||
unsigned int key; |
|||
}; |
|||
|
|||
static const unsigned int objkey(const struct obj *obj) |
|||
{ |
|||
return obj->key; |
|||
} |
|||
|
|||
/* We use the number divided by two as the hash (for lots of
|
|||
collisions), plus set all the higher bits so we can detect if they |
|||
don't get masked out. */ |
|||
static size_t objhash(const unsigned int key) |
|||
{ |
|||
size_t h = key / 2; |
|||
h |= -1UL << NUM_BITS; |
|||
return h; |
|||
} |
|||
|
|||
static bool cmp(const struct obj *obj, const unsigned int key) |
|||
{ |
|||
return obj->key == key; |
|||
} |
|||
|
|||
HTABLE_DEFINE_TYPE(struct obj, objkey, objhash, cmp, htable_obj); |
|||
|
|||
static void add_vals(struct htable_obj *ht, |
|||
struct obj val[], unsigned int num) |
|||
{ |
|||
unsigned int i; |
|||
|
|||
for (i = 0; i < num; i++) { |
|||
if (htable_obj_get(ht, i)) { |
|||
fail("%u already in hash", i); |
|||
return; |
|||
} |
|||
htable_obj_add(ht, &val[i]); |
|||
if (htable_obj_get(ht, i) != &val[i]) { |
|||
fail("%u not added to hash", i); |
|||
return; |
|||
} |
|||
} |
|||
pass("Added %u numbers to hash", i); |
|||
} |
|||
|
|||
static void find_vals(const struct htable_obj *ht, |
|||
const struct obj val[], unsigned int num) |
|||
{ |
|||
unsigned int i; |
|||
|
|||
for (i = 0; i < num; i++) { |
|||
if (htable_obj_get(ht, i) != &val[i]) { |
|||
fail("%u not found in hash", i); |
|||
return; |
|||
} |
|||
} |
|||
pass("Found %u numbers in hash", i); |
|||
} |
|||
|
|||
static void del_vals(struct htable_obj *ht, |
|||
const struct obj val[], unsigned int num) |
|||
{ |
|||
unsigned int i; |
|||
|
|||
for (i = 0; i < num; i++) { |
|||
if (!htable_obj_delkey(ht, val[i].key)) { |
|||
fail("%u not deleted from hash", i); |
|||
return; |
|||
} |
|||
} |
|||
pass("Deleted %u numbers in hash", i); |
|||
} |
|||
|
|||
static void del_vals_bykey(struct htable_obj *ht, |
|||
const struct obj val[], unsigned int num) |
|||
{ |
|||
unsigned int i; |
|||
|
|||
for (i = 0; i < num; i++) { |
|||
if (!htable_obj_delkey(ht, i)) { |
|||
fail("%u not deleted by key from hash", i); |
|||
return; |
|||
} |
|||
} |
|||
pass("Deleted %u numbers by key from hash", i); |
|||
} |
|||
|
|||
static bool check_mask(struct htable *ht, const struct obj val[], unsigned num) |
|||
{ |
|||
uint64_t i; |
|||
|
|||
for (i = 0; i < num; i++) { |
|||
if (((uintptr_t)&val[i] & ht->common_mask) != ht->common_bits) |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
unsigned int i; |
|||
struct htable_obj ht, ht2; |
|||
struct obj val[NUM_VALS], *result; |
|||
unsigned int dne; |
|||
void *p; |
|||
struct htable_obj_iter iter; |
|||
|
|||
plan_tests(29); |
|||
for (i = 0; i < NUM_VALS; i++) |
|||
val[i].key = i; |
|||
dne = i; |
|||
|
|||
htable_obj_init(&ht); |
|||
ok1(ht.raw.max == 0); |
|||
ok1(ht.raw.bits == 0); |
|||
|
|||
/* We cannot find an entry which doesn't exist. */ |
|||
ok1(!htable_obj_get(&ht, dne)); |
|||
|
|||
/* Fill it, it should increase in size. */ |
|||
add_vals(&ht, val, NUM_VALS); |
|||
ok1(ht.raw.bits == NUM_BITS + 1); |
|||
ok1(ht.raw.max < (1 << ht.raw.bits)); |
|||
|
|||
/* Mask should be set. */ |
|||
ok1(ht.raw.common_mask != 0); |
|||
ok1(ht.raw.common_mask != -1); |
|||
ok1(check_mask(&ht.raw, val, NUM_VALS)); |
|||
|
|||
/* Find all. */ |
|||
find_vals(&ht, val, NUM_VALS); |
|||
ok1(!htable_obj_get(&ht, dne)); |
|||
|
|||
/* Walk once, should get them all. */ |
|||
i = 0; |
|||
for (p = htable_obj_first(&ht,&iter); p; p = htable_obj_next(&ht, &iter)) |
|||
i++; |
|||
ok1(i == NUM_VALS); |
|||
i = 0; |
|||
for (p = htable_obj_prev(&ht,&iter); p; p = htable_obj_prev(&ht, &iter)) |
|||
i++; |
|||
ok1(i == NUM_VALS); |
|||
|
|||
/* Delete all. */ |
|||
del_vals(&ht, val, NUM_VALS); |
|||
ok1(!htable_obj_get(&ht, val[0].key)); |
|||
|
|||
/* Worst case, a "pointer" which doesn't have any matching bits. */ |
|||
htable_add(&ht.raw, 0, (void *)~(uintptr_t)&val[NUM_VALS-1]); |
|||
htable_obj_add(&ht, &val[NUM_VALS-1]); |
|||
ok1(ht.raw.common_mask == 0); |
|||
ok1(ht.raw.common_bits == 0); |
|||
/* Delete the bogus one before we trip over it. */ |
|||
htable_del(&ht.raw, 0, (void *)~(uintptr_t)&val[NUM_VALS-1]); |
|||
|
|||
/* Add the rest. */ |
|||
add_vals(&ht, val, NUM_VALS-1); |
|||
|
|||
/* Check we can find them all. */ |
|||
find_vals(&ht, val, NUM_VALS); |
|||
ok1(!htable_obj_get(&ht, dne)); |
|||
|
|||
/* Check copy. */ |
|||
ok1(htable_obj_copy(&ht2, &ht)); |
|||
|
|||
/* Delete them all by key. */ |
|||
del_vals_bykey(&ht, val, NUM_VALS); |
|||
del_vals_bykey(&ht2, val, NUM_VALS); |
|||
|
|||
/* Write two of the same value. */ |
|||
val[1] = val[0]; |
|||
htable_obj_add(&ht, &val[0]); |
|||
htable_obj_add(&ht, &val[1]); |
|||
i = 0; |
|||
|
|||
result = htable_obj_getfirst(&ht, i, &iter); |
|||
ok1(result == &val[0] || result == &val[1]); |
|||
if (result == &val[0]) { |
|||
ok1(htable_obj_getnext(&ht, i, &iter) == &val[1]); |
|||
ok1(htable_obj_getnext(&ht, i, &iter) == NULL); |
|||
|
|||
/* Deleting first should make us iterate over the other. */ |
|||
ok1(htable_obj_del(&ht, &val[0])); |
|||
ok1(htable_obj_getfirst(&ht, i, &iter) == &val[1]); |
|||
ok1(htable_obj_getnext(&ht, i, &iter) == NULL); |
|||
} else { |
|||
ok1(htable_obj_getnext(&ht, i, &iter) == &val[0]); |
|||
ok1(htable_obj_getnext(&ht, i, &iter) == NULL); |
|||
|
|||
/* Deleting first should make us iterate over the other. */ |
|||
ok1(htable_obj_del(&ht, &val[1])); |
|||
ok1(htable_obj_getfirst(&ht, i, &iter) == &val[0]); |
|||
ok1(htable_obj_getnext(&ht, i, &iter) == NULL); |
|||
} |
|||
|
|||
htable_obj_clear(&ht); |
|||
htable_obj_clear(&ht2); |
|||
return exit_status(); |
|||
} |
@ -0,0 +1,35 @@ |
|||
#include <stdlib.h> |
|||
|
|||
#include <ccan/tcon/tcon.h> |
|||
#include <ccan/build_assert/build_assert.h> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
struct inner { |
|||
int inner_val; |
|||
}; |
|||
|
|||
struct outer { |
|||
int outer_val; |
|||
struct inner inner; |
|||
}; |
|||
|
|||
struct info_base { |
|||
char *infop; |
|||
}; |
|||
|
|||
struct info_tcon { |
|||
struct info_base base; |
|||
TCON(TCON_CONTAINER(fi, struct outer, inner)); |
|||
}; |
|||
|
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
/* Const should work! */ |
|||
const struct outer *ovar = NULL; |
|||
struct outer *o; |
|||
struct info_tcon info; |
|||
|
|||
o = tcon_container_of(&info, fi, &ovar->inner); |
|||
return (o == ovar); |
|||
} |
|||
|
Loading…
Reference in new issue