/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* Copyright (c) 2020-2023 Brett Sheffield <bacs@librecast.net> */

/* mtree.h - Librecast merkle tree API */

#ifndef _MTREE_H
#define _MTREE_H 1

#include <assert.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "q.h"

#define MTREE_CHUNKSIZE 1024 * 32
#define MTREE_BLOCKSIZE 64
#define MTREE_HASHSIZE 32
#define MTREE_THREADMAX 64
static_assert(__builtin_popcount(MTREE_THREADMAX) == 1,
		"MTREE_THREADMAX must be a power of 2");

#define mtree_parent(node) (((node + 1) >> 1) - 1)

typedef struct mtree_s mtree_t;
struct mtree_s {
	size_t len;    /* total size of base (file) data */
	size_t base;   /* size of base of tree (pow of 2) */
	size_t chunks; /* number of blocks (<= base)) */
	size_t nodes;  /* count of total nodes in tree */
	void *data;    /* ptr to the base data */
	uint8_t *tree; /* ptr to tree hashes */
};

int mtree_init(mtree_t *tree, size_t sz);
void mtree_free(mtree_t *tree);
int mtree_build(mtree_t *tree, void * const data, q_t *q);
int mtree_verify(mtree_t *tree);
size_t mtree_child(mtree_t *tree, size_t node);
unsigned char *mtree_diff_map(mtree_t *t1, mtree_t *t2);
unsigned char *mtree_diff_subtree(mtree_t *t1, mtree_t *t2, size_t root, unsigned bits);
uint8_t *mtree_nnode(mtree_t *tree, size_t node);
size_t mtree_subtree_data_min(size_t base, size_t root);
size_t mtree_subtree_data_max(size_t base, size_t root);
void mtree_hexdump(mtree_t *tree, FILE *fd);
void mtree_printmap(unsigned char *map, size_t len, FILE *fd);

#endif /* _MTREE_H */
