commit 009af9ed5b873d8d5c702d5e013105d26e655d8b
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 14 Apr 2022 07:52:29 -0700
initial commit
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
| A | .envrc | | | 1 | + | 
| A | .gitignore | | | 8 | ++++++++ | 
| A | Makefile | | | 22 | ++++++++++++++++++++++ | 
| A | compiler.h | | | 85 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | configurator.c | | | 1110 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | cursor.h | | | 320 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | endian.h | | | 364 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | hex.h | | | 69 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | nostril.c | | | 426 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | random.h | | | 73 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | sha256.c | | | 302 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | sha256.h | | | 155 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | shell.nix | | | 5 | +++++ | 
13 files changed, 2940 insertions(+), 0 deletions(-)
diff --git a/.envrc b/.envrc
@@ -0,0 +1 @@
+use nix
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,8 @@
+*.o
+nostril
+configurator.out*
+configurator
+.build-result
+.buildcmd
+config.h
+tags
diff --git a/Makefile b/Makefile
@@ -0,0 +1,22 @@
+
+OBJS = sha256.o nostril.o
+HEADERS = hex.h random.h config.h sha256.h
+
+all: nostril
+
+nostril: $(OBJS) $(HEADERS)
+	$(CC) $(OBJS) -lsecp256k1 -o $@ 
+
+config.h: configurator                                                          
+	./configurator > $@                                                     
+
+configurator: configurator.c                                                    
+	$(CC) $< -o $@
+
+clean:
+	rm -f nostril *.o
+
+tags: fake
+	ctags *.c *.h
+
+.PHONY: fake
diff --git a/compiler.h b/compiler.h
@@ -0,0 +1,85 @@
+
+#ifndef COMPILER_H
+#define COMPILER_H
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+
+#if HAVE_UNALIGNED_ACCESS
+#define alignment_ok(p, n) 1
+#else
+#define alignment_ok(p, n) ((size_t)(p) % (n) == 0)
+#endif
+
+#define UNUSED __attribute__((__unused__))
+
+/**
+ * BUILD_ASSERT - assert a build-time dependency.
+ * @cond: the compile-time condition which must be true.
+ *
+ * Your compile will fail if the condition isn't true, or can't be evaluated
+ * by the compiler.  This can only be used within a function.
+ *
+ * Example:
+ *	#include <stddef.h>
+ *	...
+ *	static char *foo_to_char(struct foo *foo)
+ *	{
+ *		// This code needs string to be at start of foo.
+ *		BUILD_ASSERT(offsetof(struct foo, string) == 0);
+ *		return (char *)foo;
+ *	}
+ */
+#define BUILD_ASSERT(cond) \
+	do { (void) sizeof(char [1 - 2*!(cond)]); } while(0)
+
+/**
+ * BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression.
+ * @cond: the compile-time condition which must be true.
+ *
+ * Your compile will fail if the condition isn't true, or can't be evaluated
+ * by the compiler.  This can be used in an expression: its value is "0".
+ *
+ * Example:
+ *	#define foo_to_char(foo)					\
+ *		 ((char *)(foo)						\
+ *		  + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))
+ */
+#define BUILD_ASSERT_OR_ZERO(cond) \
+	(sizeof(char [1 - 2*!(cond)]) - 1)
+
+#define memclear(mem, size) memset(mem, 0, size)
+#define memclear_2(m1, s1, m2, s2) { memclear(m1, s1); memclear(m2, s2); }
+#define memclear_3(m1, s1, m2, s2, m3, s3) { memclear(m1, s1); memclear(m2, s2); memclear(m3, s3); }
+
+static inline void *memcheck_(const void *data, size_t len)
+{
+	(void)len;
+	return (void *)data;
+}
+
+#if HAVE_TYPEOF
+/**
+ * memcheck - check that a memory region is initialized
+ * @data: start of region
+ * @len: length in bytes
+ *
+ * When running under valgrind, this causes an error to be printed
+ * if the entire region is not defined.  Otherwise valgrind only
+ * reports an error when an undefined value is used for a branch, or
+ * written out.
+ *
+ * Example:
+ *	// Search for space, but make sure it's all initialized.
+ *	if (memchr(memcheck(somebytes, bytes_len), ' ', bytes_len)) {
+ *		printf("space was found!\n");
+ *	}
+ */
+#define memcheck(data, len) ((__typeof__((data)+0))memcheck_((data), (len)))
+#else
+#define memcheck(data, len) memcheck_((data), (len))
+#endif
+
+#endif /* COMPILER_H */
diff --git a/configurator.c b/configurator.c
@@ -0,0 +1,1110 @@
+/* Simple tool to create config.h.
+ * Would be much easier with ccan modules, but deliberately standalone.
+ *
+ * Copyright 2011 Rusty Russell <rusty@rustcorp.com.au>.  MIT license.
+ *
+ * c12r_err, c12r_errx functions copied from ccan/err/err.c
+ * Copyright Rusty Russell <rusty@rustcorp.com.au>. CC0 (Public domain) License.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#define _POSIX_C_SOURCE 200809L                /* For pclose, popen, strdup */
+
+#define EXIT_BAD_USAGE		  1
+#define EXIT_TROUBLE_RUNNING	  2
+#define EXIT_BAD_TEST		  3
+#define EXIT_BAD_INPUT		  4
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef _MSC_VER
+#define popen _popen
+#define pclose _pclose
+#endif
+
+#ifdef _MSC_VER
+#define DEFAULT_COMPILER "cl"
+/* Note:  Dash options avoid POSIX path conversion when used under msys bash
+ *        and are therefore preferred to slash (e.g. -nologo over /nologo)
+ * Note:  Disable Warning 4200 "nonstandard extension used : zero-sized array
+ *        in struct/union" for flexible array members.
+ */
+#define DEFAULT_FLAGS "-nologo -Zi -W4 -wd4200 " \
+	"-D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS"
+#define DEFAULT_OUTPUT_EXE_FLAG "-Fe:"
+#else
+#define DEFAULT_COMPILER "cc"
+#define DEFAULT_FLAGS "-g3 -ggdb -Wall -Wundef -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes -Wold-style-definition"
+#define DEFAULT_OUTPUT_EXE_FLAG "-o"
+#endif
+
+#define OUTPUT_FILE "configurator.out"
+#define INPUT_FILE "configuratortest.c"
+
+#ifdef _WIN32
+#define DIR_SEP   "\\"
+#else
+#define DIR_SEP   "/"
+#endif
+
+static const char *progname = "";
+static int verbose;
+static bool like_a_libtool = false;
+
+struct test {
+	const char *name;
+	const char *desc;
+	/*
+	 * Template style flags (pick one):
+	 * OUTSIDE_MAIN:
+	 * - put a simple boilerplate main below it.
+	 * DEFINES_FUNC:
+	 * - defines a static function called func; adds ref to avoid warnings
+	 * INSIDE_MAIN:
+	 * - put this inside main().
+	 * DEFINES_EVERYTHING:
+	 * - don't add any boilerplate at all.
+	 *
+	 * Execution flags:
+	 * EXECUTE:
+	 * - a runtime test; must compile, exit 0 means flag is set.
+	 * MAY_NOT_COMPILE:
+	 * - Only useful with EXECUTE: don't get upset if it doesn't compile.
+	 * <nothing>:
+	 * - a compile test, if it compiles must run and exit 0.
+	 */
+	const char *style;
+	const char *depends;
+	const char *link;
+	const char *fragment;
+	const char *flags;
+	const char *overrides; /* On success, force this to '1' */
+	bool done;
+	bool answer;
+};
+
+/* Terminated by a NULL name */
+static struct test *tests;
+
+static const struct test base_tests[] = {
+	{ "HAVE_UNALIGNED_ACCESS", "unaligned access to int",
+	  "DEFINES_EVERYTHING|EXECUTE", NULL, NULL,
+	  "#include <string.h>\n"
+	  "int main(int argc, char *argv[]) {\n"
+	  "	(void)argc;\n"
+	  "     char pad[sizeof(int *) * 1];\n"
+	  "	memcpy(pad, argv[0], sizeof(pad));\n"
+	  "	int *x = (int *)pad, *y = (int *)(pad + 1);\n"
+	  "	return *x == *y;\n"
+	  "}\n" },
+	{ "HAVE_TYPEOF", "__typeof__ support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "__typeof__(argc) i; i = argc; return i == argc ? 0 : 1;" },
+	{ "HAVE_BIG_ENDIAN", "big endian",
+	  "INSIDE_MAIN|EXECUTE", NULL, NULL,
+	  "union { int i; char c[sizeof(int)]; } u;\n"
+	  "u.i = 0x01020304;\n"
+	  "return u.c[0] == 0x01 && u.c[1] == 0x02 && u.c[2] == 0x03 && u.c[3] == 0x04 ? 0 : 1;" },
+	{ "HAVE_BYTESWAP_H", "<byteswap.h>",
+	  "OUTSIDE_MAIN", NULL, NULL,
+	  "#include <byteswap.h>\n" },
+	{ "HAVE_BSWAP_64", "bswap64 in byteswap.h",
+	  "DEFINES_FUNC", "HAVE_BYTESWAP_H", NULL,
+	  "#include <byteswap.h>\n"
+	  "static int func(int x) { return bswap_64(x); }" },
+	{ "HAVE_LITTLE_ENDIAN", "little endian",
+	  "INSIDE_MAIN|EXECUTE", NULL, NULL,
+	  "union { int i; char c[sizeof(int)]; } u;\n"
+	  "u.i = 0x01020304;\n"
+	  "return u.c[0] == 0x04 && u.c[1] == 0x03 && u.c[2] == 0x02 && u.c[3] == 0x01 ? 0 : 1;" },
+	/*
+	{ "HAVE_32BIT_OFF_T", "off_t is 32 bits",
+	  "DEFINES_EVERYTHING|EXECUTE|MAY_NOT_COMPILE", NULL, NULL,
+	  "#include <sys/types.h>\n"
+	  "int main(void) {\n"
+	  "	return sizeof(off_t) == 4 ? 0 : 1;\n"
+	  "}\n" },
+	{ "HAVE_ALIGNOF", "__alignof__ support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __alignof__(double) > 0 ? 0 : 1;" },
+	{ "HAVE_ASPRINTF", "asprintf() declaration",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "#ifndef _GNU_SOURCE\n"
+	  "#define _GNU_SOURCE\n"
+	  "#endif\n"
+	  "#include <stdio.h>\n"
+	  "static char *func(int x) {"
+	  "	char *p;\n"
+	  "	if (asprintf(&p, \"%u\", x) == -1) \n"
+	  "		p = NULL;\n"
+	  "	return p;\n"
+	  "}" },
+	{ "HAVE_ATTRIBUTE_COLD", "__attribute__((cold)) support",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "static int __attribute__((cold)) func(int x) { return x; }" },
+	{ "HAVE_ATTRIBUTE_CONST", "__attribute__((const)) support",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "static int __attribute__((const)) func(int x) { return x; }" },
+	{ "HAVE_ATTRIBUTE_DEPRECATED", "__attribute__((deprecated)) support",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "static int __attribute__((deprecated)) func(int x) { return x; }" },
+	{ "HAVE_ATTRIBUTE_NONNULL", "__attribute__((nonnull)) support",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "static char *__attribute__((nonnull)) func(char *p) { return p; }" },
+	{ "HAVE_ATTRIBUTE_RETURNS_NONNULL", "__attribute__((returns_nonnull)) support",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "static const char *__attribute__((returns_nonnull)) func(void) { return \"hi\"; }" },
+	{ "HAVE_ATTRIBUTE_SENTINEL", "__attribute__((sentinel)) support",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "static int __attribute__((sentinel)) func(int i, ...) { return i; }" },
+	{ "HAVE_ATTRIBUTE_PURE", "__attribute__((pure)) support",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "static int __attribute__((pure)) func(int x) { return x; }" },
+	{ "HAVE_ATTRIBUTE_MAY_ALIAS", "__attribute__((may_alias)) support",
+	  "OUTSIDE_MAIN", NULL, NULL,
+	  "typedef short __attribute__((__may_alias__)) short_a;" },
+	{ "HAVE_ATTRIBUTE_NORETURN", "__attribute__((noreturn)) support",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "#include <stdlib.h>\n"
+	  "static void __attribute__((noreturn)) func(int x) { exit(x); }" },
+	{ "HAVE_ATTRIBUTE_PRINTF", "__attribute__ format printf support",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "static void __attribute__((format(__printf__, 1, 2))) func(const char *fmt, ...) { (void)fmt; }" },
+	{ "HAVE_ATTRIBUTE_UNUSED", "__attribute__((unused)) support",
+	  "OUTSIDE_MAIN", NULL, NULL,
+	  "static int __attribute__((unused)) func(int x) { return x; }" },
+	{ "HAVE_ATTRIBUTE_USED", "__attribute__((used)) support",
+	  "OUTSIDE_MAIN", NULL, NULL,
+	  "static int __attribute__((used)) func(int x) { return x; }" },
+	{ "HAVE_BACKTRACE", "backtrace() in <execinfo.h>",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "#include <execinfo.h>\n"
+	  "static int func(int x) {"
+	  "	void *bt[10];\n"
+	  "	return backtrace(bt, 10) < x;\n"
+	  "}" },
+	{ "HAVE_BUILTIN_CHOOSE_EXPR", "__builtin_choose_expr support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_choose_expr(1, 0, \"garbage\");" },
+	{ "HAVE_BUILTIN_CLZ", "__builtin_clz support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_clz(1) == (sizeof(int)*8 - 1) ? 0 : 1;" },
+	{ "HAVE_BUILTIN_CLZL", "__builtin_clzl support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_clzl(1) == (sizeof(long)*8 - 1) ? 0 : 1;" },
+	{ "HAVE_BUILTIN_CLZLL", "__builtin_clzll support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_clzll(1) == (sizeof(long long)*8 - 1) ? 0 : 1;" },
+	{ "HAVE_BUILTIN_CTZ", "__builtin_ctz support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_ctz(1 << (sizeof(int)*8 - 1)) == (sizeof(int)*8 - 1) ? 0 : 1;" },
+	{ "HAVE_BUILTIN_CTZL", "__builtin_ctzl support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_ctzl(1UL << (sizeof(long)*8 - 1)) == (sizeof(long)*8 - 1) ? 0 : 1;" },
+	{ "HAVE_BUILTIN_CTZLL", "__builtin_ctzll support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_ctzll(1ULL << (sizeof(long long)*8 - 1)) == (sizeof(long long)*8 - 1) ? 0 : 1;" },
+	{ "HAVE_BUILTIN_CONSTANT_P", "__builtin_constant_p support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_constant_p(1) ? 0 : 1;" },
+	{ "HAVE_BUILTIN_EXPECT", "__builtin_expect support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_expect(argc == 1, 1) ? 0 : 1;" },
+	{ "HAVE_BUILTIN_FFS", "__builtin_ffs support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_ffs(0) == 0 ? 0 : 1;" },
+	{ "HAVE_BUILTIN_FFSL", "__builtin_ffsl support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_ffsl(0L) == 0 ? 0 : 1;" },
+	{ "HAVE_BUILTIN_FFSLL", "__builtin_ffsll support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_ffsll(0LL) == 0 ? 0 : 1;" },
+	{ "HAVE_BUILTIN_POPCOUNT", "__builtin_popcount support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_popcount(255) == 8 ? 0 : 1;" },
+	{ "HAVE_BUILTIN_POPCOUNTL",  "__builtin_popcountl support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_popcountl(255L) == 8 ? 0 : 1;" },
+	{ "HAVE_BUILTIN_POPCOUNTLL", "__builtin_popcountll support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_popcountll(255LL) == 8 ? 0 : 1;" },
+	{ "HAVE_BUILTIN_TYPES_COMPATIBLE_P", "__builtin_types_compatible_p support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return __builtin_types_compatible_p(char *, int) ? 1 : 0;" },
+	{ "HAVE_ICCARM_INTRINSICS", "<intrinsics.h>",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "#include <intrinsics.h>\n"
+	  "int func(int v) {\n"
+	  "	return __CLZ(__RBIT(v));\n"
+	  "}" },
+	{ "HAVE_CLOCK_GETTIME", "clock_gettime() declaration",
+	  "DEFINES_FUNC", "HAVE_STRUCT_TIMESPEC", NULL,
+	  "#include <time.h>\n"
+	  "static struct timespec func(void) {\n"
+	  "	struct timespec ts;\n"
+	  "	clock_gettime(CLOCK_REALTIME, &ts);\n"
+	  "	return ts;\n"
+	  "}\n" },
+	{ "HAVE_CLOCK_GETTIME_IN_LIBRT", "clock_gettime() in librt",
+	  "DEFINES_FUNC",
+	  "HAVE_STRUCT_TIMESPEC !HAVE_CLOCK_GETTIME",
+	  "-lrt",
+	  "#include <time.h>\n"
+	  "static struct timespec func(void) {\n"
+	  "	struct timespec ts;\n"
+	  "	clock_gettime(CLOCK_REALTIME, &ts);\n"
+	  "	return ts;\n"
+	  "}\n",
+	  "HAVE_CLOCK_GETTIME" },
+	{ "HAVE_COMPOUND_LITERALS", "compound literal support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "int *foo = (int[]) { 1, 2, 3, 4 };\n"
+	  "return foo[0] ? 0 : 1;" },
+	{ "HAVE_FCHDIR", "fchdir support",
+	  "DEFINES_EVERYTHING|EXECUTE|MAY_NOT_COMPILE", NULL, NULL,
+	  "#include <sys/types.h>\n"
+	  "#include <sys/stat.h>\n"
+	  "#include <fcntl.h>\n"
+	  "#include <unistd.h>\n"
+	  "int main(void) {\n"
+	  "	int fd = open(\"..\", O_RDONLY);\n"
+	  "	return fchdir(fd) == 0 ? 0 : 1;\n"
+	  "}\n" },
+	{ "HAVE_ERR_H", "<err.h>",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "#include <err.h>\n"
+	  "static void func(int arg) {\n"
+	  "	if (arg == 0)\n"
+	  "		err(1, \"err %u\", arg);\n"
+	  "	if (arg == 1)\n"
+	  "		errx(1, \"err %u\", arg);\n"
+	  "	if (arg == 3)\n"
+	  "		warn(\"warn %u\", arg);\n"
+	  "	if (arg == 4)\n"
+	  "		warnx(\"warn %u\", arg);\n"
+	  "}\n" },
+	{ "HAVE_FILE_OFFSET_BITS", "_FILE_OFFSET_BITS to get 64-bit offsets",
+	  "DEFINES_EVERYTHING|EXECUTE|MAY_NOT_COMPILE",
+	  "HAVE_32BIT_OFF_T", NULL,
+	  "#define _FILE_OFFSET_BITS 64\n"
+	  "#include <sys/types.h>\n"
+	  "int main(void) {\n"
+	  "	return sizeof(off_t) == 8 ? 0 : 1;\n"
+	  "}\n" },
+	{ "HAVE_FOR_LOOP_DECLARATION", "for loop declaration support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "int ret = 1;\n"
+	  "for (int i = 0; i < argc; i++) { ret = 0; };\n"
+	  "return ret;" },
+	{ "HAVE_FLEXIBLE_ARRAY_MEMBER", "flexible array member support",
+	  "OUTSIDE_MAIN", NULL, NULL,
+	  "struct foo { unsigned int x; int arr[]; };" },
+	{ "HAVE_GETPAGESIZE", "getpagesize() in <unistd.h>",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "#include <unistd.h>\n"
+	  "static int func(void) { return getpagesize(); }" },
+	{ "HAVE_ISBLANK", "isblank() in <ctype.h>",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "#ifndef _GNU_SOURCE\n"
+	  "#define _GNU_SOURCE\n"
+	  "#endif\n"
+	  "#include <ctype.h>\n"
+	  "static int func(void) { return isblank(' '); }" },
+	{ "HAVE_MEMMEM", "memmem in <string.h>",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "#ifndef _GNU_SOURCE\n"
+	  "#define _GNU_SOURCE\n"
+	  "#endif\n"
+	  "#include <string.h>\n"
+	  "static void *func(void *h, size_t hl, void *n, size_t nl) {\n"
+	  "return memmem(h, hl, n, nl);"
+	  "}\n", },
+	{ "HAVE_MEMRCHR", "memrchr in <string.h>",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "#ifndef _GNU_SOURCE\n"
+	  "#define _GNU_SOURCE\n"
+	  "#endif\n"
+	  "#include <string.h>\n"
+	  "static void *func(void *s, int c, size_t n) {\n"
+	  "return memrchr(s, c, n);"
+	  "}\n", },
+	{ "HAVE_MMAP", "mmap() declaration",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "#include <sys/mman.h>\n"
+	  "static void *func(int fd) {\n"
+	  "	return mmap(0, 65536, PROT_READ, MAP_SHARED, fd, 0);\n"
+	  "}" },
+	{ "HAVE_PROC_SELF_MAPS", "/proc/self/maps exists",
+	  "DEFINES_EVERYTHING|EXECUTE|MAY_NOT_COMPILE", NULL, NULL,
+	  "#include <sys/types.h>\n"
+	  "#include <sys/stat.h>\n"
+	  "#include <fcntl.h>\n"
+	  "int main(void) {\n"
+	  "	return open(\"/proc/self/maps\", O_RDONLY) != -1 ? 0 : 1;\n"
+	  "}\n" },
+	{ "HAVE_QSORT_R_PRIVATE_LAST", "qsort_r cmp takes trailing arg",
+	  "DEFINES_EVERYTHING|EXECUTE|MAY_NOT_COMPILE", NULL, NULL,
+	  "#ifndef _GNU_SOURCE\n"
+	  "#define _GNU_SOURCE\n"
+	  "#endif\n"
+	  "#include <stdlib.h>\n"
+	  "static int cmp(const void *lp, const void *rp, void *priv) {\n"
+	  " *(unsigned int *)priv = 1;\n"
+	  " return *(const int *)lp - *(const int *)rp; }\n"
+	  "int main(void) {\n"
+	  " int array[] = { 9, 2, 5 };\n"
+	  " unsigned int called = 0;\n"
+	  " qsort_r(array, 3, sizeof(int), cmp, &called);\n"
+	  " return called && array[0] == 2 && array[1] == 5 && array[2] == 9 ? 0 : 1;\n"
+	  "}\n" },
+	{ "HAVE_STRUCT_TIMESPEC", "struct timespec declaration",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "#include <time.h>\n"
+	  "static void func(void) {\n"
+	  "	struct timespec ts;\n"
+	  "	ts.tv_sec = ts.tv_nsec = 1;\n"
+	  "}\n" },
+	{ "HAVE_SECTION_START_STOP", "__attribute__((section)) and __start/__stop",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "static void *__attribute__((__section__(\"mysec\"))) p = &p;\n"
+	  "static int func(void) {\n"
+	  "	extern void *__start_mysec[], *__stop_mysec[];\n"
+	  "	return __stop_mysec - __start_mysec;\n"
+	  "}\n" },
+	{ "HAVE_STACK_GROWS_UPWARDS", "stack grows upwards",
+	  "DEFINES_EVERYTHING|EXECUTE", NULL, NULL,
+	  "#include <stddef.h>\n"
+	  "static ptrdiff_t nest(const void *base, unsigned int i)\n"
+	  "{\n"
+	  "	if (i == 0)\n"
+	  "		return (const char *)&i - (const char *)base;\n"
+	  "	return nest(base, i-1);\n"
+	  "}\n"
+	  "int main(int argc, char *argv[]) {\n"
+	  "	(void)argv;\n"
+	  "	return (nest(&argc, argc) > 0) ? 0 : 1;\n"
+	  "}\n" },
+	{ "HAVE_STATEMENT_EXPR", "statement expression support",
+	  "INSIDE_MAIN", NULL, NULL,
+	  "return ({ int x = argc; x == argc ? 0 : 1; });" },
+	{ "HAVE_SYS_FILIO_H", "<sys/filio.h>",
+	  "OUTSIDE_MAIN", NULL, NULL,
+	  "#include <sys/filio.h>\n" },
+	{ "HAVE_SYS_TERMIOS_H", "<sys/termios.h>",
+	  "OUTSIDE_MAIN", NULL, NULL,
+	  "#include <sys/termios.h>\n" },
+	{ "HAVE_SYS_UNISTD_H", "<sys/unistd.h>",
+	  "OUTSIDE_MAIN", NULL, NULL,
+	  "#include <sys/unistd.h>\n" },
+	{ "HAVE_UTIME", "utime() declaration",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "#include <sys/types.h>\n"
+	  "#include <utime.h>\n"
+	  "static int func(const char *filename) {\n"
+	  "	struct utimbuf times = { 0 };\n"
+	  "	return utime(filename, ×);\n"
+	  "}" },
+	{ "HAVE_WARN_UNUSED_RESULT", "__attribute__((warn_unused_result))",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "#include <sys/types.h>\n"
+	  "#include <utime.h>\n"
+	  "static __attribute__((warn_unused_result)) int func(int i) {\n"
+	  "	return i + 1;\n"
+	  "}" },
+	{ "HAVE_OPENMP", "#pragma omp and -fopenmp support",
+	  "INSIDE_MAIN|EXECUTE|MAY_NOT_COMPILE", NULL, NULL,
+	  "int i;\n"
+	  "#pragma omp parallel for\n"
+	  "for(i = 0; i < 0; i++) {};\n"
+	  "return 0;\n",
+	  "-Werror -fopenmp" },
+	{ "HAVE_VALGRIND_MEMCHECK_H", "<valgrind/memcheck.h>",
+	  "OUTSIDE_MAIN", NULL, NULL,
+	  "#include <valgrind/memcheck.h>\n" },
+	{ "HAVE_UCONTEXT", "working <ucontext.h",
+	  "DEFINES_EVERYTHING|EXECUTE|MAY_NOT_COMPILE",
+	  NULL, NULL,
+	  "#include <ucontext.h>\n"
+	  "static int x = 0;\n"
+	  "static char stack[2048];\n"
+	  "static ucontext_t a, b;\n"
+	  "static void fn(void) {\n"
+	  "	x |= 2;\n"
+	  "	setcontext(&b);\n"
+	  "	x |= 4;\n"
+	  "}\n"
+	  "int main(void) {\n"
+	  "	x |= 1;\n"
+	  "	getcontext(&a);\n"
+	  "	a.uc_stack.ss_sp = stack;\n"
+	  "	a.uc_stack.ss_size = sizeof(stack);\n"
+	  "	makecontext(&a, fn, 0);\n"
+	  "	swapcontext(&b, &a);\n"
+	  "	return (x == 3) ? 0 : 1;\n"
+	  "}\n"
+	},
+	{ "HAVE_POINTER_SAFE_MAKECONTEXT", "passing pointers via makecontext()",
+	  "DEFINES_EVERYTHING|EXECUTE|MAY_NOT_COMPILE",
+	  "HAVE_UCONTEXT", NULL,
+	  "#include <stddef.h>\n"
+	  "#include <ucontext.h>\n"
+	  "static int worked = 0;\n"
+	  "static char stack[1024];\n"
+	  "static ucontext_t a, b;\n"
+	  "static void fn(void *p, void *q) {\n"
+	  "	void *cp = &worked;\n"
+	  "	void *cq = (void *)(~((ptrdiff_t)cp));\n"
+	  "	if ((p == cp) && (q == cq))\n"
+	  "		worked = 1;\n"
+	  "	setcontext(&b);\n"
+	  "}\n"
+	  "int main(void) {\n"
+	  "	void *ap = &worked;\n"
+	  "	void *aq = (void *)(~((ptrdiff_t)ap));\n"
+	  "	getcontext(&a);\n"
+	  "	a.uc_stack.ss_sp = stack;\n"
+	  "	a.uc_stack.ss_size = sizeof(stack);\n"
+	  "	makecontext(&a, (void (*)(void))fn, 2, ap, aq);\n"
+	  "	swapcontext(&b, &a);\n"
+	  "	return worked ? 0 : 1;\n"
+	  "}\n"
+	},
+	{ "HAVE_BUILTIN_CPU_SUPPORTS", "__builtin_cpu_supports()",
+	  "DEFINES_FUNC", NULL, NULL,
+	  "#include <stdbool.h>\n"
+	  "static bool func(void) {\n"
+	  "	return __builtin_cpu_supports(\"mmx\");\n"
+	  "}"
+	},
+	{ "HAVE_CLOSEFROM", "closefrom() offered by system",
+	  "DEFINES_EVERYTHING", NULL, NULL,
+	  "#include <stdlib.h>\n"
+	  "#include <unistd.h>\n"
+	  "int main(void) {\n"
+	  "    closefrom(STDERR_FILENO + 1);\n"
+	  "    return 0;\n"
+	  "}\n"
+	},
+	{ "HAVE_F_CLOSEM", "F_CLOSEM defined for fctnl.",
+	  "DEFINES_EVERYTHING", NULL, NULL,
+	  "#include <fcntl.h>\n"
+	  "#include <unistd.h>\n"
+	  "int main(void) {\n"
+	  "    int res = fcntl(STDERR_FILENO + 1, F_CLOSEM, 0);\n"
+	  "    return res < 0;\n"
+	  "}\n"
+	},
+	{ "HAVE_NR_CLOSE_RANGE", "close_range syscall available as __NR_close_range.",
+	  "DEFINES_EVERYTHING", NULL, NULL,
+	  "#include <limits.h>\n"
+	  "#include <sys/syscall.h>\n"
+	  "#include <unistd.h>\n"
+	  "int main(void) {\n"
+	  "    int res = syscall(__NR_close_range, STDERR_FILENO + 1, INT_MAX, 0);\n"
+	  "    return res < 0;\n"
+	  "}\n"
+	},
+	{ "HAVE_F_MAXFD", "F_MAXFD defined for fcntl.",
+	  "DEFINES_EVERYTHING", NULL, NULL,
+	  "#include <fcntl.h>\n"
+	  "#include <unistd.h>\n"
+	  "int main(void) {\n"
+	  "    int res = fcntl(0, F_MAXFD);\n"
+	  "    return res < 0;\n"
+	  "}\n"
+	},
+	*/
+};
+
+static void c12r_err(int eval, const char *fmt, ...)
+{
+	int err_errno = errno;
+	va_list ap;
+
+	fprintf(stderr, "%s: ", progname);
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	fprintf(stderr, ": %s\n", strerror(err_errno));
+	exit(eval);
+}
+
+static void c12r_errx(int eval, const char *fmt, ...)
+{
+	va_list ap;
+
+	fprintf(stderr, "%s: ", progname);
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+	exit(eval);
+}
+
+static void start_test(const char *what, const char *why)
+{
+	if (like_a_libtool) {
+		printf("%s%s... ", what, why);
+		fflush(stdout);
+	}
+}
+
+static void end_test(bool result)
+{
+	if (like_a_libtool)
+		printf("%s\n", result ? "yes" : "no");
+}
+
+static size_t fcopy(FILE *fsrc, FILE *fdst)
+{
+	char buffer[BUFSIZ];
+	size_t rsize, wsize;
+	size_t copied = 0;
+
+	while ((rsize = fread(buffer, 1, BUFSIZ, fsrc)) > 0) {
+		wsize = fwrite(buffer, 1, rsize, fdst);
+		copied += wsize;
+		if (wsize != rsize)
+			break;
+	}
+
+	return copied;
+}
+
+static char *grab_stream(FILE *file)
+{
+	size_t max, ret, size = 0;
+	char *buffer;
+
+	max = BUFSIZ;
+	buffer = malloc(max);
+	while ((ret = fread(buffer+size, 1, max - size, file)) == max - size) {
+		size += ret;
+		buffer = realloc(buffer, max *= 2);
+	}
+	size += ret;
+	if (ferror(file))
+		c12r_err(EXIT_TROUBLE_RUNNING, "reading from command");
+	buffer[size] = '\0';
+	return buffer;
+}
+
+static char *run(const char *cmd, int *exitstatus)
+{
+	static const char redir[] = " 2>&1";
+	size_t cmdlen;
+	char *cmdredir;
+	FILE *cmdout;
+	char *ret;
+
+	cmdlen = strlen(cmd);
+	cmdredir = malloc(cmdlen + sizeof(redir));
+	memcpy(cmdredir, cmd, cmdlen);
+	memcpy(cmdredir + cmdlen, redir, sizeof(redir));
+
+	cmdout = popen(cmdredir, "r");
+	if (!cmdout)
+		c12r_err(EXIT_TROUBLE_RUNNING, "popen \"%s\"", cmdredir);
+
+	free(cmdredir);
+
+	ret = grab_stream(cmdout);
+	*exitstatus = pclose(cmdout);
+	return ret;
+}
+
+static char *connect_args(const char *argv[], const char *outflag,
+		const char *files)
+{
+	unsigned int i;
+	char *ret;
+	size_t len = strlen(outflag) + strlen(files) + 1;
+
+	for (i = 1; argv[i]; i++)
+		len += 1 + strlen(argv[i]);
+
+	ret = malloc(len);
+	len = 0;
+	for (i = 1; argv[i]; i++) {
+		strcpy(ret + len, argv[i]);
+		len += strlen(argv[i]);
+		if (argv[i+1] || *outflag)
+			ret[len++] = ' ';
+	}
+	strcpy(ret + len, outflag);
+	len += strlen(outflag);
+	strcpy(ret + len, files);
+	return ret;
+}
+
+static struct test *find_test(const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; tests[i].name; i++) {
+		if (strcmp(tests[i].name, name) == 0)
+			return &tests[i];
+	}
+	c12r_errx(EXIT_BAD_TEST, "Unknown test %s", name);
+	abort();
+}
+
+#define PRE_BOILERPLATE "/* Test program generated by configurator. */\n"
+#define MAIN_START_BOILERPLATE \
+	"int main(int argc, char *argv[]) {\n" \
+	"	(void)argc;\n" \
+	"	(void)argv;\n"
+#define USE_FUNC_BOILERPLATE "(void)func;\n"
+#define MAIN_BODY_BOILERPLATE "return 0;\n"
+#define MAIN_END_BOILERPLATE "}\n"
+
+static bool run_test(const char *cmd, const char *wrapper, struct test *test)
+{
+	char *output, *newcmd;
+	FILE *outf;
+	int status;
+
+	if (test->done)
+		return test->answer;
+
+	if (test->depends) {
+		size_t len;
+		const char *deps = test->depends;
+		char *dep;
+
+		/* Space-separated dependencies, could be ! for inverse. */
+		while ((len = strcspn(deps, " ")) != 0) {
+			bool positive = true;
+			if (deps[len]) {
+				dep = strdup(deps);
+				dep[len] = '\0';
+			} else {
+				dep = (char *)deps;
+			}
+
+			if (dep[0] == '!') {
+				dep++;
+				positive = false;
+			}
+			if (run_test(cmd, wrapper, find_test(dep)) != positive) {
+				test->answer = false;
+				test->done = true;
+				return test->answer;
+			}
+			if (deps[len])
+				free(dep);
+
+			deps += len;
+			deps += strspn(deps, " ");
+		}
+	}
+
+	outf = fopen(INPUT_FILE, verbose > 1 ? "w+" : "w");
+	if (!outf)
+		c12r_err(EXIT_TROUBLE_RUNNING, "creating %s", INPUT_FILE);
+
+	fprintf(outf, "%s", PRE_BOILERPLATE);
+
+	if (strstr(test->style, "INSIDE_MAIN")) {
+		fprintf(outf, "%s", MAIN_START_BOILERPLATE);
+		fprintf(outf, "%s", test->fragment);
+		fprintf(outf, "%s", MAIN_END_BOILERPLATE);
+	} else if (strstr(test->style, "OUTSIDE_MAIN")) {
+		fprintf(outf, "%s", test->fragment);
+		fprintf(outf, "%s", MAIN_START_BOILERPLATE);
+		fprintf(outf, "%s", MAIN_BODY_BOILERPLATE);
+		fprintf(outf, "%s", MAIN_END_BOILERPLATE);
+	} else if (strstr(test->style, "DEFINES_FUNC")) {
+		fprintf(outf, "%s", test->fragment);
+		fprintf(outf, "%s", MAIN_START_BOILERPLATE);
+		fprintf(outf, "%s", USE_FUNC_BOILERPLATE);
+		fprintf(outf, "%s", MAIN_BODY_BOILERPLATE);
+		fprintf(outf, "%s", MAIN_END_BOILERPLATE);
+	} else if (strstr(test->style, "DEFINES_EVERYTHING")) {
+		fprintf(outf, "%s", test->fragment);
+	} else
+		c12r_errx(EXIT_BAD_TEST, "Unknown style for test %s: %s",
+			  test->name, test->style);
+
+	if (verbose > 1) {
+		fseek(outf, 0, SEEK_SET);
+		fcopy(outf, stdout);
+	}
+
+	fclose(outf);
+
+	newcmd = strdup(cmd);
+
+	if (test->flags) {
+		newcmd = realloc(newcmd, strlen(newcmd) + strlen(" ")
+				+ strlen(test->flags) + 1);
+		strcat(newcmd, " ");
+		strcat(newcmd, test->flags);
+		if (verbose > 1)
+			printf("Extra flags line: %s", newcmd);
+	}
+
+	if (test->link) {
+		newcmd = realloc(newcmd, strlen(newcmd) + strlen(" ")
+				+ strlen(test->link) + 1);
+		strcat(newcmd, " ");
+		strcat(newcmd, test->link);
+		if (verbose > 1)
+			printf("Extra link line: %s", newcmd);
+	}
+
+	start_test("checking for ", test->desc);
+	output = run(newcmd, &status);
+
+	free(newcmd);
+
+	if (status != 0 || strstr(output, "warning")) {
+		if (verbose)
+			printf("Compile %s for %s, status %i: %s\n",
+			       status ? "fail" : "warning",
+			       test->name, status, output);
+		if (strstr(test->style, "EXECUTE")
+		    && !strstr(test->style, "MAY_NOT_COMPILE"))
+			c12r_errx(EXIT_BAD_TEST,
+				  "Test for %s did not compile:\n%s",
+				  test->name, output);
+		test->answer = false;
+		free(output);
+	} else {
+		/* Compile succeeded. */
+		free(output);
+		/* We run INSIDE_MAIN tests for sanity checking. */
+		if (strstr(test->style, "EXECUTE")
+		    || strstr(test->style, "INSIDE_MAIN")) {
+			char *cmd = malloc(strlen(wrapper) + strlen(" ." DIR_SEP OUTPUT_FILE) + 1);
+
+			strcpy(cmd, wrapper);
+			strcat(cmd, " ." DIR_SEP OUTPUT_FILE);
+			output = run(cmd, &status);
+			free(cmd);
+			if (!strstr(test->style, "EXECUTE") && status != 0)
+				c12r_errx(EXIT_BAD_TEST,
+					  "Test for %s failed with %i:\n%s",
+					  test->name, status, output);
+			if (verbose && status)
+				printf("%s exited %i\n", test->name, status);
+			free(output);
+		}
+		test->answer = (status == 0);
+	}
+	test->done = true;
+	end_test(test->answer);
+
+	if (test->answer && test->overrides) {
+		struct test *override = find_test(test->overrides);
+		override->done = true;
+		override->answer = true;
+	}
+	return test->answer;
+}
+
+static char *any_field(char **fieldname)
+{
+	char buf[1000];
+	for (;;) {
+		char *p, *eq;
+
+		if (!fgets(buf, sizeof(buf), stdin))
+			return NULL;
+
+		p = buf;
+		/* Ignore whitespace, lines starting with # */
+		while (*p == ' ' || *p == '\t')
+			p++;
+		if (*p == '#' || *p == '\n')
+			continue;
+
+		eq = strchr(p, '=');
+		if (!eq)
+			c12r_errx(EXIT_BAD_INPUT, "no = in line: %s", p);
+		*eq = '\0';
+		*fieldname = strdup(p);
+		p = eq + 1;
+		if (strlen(p) && p[strlen(p)-1] == '\n')
+			p[strlen(p)-1] = '\0';
+		return strdup(p);
+	}
+}
+
+static char *read_field(const char *name, bool compulsory)
+{
+	char *fieldname, *value;
+
+	value = any_field(&fieldname);
+	if (!value) {
+		if (!compulsory)
+			return NULL;
+		c12r_errx(EXIT_BAD_INPUT, "Could not read field %s", name);
+	}
+	if (strcmp(fieldname, name) != 0)
+		c12r_errx(EXIT_BAD_INPUT,
+			  "Expected field %s not %s", name, fieldname);
+	return value;
+}
+
+/* Test descriptions from stdin:
+ * Lines starting with # or whitespace-only are ignored.
+ *
+ * First three non-ignored lines must be:
+ *  var=<varname>
+ *  desc=<description-for-autotools-style>
+ *  style=OUTSIDE_MAIN DEFINES_FUNC INSIDE_MAIN DEFINES_EVERYTHING EXECUTE MAY_NOT_COMPILE
+ *
+ * Followed by optional lines:
+ *  depends=<space-separated-testnames, ! to invert>
+ *  link=<extra args for link line>
+ *  flags=<extra args for compile line>
+ *  overrides=<testname-to-force>
+ *
+ * Finally a code line, either:
+ *  code=<oneline> OR
+ *  code=
+ *  <lines of code>
+ *  <end-comment>
+ *
+ * And <end-comment> looks like this next comment: */
+/*END*/
+static bool read_test(struct test *test)
+{
+	char *field, *value;
+	char buf[1000];
+
+	memset(test, 0, sizeof(*test));
+	test->name = read_field("var", false);
+	if (!test->name)
+		return false;
+	test->desc = read_field("desc", true);
+	test->style = read_field("style", true);
+	/* Read any optional fields. */
+	while ((value = any_field(&field)) != NULL) {
+		if (strcmp(field, "depends") == 0)
+			test->depends = value;
+		else if (strcmp(field, "link") == 0)
+			test->link = value;
+		else if (strcmp(field, "flags") == 0)
+			test->flags = value;
+		else if (strcmp(field, "overrides") == 0)
+			test->overrides = value;
+		else if (strcmp(field, "code") == 0)
+			break;
+		else
+			c12r_errx(EXIT_BAD_INPUT, "Unknown field %s in %s",
+				  field, test->name);
+	}
+	if (!value)
+		c12r_errx(EXIT_BAD_INPUT, "Missing code in %s", test->name);
+
+	if (strlen(value) == 0) {
+		/* Multiline program, read to END comment */
+		while (fgets(buf, sizeof(buf), stdin) != 0) {
+			size_t n;
+			if (strncmp(buf, "/*END*/", 7) == 0)
+				break;
+			n = strlen(value);
+			value = realloc(value, n + strlen(buf) + 1);
+			strcpy(value + n, buf);
+			n += strlen(buf);
+		}
+	}
+	test->fragment = value;
+	return true;
+}
+
+static void read_tests(size_t num_tests)
+{
+	while (read_test(tests + num_tests)) {
+		num_tests++;
+		tests = realloc(tests, (num_tests + 1) * sizeof(tests[0]));
+		tests[num_tests].name = NULL;
+	}
+}
+
+int main(int argc, const char *argv[])
+{
+	char *cmd;
+	unsigned int i;
+	const char *default_args[]
+		= { "", DEFAULT_COMPILER, DEFAULT_FLAGS, NULL };
+	const char *outflag = DEFAULT_OUTPUT_EXE_FLAG;
+	const char *configurator_cc = NULL;
+	const char *wrapper = "";
+	const char *orig_cc;
+	const char *varfile = NULL;
+	const char *headerfile = NULL;
+	bool extra_tests = false;
+	FILE *outf;
+
+	if (argc > 0)
+		progname = argv[0];
+
+	while (argc > 1) {
+		if (strcmp(argv[1], "--help") == 0) {
+			printf("Usage: configurator [-v] [--var-file=<filename>] [-O<outflag>] [--configurator-cc=<compiler-for-tests>] [--wrapper=<wrapper-for-tests>] [--autotools-style] [--extra-tests] [<compiler> <flags>...]\n"
+			       "  <compiler> <flags> will have \"<outflag> <outfile> <infile.c>\" appended\n"
+			       "Default: %s %s %s\n",
+			       DEFAULT_COMPILER, DEFAULT_FLAGS,
+			       DEFAULT_OUTPUT_EXE_FLAG);
+			exit(0);
+		}
+		if (strncmp(argv[1], "-O", 2) == 0) {
+			argc--;
+			argv++;
+			outflag = argv[1] + 2;
+			if (!*outflag) {
+				fprintf(stderr,
+					"%s: option requires an argument -- O\n",
+					argv[0]);
+				exit(EXIT_BAD_USAGE);
+			}
+		} else if (strcmp(argv[1], "-v") == 0) {
+			argc--;
+			argv++;
+			verbose++;
+		} else if (strcmp(argv[1], "-vv") == 0) {
+			argc--;
+			argv++;
+			verbose += 2;
+		} else if (strncmp(argv[1], "--configurator-cc=", 18) == 0) {
+			configurator_cc = argv[1] + 18;
+			argc--;
+			argv++;
+		} else if (strncmp(argv[1], "--wrapper=", 10) == 0) {
+			wrapper = argv[1] + 10;
+			argc--;
+			argv++;
+		} else if (strncmp(argv[1], "--var-file=", 11) == 0) {
+			varfile = argv[1] + 11;
+			argc--;
+			argv++;
+		} else if (strcmp(argv[1], "--autotools-style") == 0) {
+			like_a_libtool = true;
+			argc--;
+			argv++;
+		} else if (strncmp(argv[1], "--header-file=", 14) == 0) {
+			headerfile = argv[1] + 14;
+			argc--;
+			argv++;
+		} else if (strcmp(argv[1], "--extra-tests") == 0) {
+			extra_tests = true;
+			argc--;
+			argv++;
+		} else if (strcmp(argv[1], "--") == 0) {
+			break;
+		} else if (argv[1][0] == '-') {
+			c12r_errx(EXIT_BAD_USAGE, "Unknown option %s", argv[1]);
+		} else {
+			break;
+		}
+	}
+
+	if (argc == 1)
+		argv = default_args;
+
+	/* Copy with NULL entry at end */
+	tests = calloc(sizeof(base_tests)/sizeof(base_tests[0]) + 1,
+		       sizeof(base_tests[0]));
+	memcpy(tests, base_tests, sizeof(base_tests));
+
+	if (extra_tests)
+		read_tests(sizeof(base_tests)/sizeof(base_tests[0]));
+
+	orig_cc = argv[1];
+	if (configurator_cc)
+		argv[1] = configurator_cc;
+
+	cmd = connect_args(argv, outflag, OUTPUT_FILE " " INPUT_FILE);
+	if (like_a_libtool) {
+		start_test("Making autoconf users comfortable", "");
+		sleep(1);
+		end_test(1);
+	}
+	for (i = 0; tests[i].name; i++)
+		run_test(cmd, wrapper, &tests[i]);
+	free(cmd);
+
+	remove(OUTPUT_FILE);
+	remove(INPUT_FILE);
+
+	if (varfile) {
+		FILE *vars;
+
+		if (strcmp(varfile, "-") == 0)
+			vars = stdout;
+		else {
+			start_test("Writing variables to ", varfile);
+			vars = fopen(varfile, "a");
+			if (!vars)
+				c12r_err(EXIT_TROUBLE_RUNNING,
+					 "Could not open %s", varfile);
+		}
+		for (i = 0; tests[i].name; i++)
+			fprintf(vars, "%s=%u\n", tests[i].name, tests[i].answer);
+		if (vars != stdout) {
+			if (fclose(vars) != 0)
+				c12r_err(EXIT_TROUBLE_RUNNING,
+					 "Closing %s", varfile);
+			end_test(1);
+		}
+	}
+
+	if (headerfile) {
+		start_test("Writing header to ", headerfile);
+		outf = fopen(headerfile, "w");
+		if (!outf)
+			c12r_err(EXIT_TROUBLE_RUNNING,
+				 "Could not open %s", headerfile);
+	} else
+		outf = stdout;
+
+	fprintf(outf, "/* Generated by CCAN configurator */\n"
+	       "#ifndef CCAN_CONFIG_H\n"
+	       "#define CCAN_CONFIG_H\n");
+	fprintf(outf, "#ifndef _GNU_SOURCE\n");
+	fprintf(outf, "#define _GNU_SOURCE /* Always use GNU extensions. */\n");
+	fprintf(outf, "#endif\n");
+	fprintf(outf, "#define CCAN_COMPILER \"%s\"\n", orig_cc);
+	cmd = connect_args(argv + 1, "", "");
+	fprintf(outf, "#define CCAN_CFLAGS \"%s\"\n", cmd);
+	free(cmd);
+	fprintf(outf, "#define CCAN_OUTPUT_EXE_CFLAG \"%s\"\n\n", outflag);
+	/* This one implies "#include <ccan/..." works, eg. for tdb2.h */
+	fprintf(outf, "#define HAVE_CCAN 1\n");
+	for (i = 0; tests[i].name; i++)
+		fprintf(outf, "#define %s %u\n", tests[i].name, tests[i].answer);
+	fprintf(outf, "#endif /* CCAN_CONFIG_H */\n");
+
+	if (headerfile) {
+		if (fclose(outf) != 0)
+			c12r_err(EXIT_TROUBLE_RUNNING, "Closing %s", headerfile);
+		end_test(1);
+	}
+
+	return 0;
+}
diff --git a/cursor.h b/cursor.h
@@ -0,0 +1,320 @@
+
+#ifndef CURSOR_H
+#define CURSOR_H
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#define unlikely(x) __builtin_expect((x),0)
+#define likely(x)   __builtin_expect((x),1)
+
+struct cursor {
+	unsigned char *start;
+	unsigned char *p;
+	unsigned char *end;
+};
+
+struct array {
+	struct cursor cur;
+	unsigned int elem_size;
+};
+
+static inline void reset_cursor(struct cursor *cursor)
+{
+	cursor->p = cursor->start;
+}
+
+static inline void wipe_cursor(struct cursor *cursor)
+{
+	reset_cursor(cursor);
+	memset(cursor->start, 0, cursor->end - cursor->start);
+}
+
+static inline void make_cursor(unsigned char *start, unsigned char *end, struct cursor *cursor)
+{
+	cursor->start = start;
+	cursor->p = start;
+	cursor->end = end;
+}
+
+static inline void make_array(struct array *a, unsigned char* start, unsigned char *end, unsigned int elem_size)
+{
+	make_cursor(start, end, &a->cur);
+	a->elem_size = elem_size;
+}
+
+static inline int cursor_eof(struct cursor *c)
+{
+	return c->p == c->end;
+}
+
+static inline void *cursor_malloc(struct cursor *mem, unsigned long size)
+{
+	void *ret;
+
+	if (mem->p + size > mem->end) {
+		return NULL;
+	}
+
+	ret = mem->p;
+	mem->p += size;
+
+	return ret;
+}
+
+static inline void *cursor_alloc(struct cursor *mem, unsigned long size)
+{
+	void *ret;
+	if (!(ret = cursor_malloc(mem, size))) {
+		return 0;
+	}
+
+	memset(ret, 0, size);
+	return ret;
+}
+
+static inline int cursor_slice(struct cursor *mem, struct cursor *slice, size_t size)
+{
+	unsigned char *p;
+	if (!(p = cursor_alloc(mem, size))) {
+		return 0;
+	}
+	make_cursor(p, mem->p, slice);
+	return 1;
+}
+
+
+static inline void copy_cursor(struct cursor *src, struct cursor *dest)
+{
+	dest->start = src->start;
+	dest->p = src->p;
+	dest->end = src->end;
+}
+
+static inline int pull_byte(struct cursor *cursor, unsigned char *c)
+{
+	if (unlikely(cursor->p + 1 > cursor->end))
+		return 0;
+
+	*c = *cursor->p;
+	cursor->p++;
+
+	return 1;
+}
+
+static inline int cursor_pull_c_str(struct cursor *cursor, const char **str)
+{
+	*str = (const char*)cursor->p;
+
+	for (; cursor->p < cursor->end; cursor->p++) {
+		if (*cursor->p == 0) {
+			cursor->p++;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+static inline int cursor_push_byte(struct cursor *cursor, unsigned char c)
+{
+	if (unlikely(cursor->p + 1 > cursor->end)) {
+		return 0;
+	}
+
+	*cursor->p = c;
+	cursor->p++;
+
+	return 1;
+}
+
+static inline int cursor_pull(struct cursor *cursor, unsigned char *data, int len)
+{
+	if (unlikely(cursor->p + len > cursor->end)) {
+		return 0;
+	}
+
+	memcpy(data, cursor->p, len);
+	cursor->p += len;
+
+	return 1;
+}
+
+static inline int pull_data_into_cursor(struct cursor *cursor,
+			  struct cursor *dest,
+			  unsigned char **data,
+			  int len)
+{
+	int ok;
+
+	if (unlikely(dest->p + len > dest->end)) {
+		printf("not enough room in dest buffer\n");
+		return 0;
+	}
+
+	ok = cursor_pull(cursor, dest->p, len);
+	if (!ok) return 0;
+
+	*data = dest->p;
+	dest->p += len;
+
+	return 1;
+}
+
+static inline int cursor_dropn(struct cursor *cur, int size, int n)
+{
+	if (n == 0)
+		return 1;
+
+	if (unlikely(cur->p - size*n < cur->start)) {
+		return 0;
+	}
+
+	cur->p -= size*n;
+	return 1;
+}
+
+static inline int cursor_drop(struct cursor *cur, int size)
+{
+	return cursor_dropn(cur, size, 1);
+}
+
+static inline unsigned char *cursor_topn(struct cursor *cur, int len, int n)
+{
+	n += 1;
+	if (unlikely(cur->p - len*n < cur->start)) {
+		return NULL;
+	}
+	return cur->p - len*n;
+}
+
+static inline unsigned char *cursor_top(struct cursor *cur, int len)
+{
+	if (unlikely(cur->p - len < cur->start)) {
+		return NULL;
+	}
+	return cur->p - len;
+}
+
+static inline int cursor_top_int(struct cursor *cur, int *i)
+{
+	unsigned char *p;
+	if (unlikely(!(p = cursor_top(cur, sizeof(*i))))) {
+		return 0;
+	}
+	*i = *((int*)p);
+	return 1;
+}
+
+static inline int cursor_pop(struct cursor *cur, unsigned char *data, int len)
+{
+	if (unlikely(cur->p - len < cur->start)) {
+		return 0;
+	}
+
+	cur->p -= len;
+	memcpy(data, cur->p, len);
+
+	return 1;
+}
+
+static inline int cursor_push(struct cursor *cursor, unsigned char *data, int len)
+{
+	if (unlikely(cursor->p + len >= cursor->end)) {
+		return 0;
+	}
+
+	if (cursor->p != data)
+		memcpy(cursor->p, data, len);
+
+	cursor->p += len;
+
+	return 1;
+}
+
+static inline int cursor_push_int(struct cursor *cursor, int i)
+{
+	return cursor_push(cursor, (unsigned char*)&i, sizeof(i));
+}
+
+static inline int cursor_len(struct cursor *cursor)
+{
+	return cursor->p - cursor->start;
+}
+
+static inline size_t cursor_count(struct cursor *cursor, size_t elem_size)
+{
+	return cursor_len(cursor)/elem_size;
+}
+
+static inline int cursor_pull_int(struct cursor *cursor, int *i)
+{
+	return cursor_pull(cursor, (unsigned char*)i, sizeof(*i));
+}
+
+static inline int cursor_push_u16(struct cursor *cursor, unsigned short i)
+{
+	return cursor_push(cursor, (unsigned char*)&i, sizeof(i));
+}
+
+static inline void *index_cursor(struct cursor *cursor, unsigned int index, int elem_size)
+{
+	unsigned char *p;
+	p = &cursor->start[elem_size * index];
+
+	if (unlikely(p >= cursor->end))
+		return NULL;
+
+	return (void*)p;
+}
+
+
+static inline int push_sized_str(struct cursor *cursor, const char *str, int len)
+{
+	return cursor_push(cursor, (unsigned char*)str, len);
+}
+
+static inline int cursor_push_str(struct cursor *cursor, const char *str)
+{
+	return cursor_push(cursor, (unsigned char*)str, strlen(str));
+}
+
+static inline int cursor_push_c_str(struct cursor *cursor, const char *str)
+{
+	return cursor_push_str(cursor, str) && cursor_push_byte(cursor, 0);
+}
+
+static inline int cursor_remaining_capacity(struct cursor *cursor)
+{
+	return cursor->end - cursor->p;
+}
+
+
+#define max(a,b) ((a) > (b) ? (a) : (b))
+static inline void cursor_print_around(struct cursor *cur, int range)
+{
+	unsigned char *c;
+
+	printf("[%ld/%ld]\n", cur->p - cur->start, cur->end - cur->start);
+
+	c = max(cur->p - range, cur->start);
+	for (; c < cur->end && c < (cur->p + range); c++) {
+		printf("%02x", *c);
+	}
+	printf("\n");
+
+	c = max(cur->p - range, cur->start);
+	for (; c < cur->end && c < (cur->p + range); c++) {
+		if (c == cur->p) {
+			printf("^");
+			continue;
+		}
+		printf("  ");
+	}
+	printf("\n");
+}
+#undef max
+
+#endif
diff --git a/endian.h b/endian.h
@@ -0,0 +1,364 @@
+/* CC0 (Public domain) */
+#ifndef CCAN_ENDIAN_H
+#define CCAN_ENDIAN_H
+#include <stdint.h>
+
+#include "config.h"
+#include "cursor.h"
+
+/**
+ * BSWAP_16 - reverse bytes in a constant uint16_t value.
+ * @val: constant value whose bytes to swap.
+ *
+ * Designed to be usable in constant-requiring initializers.
+ *
+ * Example:
+ *	struct mystruct {
+ *		char buf[BSWAP_16(0x1234)];
+ *	};
+ */
+#define BSWAP_16(val)				\
+	((((uint16_t)(val) & 0x00ff) << 8)	\
+	 | (((uint16_t)(val) & 0xff00) >> 8))
+
+/**
+ * BSWAP_32 - reverse bytes in a constant uint32_t value.
+ * @val: constant value whose bytes to swap.
+ *
+ * Designed to be usable in constant-requiring initializers.
+ *
+ * Example:
+ *	struct mystruct {
+ *		char buf[BSWAP_32(0xff000000)];
+ *	};
+ */
+#define BSWAP_32(val)					\
+	((((uint32_t)(val) & 0x000000ff) << 24)		\
+	 | (((uint32_t)(val) & 0x0000ff00) << 8)		\
+	 | (((uint32_t)(val) & 0x00ff0000) >> 8)		\
+	 | (((uint32_t)(val) & 0xff000000) >> 24))
+
+/**
+ * BSWAP_64 - reverse bytes in a constant uint64_t value.
+ * @val: constantvalue whose bytes to swap.
+ *
+ * Designed to be usable in constant-requiring initializers.
+ *
+ * Example:
+ *	struct mystruct {
+ *		char buf[BSWAP_64(0xff00000000000000ULL)];
+ *	};
+ */
+#define BSWAP_64(val)						\
+	((((uint64_t)(val) & 0x00000000000000ffULL) << 56)	\
+	 | (((uint64_t)(val) & 0x000000000000ff00ULL) << 40)	\
+	 | (((uint64_t)(val) & 0x0000000000ff0000ULL) << 24)	\
+	 | (((uint64_t)(val) & 0x00000000ff000000ULL) << 8)	\
+	 | (((uint64_t)(val) & 0x000000ff00000000ULL) >> 8)	\
+	 | (((uint64_t)(val) & 0x0000ff0000000000ULL) >> 24)	\
+	 | (((uint64_t)(val) & 0x00ff000000000000ULL) >> 40)	\
+	 | (((uint64_t)(val) & 0xff00000000000000ULL) >> 56))
+
+#if HAVE_BYTESWAP_H
+#include <byteswap.h>
+#else
+/**
+ * bswap_16 - reverse bytes in a uint16_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ *	// Output contains "1024 is 4 as two bytes reversed"
+ *	printf("1024 is %u as two bytes reversed\n", bswap_16(1024));
+ */
+static inline uint16_t bswap_16(uint16_t val)
+{
+	return BSWAP_16(val);
+}
+
+/**
+ * bswap_32 - reverse bytes in a uint32_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ *	// Output contains "1024 is 262144 as four bytes reversed"
+ *	printf("1024 is %u as four bytes reversed\n", bswap_32(1024));
+ */
+static inline uint32_t bswap_32(uint32_t val)
+{
+	return BSWAP_32(val);
+}
+#endif /* !HAVE_BYTESWAP_H */
+
+#if !HAVE_BSWAP_64
+/**
+ * bswap_64 - reverse bytes in a uint64_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ *	// Output contains "1024 is 1125899906842624 as eight bytes reversed"
+ *	printf("1024 is %llu as eight bytes reversed\n",
+ *		(unsigned long long)bswap_64(1024));
+ */
+static inline uint64_t bswap_64(uint64_t val)
+{
+	return BSWAP_64(val);
+}
+#endif
+
+/* Needed for Glibc like endiness check */
+#define	__LITTLE_ENDIAN	1234
+#define	__BIG_ENDIAN	4321
+
+/* Sanity check the defines.  We don't handle weird endianness. */
+#if !HAVE_LITTLE_ENDIAN && !HAVE_BIG_ENDIAN
+#error "Unknown endian"
+#elif HAVE_LITTLE_ENDIAN && HAVE_BIG_ENDIAN
+#error "Can't compile for both big and little endian."
+#elif HAVE_LITTLE_ENDIAN
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER	__LITTLE_ENDIAN
+#elif __BYTE_ORDER != __LITTLE_ENDIAN
+#error "__BYTE_ORDER already defined, but not equal to __LITTLE_ENDIAN"
+#endif
+#elif HAVE_BIG_ENDIAN
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER	__BIG_ENDIAN
+#elif __BYTE_ORDER != __BIG_ENDIAN
+#error "__BYTE_ORDER already defined, but not equal to __BIG_ENDIAN"
+#endif
+#endif
+
+
+#ifdef __CHECKER__
+/* sparse needs forcing to remove bitwise attribute from ccan/short_types */
+#define ENDIAN_CAST __attribute__((force))
+#define ENDIAN_TYPE __attribute__((bitwise))
+#else
+#define ENDIAN_CAST
+#define ENDIAN_TYPE
+#endif
+
+typedef uint64_t ENDIAN_TYPE leint64_t;
+typedef uint64_t ENDIAN_TYPE beint64_t;
+typedef uint32_t ENDIAN_TYPE leint32_t;
+typedef uint32_t ENDIAN_TYPE beint32_t;
+typedef uint16_t ENDIAN_TYPE leint16_t;
+typedef uint16_t ENDIAN_TYPE beint16_t;
+
+#if HAVE_LITTLE_ENDIAN
+/**
+ * CPU_TO_LE64 - convert a constant uint64_t value to little-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_LE64(native) ((ENDIAN_CAST leint64_t)(native))
+
+/**
+ * CPU_TO_LE32 - convert a constant uint32_t value to little-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_LE32(native) ((ENDIAN_CAST leint32_t)(native))
+
+/**
+ * CPU_TO_LE16 - convert a constant uint16_t value to little-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_LE16(native) ((ENDIAN_CAST leint16_t)(native))
+
+/**
+ * LE64_TO_CPU - convert a little-endian uint64_t constant
+ * @le_val: little-endian constant to convert
+ */
+#define LE64_TO_CPU(le_val) ((ENDIAN_CAST uint64_t)(le_val))
+
+/**
+ * LE32_TO_CPU - convert a little-endian uint32_t constant
+ * @le_val: little-endian constant to convert
+ */
+#define LE32_TO_CPU(le_val) ((ENDIAN_CAST uint32_t)(le_val))
+
+/**
+ * LE16_TO_CPU - convert a little-endian uint16_t constant
+ * @le_val: little-endian constant to convert
+ */
+#define LE16_TO_CPU(le_val) ((ENDIAN_CAST uint16_t)(le_val))
+
+#else /* ... HAVE_BIG_ENDIAN */
+#define CPU_TO_LE64(native) ((ENDIAN_CAST leint64_t)BSWAP_64(native))
+#define CPU_TO_LE32(native) ((ENDIAN_CAST leint32_t)BSWAP_32(native))
+#define CPU_TO_LE16(native) ((ENDIAN_CAST leint16_t)BSWAP_16(native))
+#define LE64_TO_CPU(le_val) BSWAP_64((ENDIAN_CAST uint64_t)le_val)
+#define LE32_TO_CPU(le_val) BSWAP_32((ENDIAN_CAST uint32_t)le_val)
+#define LE16_TO_CPU(le_val) BSWAP_16((ENDIAN_CAST uint16_t)le_val)
+#endif /* HAVE_BIG_ENDIAN */
+
+#if HAVE_BIG_ENDIAN
+/**
+ * CPU_TO_BE64 - convert a constant uint64_t value to big-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_BE64(native) ((ENDIAN_CAST beint64_t)(native))
+
+/**
+ * CPU_TO_BE32 - convert a constant uint32_t value to big-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_BE32(native) ((ENDIAN_CAST beint32_t)(native))
+
+/**
+ * CPU_TO_BE16 - convert a constant uint16_t value to big-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_BE16(native) ((ENDIAN_CAST beint16_t)(native))
+
+/**
+ * BE64_TO_CPU - convert a big-endian uint64_t constant
+ * @le_val: big-endian constant to convert
+ */
+#define BE64_TO_CPU(le_val) ((ENDIAN_CAST uint64_t)(le_val))
+
+/**
+ * BE32_TO_CPU - convert a big-endian uint32_t constant
+ * @le_val: big-endian constant to convert
+ */
+#define BE32_TO_CPU(le_val) ((ENDIAN_CAST uint32_t)(le_val))
+
+/**
+ * BE16_TO_CPU - convert a big-endian uint16_t constant
+ * @le_val: big-endian constant to convert
+ */
+#define BE16_TO_CPU(le_val) ((ENDIAN_CAST uint16_t)(le_val))
+
+#else /* ... HAVE_LITTLE_ENDIAN */
+#define CPU_TO_BE64(native) ((ENDIAN_CAST beint64_t)BSWAP_64(native))
+#define CPU_TO_BE32(native) ((ENDIAN_CAST beint32_t)BSWAP_32(native))
+#define CPU_TO_BE16(native) ((ENDIAN_CAST beint16_t)BSWAP_16(native))
+#define BE64_TO_CPU(le_val) BSWAP_64((ENDIAN_CAST uint64_t)le_val)
+#define BE32_TO_CPU(le_val) BSWAP_32((ENDIAN_CAST uint32_t)le_val)
+#define BE16_TO_CPU(le_val) BSWAP_16((ENDIAN_CAST uint16_t)le_val)
+#endif /* HAVE_LITTE_ENDIAN */
+
+
+/**
+ * cpu_to_le64 - convert a uint64_t value to little-endian
+ * @native: value to convert
+ */
+static inline leint64_t cpu_to_le64(uint64_t native)
+{
+	return CPU_TO_LE64(native);
+}
+
+/**
+ * cpu_to_le32 - convert a uint32_t value to little-endian
+ * @native: value to convert
+ */
+static inline leint32_t cpu_to_le32(uint32_t native)
+{
+	return CPU_TO_LE32(native);
+}
+
+/**
+ * cpu_to_le16 - convert a uint16_t value to little-endian
+ * @native: value to convert
+ */
+static inline leint16_t cpu_to_le16(uint16_t native)
+{
+	return CPU_TO_LE16(native);
+}
+
+/**
+ * le64_to_cpu - convert a little-endian uint64_t value
+ * @le_val: little-endian value to convert
+ */
+static inline uint64_t le64_to_cpu(leint64_t le_val)
+{
+	return LE64_TO_CPU(le_val);
+}
+
+/**
+ * le32_to_cpu - convert a little-endian uint32_t value
+ * @le_val: little-endian value to convert
+ */
+static inline uint32_t le32_to_cpu(leint32_t le_val)
+{
+	return LE32_TO_CPU(le_val);
+}
+
+/**
+ * le16_to_cpu - convert a little-endian uint16_t value
+ * @le_val: little-endian value to convert
+ */
+static inline uint16_t le16_to_cpu(leint16_t le_val)
+{
+	return LE16_TO_CPU(le_val);
+}
+
+/**
+ * cpu_to_be64 - convert a uint64_t value to big endian.
+ * @native: value to convert
+ */
+static inline beint64_t cpu_to_be64(uint64_t native)
+{
+	return CPU_TO_BE64(native);
+}
+
+/**
+ * cpu_to_be32 - convert a uint32_t value to big endian.
+ * @native: value to convert
+ */
+static inline beint32_t cpu_to_be32(uint32_t native)
+{
+	return CPU_TO_BE32(native);
+}
+
+/**
+ * cpu_to_be16 - convert a uint16_t value to big endian.
+ * @native: value to convert
+ */
+static inline beint16_t cpu_to_be16(uint16_t native)
+{
+	return CPU_TO_BE16(native);
+}
+
+/**
+ * be64_to_cpu - convert a big-endian uint64_t value
+ * @be_val: big-endian value to convert
+ */
+static inline uint64_t be64_to_cpu(beint64_t be_val)
+{
+	return BE64_TO_CPU(be_val);
+}
+
+/**
+ * be32_to_cpu - convert a big-endian uint32_t value
+ * @be_val: big-endian value to convert
+ */
+static inline uint32_t be32_to_cpu(beint32_t be_val)
+{
+	return BE32_TO_CPU(be_val);
+}
+
+/**
+ * be16_to_cpu - convert a big-endian uint16_t value
+ * @be_val: big-endian value to convert
+ */
+static inline uint16_t be16_to_cpu(beint16_t be_val)
+{
+	return BE16_TO_CPU(be_val);
+}
+
+/**
+ * be64/be32/be16 - 64/32/16 bit big-endian representation.
+ */
+typedef beint64_t be64;
+typedef beint32_t be32;
+typedef beint16_t be16;
+
+/**
+ * le64/le32/le16 - 64/32/16 bit little-endian representation.
+ */
+typedef leint64_t le64;
+typedef leint32_t le32;
+typedef leint16_t le16;
+
+
+#endif /* CCAN_ENDIAN_H */
diff --git a/hex.h b/hex.h
@@ -0,0 +1,69 @@
+
+static inline int char_to_hex(unsigned char *val, char c)
+{
+	if (c >= '0' && c <= '9') {
+		*val = c - '0';
+		return 1;
+	}
+ 	if (c >= 'a' && c <= 'f') {
+		*val = c - 'a' + 10;
+		return 1;
+	}
+ 	if (c >= 'A' && c <= 'F') {
+		*val = c - 'A' + 10;
+		return 1;
+	}
+	return 0;
+}
+
+static inline int hex_decode(const char *str, size_t slen, void *buf, size_t bufsize)
+{
+	unsigned char v1, v2;
+	unsigned char *p = buf;
+
+	while (slen > 1) {
+		if (!char_to_hex(&v1, str[0]) || !char_to_hex(&v2, str[1]))
+			return 0;
+		if (!bufsize)
+			return 0;
+		*(p++) = (v1 << 4) | v2;
+		str += 2;
+		slen -= 2;
+		bufsize--;
+	}
+	return slen == 0 && bufsize == 0;
+}
+
+static inline size_t hex_str_size(size_t bytes)
+{
+	return 2 * bytes + 1;
+}
+
+static inline char hexchar(unsigned int val)
+{
+	if (val < 10)
+		return '0' + val;
+	if (val < 16)
+		return 'a' + val - 10;
+	abort();
+}
+
+static inline int hex_encode(const void *buf, size_t bufsize, char *dest, size_t destsize)
+{
+	size_t i;
+
+	if (destsize < hex_str_size(bufsize)) {
+		fprintf(stderr, "hexencode: destsize(%zu) < hex_str_size(%zu)\n", destsize, hex_str_size(bufsize));
+		return 0;
+	}
+
+	for (i = 0; i < bufsize; i++) {
+		unsigned int c = ((const unsigned char *)buf)[i];
+		*(dest++) = hexchar(c >> 4);
+		*(dest++) = hexchar(c & 0xF);
+	}
+	*dest = '\0';
+
+	return 1;
+}
+
diff --git a/nostril.c b/nostril.c
@@ -0,0 +1,426 @@
+
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <secp256k1.h>
+#include <secp256k1_schnorrsig.h>
+
+#include "cursor.h"
+#include "hex.h"
+#include "sha256.h"
+#include "random.h"
+
+#define MAX_TAGS 32
+#define MAX_TAG_ELEMS 16
+
+#define HAS_CREATED_AT (1<<1)
+#define HAS_KIND (1<<2)
+#define HAS_ENVELOPE (1<<2)
+
+struct key {
+	secp256k1_keypair pair;
+	unsigned char pubkey[32];
+};
+
+struct args {
+	unsigned int flags;
+	int kind;
+
+	const char *sec;
+	const char *content;
+	
+	uint64_t created_at;
+};
+
+struct nostr_tag {
+	const char *strs[MAX_TAG_ELEMS];
+	int num_elems;
+};
+
+struct nostr_event {
+	unsigned char id[32];
+	unsigned char pubkey[32];
+	unsigned char sig[64];
+
+	const char *content;
+
+	uint64_t created_at;
+	int kind;
+
+	struct nostr_tag tags[MAX_TAGS];
+	int num_tags;
+};
+
+void usage()
+{
+	printf("usage: nostril <content>\n");
+	exit(1);
+}
+
+
+inline static int cursor_push_escaped_char(struct cursor *cur, char c)
+{
+        switch (c) {
+        case '"':  return cursor_push_str(cur, "\\\"");
+        case '\\': return cursor_push_str(cur, "\\\\");
+        case '\b': return cursor_push_str(cur, "\\b");
+        case '\f': return cursor_push_str(cur, "\\f");
+        case '\n': return cursor_push_str(cur, "\\n");
+        case '\r': return cursor_push_str(cur, "\\r");
+        case '\t': return cursor_push_str(cur, "\\t");
+        // TODO: \u hex hex hex hex
+        }
+        return cursor_push_byte(cur, c);
+}
+
+static int cursor_push_jsonstr(struct cursor *cur, const char *str)
+{
+	int i;
+        int len;
+
+	len = strlen(str);
+
+        if (!cursor_push_byte(cur, '"'))
+                return 0;
+
+        for (i = 0; i < len; i++) {
+                if (!cursor_push_escaped_char(cur, str[i]))
+                        return 0;
+        }
+
+        if (!cursor_push_byte(cur, '"'))
+                return 0;
+
+        return 1;
+}
+
+static int cursor_push_tag(struct cursor *cur, struct nostr_tag *tag)
+{
+        int i;
+
+        if (!cursor_push_byte(cur, '['))
+                return 0;
+
+        for (i = 0; i < tag->num_elems; i++) {
+                if (!cursor_push_jsonstr(cur, tag->strs[i]))
+                        return 0;
+                if (i != tag->num_elems-1) {
+                        if (!cursor_push_byte(cur, ','))
+                                return 0;
+                }
+        }
+
+        return cursor_push_byte(cur, ']');
+}
+
+static int cursor_push_tags(struct cursor *cur, struct nostr_event *ev)
+{
+        int i;
+
+        if (!cursor_push_byte(cur, '['))
+                return 0;
+
+        for (i = 0; i < ev->num_tags; i++) {
+                if (!cursor_push_tag(cur, &ev->tags[i]))
+                        return 0;
+                if (i != ev->num_tags-1) {
+                        if (!cursor_push_str(cur, ","))
+                                return 0;
+                }
+        }
+
+        return cursor_push_byte(cur, ']');
+}
+
+
+int event_commitment(struct nostr_event *ev, unsigned char *buf, int buflen)
+{
+	char timebuf[16] = {0};
+	char kindbuf[16] = {0};
+	char pubkey[65];
+	struct cursor cur;
+	int ok;
+
+	ok = hex_encode(ev->pubkey, sizeof(ev->pubkey), pubkey, sizeof(pubkey));
+	assert(ok);
+
+	make_cursor(buf, buf + buflen, &cur);
+
+	snprintf(timebuf, sizeof(timebuf), "%" PRIu64 "", ev->created_at);
+        snprintf(kindbuf, sizeof(kindbuf), "%d", ev->kind);
+
+	ok =
+                cursor_push_str(&cur, "[0,\"") &&
+                cursor_push_str(&cur, pubkey) &&
+                cursor_push_str(&cur, "\",") &&
+                cursor_push_str(&cur, timebuf) &&
+                cursor_push_str(&cur, ",") &&
+                cursor_push_str(&cur, kindbuf) &&
+                cursor_push_str(&cur, ",") &&
+                cursor_push_tags(&cur, ev) &&
+                cursor_push_str(&cur, ",") &&
+                cursor_push_jsonstr(&cur, ev->content) &&
+                cursor_push_str(&cur, "]");
+
+	if (!ok)
+		return 0;
+
+	return cur.p - cur.start;
+}
+
+static int make_sig(secp256k1_context *ctx, struct key *key,
+		unsigned char *id, unsigned char sig[64])
+{
+	unsigned char aux[32];
+
+	if (!fill_random(aux, sizeof(aux))) {
+		return 0;
+	}
+
+	return secp256k1_schnorrsig_sign(ctx, sig, id, &key->pair, aux);
+}
+
+static int create_key(secp256k1_context *ctx, struct key *key, unsigned char seckey[32])
+{
+	secp256k1_xonly_pubkey pubkey;
+
+	/* Try to create a keypair with a valid context, it should only
+	 * fail if the secret key is zero or out of range. */
+	if (!secp256k1_keypair_create(ctx, &key->pair, seckey))
+		return 0;
+
+	if (!secp256k1_keypair_xonly_pub(ctx, &pubkey, NULL, &key->pair))
+		return 0;
+
+	/* Serialize the public key. Should always return 1 for a valid public key. */
+	return secp256k1_xonly_pubkey_serialize(ctx, key->pubkey, &pubkey);
+}
+
+static int decode_key(secp256k1_context *ctx, const char *secstr, struct key *key)
+{
+	unsigned char seckey[32];
+	int ok;
+
+	if (!hex_decode(secstr, strlen(secstr), seckey, 32)) {
+		fprintf(stderr, "could not hex decode secret key\n");
+		return 0;
+	}
+
+	return create_key(ctx, key, seckey);
+}
+
+static int generate_key(secp256k1_context *ctx, struct key *key)
+{
+	unsigned char seckey[32];
+
+	/* If the secret key is zero or out of range (bigger than secp256k1's
+	 * order), we try to sample a new key. Note that the probability of this
+	 * happening is negligible. */
+	if (!fill_random(seckey, sizeof(seckey))) {
+		return 0;
+	}
+
+	return create_key(ctx, key, seckey);
+}
+
+
+static int init_secp_context(secp256k1_context **ctx)
+{
+	unsigned char randomize[32];
+
+	*ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+	if (!fill_random(randomize, sizeof(randomize))) {
+		return 0;
+	}
+
+	/* Randomizing the context is recommended to protect against side-channel
+	 * leakage See `secp256k1_context_randomize` in secp256k1.h for more
+	 * information about it. This should never fail. */
+	return secp256k1_context_randomize(*ctx, randomize);
+}
+
+static int generate_event_id(struct nostr_event *ev)
+{
+	static unsigned char buf[32000];
+
+	int len;
+
+	if (!(len = event_commitment(ev, buf, sizeof(buf)))) {
+		fprintf(stderr, "event_commitment: buffer out of space\n");
+		return 0;
+	}
+
+	fprintf(stderr, "commitment: '%.*s'\n", len, buf);
+	
+	sha256((struct sha256*)ev->id, buf, len);
+
+	return 1;
+}
+
+static int sign_event(secp256k1_context *ctx, struct key *key, struct nostr_event *ev)
+{
+	if (!make_sig(ctx, key, ev->id, ev->sig)) {
+		fprintf(stderr, "Signature generation failed\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static int print_event(struct nostr_event *ev, int envelope)
+{
+	unsigned char buf[32000];
+	char pubkey[65];
+	char id[65];
+	char sig[129];
+	struct cursor cur;
+	int ok;
+
+	ok = hex_encode(ev->id, sizeof(ev->id), id, sizeof(id)) &&
+	hex_encode(ev->pubkey, sizeof(ev->pubkey), pubkey, sizeof(pubkey)) &&
+	hex_encode(ev->sig, sizeof(ev->sig), sig, sizeof(sig));
+
+	assert(ok);
+
+	make_cursor(buf, buf+sizeof(buf), &cur);
+	if (!cursor_push_tags(&cur, ev))
+		return 0;
+
+	if (envelope)
+		printf("[\"EVENT\",");
+
+	printf("{\"id\": \"%s\",", id);
+	printf("\"pubkey\": \"%s\",", pubkey);
+	printf("\"created_at\": %" PRIu64 ",", ev->created_at);
+	printf("\"kind\": %d,", ev->kind);
+	printf("\"tags\": %.*s,", (int)cursor_len(&cur), cur.start);
+
+	reset_cursor(&cur);
+	if (!cursor_push_jsonstr(&cur, ev->content))
+		return 0;
+
+	printf("\"content\": %.*s,", (int)cursor_len(&cur), cur.start);
+	printf("\"sig\": \"%s\"}", sig);
+
+	if (envelope)
+		printf("]");
+
+	printf("\n");
+	
+	return 1;
+}
+
+static void make_event_from_args(struct nostr_event *ev, struct args *args)
+{
+	ev->tags[0].strs[0] = "tag";
+	ev->tags[0].strs[1] = "a";
+	ev->tags[0].num_elems = 2;
+	ev->num_tags = 0;
+
+	ev->created_at = args->flags & HAS_CREATED_AT? args->created_at : time(NULL);
+	ev->content = args->content;
+	ev->kind = 1;
+}
+
+static int parse_num(const char *arg, uint64_t *t)
+{
+	*t = strtol(arg, NULL, 10); 
+	return errno != EINVAL;
+}
+
+static int parse_args(int argc, const char *argv[], struct args *args)
+{
+	const char *arg;
+	uint64_t n;
+
+	argv++; argc--;
+	for (; argc; ) {
+		arg = *argv++; argc--;
+		if (!argc) {
+			args->content = arg;
+			return 1;
+		}
+
+		if (!strcmp(arg, "--sec")) {
+			args->sec = *argv++; argc--;
+		} else if (!strcmp(arg, "--created-at")) {
+			arg = *argv++; argc--;
+			if (!parse_num(arg, &args->created_at)) {
+				fprintf(stderr, "created-at must be a unix timestamp\n");
+				return 0;
+			} else {
+				args->flags |= HAS_CREATED_AT;
+			}
+		} else if (!strcmp(arg, "--kind")) {
+			if (!parse_num(arg, &n)) {
+				fprintf(stderr, "kind should be a number, got '%s'\n", arg);
+				return 0;
+			}
+			args->kind = (int)n;
+			args->flags |= HAS_KIND;
+		} else if (!strcmp(arg, "--envelope")) {
+			args->flags |= HAS_ENVELOPE;
+		} else if (!strncmp(arg, "--", 2)) {
+			fprintf(stderr, "unknown argument: %s\n", arg);
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+int main(int argc, const char *argv[])
+{
+	struct args args = {0};
+	struct nostr_event ev = {0};
+	struct key key;
+        secp256k1_context *ctx;
+	int ok;
+
+	if (argc < 2)
+		usage();
+
+        if (!init_secp_context(&ctx))
+		return 2;
+
+	if (!parse_args(argc, argv, &args))
+		return 10;
+
+	make_event_from_args(&ev, &args);
+
+	if (args.sec) {
+		if (!decode_key(ctx, args.sec, &key)) {
+			return 8;
+		}
+	} else {
+		if (!generate_key(ctx, &key)) {
+			fprintf(stderr, "could not generate key");
+			return 4;
+		}
+	}
+
+	// set the event's pubkey
+	memcpy(ev.pubkey, key.pubkey, 32);
+
+	if (!generate_event_id(&ev)) {
+		fprintf(stderr, "could not generate event id\n");
+		return 5;
+	}
+
+	if (!sign_event(ctx, &key, &ev)) {
+		fprintf(stderr, "could not sign event\n");
+		return 6;
+	}
+
+	if (!print_event(&ev, args.flags & HAS_ENVELOPE)) {
+		fprintf(stderr, "buffer too small\n");
+		return 88;
+	}
+
+	return 0;
+}
+
diff --git a/random.h b/random.h
@@ -0,0 +1,73 @@
+/*************************************************************************
+ * Copyright (c) 2020-2021 Elichai Turkel                                *
+ * Distributed under the CC0 software license, see the accompanying file *
+ * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
+ *************************************************************************/
+
+/*
+ * This file is an attempt at collecting best practice methods for obtaining randomness with different operating systems.
+ * It may be out-of-date. Consult the documentation of the operating system before considering to use the methods below.
+ *
+ * Platform randomness sources:
+ * Linux   -> `getrandom(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. http://man7.org/linux/man-pages/man2/getrandom.2.html, https://linux.die.net/man/4/urandom
+ * macOS   -> `getentropy(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. https://www.unix.com/man-page/mojave/2/getentropy, https://opensource.apple.com/source/xnu/xnu-517.12.7/bsd/man/man4/random.4.auto.html
+ * FreeBSD -> `getrandom(2)`(`sys/random.h`), if not available `kern.arandom` should be used. https://www.freebsd.org/cgi/man.cgi?query=getrandom, https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
+ * OpenBSD -> `getentropy(2)`(`unistd.h`), if not available `/dev/urandom` should be used. https://man.openbsd.org/getentropy, https://man.openbsd.org/urandom
+ * Windows -> `BCryptGenRandom`(`bcrypt.h`). https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
+ */
+
+#if defined(_WIN32)
+#include <windows.h>
+#include <ntstatus.h>
+#include <bcrypt.h>
+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
+#include <sys/random.h>
+#elif defined(__OpenBSD__)
+#include <unistd.h>
+#else
+#error "Couldn't identify the OS"
+#endif
+
+#include <stddef.h>
+#include <limits.h>
+#include <stdio.h>
+
+
+/* Returns 1 on success, and 0 on failure. */
+static int fill_random(unsigned char* data, size_t size) {
+#if defined(_WIN32)
+    NTSTATUS res = BCryptGenRandom(NULL, data, size, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+    if (res != STATUS_SUCCESS || size > ULONG_MAX) {
+        return 0;
+    } else {
+        return 1;
+    }
+#elif defined(__linux__) || defined(__FreeBSD__)
+    /* If `getrandom(2)` is not available you should fallback to /dev/urandom */
+    ssize_t res = getrandom(data, size, 0);
+    if (res < 0 || (size_t)res != size ) {
+        return 0;
+    } else {
+        return 1;
+    }
+#elif defined(__APPLE__) || defined(__OpenBSD__)
+    /* If `getentropy(2)` is not available you should fallback to either
+     * `SecRandomCopyBytes` or /dev/urandom */
+    int res = getentropy(data, size);
+    if (res == 0) {
+        return 1;
+    } else {
+        return 0;
+    }
+#endif
+    return 0;
+}
+
+static void print_hex(unsigned char* data, size_t size) {
+    size_t i;
+    printf("0x");
+    for (i = 0; i < size; i++) {
+        printf("%02x", data[i]);
+    }
+    printf("\n");
+}
diff --git a/sha256.c b/sha256.c
@@ -0,0 +1,302 @@
+/* MIT (BSD) license - see LICENSE file for details */
+/* SHA256 core code translated from the Bitcoin project's C++:
+ *
+ * src/crypto/sha256.cpp commit 417532c8acb93c36c2b6fd052b7c11b6a2906aa2
+ * Copyright (c) 2014 The Bitcoin Core developers
+ * Distributed under the MIT software license, see the accompanying
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.
+ */
+#include "sha256.h"
+#include "endian.h"
+#include "compiler.h"
+#include <stdbool.h>
+#include <assert.h>
+#include <string.h>
+
+static void invalidate_sha256(struct sha256_ctx *ctx)
+{
+#ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL
+	ctx->c.md_len = 0;
+#else
+	ctx->bytes = (size_t)-1;
+#endif
+}
+
+static void check_sha256(struct sha256_ctx *ctx)
+{
+#ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL
+	assert(ctx->c.md_len != 0);
+#else
+	assert(ctx->bytes != (size_t)-1);
+#endif
+}
+
+#ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL
+void sha256_init(struct sha256_ctx *ctx)
+{
+	SHA256_Init(&ctx->c);
+}
+
+void sha256_update(struct sha256_ctx *ctx, const void *p, size_t size)
+{
+	check_sha256(ctx);
+	SHA256_Update(&ctx->c, p, size);
+}
+
+void sha256_done(struct sha256_ctx *ctx, struct sha256 *res)
+{
+	SHA256_Final(res->u.u8, &ctx->c);
+	invalidate_sha256(ctx);
+}
+#else
+static uint32_t Ch(uint32_t x, uint32_t y, uint32_t z)
+{
+	return z ^ (x & (y ^ z));
+}
+static uint32_t Maj(uint32_t x, uint32_t y, uint32_t z)
+{
+	return (x & y) | (z & (x | y));
+}
+static uint32_t Sigma0(uint32_t x)
+{
+	return (x >> 2 | x << 30) ^ (x >> 13 | x << 19) ^ (x >> 22 | x << 10);
+}
+static uint32_t Sigma1(uint32_t x)
+{
+	return (x >> 6 | x << 26) ^ (x >> 11 | x << 21) ^ (x >> 25 | x << 7);
+}
+static uint32_t sigma0(uint32_t x)
+{
+	return (x >> 7 | x << 25) ^ (x >> 18 | x << 14) ^ (x >> 3);
+}
+static uint32_t sigma1(uint32_t x)
+{
+	return (x >> 17 | x << 15) ^ (x >> 19 | x << 13) ^ (x >> 10);
+}
+
+/** One round of SHA-256. */
+static void Round(uint32_t a, uint32_t b, uint32_t c, uint32_t *d, uint32_t e, uint32_t f, uint32_t g, uint32_t *h, uint32_t k, uint32_t w)
+{
+	uint32_t t1 = *h + Sigma1(e) + Ch(e, f, g) + k + w;
+	uint32_t t2 = Sigma0(a) + Maj(a, b, c);
+	*d += t1;
+	*h = t1 + t2;
+}
+
+/** Perform one SHA-256 transformation, processing a 64-byte chunk. */
+static void Transform(uint32_t *s, const uint32_t *chunk)
+{
+	uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
+	uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
+
+	Round(a, b, c, &d, e, f, g, &h, 0x428a2f98, w0 = be32_to_cpu(chunk[0]));
+	Round(h, a, b, &c, d, e, f, &g, 0x71374491, w1 = be32_to_cpu(chunk[1]));
+	Round(g, h, a, &b, c, d, e, &f, 0xb5c0fbcf, w2 = be32_to_cpu(chunk[2]));
+	Round(f, g, h, &a, b, c, d, &e, 0xe9b5dba5, w3 = be32_to_cpu(chunk[3]));
+	Round(e, f, g, &h, a, b, c, &d, 0x3956c25b, w4 = be32_to_cpu(chunk[4]));
+	Round(d, e, f, &g, h, a, b, &c, 0x59f111f1, w5 = be32_to_cpu(chunk[5]));
+	Round(c, d, e, &f, g, h, a, &b, 0x923f82a4, w6 = be32_to_cpu(chunk[6]));
+	Round(b, c, d, &e, f, g, h, &a, 0xab1c5ed5, w7 = be32_to_cpu(chunk[7]));
+	Round(a, b, c, &d, e, f, g, &h, 0xd807aa98, w8 = be32_to_cpu(chunk[8]));
+	Round(h, a, b, &c, d, e, f, &g, 0x12835b01, w9 = be32_to_cpu(chunk[9]));
+	Round(g, h, a, &b, c, d, e, &f, 0x243185be, w10 = be32_to_cpu(chunk[10]));
+	Round(f, g, h, &a, b, c, d, &e, 0x550c7dc3, w11 = be32_to_cpu(chunk[11]));
+	Round(e, f, g, &h, a, b, c, &d, 0x72be5d74, w12 = be32_to_cpu(chunk[12]));
+	Round(d, e, f, &g, h, a, b, &c, 0x80deb1fe, w13 = be32_to_cpu(chunk[13]));
+	Round(c, d, e, &f, g, h, a, &b, 0x9bdc06a7, w14 = be32_to_cpu(chunk[14]));
+	Round(b, c, d, &e, f, g, h, &a, 0xc19bf174, w15 = be32_to_cpu(chunk[15]));
+
+	Round(a, b, c, &d, e, f, g, &h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1));
+	Round(h, a, b, &c, d, e, f, &g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2));
+	Round(g, h, a, &b, c, d, e, &f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3));
+	Round(f, g, h, &a, b, c, d, &e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4));
+	Round(e, f, g, &h, a, b, c, &d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5));
+	Round(d, e, f, &g, h, a, b, &c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6));
+	Round(c, d, e, &f, g, h, a, &b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7));
+	Round(b, c, d, &e, f, g, h, &a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8));
+	Round(a, b, c, &d, e, f, g, &h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9));
+	Round(h, a, b, &c, d, e, f, &g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10));
+	Round(g, h, a, &b, c, d, e, &f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11));
+	Round(f, g, h, &a, b, c, d, &e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12));
+	Round(e, f, g, &h, a, b, c, &d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13));
+	Round(d, e, f, &g, h, a, b, &c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14));
+	Round(c, d, e, &f, g, h, a, &b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15));
+	Round(b, c, d, &e, f, g, h, &a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0));
+
+	Round(a, b, c, &d, e, f, g, &h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1));
+	Round(h, a, b, &c, d, e, f, &g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2));
+	Round(g, h, a, &b, c, d, e, &f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3));
+	Round(f, g, h, &a, b, c, d, &e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4));
+	Round(e, f, g, &h, a, b, c, &d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5));
+	Round(d, e, f, &g, h, a, b, &c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6));
+	Round(c, d, e, &f, g, h, a, &b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7));
+	Round(b, c, d, &e, f, g, h, &a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8));
+	Round(a, b, c, &d, e, f, g, &h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9));
+	Round(h, a, b, &c, d, e, f, &g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10));
+	Round(g, h, a, &b, c, d, e, &f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11));
+	Round(f, g, h, &a, b, c, d, &e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12));
+	Round(e, f, g, &h, a, b, c, &d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13));
+	Round(d, e, f, &g, h, a, b, &c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14));
+	Round(c, d, e, &f, g, h, a, &b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15));
+	Round(b, c, d, &e, f, g, h, &a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0));
+
+	Round(a, b, c, &d, e, f, g, &h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1));
+	Round(h, a, b, &c, d, e, f, &g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2));
+	Round(g, h, a, &b, c, d, e, &f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3));
+	Round(f, g, h, &a, b, c, d, &e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4));
+	Round(e, f, g, &h, a, b, c, &d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5));
+	Round(d, e, f, &g, h, a, b, &c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6));
+	Round(c, d, e, &f, g, h, a, &b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7));
+	Round(b, c, d, &e, f, g, h, &a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8));
+	Round(a, b, c, &d, e, f, g, &h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9));
+	Round(h, a, b, &c, d, e, f, &g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10));
+	Round(g, h, a, &b, c, d, e, &f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11));
+	Round(f, g, h, &a, b, c, d, &e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12));
+	Round(e, f, g, &h, a, b, c, &d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13));
+	Round(d, e, f, &g, h, a, b, &c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14));
+	Round(c, d, e, &f, g, h, a, &b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15));
+	Round(b, c, d, &e, f, g, h, &a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0));
+
+	s[0] += a;
+	s[1] += b;
+	s[2] += c;
+	s[3] += d;
+	s[4] += e;
+	s[5] += f;
+	s[6] += g;
+	s[7] += h;
+}
+
+
+static void add(struct sha256_ctx *ctx, const void *p, size_t len)
+{
+	const unsigned char *data = p;
+	size_t bufsize = ctx->bytes % 64;
+
+	if (bufsize + len >= 64) {
+		/* Fill the buffer, and process it. */
+		memcpy(ctx->buf.u8 + bufsize, data, 64 - bufsize);
+		ctx->bytes += 64 - bufsize;
+		data += 64 - bufsize;
+		len -= 64 - bufsize;
+		Transform(ctx->s, ctx->buf.u32);
+		bufsize = 0;
+	}
+
+	while (len >= 64) {
+		/* Process full chunks directly from the source. */
+		if (alignment_ok(data, sizeof(uint32_t)))
+			Transform(ctx->s, (const uint32_t *)data);
+		else {
+			memcpy(ctx->buf.u8, data, sizeof(ctx->buf));
+			Transform(ctx->s, ctx->buf.u32);
+		}
+		ctx->bytes += 64;
+		data += 64;
+		len -= 64;
+	}
+
+	if (len) {
+		/* Fill the buffer with what remains. */
+		memcpy(ctx->buf.u8 + bufsize, data, len);
+		ctx->bytes += len;
+	}
+}
+
+void sha256_init(struct sha256_ctx *ctx)
+{
+	struct sha256_ctx init = SHA256_INIT;
+	*ctx = init;
+}
+
+void sha256_update(struct sha256_ctx *ctx, const void *p, size_t size)
+{
+	check_sha256(ctx);
+	add(ctx, p, size);
+}
+
+void sha256_done(struct sha256_ctx *ctx, struct sha256 *res)
+{
+	static const unsigned char pad[64] = {0x80};
+	uint64_t sizedesc;
+	size_t i;
+
+	sizedesc = cpu_to_be64((uint64_t)ctx->bytes << 3);
+	/* Add '1' bit to terminate, then all 0 bits, up to next block - 8. */
+	add(ctx, pad, 1 + ((128 - 8 - (ctx->bytes % 64) - 1) % 64));
+	/* Add number of bits of data (big endian) */
+	add(ctx, &sizedesc, 8);
+	for (i = 0; i < sizeof(ctx->s) / sizeof(ctx->s[0]); i++)
+		res->u.u32[i] = cpu_to_be32(ctx->s[i]);
+	invalidate_sha256(ctx);
+}
+#endif
+
+void sha256(struct sha256 *sha, const void *p, size_t size)
+{
+	struct sha256_ctx ctx;
+
+	sha256_init(&ctx);
+	sha256_update(&ctx, p, size);
+	sha256_done(&ctx, sha);
+}
+
+void sha256_u8(struct sha256_ctx *ctx, uint8_t v)
+{
+	sha256_update(ctx, &v, sizeof(v));
+}
+
+void sha256_u16(struct sha256_ctx *ctx, uint16_t v)
+{
+	sha256_update(ctx, &v, sizeof(v));
+}
+
+void sha256_u32(struct sha256_ctx *ctx, uint32_t v)
+{
+	sha256_update(ctx, &v, sizeof(v));
+}
+
+void sha256_u64(struct sha256_ctx *ctx, uint64_t v)
+{
+	sha256_update(ctx, &v, sizeof(v));
+}
+
+/* Add as little-endian */
+void sha256_le16(struct sha256_ctx *ctx, uint16_t v)
+{
+	leint16_t lev = cpu_to_le16(v);
+	sha256_update(ctx, &lev, sizeof(lev));
+}
+
+void sha256_le32(struct sha256_ctx *ctx, uint32_t v)
+{
+	leint32_t lev = cpu_to_le32(v);
+	sha256_update(ctx, &lev, sizeof(lev));
+}
+
+void sha256_le64(struct sha256_ctx *ctx, uint64_t v)
+{
+	leint64_t lev = cpu_to_le64(v);
+	sha256_update(ctx, &lev, sizeof(lev));
+}
+
+/* Add as big-endian */
+void sha256_be16(struct sha256_ctx *ctx, uint16_t v)
+{
+	beint16_t bev = cpu_to_be16(v);
+	sha256_update(ctx, &bev, sizeof(bev));
+}
+
+void sha256_be32(struct sha256_ctx *ctx, uint32_t v)
+{
+	beint32_t bev = cpu_to_be32(v);
+	sha256_update(ctx, &bev, sizeof(bev));
+}
+
+void sha256_be64(struct sha256_ctx *ctx, uint64_t v)
+{
+	beint64_t bev = cpu_to_be64(v);
+	sha256_update(ctx, &bev, sizeof(bev));
+}
+
+
diff --git a/sha256.h b/sha256.h
@@ -0,0 +1,155 @@
+
+#ifndef CCAN_CRYPTO_SHA256_H
+#define CCAN_CRYPTO_SHA256_H
+
+
+/** Output length for `wally_sha256` */
+#define SHA256_LEN 32
+
+
+/* BSD-MIT - see LICENSE file for details */
+/* #include "config.h" */
+#include <stdint.h>
+#include <stdlib.h>
+
+/* Uncomment this to use openssl's SHA256 routines (and link with -lcrypto) */
+/*#define CCAN_CRYPTO_SHA256_USE_OPENSSL 1*/
+
+#ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL
+#include <openssl/sha.h>
+#endif
+
+/**
+ * struct sha256 - structure representing a completed SHA256.
+ * @u.u8: an unsigned char array.
+ * @u.u32: a 32-bit integer array.
+ *
+ * Other fields may be added to the union in future.
+ */
+struct sha256 {
+	union {
+		uint32_t u32[8];
+		unsigned char u8[32];
+	} u;
+};
+
+/**
+ * sha256 - return sha256 of an object.
+ * @sha256: the sha256 to fill in
+ * @p: pointer to memory,
+ * @size: the number of bytes pointed to by @p
+ *
+ * The bytes pointed to by @p is SHA256 hashed into @sha256.  This is
+ * equivalent to sha256_init(), sha256_update() then sha256_done().
+ */
+void sha256(struct sha256 *sha, const void *p, size_t size);
+
+/**
+ * struct sha256_ctx - structure to store running context for sha256
+ */
+struct sha256_ctx {
+#ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL
+	SHA256_CTX c;
+#else
+	uint32_t s[8];
+	union {
+		uint32_t u32[16];
+		unsigned char u8[64];
+	} buf;
+	size_t bytes;
+#endif
+};
+
+/**
+ * sha256_init - initialize an SHA256 context.
+ * @ctx: the sha256_ctx to initialize
+ *
+ * This must be called before sha256_update or sha256_done, or
+ * alternately you can assign SHA256_INIT.
+ *
+ * If it was already initialized, this forgets anything which was
+ * hashed before.
+ *
+ * Example:
+ * static void hash_all(const char **arr, struct sha256 *hash)
+ * {
+ *	size_t i;
+ *	struct sha256_ctx ctx;
+ *
+ *	sha256_init(&ctx);
+ *	for (i = 0; arr[i]; i++)
+ *		sha256_update(&ctx, arr[i], strlen(arr[i]));
+ *	sha256_done(&ctx, hash);
+ * }
+ */
+void sha256_init(struct sha256_ctx *ctx);
+
+/**
+ * SHA256_INIT - initializer for an SHA256 context.
+ *
+ * This can be used to statically initialize an SHA256 context (instead
+ * of sha256_init()).
+ *
+ * Example:
+ * static void hash_all(const char **arr, struct sha256 *hash)
+ * {
+ *	size_t i;
+ *	struct sha256_ctx ctx = SHA256_INIT;
+ *
+ *	for (i = 0; arr[i]; i++)
+ *		sha256_update(&ctx, arr[i], strlen(arr[i]));
+ *	sha256_done(&ctx, hash);
+ * }
+ */
+#ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL
+#define SHA256_INIT							\
+	{ { { 0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul,	\
+	      0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul }, \
+		0x0, 0x0,						\
+		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	\
+			0x0, 0x20 } }
+#else
+#define SHA256_INIT							\
+	{ { 0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul,	\
+	    0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul },	\
+	  { { 0 } }, 0 }
+#endif
+
+/**
+ * sha256_update - include some memory in the hash.
+ * @ctx: the sha256_ctx to use
+ * @p: pointer to memory,
+ * @size: the number of bytes pointed to by @p
+ *
+ * You can call this multiple times to hash more data, before calling
+ * sha256_done().
+ */
+void sha256_update(struct sha256_ctx *ctx, const void *p, size_t size);
+
+/**
+ * sha256_done - finish SHA256 and return the hash
+ * @ctx: the sha256_ctx to complete
+ * @res: the hash to return.
+ *
+ * Note that @ctx is *destroyed* by this, and must be reinitialized.
+ * To avoid that, pass a copy instead.
+ */
+void sha256_done(struct sha256_ctx *sha256, struct sha256 *res);
+
+/* Add various types to an SHA256 hash */
+void sha256_u8(struct sha256_ctx *ctx, uint8_t v);
+void sha256_u16(struct sha256_ctx *ctx, uint16_t v);
+void sha256_u32(struct sha256_ctx *ctx, uint32_t v);
+void sha256_u64(struct sha256_ctx *ctx, uint64_t v);
+
+/* Add as little-endian */
+void sha256_le16(struct sha256_ctx *ctx, uint16_t v);
+void sha256_le32(struct sha256_ctx *ctx, uint32_t v);
+void sha256_le64(struct sha256_ctx *ctx, uint64_t v);
+
+/* Add as big-endian */
+void sha256_be16(struct sha256_ctx *ctx, uint16_t v);
+void sha256_be32(struct sha256_ctx *ctx, uint32_t v);
+void sha256_be64(struct sha256_ctx *ctx, uint64_t v);
+
+#endif /* CCAN_CRYPTO_SHA256_H */
diff --git a/shell.nix b/shell.nix
@@ -0,0 +1,5 @@
+{ pkgs ? import <nixpkgs> {} }:
+with pkgs;
+mkShell {
+  buildInputs = [ secp256k1 ];
+}