diff --git a/.dat/content.bitfield b/.dat/content.bitfield index 1a07e8e..91ce371 100644 Binary files a/.dat/content.bitfield and b/.dat/content.bitfield differ diff --git a/.dat/content.signatures b/.dat/content.signatures index 59e7378..2c3a1b7 100644 Binary files a/.dat/content.signatures and b/.dat/content.signatures differ diff --git a/.dat/content.tree b/.dat/content.tree index e21a90a..3411a76 100644 Binary files a/.dat/content.tree and b/.dat/content.tree differ diff --git a/.dat/metadata.bitfield b/.dat/metadata.bitfield index 67a52f9..d8a0ead 100644 Binary files a/.dat/metadata.bitfield and b/.dat/metadata.bitfield differ diff --git a/.dat/metadata.data b/.dat/metadata.data index 38ea15d..a799382 100644 Binary files a/.dat/metadata.data and b/.dat/metadata.data differ diff --git a/.dat/metadata.signatures b/.dat/metadata.signatures index 11584c9..1f4e568 100644 Binary files a/.dat/metadata.signatures and b/.dat/metadata.signatures differ diff --git a/.dat/metadata.tree b/.dat/metadata.tree index be4e27e..d127356 100644 Binary files a/.dat/metadata.tree and b/.dat/metadata.tree differ diff --git a/docs/sleep.3 b/docs/dat.sleep.3 similarity index 100% rename from docs/sleep.3 rename to docs/dat.sleep.3 diff --git a/extra/datthang.png b/extra/datthang.png new file mode 100644 index 0000000..d6e4c53 Binary files /dev/null and b/extra/datthang.png differ diff --git a/src/sleep.c b/src/sleep.c index e69de29..3ed5418 100644 --- a/src/sleep.c +++ b/src/sleep.c @@ -0,0 +1,46 @@ +#include "sleep.h" +#include +#include +#include +#include +#include + +static int write_header(const char *path, uint32_t magicka, uint16_t entry_size, const char *algo) { + FILE *f = fopen(path, "wb"); + if (!f) return -1; + + sleep_header_t h; + memset(&h, 0, sizeof(h)); + h.magicka = ((magicka >> 24) & 0xff) | ((magicka >> 8) & 0xff00) | ((magicka << 8) & 0xff0000) | ((magicka << 24) & 0xff000000); + h.version = 0; + h.entry_size = (entry_size >> 8) | (entry_size << 8); // BE16 + h.algo_len = algo ? (uint8_t)strlen(algo) : 0; + if (algo) strncopy(h.algo, algo, sizeof(h.algo)); + if (fwrite(&h, 1, sizeof(h), f) != sizeof(h)) { + fclose(f); + return -1; + } + fclose(f); + return 0; +} + +int sleep_init(const char *root) { + char path[512]; + + // makedir .dat(t) testing + sprintf(path, sizeof(path), "%s/.datt", root); + if (mkdir(path, 0700) && errno != EEXIST) return -1; + + // content.* signatures, tree, bitfield, key + + // metadata.* signatures, tree, bitfield, key + return 0; +} + +int main(void) { + if (sleep_init(".")) { + perror("sleep_init failed"); + return 1; + } + return 0; +} diff --git a/src/sleep_crypto.c b/src/sleep_crypto.c index 4291cea..df028e1 100644 --- a/src/sleep_crypto.c +++ b/src/sleep_crypto.c @@ -24,3 +24,34 @@ int sleep_load_pubkey(const char *path, uint8_t pubkey[SLEEP_PUBLIC_KEY_BYTES]) return (read == SLEEP_PUBLIC_KEY_BYTES) ? 0 : -1; } +int sleep_blake2b(uint8_t out[SLEEP_BLAKE2B_BYTES], const uint8_t *in, size_t inlen) { + return crypto_generichash(out, SLEEP_BLAKE2B_BYTES, in, inlen, NULL, 0); +} + +int sleep_sign(uint8_t sig[SLEEP_SIGNATURE_BYTES], const uint8_t *msg, size_t msglen, const sleep_keypair_t *kp) { + return crypto_sign_detached(sig, NULL, msg, msglen, kp->seckey); +} + +int sleep_verify(const uint8_t sig[SLEEP_SIGNATURE_BYTES], const uint8_t *msg, size_t msglen, const uint8_t pubkey[SLEEP_PUBLIC_KEY_BYTES]) { + return crypto_sign_verify_detached(sig, msg, msglen, pubkey); +} + +int sleep_sign_roots(uint8_t sig[SLEEP_SIGNATURE_BYTES], const uint8_t *roots, size_t nroots, const uint64_t *indices, const uint64_t *lengths, const sleep_keypair_t *kp) { + uint8_t bug[1024]; // FIXME dynamic + size_t ctxlen = strlen(SLEEP_CONTEXT); + memcpy(bug, SLEEP_CONTEXT, ctxlen); + size_t off = ctxlen; // off defined in scope? + off += encode_roots(bug + off, roots, nroots, indices, lengths); + return sleep_sign(sig, bug, off, kp); +} + +int sleep_verify_roots(const uint8_t sig[SLEEP_SIGNATURE_BYTES], const uint8_t *roots, size_t nroots, const uint64_t *indices, const uint64_t *lengths, const uint8_t pub[SLEEP_PUBLIC_KEY_BYTES]) { + uint8_t bug[1024]; // FIXME dynamic + size_t ctxlen = strlen(SLEEP_CONTEXT); + memcpy(bug, SLEEP_CONTEXT, ctxlen); + size_t off = ctxlen; // off defined in scope? + off += encode_roots(bug + off, roots, nroots, indices, lengths +); + return sleep_verify(sig, bug, off, kp); +} + diff --git a/src/sleep_tree.c b/src/sleep_tree.c index 8221d8a..1a2ded9 100644 --- a/src/sleep_tree.c +++ b/src/sleep_tree.c @@ -24,7 +24,7 @@ static inline unsigned int _ctzll_fallback(uint64_t x) { } return 1; } -static inline unsigned int flattree_ctzll(uint64_t x) { +static inline unsigned int tree_ctzll(uint64_t x) { #if defined(__GNUC__) || defined(__clang__) || define(__MUSL__) if (x == 0) return 64; return (unsigned int)__builtin_ctzll(x); @@ -33,6 +33,78 @@ static inline unsigned int flattree_ctzll(uint64_t x) { #endif } +static inline uint64_t sleep_tree_index(uint64_t depth, uint64_t offset) { + if (depth >= 63) { + return UINT64_MAX; + } + return (offset << (depth + 1)) | ((depth == 0) ? 0ULL : ((1ULL << depth) - 1ULL)); +} + +static inline uint64_t sleep_tree_depth(uint64_t i) { + uint64_t inverted = ~i; + return (uint64_t)tree_ctzll(inverted); +} + +static inline int tree_is_even(uint64_t i) { + return (i & 1ULL) == 0ULL; } +static inline int tree_is_odd(uint64_t i) { + return (i & 1ULL) != 0ULL; } + +static inline uint64_t sleep_tree_offset(uint64_t i) { + uint64_t d = sleep_tree_depth(i); + if (tree_is_even(i)) { + return i / 2; + } else { + return i >> (d + 1); + } +} + +static inline uint64_t sleep_tree_parent(uint64_t i) { + uint64_t d = sleep_tree_depth(i); + return sleep_tree_index(d, sleep_tree_offset(i) ^ 1ULL); +} + +static inline int sleep_tree_left_child(uint64_t i, uint64_t *out) { // set + if (tree_is_even(i)) return 0; + uint64_t d = sleep_tree_depth(i); + if (d == 0) { + *out = i; + return 1; + } + *out = sleep_tree_index(d - 1, sleep_tree_offset(i) << 1); + return 1; +} + +static inline int sleep_tree_right_child(uint64_t i, uint64_t *out) { // horus + if (tree_is_even(i)) return 0; + uint64_t d = sleep_tree_depth(i); + if (d == 0) { + *out = i; + return 1; + } + *out = sleep_tree_index(d - 1, (slep_tree_offset(i) << 1) + 1ULL); + return 1; +} + +static inline uint64_t sleep_tree_left_span(uint64_t i) { + uint64_t d = sleep_tree_depth(i); + if (d == 0) return i; + return sleep_tree_offset(i) * (2ULL << d); +} + +static inline uint64_t sleep_tree_right_span(uint64_t i) { + uint64_t d = sleep_tree_depth(i); + if (d == 0) return i; + return (sleep_tree_offset(i) + 1ULL) * (2ULL << d) - 2ULL; +} + +static inline void sleep_tree_spans(uint64_t i, uint64_t *left, uint64_t *right) { + *left = sleep_tree_left_span(i); + *right = sleep_tree_right_span(i); +} + +// TODO static inline int sleep_tree_full_roots + // भव न सन हृदयं int sleep_tree_hash_block(const uint8_t *data, size_t len, uint8_t out_hash[32]) { #ifndef SLEEP_SALT @@ -86,7 +158,7 @@ int sleep_tree_build(const uint8_t **blocks, size_t *block_lens, size_t nblocks, free(roots); return -1; } - leaf.index = flattree_index(0, (uint64_t)i); // 2 * i ... FIXME flattree naming conventions, defined in scope? + leaf.index = sleep_tree_index(0, (uint64_t)i); // 2 * i ... leaf.size = (uint64_t)block_lens[i]; if (nodes_len >= max_nodes) { size_t newcap = max_nodes * 2; @@ -120,5 +192,3 @@ int sleep_tree_build(const uint8_t **blocks, size_t *block_lens, size_t nblocks, free(roots); return 0; } - -