upleb.uk

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

summaryrefslogtreecommitdiff
path: root/main/nostr_event.c
blob: b55c47da120a5f085a7393e3386ffdd5b38ab3f6 (plain)
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;
}