upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/main/nostr_event.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/nostr_event.c')
-rw-r--r--main/nostr_event.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/main/nostr_event.c b/main/nostr_event.c
new file mode 100644
index 0000000..b55c47d
--- /dev/null
+++ b/main/nostr_event.c
@@ -0,0 +1,112 @@
1#include "nostr_event.h"
2#include "esp_log.h"
3#include "esp_err.h"
4#include "mbedtls/sha256.h"
5#include "secp256k1.h"
6#include "secp256k1_extrakeys.h"
7#include "secp256k1_schnorrsig.h"
8#include "cJSON.h"
9#include <string.h>
10#include <stdio.h>
11#include <sys/time.h>
12
13static const char *TAG = "nostr_event";
14
15static void bytes_to_hex(const uint8_t *bytes, size_t len, char *hex)
16{
17 for (size_t i = 0; i < len; i++)
18 sprintf(hex + i * 2, "%02x", bytes[i]);
19 hex[len * 2] = '\0';
20}
21
22esp_err_t nostr_event_init(nostr_event_t *event, const char *npub_hex,
23 int kind, const char *tags_json, const char *content)
24{
25 memset(event, 0, sizeof(*event));
26 strncpy(event->pubkey, npub_hex, sizeof(event->pubkey) - 1);
27 event->kind = kind;
28 event->tags_json = tags_json ? tags_json : "[]";
29 event->content = content ? content : "";
30
31 struct timeval tv;
32 gettimeofday(&tv, NULL);
33 event->created_at = (uint64_t)tv.tv_sec;
34
35 cJSON *serial = cJSON_CreateArray();
36 cJSON_AddItemToArray(serial, cJSON_CreateNumber(0));
37 cJSON_AddItemToArray(serial, cJSON_CreateString(event->pubkey));
38 cJSON_AddItemToArray(serial, cJSON_CreateNumber((double)event->created_at));
39 cJSON_AddItemToArray(serial, cJSON_CreateNumber(event->kind));
40 cJSON_AddItemToArray(serial, cJSON_Parse(event->tags_json));
41 cJSON_AddItemToArray(serial, cJSON_CreateString(event->content));
42
43 char *serialized = cJSON_PrintUnformatted(serial);
44 cJSON_Delete(serial);
45
46 uint8_t hash[32];
47 mbedtls_sha256((const unsigned char *)serialized, strlen(serialized),
48 hash, 0);
49 free(serialized);
50
51 bytes_to_hex(hash, 32, event->id);
52 return ESP_OK;
53}
54
55esp_err_t nostr_event_sign(nostr_event_t *event, const uint8_t nsec[32])
56{
57 uint8_t msg[32];
58 for (size_t i = 0; i < 32; i++) {
59 unsigned int byte;
60 sscanf(event->id + i * 2, "%02x", &byte);
61 msg[i] = (uint8_t)byte;
62 }
63
64 secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
65 if (!ctx) {
66 ESP_LOGE(TAG, "Failed to create secp256k1 context");
67 return ESP_ERR_NO_MEM;
68 }
69
70 secp256k1_keypair keypair;
71 if (!secp256k1_keypair_create(ctx, &keypair, nsec)) {
72 ESP_LOGE(TAG, "Invalid nsec for signing");
73 secp256k1_context_destroy(ctx);
74 return ESP_ERR_INVALID_ARG;
75 }
76
77 uint8_t sig[64];
78 if (!secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL)) {
79 ESP_LOGE(TAG, "Schnorr signing failed");
80 secp256k1_context_destroy(ctx);
81 return ESP_FAIL;
82 }
83
84 bytes_to_hex(sig, 64, event->sig);
85 secp256k1_context_destroy(ctx);
86 return ESP_OK;
87}
88
89esp_err_t nostr_event_to_json(const nostr_event_t *event, char *buf, size_t buf_len)
90{
91 cJSON *root = cJSON_CreateObject();
92 cJSON_AddStringToObject(root, "id", event->id);
93 cJSON_AddStringToObject(root, "pubkey", event->pubkey);
94 cJSON_AddNumberToObject(root, "created_at", (double)event->created_at);
95 cJSON_AddNumberToObject(root, "kind", event->kind);
96 cJSON_AddItemToObject(root, "tags", cJSON_Parse(event->tags_json));
97 cJSON_AddStringToObject(root, "content", event->content);
98 cJSON_AddStringToObject(root, "sig", event->sig);
99
100 char *json = cJSON_PrintUnformatted(root);
101 cJSON_Delete(root);
102
103 if (!json) return ESP_FAIL;
104 size_t len = strlen(json);
105 if (len >= buf_len) {
106 free(json);
107 return ESP_ERR_NO_MEM;
108 }
109 memcpy(buf, json, len + 1);
110 free(json);
111 return ESP_OK;
112}