diff options
Diffstat (limited to 'main/nostr_event.c')
| -rw-r--r-- | main/nostr_event.c | 112 |
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 | |||
| 13 | static const char *TAG = "nostr_event"; | ||
| 14 | |||
| 15 | static 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 | |||
| 22 | esp_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 | |||
| 55 | esp_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 | |||
| 89 | esp_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 | } | ||