mirror of
https://github.com/jb55/nostril.git
synced 2024-12-24 11:15:51 -05:00
initial commit
Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
commit
009af9ed5b
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
*.o
|
||||
nostril
|
||||
configurator.out*
|
||||
configurator
|
||||
.build-result
|
||||
.buildcmd
|
||||
config.h
|
||||
tags
|
22
Makefile
Normal file
22
Makefile
Normal 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
85
compiler.h
Normal 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
1110
configurator.c
Normal file
File diff suppressed because it is too large
Load Diff
320
cursor.h
Normal file
320
cursor.h
Normal 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
364
endian.h
Normal 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
69
hex.h
Normal 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
426
nostril.c
Normal 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
73
random.h
Normal 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
302
sha256.c
Normal 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
155
sha256.h
Normal 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 */
|
Loading…
Reference in New Issue
Block a user