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