X-Git-Url: https://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fcrypto%2Fshachain%2Fshachain.c;h=6cfb7244f981472994c813eb8d91fb72df99fd75;hp=a14d95b8cd4d4c665dca18ab88313f90677e314d;hb=d23fb57c8e276090325162966b094ebf71e73e68;hpb=9fc07111603c6e892ed768f900465282314b2982 diff --git a/ccan/crypto/shachain/shachain.c b/ccan/crypto/shachain/shachain.c index a14d95b8..6cfb7244 100644 --- a/ccan/crypto/shachain/shachain.c +++ b/ccan/crypto/shachain/shachain.c @@ -5,15 +5,39 @@ #include #include +#define INDEX_BITS ((sizeof(shachain_index_t)) * CHAR_BIT) + static void change_bit(unsigned char *arr, size_t index) { arr[index / CHAR_BIT] ^= (1 << (index % CHAR_BIT)); } -/* We can only ever *unset* bits, so to must only have bits in from. */ +static int count_trailing_zeroes(shachain_index_t index) +{ +#if HAVE_BUILTIN_CTZLL + return index ? __builtin_ctzll(index) : INDEX_BITS; +#else + int i; + + for (i = 0; i < INDEX_BITS; i++) { + if (index & (1ULL << i)) + break; + } + return i; +#endif +} + static bool can_derive(shachain_index_t from, shachain_index_t to) { - return (~from & to) == 0; + shachain_index_t mask; + + /* Corner case: can always derive from seed. */ + if (from == 0) + return true; + + /* Leading bits must be the same */ + mask = ~((1ULL << count_trailing_zeroes(from))-1); + return ((from ^ to) & mask) == 0; } static void derive(shachain_index_t from, shachain_index_t to, @@ -28,12 +52,12 @@ static void derive(shachain_index_t from, shachain_index_t to, /* We start with the first hash. */ *hash = *from_hash; - /* This represents the bits set in from, and not to. */ + /* 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)); } } } @@ -41,39 +65,42 @@ static void derive(shachain_index_t from, shachain_index_t to, void shachain_from_seed(const struct sha256 *seed, shachain_index_t index, struct sha256 *hash) { - derive((shachain_index_t)-1ULL, index, seed, hash); + derive(0, index, seed, hash); } -void shachain_init(struct shachain *shachain) +void shachain_init(struct shachain *chain) { - shachain->num_valid = 0; + chain->num_valid = 0; + chain->min_index = 0; } bool shachain_add_hash(struct shachain *chain, shachain_index_t index, const struct sha256 *hash) { - int i; + 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)) { - 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)) != 0) - return false; - break; - } + /* You have to insert them in order! */ + assert(index == chain->min_index - 1 || + (index == (shachain_index_t)(-1ULL) && chain->num_valid == 0)); + + 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; }