initial commit

Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
William Casarin 2022-04-14 07:52:29 -07:00
commit 009af9ed5b
13 changed files with 2940 additions and 0 deletions

1
.envrc Normal file
View File

@ -0,0 +1 @@
use nix

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
*.o
nostril
configurator.out*
configurator
.build-result
.buildcmd
config.h
tags

22
Makefile Normal file
View File

@ -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

85
compiler.h Normal file
View File

@ -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 */

1110
configurator.c Normal file

File diff suppressed because it is too large Load Diff

320
cursor.h Normal file
View File

@ -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

364
endian.h Normal file
View File

@ -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 */

69
hex.h Normal file
View File

@ -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;
}

426
nostril.c Normal file
View File

@ -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;
}

73
random.h Normal file
View File

@ -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");
}

302
sha256.c Normal file
View File

@ -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));
}

155
sha256.h Normal file
View File

@ -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 */

5
shell.nix Normal file
View File

@ -0,0 +1,5 @@
{ pkgs ? import <nixpkgs> {} }:
with pkgs;
mkShell {
buildInputs = [ secp256k1 ];
}