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