Refactor and consolidate test suite

- Moved old tests from tests/old/ to main tests/ directory
- Renamed nostr_test_bip32.c to bip32_test.c for consistency
- Renamed nostr_crypto_test.c to crypto_test.c for consistency
- Renamed wss_test.c and moved from old directory
- Fixed unused variable warning in bip32_test.c
- Updated build system and workspace rules
- Cleaned up old compiled test executables
- Updated nostr_common.h and core_relays.c
- Removed obsolete nostr_core.h.old backup file

This consolidates all active tests into the main directory and removes
outdated test files while maintaining a clean, organized structure.
This commit is contained in:
2025-08-16 08:38:41 -04:00
parent c3a9482882
commit 76e883fad4
21 changed files with 101 additions and 928 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,461 +0,0 @@
/*
* NOSTR Crypto Test Suite
* Tests all cryptographic primitives and BIP implementations
* with known good test vectors
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "../nostr_core/utils.h"
// Helper function to convert hex string to bytes
static void hex_to_bytes(const char* hex, unsigned char* bytes, size_t len) {
for (size_t i = 0; i < len; i++) {
sscanf(hex + i * 2, "%02hhx", &bytes[i]);
}
}
// Helper function to compare byte arrays and print results
static int test_bytes_equal(const char* test_name,
const unsigned char* result,
const unsigned char* expected,
size_t len) {
if (memcmp(result, expected, len) == 0) {
printf("✓ %s: PASSED\n", test_name);
return 1;
} else {
printf("❌ %s: FAILED\n", test_name);
printf(" Expected: ");
for (size_t i = 0; i < len; i++) printf("%02x", expected[i]);
printf("\n Got: ");
for (size_t i = 0; i < len; i++) printf("%02x", result[i]);
printf("\n");
return 0;
}
}
// =============================================================================
// SHA-256 TESTS
// =============================================================================
static int test_sha256_empty_string() {
unsigned char result[32];
unsigned char expected[32];
// Empty string SHA-256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
hex_to_bytes("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", expected, 32);
nostr_sha256((const unsigned char*)"", 0, result);
return test_bytes_equal("SHA-256 empty string", result, expected, 32);
}
static int test_sha256_abc() {
unsigned char result[32];
unsigned char expected[32];
// "abc" SHA-256: ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
hex_to_bytes("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", expected, 32);
nostr_sha256((const unsigned char*)"abc", 3, result);
return test_bytes_equal("SHA-256 'abc'", result, expected, 32);
}
static int test_sha256_hello_world() {
unsigned char result[32];
unsigned char expected[32];
// "hello world" SHA-256: b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
hex_to_bytes("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", expected, 32);
nostr_sha256((const unsigned char*)"hello world", 11, result);
return test_bytes_equal("SHA-256 'hello world'", result, expected, 32);
}
static int test_sha256_long_string() {
unsigned char result[32];
unsigned char expected[32];
// "The quick brown fox jumps over the lazy dog" SHA-256: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592
hex_to_bytes("d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592", expected, 32);
const char* msg = "The quick brown fox jumps over the lazy dog";
nostr_sha256((const unsigned char*)msg, strlen(msg), result);
return test_bytes_equal("SHA-256 long string", result, expected, 32);
}
static int test_sha256_vectors() {
printf("\n=== SHA-256 Tests ===\n");
int passed = 0;
passed += test_sha256_empty_string();
passed += test_sha256_abc();
passed += test_sha256_hello_world();
passed += test_sha256_long_string();
printf("SHA-256: %d/4 tests passed\n", passed);
return (passed == 4) ? 1 : 0;
}
// =============================================================================
// HMAC-SHA256 TESTS
// =============================================================================
static int test_hmac_rfc4231_test1() {
unsigned char result[32];
unsigned char expected[32];
// RFC 4231 Test Case 1
// Key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (20 bytes)
// Data = "Hi There"
// HMAC-SHA256 = b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7
unsigned char key[20];
memset(key, 0x0b, 20);
hex_to_bytes("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7", expected, 32);
nostr_hmac_sha256(key, 20, (const unsigned char*)"Hi There", 8, result);
return test_bytes_equal("HMAC-SHA256 RFC4231 Test 1", result, expected, 32);
}
static int test_hmac_rfc4231_test2() {
unsigned char result[32];
unsigned char expected[32];
// RFC 4231 Test Case 2
// Key = "Jefe"
// Data = "what do ya want for nothing?"
// HMAC-SHA256 = 5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843
hex_to_bytes("5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", expected, 32);
const char* data = "what do ya want for nothing?";
nostr_hmac_sha256((const unsigned char*)"Jefe", 4, (const unsigned char*)data, strlen(data), result);
return test_bytes_equal("HMAC-SHA256 RFC4231 Test 2", result, expected, 32);
}
static int test_hmac_vectors() {
printf("\n=== HMAC-SHA256 Tests ===\n");
int passed = 0;
passed += test_hmac_rfc4231_test1();
passed += test_hmac_rfc4231_test2();
printf("HMAC-SHA256: %d/2 tests passed\n", passed);
return (passed == 2) ? 1 : 0;
}
// =============================================================================
// PBKDF2 TESTS
// =============================================================================
static int test_pbkdf2_bip39_example() {
unsigned char result[64];
// Test BIP39 seed generation with empty passphrase
// This should not crash and should produce 64 bytes
const char* mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
int ret = nostr_pbkdf2_hmac_sha512((const unsigned char*)mnemonic, strlen(mnemonic),
(const unsigned char*)"mnemonic", 8,
2048, result, 64);
if (ret == 0) {
printf("✓ PBKDF2 BIP39 seed generation: PASSED\n");
return 1;
} else {
printf("❌ PBKDF2 BIP39 seed generation: FAILED\n");
return 0;
}
}
static int test_pbkdf2_vectors() {
printf("\n=== PBKDF2 Tests ===\n");
int passed = 0;
// Note: RFC 6070 test may not match exactly due to PBKDF2-SHA512 vs PBKDF2-SHA1
// but we test that it doesn't crash and produces reasonable output
passed += test_pbkdf2_bip39_example();
printf("PBKDF2: %d/1 tests passed\n", passed);
return (passed == 1) ? 1 : 0;
}
// =============================================================================
// BIP39 TESTS
// =============================================================================
static int test_bip39_entropy_to_mnemonic() {
// Test with known entropy
unsigned char entropy[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
char mnemonic[256];
int ret = nostr_bip39_mnemonic_from_bytes(entropy, 16, mnemonic);
// Should generate a valid 12-word mnemonic from zero entropy
if (ret == 0 && strlen(mnemonic) > 0) {
printf("✓ BIP39 entropy to mnemonic: PASSED (%s)\n", mnemonic);
return 1;
} else {
printf("❌ BIP39 entropy to mnemonic: FAILED\n");
return 0;
}
}
static int test_bip39_mnemonic_validation() {
// Test valid mnemonic
const char* valid_mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
if (nostr_bip39_mnemonic_validate(valid_mnemonic) == 0) {
printf("✓ BIP39 mnemonic validation (valid): PASSED\n");
} else {
printf("❌ BIP39 mnemonic validation (valid): FAILED\n");
return 0;
}
// Test invalid mnemonic
const char* invalid_mnemonic = "invalid words that are not in wordlist";
if (nostr_bip39_mnemonic_validate(invalid_mnemonic) != 0) {
printf("✓ BIP39 mnemonic validation (invalid): PASSED\n");
return 1;
} else {
printf("❌ BIP39 mnemonic validation (invalid): FAILED\n");
return 0;
}
}
static int test_bip39_mnemonic_to_seed() {
const char* mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
unsigned char seed[64];
int ret = nostr_bip39_mnemonic_to_seed(mnemonic, "", seed, sizeof(seed));
if (ret == 0) {
printf("✓ BIP39 mnemonic to seed: PASSED\n");
return 1;
} else {
printf("❌ BIP39 mnemonic to seed: FAILED\n");
return 0;
}
}
static int test_bip39_vectors() {
printf("\n=== BIP39 Tests ===\n");
int passed = 0;
passed += test_bip39_entropy_to_mnemonic();
passed += test_bip39_mnemonic_validation();
passed += test_bip39_mnemonic_to_seed();
printf("BIP39: %d/3 tests passed\n", passed);
return (passed == 3) ? 1 : 0;
}
// =============================================================================
// BIP32 TESTS
// =============================================================================
static int test_bip32_seed_to_master_key() {
// Test seed to master key derivation
unsigned char seed[64];
memset(seed, 0x01, 64); // Simple test seed
nostr_hd_key_t master_key;
int ret = nostr_bip32_key_from_seed(seed, 64, &master_key);
if (ret == 0) {
printf("✓ BIP32 seed to master key: PASSED\n");
return 1;
} else {
printf("❌ BIP32 seed to master key: FAILED\n");
return 0;
}
}
static int test_bip32_key_derivation() {
// Test key derivation path
unsigned char seed[64];
memset(seed, 0x01, 64);
nostr_hd_key_t master_key;
if (nostr_bip32_key_from_seed(seed, 64, &master_key) != 0) {
printf("❌ BIP32 key derivation setup: FAILED\n");
return 0;
}
// Test NIP-06 derivation path: m/44'/1237'/0'/0/0
nostr_hd_key_t derived_key;
uint32_t path[] = {
0x80000000 + 44, // 44' (hardened)
0x80000000 + 1237, // 1237' (hardened)
0x80000000 + 0, // 0' (hardened)
0, // 0 (not hardened)
0 // 0 (not hardened)
};
int ret = nostr_bip32_derive_path(&master_key, path, 5, &derived_key);
if (ret == 0) {
printf("✓ BIP32 NIP-06 key derivation: PASSED\n");
return 1;
} else {
printf("❌ BIP32 NIP-06 key derivation: FAILED\n");
return 0;
}
}
static int test_bip32_vectors() {
printf("\n=== BIP32 Tests ===\n");
int passed = 0;
passed += test_bip32_seed_to_master_key();
passed += test_bip32_key_derivation();
printf("BIP32: %d/2 tests passed\n", passed);
return (passed == 2) ? 1 : 0;
}
// =============================================================================
// SECP256K1 TESTS
// =============================================================================
static int test_secp256k1_private_key_validation() {
// Test valid private key
unsigned char valid_key[32];
memset(valid_key, 0x01, 32); // Simple valid key
if (nostr_ec_private_key_verify(valid_key) == 0) {
printf("✓ secp256k1 private key validation (valid): PASSED\n");
} else {
printf("❌ secp256k1 private key validation (valid): FAILED\n");
return 0;
}
// Test invalid private key (all zeros)
unsigned char invalid_key[32];
memset(invalid_key, 0x00, 32);
if (nostr_ec_private_key_verify(invalid_key) != 0) {
printf("✓ secp256k1 private key validation (invalid): PASSED\n");
return 1;
} else {
printf("❌ secp256k1 private key validation (invalid): FAILED\n");
return 0;
}
}
static int test_secp256k1_public_key_generation() {
unsigned char private_key[32];
unsigned char public_key[32];
// Use a known private key
memset(private_key, 0x01, 32);
int ret = nostr_ec_public_key_from_private_key(private_key, public_key);
if (ret == 0) {
printf("✓ secp256k1 public key generation: PASSED\n");
return 1;
} else {
printf("❌ secp256k1 public key generation: FAILED\n");
return 0;
}
}
static int test_secp256k1_sign_verify() {
unsigned char private_key[32];
unsigned char message[32];
unsigned char signature[64];
// Simple test data
memset(private_key, 0x01, 32);
memset(message, 0x02, 32);
// Test signing
int ret = nostr_ec_sign(private_key, message, signature);
if (ret == 0) {
printf("✓ secp256k1 signing: PASSED\n");
return 1;
} else {
printf("❌ secp256k1 signing: FAILED\n");
return 0;
}
}
static int test_secp256k1_vectors() {
printf("\n=== secp256k1 Tests ===\n");
int passed = 0;
passed += test_secp256k1_private_key_validation();
passed += test_secp256k1_public_key_generation();
passed += test_secp256k1_sign_verify();
printf("secp256k1: %d/3 tests passed\n", passed);
return (passed == 3) ? 1 : 0;
}
// =============================================================================
// MAIN TEST RUNNER
// =============================================================================
int main() {
printf("NOSTR Crypto Library Test Suite\n");
printf("==============================\n");
// Initialize crypto
if (nostr_crypto_init() != 0) {
printf("❌ Failed to initialize crypto library\n");
return 1;
}
int passed = 0, total = 0;
// Run all test suites
if (test_sha256_vectors()) passed++;
total++;
if (test_hmac_vectors()) passed++;
total++;
if (test_pbkdf2_vectors()) passed++;
total++;
if (test_bip39_vectors()) passed++;
total++;
if (test_bip32_vectors()) passed++;
total++;
if (test_secp256k1_vectors()) passed++;
total++;
// Print final results
printf("\n==============================\n");
printf("FINAL RESULTS: %d/%d test suites passed\n", passed, total);
if (passed == total) {
printf("🎉 ALL TESTS PASSED! Crypto implementation is working correctly.\n");
} else {
printf("❌ Some tests failed. Please review the implementation.\n");
}
// Cleanup
nostr_crypto_cleanup();
return (passed == total) ? 0 : 1;
}

Binary file not shown.

View File

@@ -1,434 +0,0 @@
/*
* NOSTR Event Generation Test Suite
* Tests complete workflow from mnemonic to signed event using specific test vectors
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "../nostr_core/nostr_core.h"
#include "../cjson/cJSON.h"
// Test vector structure
typedef struct {
const char* mnemonic;
const char* expected_nsec_hex;
const char* expected_nsec;
const char* expected_npub_hex;
const char* expected_npub;
const char* name;
} test_vector_t;
// Test vectors to validate against
static const test_vector_t TEST_VECTORS[] = {
{
.name = "Vector 1",
.mnemonic = "fetch risk mention yellow cluster hunt voyage acquire leader caution romance solid",
.expected_nsec_hex = "b46173ac0cc222f73246d6be63f5c0bd90d92b118f99f582cd11d077490d0794",
.expected_nsec = "nsec1k3sh8tqvcg30wvjx66lx8awqhkgdj2c337vltqkdz8g8wjgdq72q3mrze9",
.expected_npub_hex = "a11258677dd416ca4c9e352e0e02ad2d8784a18c3a963604d0c63dc7b74eec66",
.expected_npub = "npub15yf9sema6stv5ny7x5hquq4d9krcfgvv82trvpxscc7u0d6wa3nqmvcv3a"
},
{
.name = "Vector 2",
.mnemonic = "leader monkey parrot ring guide accident before fence cannon height naive bean",
.expected_nsec_hex = "7f7ff03d123792d6ac594bfa67bf6d0c0ab55b6b1fdb6249303fe861f1ccba9a",
.expected_nsec = "nsec10allq0gjx7fddtzef0ax00mdps9t2kmtrldkyjfs8l5xruwvh2dq0lhhkp",
.expected_npub_hex = "17162c921dc4d2518f9a101db33695df1afb56ab82f5ff3e5da6eec3ca5cd917",
.expected_npub = "npub1zutzeysacnf9rru6zqwmxd54mud0k44tst6l70ja5mhv8jjumytsd2x7nu"
},
{
.name = "Vector 3",
.mnemonic = "what bleak badge arrange retreat wolf trade produce cricket blur garlic valid proud rude strong choose busy staff weather area salt hollow arm fade",
.expected_nsec_hex = "c15d739894c81a2fcfd3a2df85a0d2c0dbc47a280d092799f144d73d7ae78add",
.expected_nsec = "nsec1c9wh8xy5eqdzln7n5t0ctgxjcrdug73gp5yj0x03gntn67h83twssdfhel",
.expected_npub_hex = "d41b22899549e1f3d335a31002cfd382174006e166d3e658e3a5eecdb6463573",
.expected_npub = "npub16sdj9zv4f8sl85e45vgq9n7nsgt5qphpvmf7vk8r5hhvmdjxx4es8rq74h"
}
};
static const size_t NUM_TEST_VECTORS = sizeof(TEST_VECTORS) / sizeof(TEST_VECTORS[0]);
// Constants for event generation test
static const uint32_t TEST_CREATED_AT = 1698623783;
static const char* TEST_CONTENT = "Hello";
// Expected events for each test vector
typedef struct {
const char* expected_event_id;
const char* expected_signature;
const char* expected_json;
} expected_event_t;
static const expected_event_t EXPECTED_EVENTS[] = {
{
// Vector 1 expected event
.expected_event_id = "c790e29519cc43ad87a4e061c36b4740cf1085e2c9eabb6971ea97f3859eb008",
.expected_signature = "9acb3e409a8b329316bd4184ad74a50db7764a4370ad863f97fb37858d87c380c9299a7adef19dfd29481f51eb81e28ebba2a6d2bbcc4085a1b07ca8339e8d0c",
.expected_json = "{\n"
"\t\"pubkey\":\t\"a11258677dd416ca4c9e352e0e02ad2d8784a18c3a963604d0c63dc7b74eec66\",\n"
"\t\"created_at\":\t1698623783,\n"
"\t\"kind\":\t1,\n"
"\t\"tags\":\t[],\n"
"\t\"content\":\t\"Hello\",\n"
"\t\"id\":\t\"c790e29519cc43ad87a4e061c36b4740cf1085e2c9eabb6971ea97f3859eb008\",\n"
"\t\"sig\":\t\"9acb3e409a8b329316bd4184ad74a50db7764a4370ad863f97fb37858d87c380c9299a7adef19dfd29481f51eb81e28ebba2a6d2bbcc4085a1b07ca8339e8d0c\"\n"
"}"
},
{
// Vector 2 expected event
.expected_event_id = "e28fda46caa56eb6f62c7871409e6c76cd43a47fca14878b91e49d8ee8e52c27",
.expected_signature = "7a7ce178e18b1065a9642985a3fb815ed52772c34fc6e67515de012558968f6428509b9cf93cf6faf17db387b833196a5be48ed1154c1c2dffb1c30293318e3d",
.expected_json = "{\n"
"\t\"pubkey\":\t\"17162c921dc4d2518f9a101db33695df1afb56ab82f5ff3e5da6eec3ca5cd917\",\n"
"\t\"created_at\":\t1698623783,\n"
"\t\"kind\":\t1,\n"
"\t\"tags\":\t[],\n"
"\t\"content\":\t\"Hello\",\n"
"\t\"id\":\t\"e28fda46caa56eb6f62c7871409e6c76cd43a47fca14878b91e49d8ee8e52c27\",\n"
"\t\"sig\":\t\"7a7ce178e18b1065a9642985a3fb815ed52772c34fc6e67515de012558968f6428509b9cf93cf6faf17db387b833196a5be48ed1154c1c2dffb1c30293318e3d\"\n"
"}"
},
{
// Vector 3 expected event
.expected_event_id = "ad349fdb162ea874d8b685e682b9dcc84b5bd72c4efac51e295db39b7623cde0",
.expected_signature = "11e2280cca6f2e0f638fbf60f8aa744a4c228ba19f4d787a51298ec23be4a226e5046477cf6444a804c81aa08dd287e9647f0b45f8a02700da4a387187d4b3dc",
.expected_json = "{\n"
"\t\"pubkey\":\t\"d41b22899549e1f3d335a31002cfd382174006e166d3e658e3a5eecdb6463573\",\n"
"\t\"created_at\":\t1698623783,\n"
"\t\"kind\":\t1,\n"
"\t\"tags\":\t[],\n"
"\t\"content\":\t\"Hello\",\n"
"\t\"id\":\t\"ad349fdb162ea874d8b685e682b9dcc84b5bd72c4efac51e295db39b7623cde0\",\n"
"\t\"sig\":\t\"11e2280cca6f2e0f638fbf60f8aa744a4c228ba19f4d787a51298ec23be4a226e5046477cf6444a804c81aa08dd287e9647f0b45f8a02700da4a387187d4b3dc\"\n"
"}"
}
};
// Helper functions
static void print_test_result(const char* test_name, int passed, const char* expected, const char* actual) {
if (passed) {
printf("✓ %s: PASSED\n", test_name);
} else {
printf("❌ %s: FAILED\n", test_name);
printf(" Expected: %s\n", expected);
printf(" Actual: %s\n", actual);
}
}
static void bytes_to_hex_lowercase(const unsigned char* bytes, size_t len, char* hex_out) {
for (size_t i = 0; i < len; i++) {
sprintf(hex_out + i * 2, "%02x", bytes[i]);
}
hex_out[len * 2] = '\0';
}
// Test single vector for mnemonic to keys
static int test_single_vector_mnemonic_to_keys(const test_vector_t* vector, unsigned char* private_key_out, unsigned char* public_key_out) {
printf("\n=== Testing %s: Mnemonic to Keys ===\n", vector->name);
printf("Input mnemonic: %s\n", vector->mnemonic);
printf("Input account: 0\n");
unsigned char private_key[32];
unsigned char public_key[32];
// Derive keys from mnemonic using account 0
printf("Calling nostr_derive_keys_from_mnemonic()...\n");
int ret = nostr_derive_keys_from_mnemonic(vector->mnemonic, 0, private_key, public_key);
printf("Function returned: %d\n", ret);
if (ret != NOSTR_SUCCESS) {
printf("❌ Key derivation failed with code: %d\n", ret);
printf("Expected: Success (0)\n");
printf("Actual: Error (%d)\n", ret);
return 0;
}
// Convert private key to hex (lowercase)
char nsec_hex[65];
bytes_to_hex_lowercase(private_key, 32, nsec_hex);
// Convert public key to hex (lowercase)
char npub_hex[65];
bytes_to_hex_lowercase(public_key, 32, npub_hex);
// Test nsecHex
printf("\nPrivate Key (nsecHex):\n");
printf("Expected: %s\n", vector->expected_nsec_hex);
printf("Actual: %s\n", nsec_hex);
int nsec_hex_match = (strcmp(nsec_hex, vector->expected_nsec_hex) == 0);
printf("Result: %s\n", nsec_hex_match ? "✓ PASS" : "❌ FAIL");
// Test npubHex
printf("\nPublic Key (npubHex):\n");
printf("Expected: %s\n", vector->expected_npub_hex);
printf("Actual: %s\n", npub_hex);
int npub_hex_match = (strcmp(npub_hex, vector->expected_npub_hex) == 0);
printf("Result: %s\n", npub_hex_match ? "✓ PASS" : "❌ FAIL");
// Copy keys for use in other tests
if (private_key_out) memcpy(private_key_out, private_key, 32);
if (public_key_out) memcpy(public_key_out, public_key, 32);
return nsec_hex_match && npub_hex_match;
}
// Test single vector for nsec encoding
static int test_single_vector_nsec_encoding(const test_vector_t* vector, const unsigned char* private_key) {
printf("\n=== Testing %s: nsec Encoding ===\n", vector->name);
// Show input private key in hex
char private_key_hex[65];
bytes_to_hex_lowercase(private_key, 32, private_key_hex);
printf("Input private key (hex): %s\n", private_key_hex);
char nsec[100];
printf("Calling nostr_key_to_bech32() with hrp='nsec'...\n");
int ret = nostr_key_to_bech32(private_key, "nsec", nsec);
printf("Function returned: %d\n", ret);
if (ret != NOSTR_SUCCESS) {
printf("❌ nsec encoding failed with code: %d\n", ret);
printf("Expected: Success (0)\n");
printf("Actual: Error (%d)\n", ret);
return 0;
}
printf("\nnsec Encoding:\n");
printf("Expected: %s\n", vector->expected_nsec);
printf("Actual: %s\n", nsec);
int nsec_match = (strcmp(nsec, vector->expected_nsec) == 0);
printf("Result: %s\n", nsec_match ? "✓ PASS" : "❌ FAIL");
return nsec_match;
}
// Test single vector for npub encoding
static int test_single_vector_npub_encoding(const test_vector_t* vector, const unsigned char* public_key) {
printf("\n=== Testing %s: npub Encoding ===\n", vector->name);
char npub[100];
int ret = nostr_key_to_bech32(public_key, "npub", npub);
if (ret != NOSTR_SUCCESS) {
printf("❌ npub encoding failed with code: %d\n", ret);
return 0;
}
int npub_match = (strcmp(npub, vector->expected_npub) == 0);
print_test_result("npub encoding", npub_match, vector->expected_npub, npub);
return npub_match;
}
// Test single vector for event generation
static int test_single_vector_event_generation(const test_vector_t* vector, const unsigned char* private_key, size_t vector_index) {
printf("\n=== Testing %s: Signed Event Generation ===\n", vector->name);
// Create and sign event with fixed timestamp
cJSON* event = nostr_create_and_sign_event(1, TEST_CONTENT, NULL, 0, private_key, TEST_CREATED_AT);
if (!event) {
printf("❌ Event creation failed\n");
return 0;
}
// Extract event fields
cJSON* id_item = cJSON_GetObjectItem(event, "id");
cJSON* pubkey_item = cJSON_GetObjectItem(event, "pubkey");
cJSON* created_at_item = cJSON_GetObjectItem(event, "created_at");
cJSON* kind_item = cJSON_GetObjectItem(event, "kind");
cJSON* content_item = cJSON_GetObjectItem(event, "content");
cJSON* sig_item = cJSON_GetObjectItem(event, "sig");
cJSON* tags_item = cJSON_GetObjectItem(event, "tags");
if (!id_item || !pubkey_item || !created_at_item || !kind_item ||
!content_item || !sig_item || !tags_item) {
printf("❌ Event missing required fields\n");
cJSON_Delete(event);
return 0;
}
// Validate field types
if (!cJSON_IsString(id_item) || !cJSON_IsString(pubkey_item) ||
!cJSON_IsNumber(created_at_item) || !cJSON_IsNumber(kind_item) ||
!cJSON_IsString(content_item) || !cJSON_IsString(sig_item) ||
!cJSON_IsArray(tags_item)) {
printf("❌ Event fields have wrong types\n");
cJSON_Delete(event);
return 0;
}
// Extract values
const char* event_id = cJSON_GetStringValue(id_item);
const char* pubkey = cJSON_GetStringValue(pubkey_item);
uint32_t created_at = (uint32_t)cJSON_GetNumberValue(created_at_item);
int kind = (int)cJSON_GetNumberValue(kind_item);
const char* content = cJSON_GetStringValue(content_item);
const char* signature = cJSON_GetStringValue(sig_item);
// Test each field
int tests_passed = 0;
int total_tests = 7;
// Test kind
if (kind == 1) {
printf("✓ Event kind: PASSED (1)\n");
tests_passed++;
} else {
printf("❌ Event kind: FAILED (expected 1, got %d)\n", kind);
}
// Test pubkey - only check for first vector since we have expected values for that one
if (strcmp(vector->name, "Vector 1") == 0) {
int pubkey_match = (strcmp(pubkey, vector->expected_npub_hex) == 0);
print_test_result("Event pubkey", pubkey_match, vector->expected_npub_hex, pubkey);
if (pubkey_match) tests_passed++;
} else {
// For other vectors, just check that pubkey matches the expected public key
int pubkey_match = (strcmp(pubkey, vector->expected_npub_hex) == 0);
print_test_result("Event pubkey", pubkey_match, vector->expected_npub_hex, pubkey);
if (pubkey_match) tests_passed++;
}
// Test created_at
if (created_at == TEST_CREATED_AT) {
printf("✓ Event created_at: PASSED (%u)\n", created_at);
tests_passed++;
} else {
printf("❌ Event created_at: FAILED (expected %u, got %u)\n", TEST_CREATED_AT, created_at);
}
// Test content
int content_match = (strcmp(content, TEST_CONTENT) == 0);
print_test_result("Event content", content_match, TEST_CONTENT, content);
if (content_match) tests_passed++;
// Test tags (should be empty array)
int tags_empty = (cJSON_GetArraySize(tags_item) == 0);
if (tags_empty) {
printf("✓ Event tags: PASSED (empty array)\n");
tests_passed++;
} else {
printf("❌ Event tags: FAILED (expected empty array, got %d items)\n",
cJSON_GetArraySize(tags_item));
}
// Get expected event for this vector
const expected_event_t* expected = &EXPECTED_EVENTS[vector_index];
// Test event ID and signature
int id_match = (strcmp(event_id, expected->expected_event_id) == 0);
print_test_result("Event ID", id_match, expected->expected_event_id, event_id);
if (id_match) tests_passed++;
int sig_match = (strcmp(signature, expected->expected_signature) == 0);
print_test_result("Event signature", sig_match, expected->expected_signature, signature);
if (sig_match) tests_passed++;
// Print expected vs generated event JSONs side by side
printf("\n=== EXPECTED EVENT JSON ===\n");
printf("%s\n", expected->expected_json);
printf("\n=== GENERATED EVENT JSON ===\n");
char* event_json = cJSON_Print(event);
if (event_json) {
printf("%s\n", event_json);
free(event_json);
}
cJSON_Delete(event);
printf("\nEvent generation: %d/%d tests passed\n", tests_passed, total_tests);
return (tests_passed == total_tests);
}
// Test all vectors
static int test_all_vectors() {
printf("\n=== Testing All Vectors ===\n");
int total_vectors_passed = 0;
for (size_t i = 0; i < NUM_TEST_VECTORS; i++) {
const test_vector_t* vector = &TEST_VECTORS[i];
printf("\n" "==========================================\n");
printf("Testing %s\n", vector->name);
printf("==========================================\n");
unsigned char private_key[32];
unsigned char public_key[32];
// Step 1: Test mnemonic to keys
int keys_passed = test_single_vector_mnemonic_to_keys(vector, private_key, public_key);
// Step 2: Test nsec encoding
int nsec_passed = test_single_vector_nsec_encoding(vector, private_key);
// Step 3: Test npub encoding
int npub_passed = test_single_vector_npub_encoding(vector, public_key);
// Step 4: Test event generation (only if keys work)
int event_passed = 0;
if (keys_passed) {
event_passed = test_single_vector_event_generation(vector, private_key, i);
}
// Summary for this vector
printf("\n%s Summary:\n", vector->name);
printf(" Keys: %s\n", keys_passed ? "✓ PASS" : "❌ FAIL");
printf(" nsec: %s\n", nsec_passed ? "✓ PASS" : "❌ FAIL");
printf(" npub: %s\n", npub_passed ? "✓ PASS" : "❌ FAIL");
printf(" Event: %s\n", event_passed ? "✓ PASS" : "❌ FAIL");
if (keys_passed && nsec_passed && npub_passed && event_passed) {
printf(" Overall: ✓ PASS\n");
total_vectors_passed++;
} else {
printf(" Overall: ❌ FAIL\n");
}
}
printf("\n" "==========================================\n");
printf("FINAL RESULTS: %d/%zu vectors passed\n", total_vectors_passed, NUM_TEST_VECTORS);
printf("==========================================\n");
return (total_vectors_passed == (int)NUM_TEST_VECTORS);
}
int main() {
printf("NOSTR Event Generation Test Suite\n");
printf("=================================\n");
printf("Testing against multiple test vectors for ecosystem compatibility\n");
// Initialize NOSTR library
if (nostr_init() != NOSTR_SUCCESS) {
printf("❌ Failed to initialize NOSTR library\n");
return 1;
}
// Run all vector tests
int success = test_all_vectors();
// Print final results
printf("\n=================================\n");
if (success) {
printf("🎉 ALL TEST VECTORS PASSED!\n");
printf("✅ Your NOSTR implementation produces the exact same results as all test vectors\n");
printf("✅ This confirms compatibility with other NOSTR tools\n");
} else {
printf("❌ SOME TEST VECTORS FAILED\n");
printf("❌ Your implementation produces different results than expected\n");
printf("❌ This indicates compatibility issues with other NOSTR tools\n");
printf("\nFor debugging purposes, review the detailed output above to see:\n");
printf(" - Which vectors passed/failed\n");
printf(" - Expected vs actual values for each test\n");
printf(" - Whether the issue is in key derivation, encoding, or event generation\n");
}
// Cleanup
nostr_cleanup();
return success ? 0 : 1;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,103 +0,0 @@
/*
* WebSocket SSL Test - Test OpenSSL WebSocket implementation
* Connect to a NOSTR relay and fetch one type 1 event
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../nostr_core/nostr_core.h"
#include "../cjson/cJSON.h"
// Progress callback to show connection status
static void progress_callback(
const char* relay_url,
const char* status,
const char* event_id,
int events_received,
int total_relays,
int completed_relays,
void* user_data)
{
printf("Progress: %s - %s", relay_url ? relay_url : "Summary", status);
if (event_id) {
printf(" (Event: %.12s...)", event_id);
}
printf(" [%d/%d events, %d/%d relays]\n",
events_received, *(int*)user_data, completed_relays, total_relays);
}
int main() {
printf("WebSocket SSL Test - Testing OpenSSL WebSocket with NOSTR relay\n");
printf("================================================================\n");
// Initialize NOSTR library
if (nostr_init() != NOSTR_SUCCESS) {
printf("❌ Failed to initialize NOSTR library\n");
return 1;
}
printf("✅ NOSTR library initialized\n");
// Setup relay and filter
const char* relay_urls[] = {"wss://nostr.mom"};
int relay_count = 1;
// Create filter for type 1 events (text notes), limit to 1 event
cJSON* filter = cJSON_CreateObject();
cJSON* kinds = cJSON_CreateArray();
cJSON_AddItemToArray(kinds, cJSON_CreateNumber(1));
cJSON_AddItemToObject(filter, "kinds", kinds);
cJSON_AddItemToObject(filter, "limit", cJSON_CreateNumber(1));
printf("📡 Connecting to %s...\n", relay_urls[0]);
printf("🔍 Requesting 1 type 1 event (text note)...\n\n");
// Query the relay
int result_count = 0;
int expected_events = 1;
cJSON** events = synchronous_query_relays_with_progress(
relay_urls,
relay_count,
filter,
RELAY_QUERY_FIRST_RESULT, // Return as soon as we get the first event
&result_count,
10, // 10 second timeout
progress_callback,
&expected_events
);
// Process results
if (events && result_count > 0) {
printf("\n✅ Successfully received %d event(s)!\n", result_count);
printf("📄 Raw JSON event data:\n");
printf("========================\n");
for (int i = 0; i < result_count; i++) {
char* json_string = cJSON_Print(events[i]);
if (json_string) {
printf("%s\n\n", json_string);
free(json_string);
}
cJSON_Delete(events[i]);
}
free(events);
printf("🎉 WebSocket SSL Test PASSED - OpenSSL WebSocket working correctly!\n");
} else {
printf("\n❌ No events received or query failed\n");
printf("❌ WebSocket SSL Test FAILED\n");
// Cleanup and return error
cJSON_Delete(filter);
nostr_cleanup();
return 1;
}
// Cleanup
cJSON_Delete(filter);
nostr_cleanup();
printf("✅ WebSocket connection and TLS working with OpenSSL\n");
return 0;
}