242 lines
9.1 KiB
C
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, <c_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;
|
|
}
|