Files
nostr_core_lib/tests/nip03_test.c
T

242 lines
9.1 KiB
C

/*
* NOSTR Core Library - NIP-03 Test
*/
#include "nostr_core/nostr_core.h"
#include "nostr_core/nip003.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
void test_nip03_create_proof_event() {
printf("🧪 Testing NIP-03 proof event creation...\n");
unsigned char private_key[32];
unsigned char public_key[32];
nostr_generate_keypair(private_key, public_key);
const char* target_id = "e71c6ea722987debdb60f81f9ea4f604b5ac0664120dd64fb9d23abc4ec7c323";
int target_kind = 1;
const char* ots_b64 = "base64encodedotsdata";
const char* relay = "wss://relay.example.com";
cJSON* event = nostr_nip03_create_proof_event(target_id, target_kind, ots_b64, relay, private_key);
assert(event != NULL);
// Verify kind
cJSON* kind = cJSON_GetObjectItem(event, "kind");
assert(kind != NULL && kind->valueint == 1040);
// Verify content
cJSON* content = cJSON_GetObjectItem(event, "content");
assert(content != NULL && strcmp(content->valuestring, ots_b64) == 0);
// Verify tags
cJSON* tags = cJSON_GetObjectItem(event, "tags");
assert(tags != NULL && cJSON_GetArraySize(tags) == 2);
cJSON* e_tag = cJSON_GetArrayItem(tags, 0);
assert(strcmp(cJSON_GetArrayItem(e_tag, 0)->valuestring, "e") == 0);
assert(strcmp(cJSON_GetArrayItem(e_tag, 1)->valuestring, target_id) == 0);
assert(strcmp(cJSON_GetArrayItem(e_tag, 2)->valuestring, relay) == 0);
cJSON* k_tag = cJSON_GetArrayItem(tags, 1);
assert(strcmp(cJSON_GetArrayItem(k_tag, 0)->valuestring, "k") == 0);
assert(strcmp(cJSON_GetArrayItem(k_tag, 1)->valuestring, "1") == 0);
printf("✅ NIP-03 proof event creation test passed!\n");
cJSON_Delete(event);
}
void test_nip03_create_proof_event_with_signer() {
printf("🧪 Testing NIP-03 proof event creation with signer...\n");
unsigned char private_key[32];
unsigned char public_key[32];
nostr_generate_keypair(private_key, public_key);
nostr_signer_t* signer = nostr_signer_local(private_key);
assert(signer != NULL);
const char* target_id = "e71c6ea722987debdb60f81f9ea4f604b5ac0664120dd64fb9d23abc4ec7c323";
int target_kind = 1;
const char* ots_b64 = "base64encodedotsdata";
cJSON* event = nostr_nip03_create_proof_event_with_signer(target_id, target_kind, ots_b64, NULL, signer);
assert(event != NULL);
// Verify kind
cJSON* kind = cJSON_GetObjectItem(event, "kind");
assert(kind != NULL && kind->valueint == 1040);
// Verify content
cJSON* content = cJSON_GetObjectItem(event, "content");
assert(content != NULL && strcmp(content->valuestring, ots_b64) == 0);
// Verify tags (no relay URL, so e_tag has only 2 elements)
cJSON* tags = cJSON_GetObjectItem(event, "tags");
assert(tags != NULL && cJSON_GetArraySize(tags) == 2);
cJSON* e_tag = cJSON_GetArrayItem(tags, 0);
assert(strcmp(cJSON_GetArrayItem(e_tag, 0)->valuestring, "e") == 0);
assert(strcmp(cJSON_GetArrayItem(e_tag, 1)->valuestring, target_id) == 0);
assert(cJSON_GetArraySize(e_tag) == 2); /* no relay URL */
printf("✅ NIP-03 proof event creation with signer test passed!\n");
cJSON_Delete(event);
nostr_signer_free(signer);
}
/*
* This is a real pending OTS proof (base64 encoded) from the OpenTimestamps
* calendar. It contains only pending attestations (no Bitcoin attestation),
* so is_proof_complete should return 0.
*
* The proof was generated for a test file and submitted to 3 calendars:
* - alice.btc.calendar.opentimestamps.org
* - bob.btc.calendar.opentimestamps.org
* - finney.calendar.eternitywall.com
*
* File digest (SHA256): dd4861b2521f83430a93696ca83b085b7fb8fd17ed6a2cee9496ec87d9fd0d6c
*/
static const char* PENDING_OTS_B64 =
"AE9wZW5UaW1lc3RhbXBzAABQcm9vZgC/ieLohOiSlAEI3UhhslIfg0MKk2lsqDsIW3+4/Rftaizu"
"lJbsh9n9DWzwEPH1H7z7SBTEU40qNFhcPKcI//AIxd2zXDTCN5cI8BCIgv8EsqQXO7DY4MNvo50e"
"CPEgksMhj36iAZdVcrXi4Q+Y/opid1wVrerjQ+gjGP5DB3wI8QRqVlUo8Ai72PBveP4l/QCD3+MN"
"LvkMji4taHR0cHM6Ly9hbGljZS5idGMuY2FsZW5kYXIub3BlbnRpbWVzdGFtcHMub3Jn//AIb923"
"oTIXfHkI8BDEnrX0tZZwN/drZnEOh+sACPEgcsd1lsM45YKtSytPZWr+Wkn3MMffWkFzj0qK7ehe"
"90wI8QRqVlUo8AjeBSDPqcrx9QCD3+MNLvkMjiwraHR0cHM6Ly9ib2IuYnRjLmNhbGVuZGFyLm9w"
"ZW50aW1lc3RhbXBzLm9yZ/AQjt5nZXTx0ZchzqvQ2HoNoAjxIKzXgsLhE8UXDdGZSuVT9f5FvggB"
"2nwYP7dmO/NjZwO1CPEEalZVKfAIeB6WGBjHG7gAg9/jDS75DI4pKGh0dHBzOi8vZmlubmV5LmNh"
"bGVuZGFyLmV0ZXJuaXR5d2FsbC5jb20=";
void test_nip03_is_proof_complete_pending() {
printf("🧪 Testing NIP-03 is_proof_complete with pending proof...\n");
int result = nostr_nip03_is_proof_complete(PENDING_OTS_B64);
printf(" Result: %d (expected 0 = pending)\n", result);
assert(result == 0);
printf("✅ NIP-03 is_proof_complete (pending) test passed!\n");
}
void test_nip03_get_attestation_info_pending() {
printf("🧪 Testing NIP-03 get_attestation_info with pending proof...\n");
int has_bitcoin = 0, has_litecoin = 0, has_pending = 0;
uint64_t btc_height = 0, ltc_height = 0;
char* pending_uri = NULL;
int rc = nostr_nip03_get_attestation_info(PENDING_OTS_B64,
&has_bitcoin, &has_litecoin, &has_pending,
&btc_height, &ltc_height, &pending_uri);
assert(rc == 0);
assert(has_bitcoin == 0);
assert(has_litecoin == 0);
assert(has_pending == 1);
assert(pending_uri != NULL);
printf(" Pending URI: %s\n", pending_uri);
/* Should be one of the known calendar URLs */
assert(strstr(pending_uri, "opentimestamps.org") != NULL ||
strstr(pending_uri, "eternitywall.com") != NULL);
free(pending_uri);
printf("✅ NIP-03 get_attestation_info (pending) test passed!\n");
}
void test_nip03_is_proof_complete_invalid() {
printf("🧪 Testing NIP-03 is_proof_complete with invalid data...\n");
/* Invalid base64 / not an OTS file */
int result = nostr_nip03_is_proof_complete("notavalidotsfile");
printf(" Result: %d (expected -1 = error)\n", result);
assert(result == -1);
/* NULL input */
result = nostr_nip03_is_proof_complete(NULL);
assert(result == -1);
printf("✅ NIP-03 is_proof_complete (invalid) test passed!\n");
}
void test_nip03_verify_proof_pending() {
printf("🧪 Testing NIP-03 verify_proof with pending proof...\n");
/* The file digest for this proof */
const char* expected_digest = "dd4861b2521f83430a93696ca83b085b7fb8fd17ed6a2cee9496ec87d9fd0d6c";
uint64_t block_height = 0;
time_t block_time = 0;
int rc = nostr_nip03_verify_proof(PENDING_OTS_B64, expected_digest,
&block_height, &block_time);
printf(" Result: %d (expected 1 = no bitcoin attestation)\n", rc);
/* Should return 1 (no Bitcoin attestation found, but digest matches) */
assert(rc == 1);
/* Test with wrong digest */
rc = nostr_nip03_verify_proof(PENDING_OTS_B64,
"0000000000000000000000000000000000000000000000000000000000000000",
&block_height, &block_time);
printf(" Result with wrong digest: %d (expected -2 = digest mismatch)\n", rc);
assert(rc == -2);
printf("✅ NIP-03 verify_proof (pending) test passed!\n");
}
void test_nip03_create_and_verify_roundtrip() {
printf("🧪 Testing NIP-03 create proof event + verify roundtrip...\n");
unsigned char private_key[32];
unsigned char public_key[32];
nostr_generate_keypair(private_key, public_key);
/* Create a proof event with the pending OTS data */
const char* target_id = "dd4861b2521f83430a93696ca83b085b7fb8fd17ed6a2cee9496ec87d9fd0d6c";
cJSON* proof_event = nostr_nip03_create_proof_event(target_id, 1, PENDING_OTS_B64, NULL, private_key);
assert(proof_event != NULL);
/* Verify the event is valid */
int validate_rc = nostr_validate_event(proof_event);
assert(validate_rc == NOSTR_SUCCESS);
/* Extract the OTS data from the event content and check completeness */
cJSON* content = cJSON_GetObjectItem(proof_event, "content");
assert(content != NULL && cJSON_IsString(content));
int complete = nostr_nip03_is_proof_complete(content->valuestring);
assert(complete == 0); /* pending */
char* json = cJSON_Print(proof_event);
printf(" Created proof event (kind 1040), %zu bytes\n", strlen(json));
free(json);
cJSON_Delete(proof_event);
printf("✅ NIP-03 create + verify roundtrip test passed!\n");
}
int main() {
if (nostr_init() != NOSTR_SUCCESS) {
fprintf(stderr, "Failed to initialize NOSTR library\n");
return 1;
}
test_nip03_create_proof_event();
test_nip03_create_proof_event_with_signer();
test_nip03_is_proof_complete_pending();
test_nip03_get_attestation_info_pending();
test_nip03_is_proof_complete_invalid();
test_nip03_verify_proof_pending();
test_nip03_create_and_verify_roundtrip();
// Note: We don't test nostr_nip03_request_timestamp here as it requires a live OTS calendar
// and network access, which might be flaky in a test environment.
// See tests/nip03_live_test.c for live network tests.
nostr_cleanup();
printf("\n🎉 All NIP-03 tests passed!\n");
return 0;
}