X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fcrypto%2Fshachain%2Fshachain.c;h=9cb54a37bdd9da6c18b1567e400ca132010af9a2;hp=4b6a31db3f93f419282ead63467495999263fd54;hb=e6abb93d50ba9f1e90163d7db53be70b8ef81a96;hpb=fc6655ed3c4840a5d4d669ad3c44e2ffe1019173 diff --git a/ccan/crypto/shachain/shachain.c b/ccan/crypto/shachain/shachain.c index 4b6a31db..9cb54a37 100644 --- a/ccan/crypto/shachain/shachain.c +++ b/ccan/crypto/shachain/shachain.c @@ -10,77 +10,116 @@ static void change_bit(unsigned char *arr, size_t index) arr[index / CHAR_BIT] ^= (1 << (index % CHAR_BIT)); } -static void derive(shachain_index_t index, size_t bits, struct sha256 *hash) +static unsigned int count_trailing_zeroes(uint64_t index) { +#if HAVE_BUILTIN_CTZLL + return index ? (unsigned int)__builtin_ctzll(index) : SHACHAIN_BITS; +#else + unsigned int i; + + for (i = 0; i < SHACHAIN_BITS; i++) { + if (index & (1ULL << i)) + break; + } + return i; +#endif +} + +static bool can_derive(uint64_t from, uint64_t to) +{ + uint64_t mask; + + /* Corner case: can always derive from seed. */ + if (from == 0) + return true; + + /* Leading bits must be the same */ + mask = ~(((uint64_t)1 << count_trailing_zeroes(from))-1); + return ((from ^ to) & mask) == 0; +} + +static void derive(uint64_t from, uint64_t to, + const struct sha256 *from_hash, + struct sha256 *hash) +{ + uint64_t branches; int i; - for (i = bits - 1; i >= 0; i--) { - if (!((index >> i) & 1)) { + assert(can_derive(from, to)); + + /* We start with the first hash. */ + *hash = *from_hash; + + /* This represents the bits set in to, and not from. */ + branches = from ^ to; + for (i = ilog64(branches) - 1; i >= 0; i--) { + if (((branches >> i) & 1)) { change_bit(hash->u.u8, i); - sha256(hash, hash, 1); + sha256(hash, hash, sizeof(*hash)); } } } -void shachain_from_seed(const struct sha256 *seed, shachain_index_t index, +void shachain_from_seed(const struct sha256 *seed, uint64_t index, struct sha256 *hash) { - *hash = *seed; - derive(index, sizeof(index) * CHAR_BIT, hash); + derive(0, index, seed, hash); } -void shachain_init(struct shachain *shachain) +uint64_t shachain_next_index(const struct shachain *chain) { - shachain->num_valid = 0; + return chain->min_index - 1; } -/* We can only ever *unset* bits, so to must only have bits in from. */ -static bool can_derive(shachain_index_t from, shachain_index_t to) +void shachain_init(struct shachain *chain) { - return (~from & to) == 0; + chain->num_valid = 0; + /* This is 0 in the case where SHACHAIN_BITS is 64. */ + chain->min_index = (UINT64_MAX >> (64 - SHACHAIN_BITS)) + 1; } -void shachain_add_hash(struct shachain *chain, - shachain_index_t index, const struct sha256 *hash) +bool shachain_add_hash(struct shachain *chain, + uint64_t index, const struct sha256 *hash) { - int i; + unsigned int i, pos; - for (i = 0; i < chain->num_valid; i++) { - /* If we could derive this value, we don't need it, - * not any others (since they're in order). */ - if (can_derive(index, chain->known[i].index)) - break; + /* You have to insert them in order! */ + assert(index == shachain_next_index(chain)); + + pos = count_trailing_zeroes(index); + + /* All derivable answers must be valid. */ + /* FIXME: Is it sufficient to check just the next answer? */ + for (i = 0; i < pos; i++) { + struct sha256 expect; + + /* Make sure the others derive as expected! */ + derive(index, chain->known[i].index, hash, &expect); + if (memcmp(&expect, &chain->known[i].hash, sizeof(expect))) + return false; } - /* This can happen if you skip indices! */ - assert(i < sizeof(chain->known) / sizeof(chain->known[0])); - chain->known[i].index = index; - chain->known[i].hash = *hash; - chain->num_valid = i+1; + chain->known[pos].index = index; + chain->known[pos].hash = *hash; + if (pos + 1 > chain->num_valid) + chain->num_valid = pos + 1; + chain->min_index = index; + return true; } bool shachain_get_hash(const struct shachain *chain, - shachain_index_t index, struct sha256 *hash) + uint64_t index, struct sha256 *hash) { - int i; + unsigned int i; for (i = 0; i < chain->num_valid; i++) { - shachain_index_t diff; - /* If we can get from key to index only by resetting bits, * we can derive from it => index has no bits key doesn't. */ if (!can_derive(chain->known[i].index, index)) continue; - /* Start from this hash. */ - *hash = chain->known[i].hash; - - /* This indicates the bits which are in 'index' and - * not the key */ - diff = index ^ chain->known[i].index; - - /* Using ilog64 here is an optimization. */ - derive(~diff, ilog64(diff), hash); + derive(chain->known[i].index, index, &chain->known[i].hash, + hash); return true; } return false;