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 ];
+}