Skip to content

Commit cee688d

Browse files
committed
add ndb_sign_id and ndb_calculate_id
also do this on finalization optionally
1 parent 4e75ac7 commit cee688d

File tree

9 files changed

+242
-43
lines changed

9 files changed

+242
-43
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ test_contacts_ndb_note
99
bench
1010
configurator
1111
config.h
12+
libsecp256k1.a
13+
.direnv/

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "deps/secp256k1"]
2+
path = deps/secp256k1
3+
url = https://github.com/bitcoin-core/secp256k1

Makefile

+28-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
CFLAGS = -Wall -Wno-unused-function -Werror -O2 -g
2-
HEADERS = sha256.h nostrdb.h cursor.h hex.h jsmn.h config.h sha256.h
2+
HEADERS = sha256.h nostrdb.h cursor.h hex.h jsmn.h config.h sha256.h random.h
33
SRCS = nostrdb.c sha256.c
4-
DEPS = $(SRCS) $(HEADERS)
4+
LDS = $(SRCS) $(ARS)
5+
ARS = libsecp256k1.a
6+
DEPS = $(SRCS) $(HEADERS) $(ARS)
7+
PREFIX ?= /usr/local
8+
SUBMODULES = deps/secp256k1
59

610
check: test
711
./test
@@ -21,11 +25,31 @@ configurator: configurator.c
2125
config.h: configurator
2226
./configurator > $@
2327

28+
deps/secp256k1/.git:
29+
@devtools/refresh-submodules.sh $(SUBMODULES)
30+
31+
deps/secp256k1/include/secp256k1.h: deps/secp256k1/.git
32+
33+
deps/secp256k1/configure: deps/secp256k1/.git
34+
cd deps/secp256k1; \
35+
./autogen.sh
36+
37+
deps/secp256k1/.libs/libsecp256k1.a: deps/secp256k1/config.log
38+
cd deps/secp256k1; \
39+
make -j libsecp256k1.la
40+
41+
deps/secp256k1/config.log: deps/secp256k1/configure
42+
cd deps/secp256k1; \
43+
./configure --disable-shared --enable-module-ecdh --enable-module-schnorrsig --enable-module-extrakeys
44+
45+
libsecp256k1.a: deps/secp256k1/.libs/libsecp256k1.a
46+
cp $< $@
47+
2448
bench: bench.c $(DEPS)
25-
$(CC) $(CFLAGS) bench.c $(SRCS) -o $@
49+
$(CC) $(CFLAGS) bench.c $(LDS) -o $@
2650

2751
test: test.c $(DEPS)
28-
$(CC) $(CFLAGS) test.c $(SRCS) -o $@
52+
$(CC) $(CFLAGS) test.c $(LDS) -o $@
2953

3054
%.o: %.c
3155
$(CC) $(CFLAGS)

deps/secp256k1

Submodule secp256k1 added at 2bd5f3e

devtools/refresh-submodules.sh

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#! /bin/sh
2+
3+
if [ $# = 0 ]; then
4+
echo "Usage: $0 <submoduledir1>..." >&2
5+
exit 1
6+
fi
7+
8+
# If no git dir (or, if we're a submodule, git file), forget it.
9+
[ -e .git ] || exit 0
10+
11+
# git submodule can't run in parallel. Really.
12+
# Wait for it to finish if in parallel.
13+
if ! mkdir .refresh-submodules 2>/dev/null ; then
14+
# If we don't make progress in ~60 seconds, force delete and retry.
15+
LIMIT=$((50 + $$ % 20))
16+
i=0
17+
while [ $i -lt $LIMIT ]; do
18+
[ -d .refresh-submodules ] || exit 0
19+
sleep 1
20+
i=$((i + 1))
21+
done
22+
rmdir .refresh-submodules
23+
exec "$0" "$@" || exit 1
24+
fi
25+
26+
trap "rmdir .refresh-submodules" EXIT
27+
28+
# Be a little careful here, since we do rm -rf!
29+
for m in "$@"; do
30+
if ! grep -q "path = $m\$" .gitmodules; then
31+
echo "$m is not a submodule!" >&2
32+
exit 1
33+
fi
34+
done
35+
36+
# git submodule can segfault. Really.
37+
if [ "$(git submodule status "$@" | grep -c '^ ')" != $# ]; then
38+
echo Reinitializing submodules "$@" ...
39+
git submodule sync "$@"
40+
rm -rf "$@"
41+
git submodule update --init --recursive "$@"
42+
fi

nostrdb.c

+67-14
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "jsmn.h"
44
#include "hex.h"
55
#include "cursor.h"
6+
#include "random.h"
67
#include "sha256.h"
78
#include <stdlib.h>
89
#include <limits.h>
@@ -25,7 +26,6 @@ int ndb_builder_init(struct ndb_builder *builder, unsigned char *buf,
2526
int bufsize)
2627
{
2728
struct ndb_note *note;
28-
struct cursor mem;
2929
int half, size, str_indices_size;
3030

3131
// come on bruh
@@ -39,14 +39,14 @@ int ndb_builder_init(struct ndb_builder *builder, unsigned char *buf,
3939
//debug("size %d half %d str_indices %d\n", size, half, str_indices_size);
4040

4141
// make a safe cursor of our available memory
42-
make_cursor(buf, buf + bufsize, &mem);
42+
make_cursor(buf, buf + bufsize, &builder->mem);
4343

4444
note = builder->note = (struct ndb_note *)buf;
4545

4646
// take slices of the memory into subcursors
47-
if (!(cursor_slice(&mem, &builder->note_cur, half) &&
48-
cursor_slice(&mem, &builder->strings, half) &&
49-
cursor_slice(&mem, &builder->str_indices, str_indices_size))) {
47+
if (!(cursor_slice(&builder->mem, &builder->note_cur, half) &&
48+
cursor_slice(&builder->mem, &builder->strings, half) &&
49+
cursor_slice(&builder->mem, &builder->str_indices, str_indices_size))) {
5050
return 0;
5151
}
5252

@@ -265,7 +265,7 @@ static int ndb_event_commitment(struct ndb_note *ev, unsigned char *buf, int buf
265265
return cur.p - cur.start;
266266
}
267267

268-
int ndb_calculate_note_id(struct ndb_note *note, unsigned char *buf, int buflen) {
268+
int ndb_calculate_id(struct ndb_note *note, unsigned char *buf, int buflen) {
269269
int len;
270270

271271
if (!(len = ndb_event_commitment(note, buf, buflen)))
@@ -278,12 +278,50 @@ int ndb_calculate_note_id(struct ndb_note *note, unsigned char *buf, int buflen)
278278
return 1;
279279
}
280280

281+
int ndb_sign_id(secp256k1_context *ctx, struct ndb_keypair *keypair,
282+
unsigned char id[32], unsigned char sig[64])
283+
{
284+
unsigned char aux[32];
285+
286+
if (!fill_random(aux, sizeof(aux)))
287+
return 0;
288+
289+
return secp256k1_schnorrsig_sign32(ctx, sig, id, &keypair->pair, aux);
290+
}
291+
292+
int ndb_create_keypair(secp256k1_context *ctx, struct ndb_keypair *key)
293+
{
294+
secp256k1_xonly_pubkey pubkey;
295+
296+
/* Try to create a keypair with a valid context, it should only
297+
* fail if the secret key is zero or out of range. */
298+
if (!secp256k1_keypair_create(ctx, &key->pair, key->secret))
299+
return 0;
300+
301+
if (!secp256k1_keypair_xonly_pub(ctx, &pubkey, NULL, &key->pair))
302+
return 0;
303+
304+
/* Serialize the public key. Should always return 1 for a valid public key. */
305+
return secp256k1_xonly_pubkey_serialize(ctx, key->pubkey, &pubkey);
306+
}
281307

282-
int ndb_builder_finalize(struct ndb_builder *builder, struct ndb_note **note)
308+
int ndb_decode_key(secp256k1_context *ctx, const char *secstr,
309+
struct ndb_keypair *keypair)
310+
{
311+
if (!hex_decode(secstr, strlen(secstr), keypair->secret, 32)) {
312+
fprintf(stderr, "could not hex decode secret key\n");
313+
return 0;
314+
}
315+
316+
return ndb_create_keypair(ctx, keypair);
317+
}
318+
319+
int ndb_builder_finalize(struct ndb_builder *builder, struct ndb_note **note,
320+
struct ndb_keypair *keypair)
283321
{
284322
int strings_len = builder->strings.p - builder->strings.start;
285-
unsigned char *end = builder->note_cur.p + strings_len;
286-
int total_size = end - builder->note_cur.start;
323+
unsigned char *note_end = builder->note_cur.p + strings_len;
324+
int total_size = note_end - builder->note_cur.start;
287325

288326
// move the strings buffer next to the end of our ndb_note
289327
memmove(builder->note_cur.p, builder->strings.start, strings_len);
@@ -296,6 +334,22 @@ int ndb_builder_finalize(struct ndb_builder *builder, struct ndb_note **note)
296334

297335
*note = builder->note;
298336

337+
// generate id and sign if we're building this manually
338+
if (keypair) {
339+
// use the remaining memory for building our id buffer
340+
unsigned char *end = builder->mem.end;
341+
unsigned char *start = (unsigned char*)(*note) + total_size;
342+
343+
if (!ndb_calculate_id(*note, start, end - start))
344+
return 0;
345+
346+
secp256k1_context *ctx =
347+
secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
348+
349+
if (!ndb_sign_id(ctx, keypair, (*note)->id, (*note)->sig))
350+
return 0;
351+
}
352+
299353
return total_size;
300354
}
301355

@@ -626,7 +680,7 @@ int ndb_note_from_json(const char *json, int len, struct ndb_note **note,
626680
// sig
627681
tok = &parser.toks[i+1];
628682
hex_decode(json + tok->start, toksize(tok), hexbuf, sizeof(hexbuf));
629-
ndb_builder_set_signature(&parser.builder, hexbuf);
683+
ndb_builder_set_sig(&parser.builder, hexbuf);
630684
} else if (start[0] == 'k' && jsoneq(json, tok, tok_len, "kind")) {
631685
// kind
632686
tok = &parser.toks[i+1];
@@ -668,7 +722,7 @@ int ndb_note_from_json(const char *json, int len, struct ndb_note **note,
668722
}
669723
}
670724

671-
return ndb_builder_finalize(&parser.builder, note);
725+
return ndb_builder_finalize(&parser.builder, note, NULL);
672726
}
673727

674728
void ndb_builder_set_pubkey(struct ndb_builder *builder, unsigned char *pubkey)
@@ -681,10 +735,9 @@ void ndb_builder_set_id(struct ndb_builder *builder, unsigned char *id)
681735
memcpy(builder->note->id, id, 32);
682736
}
683737

684-
void ndb_builder_set_signature(struct ndb_builder *builder,
685-
unsigned char *signature)
738+
void ndb_builder_set_sig(struct ndb_builder *builder, unsigned char *sig)
686739
{
687-
memcpy(builder->note->signature, signature, 64);
740+
memcpy(builder->note->sig, sig, 64);
688741
}
689742

690743
void ndb_builder_set_kind(struct ndb_builder *builder, uint32_t kind)

nostrdb.h

+22-20
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
#include <inttypes.h>
55
#include "cursor.h"
66

7+
#include "secp256k1.h"
8+
#include "secp256k1_ecdh.h"
9+
#include "secp256k1_schnorrsig.h"
10+
711
struct ndb_str {
812
unsigned char flag;
913
union {
@@ -12,6 +16,13 @@ struct ndb_str {
1216
};
1317
};
1418

19+
struct ndb_keypair {
20+
unsigned char pubkey[32];
21+
unsigned char secret[32];
22+
secp256k1_keypair pair;
23+
};
24+
25+
1526
// these must be byte-aligned, they are directly accessing the serialized data
1627
// representation
1728
#pragma pack(push, 1)
@@ -47,7 +58,7 @@ struct ndb_note {
4758
unsigned char padding[3]; // keep things aligned
4859
unsigned char id[32];
4960
unsigned char pubkey[32];
50-
unsigned char signature[64];
61+
unsigned char sig[64];
5162

5263
uint32_t created_at;
5364
uint32_t kind;
@@ -62,6 +73,7 @@ struct ndb_note {
6273
#pragma pack(pop)
6374

6475
struct ndb_builder {
76+
struct cursor mem;
6577
struct cursor note_cur;
6678
struct cursor strings;
6779
struct cursor str_indices;
@@ -78,22 +90,23 @@ struct ndb_iterator {
7890
};
7991

8092
// HELPERS
81-
int ndb_calculate_note_id(struct ndb_note *note, unsigned char *buf, int buflen);
82-
// BYE HELPERS
93+
int ndb_calculate_id(struct ndb_note *note, unsigned char *buf, int buflen);
94+
int ndb_sign_id(secp256k1_context *ctx, struct ndb_keypair *keypair, unsigned char id[32], unsigned char sig[64]);
95+
int ndb_create_keypair(secp256k1_context *ctx, struct ndb_keypair *key);
96+
int ndb_decode_key(secp256k1_context *ctx, const char *secstr, struct ndb_keypair *keypair);
8397

84-
// HI BUILDER
98+
// BUILDER
8599
int ndb_note_from_json(const char *json, int len, struct ndb_note **, unsigned char *buf, int buflen);
86100
int ndb_builder_init(struct ndb_builder *builder, unsigned char *buf, int bufsize);
87-
int ndb_builder_finalize(struct ndb_builder *builder, struct ndb_note **note);
101+
int ndb_builder_finalize(struct ndb_builder *builder, struct ndb_note **note, struct ndb_keypair *privkey);
88102
int ndb_builder_set_content(struct ndb_builder *builder, const char *content, int len);
89103
void ndb_builder_set_created_at(struct ndb_builder *builder, uint32_t created_at);
90-
void ndb_builder_set_signature(struct ndb_builder *builder, unsigned char *signature);
104+
void ndb_builder_set_sig(struct ndb_builder *builder, unsigned char *sig);
91105
void ndb_builder_set_pubkey(struct ndb_builder *builder, unsigned char *pubkey);
92106
void ndb_builder_set_id(struct ndb_builder *builder, unsigned char *id);
93107
void ndb_builder_set_kind(struct ndb_builder *builder, uint32_t kind);
94108
int ndb_builder_new_tag(struct ndb_builder *builder);
95109
int ndb_builder_push_tag_str(struct ndb_builder *builder, const char *str, int len);
96-
// BYE BUILDER
97110

98111
static inline struct ndb_str ndb_note_str(struct ndb_note *note,
99112
union ndb_packed_str *pstr)
@@ -116,17 +129,6 @@ static inline struct ndb_str ndb_tag_str(struct ndb_note *note,
116129
return ndb_note_str(note, &tag->strs[ind]);
117130
}
118131

119-
static inline int ndb_tag_matches_char(struct ndb_note *note,
120-
struct ndb_tag *tag, int ind, char c)
121-
{
122-
struct ndb_str str = ndb_tag_str(note, tag, ind);
123-
if (str.str[0] == '\0')
124-
return 0;
125-
else if (str.str[0] == c)
126-
return 1;
127-
return 0;
128-
}
129-
130132
static inline struct ndb_str ndb_iter_tag_str(struct ndb_iterator *iter,
131133
int ind)
132134
{
@@ -143,9 +145,9 @@ static inline unsigned char * ndb_note_pubkey(struct ndb_note *note)
143145
return note->pubkey;
144146
}
145147

146-
static inline unsigned char * ndb_note_signature(struct ndb_note *note)
148+
static inline unsigned char * ndb_note_sig(struct ndb_note *note)
147149
{
148-
return note->signature;
150+
return note->sig;
149151
}
150152

151153
static inline uint32_t ndb_note_created_at(struct ndb_note *note)

0 commit comments

Comments
 (0)