]> git.ozlabs.org Git - ccan/blob - ccan/crypto/shachain/shachain.h
ba4ba11cd64c02d1d66a362d35bac98e39a2f0bc
[ccan] / ccan / crypto / shachain / shachain.h
1 /* MIT (BSD) license - see LICENSE file for details */
2 #ifndef CCAN_CRYPTO_SHACHAIN_H
3 #define CCAN_CRYPTO_SHACHAIN_H
4 #include "config.h"
5 #include <ccan/crypto/sha256/sha256.h>
6 #include <stdbool.h>
7 #include <stdint.h>
8
9 /* Useful for testing. */
10 #ifndef shachain_index_t
11 #define shachain_index_t uint64_t
12 #endif
13
14 /**
15  * shachain_from_seed - Generate an unpredictable SHA from a seed value.
16  * @seed: (secret) seed value to use
17  * @index: index of value to generate (0 == seed)
18  * @hash: value generated
19  *
20  * There will be no way to derive the result from that generated for
21  * any *greater* index.
22  *
23  * Example:
24  * #include <time.h>
25  *
26  * static void next_hash(struct sha256 *hash)
27  * {
28  *      static uint64_t index = 0xFFFFFFFFFFFFFFFFULL;
29  *      static struct sha256 seed;
30  *
31  *      // First time, initialize seed.
32  *      if (index == 0xFFFFFFFFFFFFFFFFULL) {
33  *              // DO NOT DO THIS!  Very predictable!
34  *              time_t now = time(NULL);
35  *              memcpy(&seed, &now, sizeof(now));
36  *      }
37  *
38  *      shachain_from_seed(&seed, index--, hash);
39  * }
40  */
41 void shachain_from_seed(const struct sha256 *seed, shachain_index_t index,
42                         struct sha256 *hash);
43
44 /**
45  * shachain - structure for recording/deriving decrementing chain members
46  * @min_index: minimum index value successfully shachain_add_hash()ed.
47  * @num_valid: number of known[] array valid.  If non-zero, @min_index valid.
48  * @known: known values to allow us to derive those >= @min_index.
49  *
50  * This is sufficient storage to derive any shachain hash value previously
51  * added.
52  */
53 struct shachain {
54         shachain_index_t min_index;
55         unsigned int num_valid;
56         struct {
57                 shachain_index_t index;
58                 struct sha256 hash;
59         } known[sizeof(shachain_index_t) * 8 + 1];
60 };
61
62 /**
63  * shachain_init - initialize an shachain
64  * @chain: the chain to initialize
65  *
66  * Alternately, ensure that it's all zero.
67  */
68 void shachain_init(struct shachain *chain);
69
70 /**
71  * shachain_add_hash - record the hash for the next index.
72  * @chain: the chain to add to
73  * @index: the index of the hash
74  * @hash: the hash value.
75  *
76  * You can only add index 0xFFFFFFFFFFFFFFFF (for a freshly
77  * initialized chain), or one less than the previously successfully
78  * added value.
79  *
80  * This can fail (return false without altering @chain) if the hash
81  * for this index isn't consistent with previous hashes (ie. wasn't
82  * generated from the same seed), though it can't always detect that.
83  * If the hash is inconsistent yet undetected, the next addition will
84  * fail.
85  *
86  * Example:
87  * static void next_hash(const struct sha256 *hash)
88  * {
89  *      static uint64_t index = 0xFFFFFFFFFFFFFFFFULL;
90  *      static struct shachain chain;
91  *
92  *      if (!shachain_add_hash(&chain, index--, hash))
93  *              errx(1, "Corrupted hash value?");
94  * }
95  */
96 bool shachain_add_hash(struct shachain *chain,
97                        shachain_index_t index, const struct sha256 *hash);
98
99 /**
100  * shachain_get_hash - get the hash for a given index.
101  * @chain: the chain query
102  * @index: the index of the hash to get
103  * @hash: the hash value.
104  *
105  * This will return true and set @hash to that given in the successful
106  * shachain_get_hash() call for that index.  If there was no
107  * successful shachain_get_hash() for that index, it will return
108  * false.
109  *
110  * Example:
111  * #include <ccan/structeq/structeq.h>
112  *
113  * static void next_hash(const struct sha256 *hash)
114  * {
115  *      static uint64_t index = 0xFFFFFFFFFFFFFFFFULL;
116  *      static struct shachain chain;
117  *
118  *      if (!shachain_add_hash(&chain, index--, hash))
119  *              errx(1, "Corrupted hash value?");
120  *      else {
121  *              struct sha256 check;
122  *              assert(shachain_get_hash(&chain, index+1, &check));
123  *              assert(structeq(&check, hash));
124  *      }
125  * }
126  */
127 bool shachain_get_hash(const struct shachain *chain,
128                        shachain_index_t index, struct sha256 *hash);
129 #endif /* CCAN_CRYPTO_SHACHAIN_H */