Working in the mines

This commit is contained in:
2025-08-16 08:51:04 -04:00
parent 76e883fad4
commit 9fd4c61df7
11 changed files with 37 additions and 522 deletions

View File

@@ -1,327 +0,0 @@
/*
* ChaCha20 Test Suite - RFC 8439 Reference Test Vectors
*
* This test suite validates our ChaCha20 implementation against the official
* test vectors from RFC 8439 "ChaCha20 and Poly1305 for IETF Protocols".
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include "../nostr_core/nostr_chacha20.h"
// Helper function to convert hex string to bytes
static int hex_to_bytes(const char* hex, uint8_t* bytes, size_t len) {
for (size_t i = 0; i < len; i++) {
if (sscanf(hex + 2*i, "%2hhx", &bytes[i]) != 1) {
return -1;
}
}
return 0;
}
// Helper function to convert bytes to hex string for display
static void bytes_to_hex(const uint8_t* bytes, size_t len, char* hex) {
for (size_t i = 0; i < len; i++) {
sprintf(hex + 2*i, "%02x", bytes[i]);
}
hex[2*len] = '\0';
}
// Helper function to compare byte arrays
static int bytes_equal(const uint8_t* a, const uint8_t* b, size_t len) {
return memcmp(a, b, len) == 0;
}
// Test 1: ChaCha Quarter Round (RFC 8439 Section 2.1.1)
static int test_quarter_round() {
printf("=== Test 1: ChaCha Quarter Round ===\n");
uint32_t state[16] = {0};
state[0] = 0x11111111;
state[1] = 0x01020304;
state[2] = 0x9b8d6f43;
state[3] = 0x01234567;
printf("Input: a=0x%08x, b=0x%08x, c=0x%08x, d=0x%08x\n",
state[0], state[1], state[2], state[3]);
chacha20_quarter_round(state, 0, 1, 2, 3);
printf("Output: a=0x%08x, b=0x%08x, c=0x%08x, d=0x%08x\n",
state[0], state[1], state[2], state[3]);
// Expected values from RFC 8439
uint32_t expected[4] = {0xea2a92f4, 0xcb1cf8ce, 0x4581472e, 0x5881c4bb};
if (state[0] == expected[0] && state[1] == expected[1] &&
state[2] == expected[2] && state[3] == expected[3]) {
printf("✅ Quarter round test PASSED\n\n");
return 1;
} else {
printf("❌ Quarter round test FAILED\n");
printf("Expected: a=0x%08x, b=0x%08x, c=0x%08x, d=0x%08x\n\n",
expected[0], expected[1], expected[2], expected[3]);
return 0;
}
}
// Test 2: ChaCha20 Block Function - RFC 8439 Appendix A.1 Test Vectors
static int test_chacha20_block_1() {
printf("=== Test 2: ChaCha20 Block Function - RFC 8439 Test Vectors ===\n");
uint8_t key[32] = {0};
uint8_t nonce[12] = {0};
uint8_t output0[64], output1[64];
printf("Key: all zeros\n");
printf("Nonce: all zeros\n");
// Test counter = 0 (RFC 8439 Appendix A.1 Test Vector #1)
printf("\nTesting counter = 0:\n");
chacha20_block(key, 0, nonce, output0);
char hex_output0[129];
bytes_to_hex(output0, 64, hex_output0);
printf("Counter=0 output: %s\n", hex_output0);
// Test counter = 1 (RFC 8439 Appendix A.1 Test Vector #2)
printf("\nTesting counter = 1:\n");
chacha20_block(key, 1, nonce, output1);
char hex_output1[129];
bytes_to_hex(output1, 64, hex_output1);
printf("Counter=1 output: %s\n", hex_output1);
// Expected for counter=0 from RFC 8439 Appendix A.1 Test Vector #1
const char* expected_counter0_hex =
"76b8e0ada0f13d90405d6ae55386bd28"
"bdd219b8a08ded1aa836efcc8b770dc7"
"da41597c5157488d7724e03fb8d84a37"
"6a43b8f41518a11cc387b669b2ee6586";
// Expected for counter=1 from RFC 8439 Appendix A.1 Test Vector #2
const char* expected_counter1_hex =
"9f07e7be5551387a98ba977c732d080d"
"cb0f29a048e3656912c6533e32ee7aed"
"29b721769ce64e43d57133b074d839d5"
"31ed1f28510afb45ace10a1f4b794d6f";
uint8_t expected0[64], expected1[64];
hex_to_bytes(expected_counter0_hex, expected0, 64);
hex_to_bytes(expected_counter1_hex, expected1, 64);
printf("\nExpected counter=0: %s\n", expected_counter0_hex);
printf("Expected counter=1: %s\n", expected_counter1_hex);
int test0_pass = bytes_equal(output0, expected0, 64);
int test1_pass = bytes_equal(output1, expected1, 64);
if (test0_pass) printf("✅ Counter=0 test PASSED\n");
else printf("❌ Counter=0 test FAILED\n");
if (test1_pass) printf("✅ Counter=1 test PASSED\n");
else printf("❌ Counter=1 test FAILED\n");
printf("\n");
return test0_pass && test1_pass; // Both tests must pass
}
// Test 3: ChaCha20 Block Function - Test Vector #2 (RFC 8439 Appendix A.1)
static int test_chacha20_block_2() {
printf("=== Test 3: ChaCha20 Block Function - Different Key ===\n");
// Key with last byte = 1, all-zero nonce, counter = 1
uint8_t key[32] = {0};
key[31] = 0x01; // Last byte = 1
uint8_t nonce[12] = {0};
uint32_t counter = 1;
uint8_t output[64];
printf("Key: all zeros except last byte = 0x01\n");
printf("Nonce: all zeros\n");
printf("Counter: %u\n", counter);
int result = chacha20_block(key, counter, nonce, output);
if (result != 0) {
printf("❌ ChaCha20 block function failed\n\n");
return 0;
}
// Expected output from RFC 8439 Appendix A.1 Test Vector #3
const char* expected_hex =
"3aeb5224ecf849929b9d828db1ced4dd"
"832025e8018b8160b82284f3c949aa5a"
"8eca00bbb4a73bdad192b5c42f73f2fd"
"4e273644c8b36125a64addeb006c13a0";
uint8_t expected[64];
hex_to_bytes(expected_hex, expected, 64);
char hex_output[129];
bytes_to_hex(output, 64, hex_output);
printf("Output: %s\n", hex_output);
if (bytes_equal(output, expected, 64)) {
printf("✅ ChaCha20 block test #2 PASSED\n\n");
return 1;
} else {
printf("❌ ChaCha20 block test #2 FAILED\n");
printf("Expected: %s\n\n", expected_hex);
return 0;
}
}
// Test 4: ChaCha20 Encryption - "Sunscreen" Test (RFC 8439 Section 2.4.2)
static int test_chacha20_encryption() {
printf("=== Test 4: ChaCha20 Encryption - Sunscreen Text ===\n");
// Key and nonce from RFC 8439 Section 2.4.2
const char* key_hex =
"000102030405060708090a0b0c0d0e0f"
"101112131415161718191a1b1c1d1e1f";
const char* nonce_hex = "000000000000004a00000000";
uint8_t key[32];
uint8_t nonce[12];
hex_to_bytes(key_hex, key, 32);
hex_to_bytes(nonce_hex, nonce, 12);
// Test plaintext (first part of "Sunscreen" text)
const char* plaintext =
"Ladies and Gentlemen of the class of '99: If I could offer you "
"only one tip for the future, sunscreen would be it.";
size_t plaintext_len = strlen(plaintext);
printf("Plaintext: \"%.50s...\"\n", plaintext);
printf("Length: %zu bytes\n", plaintext_len);
uint8_t ciphertext[256];
uint32_t counter = 1;
int result = chacha20_encrypt(key, counter, nonce,
(const uint8_t*)plaintext,
ciphertext, plaintext_len);
if (result != 0) {
printf("❌ ChaCha20 encryption failed\n\n");
return 0;
}
// Expected ciphertext (first 64 bytes) from RFC 8439
const char* expected_hex =
"6e2e359a2568f98041ba0728dd0d6981"
"e97e7aec1d4360c20a27afccfd9fae0b"
"f91b65c5524733ab8f593dabcd62b357"
"1639d624e65152ab8f530c359f0861d8";
uint8_t expected[64];
hex_to_bytes(expected_hex, expected, 64);
char hex_output[129];
bytes_to_hex(ciphertext, 64, hex_output);
printf("Ciphertext (first 64 bytes): %s\n", hex_output);
if (bytes_equal(ciphertext, expected, 64)) {
printf("✅ ChaCha20 encryption test PASSED\n");
// Test decryption (should get back original plaintext)
uint8_t decrypted[256];
result = chacha20_encrypt(key, counter, nonce, ciphertext, decrypted, plaintext_len);
if (result == 0 && memcmp(plaintext, decrypted, plaintext_len) == 0) {
printf("✅ ChaCha20 decryption test PASSED\n\n");
return 1;
} else {
printf("❌ ChaCha20 decryption test FAILED\n\n");
return 0;
}
} else {
printf("❌ ChaCha20 encryption test FAILED\n");
printf("Expected: %s\n\n", expected_hex);
return 0;
}
}
// Test 5: ChaCha20 Edge Cases and Additional Validation
static int test_chacha20_edge_cases() {
printf("=== Test 5: ChaCha20 Edge Cases and Additional Validation ===\n");
uint8_t key[32];
uint8_t nonce[12];
uint8_t input[64];
uint8_t output[64];
// Initialize test data
memset(key, 0, 32);
memset(nonce, 0, 12);
memset(input, 0xAA, 64); // Fill with test pattern
printf("Testing various scenarios...\n");
// Test 1: Counter = 0
int result1 = chacha20_encrypt(key, 0, nonce, input, output, 64);
printf("Counter=0 (64 bytes): %s\n", result1 == 0 ? "PASS" : "FAIL");
// Test 2: Counter = 1
int result2 = chacha20_encrypt(key, 1, nonce, input, output, 64);
printf("Counter=1 (64 bytes): %s\n", result2 == 0 ? "PASS" : "FAIL");
// Test 3: Empty data (0 bytes)
int result3 = chacha20_encrypt(key, 0, nonce, input, output, 0);
printf("Zero-length data: %s\n", result3 == 0 ? "PASS" : "FAIL");
// Test 4: Single byte
int result4 = chacha20_encrypt(key, 0, nonce, input, output, 1);
printf("Single byte: %s\n", result4 == 0 ? "PASS" : "FAIL");
// Test 5: Partial block (35 bytes)
int result5 = chacha20_encrypt(key, 0, nonce, input, output, 35);
printf("Partial block (35 bytes): %s\n", result5 == 0 ? "PASS" : "FAIL");
// Test 6: Multi-block (128 bytes)
uint8_t large_input[128];
uint8_t large_output[128];
memset(large_input, 0x55, 128);
int result6 = chacha20_encrypt(key, 0, nonce, large_input, large_output, 128);
printf("Multi-block (128 bytes): %s\n", result6 == 0 ? "PASS" : "FAIL");
if (result1 == 0 && result2 == 0 && result3 == 0 &&
result4 == 0 && result5 == 0 && result6 == 0) {
printf("✅ All edge case tests PASSED\n\n");
return 1;
} else {
printf("❌ Some edge case tests FAILED\n\n");
return 0;
}
}
// Main test function
int main() {
printf("🧪 ChaCha20 Test Suite - RFC 8439 Reference Vectors\n");
printf("=====================================================\n\n");
int passed = 0;
int total = 5;
if (test_quarter_round()) passed++;
if (test_chacha20_block_1()) passed++;
if (test_chacha20_block_2()) passed++;
if (test_chacha20_encryption()) passed++;
if (test_chacha20_edge_cases()) passed++;
printf("=== Test Summary ===\n");
printf("Passed: %d/%d tests\n", passed, total);
if (passed == total) {
printf("🎉 ALL CHACHA20 TESTS PASSED! 🎉\n");
printf("\nOur ChaCha20 implementation is RFC 8439 compliant and ready for production use.\n");
printf("✅ Quarter round operations work correctly\n");
printf("✅ Block function matches reference vectors\n");
printf("✅ Encryption/decryption is bidirectional\n");
printf("✅ Edge cases handled properly\n");
return 0;
} else {
printf("❌ Some tests failed. ChaCha20 implementation needs fixes.\n");
return 1;
}
}

View File

@@ -1,22 +0,0 @@
#include <stdio.h>
#include "../nostr_core/nostr_core.h"
int main(void) {
printf("=== Testing library initialization only ===\n");
printf("About to call nostr_init()...\n");
int result = nostr_init();
if (result != NOSTR_SUCCESS) {
printf("ERROR: Failed to initialize NOSTR library: %s\n", nostr_strerror(result));
return 1;
}
printf("✅ Library initialized successfully!\n");
printf("About to call nostr_cleanup()...\n");
nostr_cleanup();
printf("✅ Library cleanup completed!\n");
return 0;
}

View File

@@ -1,78 +0,0 @@
/*
* Single Test Vector to Debug Segfault
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../nostr_core/nostr_core.h"
void hex_to_bytes(const char* hex_str, unsigned char* bytes) {
size_t len = strlen(hex_str);
for (size_t i = 0; i < len; i += 2) {
sscanf(hex_str + i, "%2hhx", &bytes[i / 2]);
}
}
int main(void) {
printf("=== Single Test Vector Debug ===\n");
// Initialize the library
printf("Initializing library...\n");
if (nostr_init() != NOSTR_SUCCESS) {
printf("ERROR: Failed to initialize NOSTR library\n");
return 1;
}
printf("✅ Library initialized\n");
// Test Vector 1 data
const char* sk1_hex = "91ba716fa9e7ea2fcbad360cf4f8e0d312f73984da63d90f524ad61a6a1e7dbe";
const char* sk2_hex = "96f6fa197aa07477ab88f6981118466ae3a982faab8ad5db9d5426870c73d220";
const char* pk1_hex = "b38ce15d3d9874ee710dfabb7ff9801b1e0e20aace6e9a1a05fa7482a04387d1";
const char* pk2_hex = "dcb33a629560280a0ee3b6b99b68c044fe8914ad8a984001ebf6099a9b474dc3";
const char* plaintext = "nanana";
printf("Converting hex keys...\n");
unsigned char sk1[32], sk2[32], pk1[32], pk2[32];
hex_to_bytes(sk1_hex, sk1);
hex_to_bytes(sk2_hex, sk2);
hex_to_bytes(pk1_hex, pk1);
hex_to_bytes(pk2_hex, pk2);
printf("✅ Keys converted\n");
printf("Testing encryption...\n");
char encrypted[NOSTR_NIP04_MAX_ENCRYPTED_SIZE];
int result = nostr_nip04_encrypt(sk1, pk2, plaintext, encrypted, sizeof(encrypted));
if (result != NOSTR_SUCCESS) {
printf("❌ ENCRYPTION FAILED: %s\n", nostr_strerror(result));
nostr_cleanup();
return 1;
}
printf("✅ Encryption successful: %s\n", encrypted);
printf("Testing decryption...\n");
char decrypted[NOSTR_NIP04_MAX_PLAINTEXT_SIZE];
result = nostr_nip04_decrypt(sk2, pk1, encrypted, decrypted, sizeof(decrypted));
if (result != NOSTR_SUCCESS) {
printf("❌ DECRYPTION FAILED: %s\n", nostr_strerror(result));
nostr_cleanup();
return 1;
}
printf("✅ Decryption successful: \"%s\"\n", decrypted);
if (strcmp(plaintext, decrypted) == 0) {
printf("✅ TEST PASSED - Round-trip successful!\n");
} else {
printf("❌ TEST FAILED - Messages don't match\n");
nostr_cleanup();
return 1;
}
printf("Cleaning up...\n");
nostr_cleanup();
printf("✅ Test completed successfully!\n");
return 0;
}

View File

@@ -1,418 +0,0 @@
/*
* NOSTR Core Library - Static Linking Only Test (Binary Analysis Version)
*
* NOTE: For faster and more reliable static linking verification, see
* makefile_static_test.c which analyzes the build configuration directly.
* This test complements it by analyzing actual compiled binaries.
*
* This test verifies that the library maintains its self-contained,
* static-only design with no external cryptographic dependencies.
*
* Test Categories:
* 1. Library dependency analysis using ldd/otool
* 2. Symbol resolution verification using nm/objdump
* 3. Build process validation
* 4. Runtime independence verification
* 5. Library size and content verification
*/
#define _GNU_SOURCE // For popen/pclose on Linux
#include "../nostr_core/nostr_core.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include "../cjson/cJSON.h"
// ANSI color codes for output
#define GREEN "\033[32m"
#define RED "\033[31m"
#define YELLOW "\033[33m"
#define BLUE "\033[34m"
#define RESET "\033[0m"
// Test result tracking
static int tests_run = 0;
static int tests_passed = 0;
// Helper function to run shell commands and capture output
static int run_command(const char* command, char* output, size_t output_size) {
FILE* fp = popen(command, "r");
if (!fp) {
return -1;
}
size_t total = 0;
while (total < output_size - 1 && fgets(output + total, output_size - total, fp)) {
total = strlen(output);
}
int status = pclose(fp);
return WEXITSTATUS(status);
}
// Helper function to check if file exists
static int file_exists(const char* path) {
struct stat st;
return stat(path, &st) == 0;
}
// Test macro
#define RUN_TEST(test_name, test_func) do { \
printf(BLUE "[TEST] " RESET "%s...\n", test_name); \
tests_run++; \
if (test_func()) { \
printf(GREEN "[PASS] " RESET "%s\n\n", test_name); \
tests_passed++; \
} else { \
printf(RED "[FAIL] " RESET "%s\n\n", test_name); \
} \
} while(0)
// Test 1: Library Dependency Analysis
static int test_library_dependency_analysis(void) {
char command[512];
char output[4096];
int result;
// Check if we have the main library
if (!file_exists("../libnostr_core.a")) {
printf(RED "ERROR: " RESET "libnostr_core.a not found. Run 'make' first.\n");
return 0;
}
// Create a simple test binary to analyze
printf("Creating test binary for dependency analysis...\n");
const char* test_code =
"#include \"nostr_core/nostr_core.h\"\n"
"#include <stdio.h>\n"
"int main() {\n"
" if (nostr_init() == NOSTR_SUCCESS) {\n"
" unsigned char privkey[32], pubkey[32];\n"
" if (nostr_generate_keypair(privkey, pubkey) == NOSTR_SUCCESS) {\n"
" printf(\"Crypto test passed\\n\");\n"
" }\n"
" nostr_cleanup();\n"
" }\n"
" return 0;\n"
"}\n";
FILE* fp = fopen("/tmp/static_test.c", "w");
if (!fp) {
printf(RED "ERROR: " RESET "Cannot create temporary test file\n");
return 0;
}
fputs(test_code, fp);
fclose(fp);
// Compile the test binary
snprintf(command, sizeof(command),
"gcc -I.. -Wall -Wextra -std=c99 /tmp/static_test.c -o /tmp/static_test ../libnostr_core.a -lm -static 2>/dev/null");
result = system(command);
if (result != 0) {
printf(RED "ERROR: " RESET "Failed to compile test binary\n");
return 0;
}
// Analyze dependencies with ldd (Linux) or otool (macOS)
printf("Analyzing binary dependencies...\n");
#ifdef __linux__
snprintf(command, sizeof(command), "ldd /tmp/static_test 2>&1");
#elif __APPLE__
snprintf(command, sizeof(command), "otool -L /tmp/static_test 2>&1");
#else
printf(YELLOW "WARNING: " RESET "Unknown platform, skipping dependency analysis\n");
cleanup_and_return:
unlink("/tmp/static_test.c");
unlink("/tmp/static_test");
return 1;
#endif
result = run_command(command, output, sizeof(output));
// Check for problematic dynamic dependencies (updated for OpenSSL migration)
const char* forbidden_libs[] = {
"libsecp256k1", // Should be statically linked
"libwally", // Not used
"libsodium" // Not used
};
int found_forbidden = 0;
for (int i = 0; i < 3; i++) {
if (strstr(output, forbidden_libs[i])) {
printf(RED "ERROR: " RESET "Found forbidden dynamic dependency: %s\n", forbidden_libs[i]);
found_forbidden = 1;
}
}
if (!found_forbidden) {
printf(GREEN "GOOD: " RESET "No forbidden cryptographic dependencies found\n");
}
// For static binaries, ldd should say "not a dynamic executable" or show minimal deps
#ifdef __linux__
if (strstr(output, "not a dynamic executable") || strstr(output, "statically linked")) {
printf(GREEN "EXCELLENT: " RESET "Binary is statically linked\n");
} else {
printf(YELLOW "INFO: " RESET "Binary appears to have some dynamic dependencies:\n");
printf("%s\n", output);
}
#endif
// Cleanup
unlink("/tmp/static_test.c");
unlink("/tmp/static_test");
return !found_forbidden;
}
// Test 2: Symbol Resolution Verification
static int test_symbol_resolution_verification(void) {
printf("Verifying secp256k1 symbols are present in static library...\n");
// Use system() command instead of popen to avoid buffer issues
int result = system("nm ../libnostr_core.a | grep -q secp256k1 2>/dev/null");
if (result != 0) {
printf(RED "ERROR: " RESET "No secp256k1 symbols found in library\n");
return 0;
}
// Test individual symbols with specific commands
const char* required_symbols[] = {
"nostr_secp256k1_context_create",
"nostr_secp256k1_ec_pubkey_create",
"nostr_secp256k1_schnorrsig_sign32",
"nostr_secp256k1_schnorrsig_verify",
"nostr_secp256k1_ecdh"
};
int symbols_found = 0;
char command[256];
for (int i = 0; i < 5; i++) {
snprintf(command, sizeof(command), "nm ../libnostr_core.a | grep -q '%s' 2>/dev/null", required_symbols[i]);
if (system(command) == 0) {
symbols_found++;
printf(GREEN "FOUND: " RESET "%s\n", required_symbols[i]);
} else {
printf(YELLOW "MISSING: " RESET "%s\n", required_symbols[i]);
}
}
if (symbols_found >= 3) {
printf(GREEN "GOOD: " RESET "Found %d/5 critical secp256k1 symbols\n", symbols_found);
return 1;
} else {
printf(RED "ERROR: " RESET "Only found %d/5 critical secp256k1 symbols\n", symbols_found);
return 0;
}
}
// Test 3: Build Process Validation
static int test_build_process_validation(void) {
char command[512];
int result;
printf("Testing minimal build requirements...\n");
// Test that we can build with only libnostr_core.a and -lm
const char* minimal_test =
"#include \"nostr_core/nostr_core.h\"\n"
"int main() { return nostr_init() == NOSTR_SUCCESS ? 0 : 1; }\n";
FILE* fp = fopen("/tmp/minimal_test.c", "w");
if (!fp) return 0;
fputs(minimal_test, fp);
fclose(fp);
// Try to build with minimal dependencies
snprintf(command, sizeof(command),
"gcc -I.. -Wall -Wextra -std=c99 /tmp/minimal_test.c -o /tmp/minimal_test ../libnostr_core.a -lm 2>/dev/null");
result = system(command);
unlink("/tmp/minimal_test.c");
if (result == 0) {
printf(GREEN "EXCELLENT: " RESET "Can build with only libnostr_core.a and -lm\n");
// Test that it actually runs
result = system("/tmp/minimal_test");
unlink("/tmp/minimal_test");
if (result == 0) {
printf(GREEN "EXCELLENT: " RESET "Minimal binary runs successfully\n");
return 1;
} else {
printf(RED "ERROR: " RESET "Minimal binary failed to run\n");
return 0;
}
} else {
printf(RED "ERROR: " RESET "Cannot build with minimal dependencies\n");
unlink("/tmp/minimal_test");
return 0;
}
}
// Test 4: Runtime Independence Test
static int test_runtime_independence(void) {
printf("Testing runtime independence (crypto functionality)...\n");
// Initialize the library
if (nostr_init() != NOSTR_SUCCESS) {
printf(RED "ERROR: " RESET "Library initialization failed\n");
return 0;
}
// Test key generation
unsigned char private_key[32];
unsigned char public_key[32];
if (nostr_generate_keypair(private_key, public_key) != NOSTR_SUCCESS) {
printf(RED "ERROR: " RESET "Key generation failed\n");
nostr_cleanup();
return 0;
}
printf(GREEN "GOOD: " RESET "Key generation works\n");
// Test bech32 encoding
char nsec[100], npub[100];
if (nostr_key_to_bech32(private_key, "nsec", nsec) != NOSTR_SUCCESS ||
nostr_key_to_bech32(public_key, "npub", npub) != NOSTR_SUCCESS) {
printf(RED "ERROR: " RESET "Bech32 encoding failed\n");
nostr_cleanup();
return 0;
}
printf(GREEN "GOOD: " RESET "Bech32 encoding works\n");
// Test signing
cJSON* event = nostr_create_and_sign_event(1, "Test message", NULL, private_key, 0);
if (!event) {
printf(RED "ERROR: " RESET "Event creation/signing failed\n");
nostr_cleanup();
return 0;
}
printf(GREEN "GOOD: " RESET "Event signing works\n");
cJSON_Delete(event);
// Test NIP-44 encryption if available
char plaintext[] = "Hello, NOSTR!";
char encrypted[1024];
char decrypted[1024];
// Generate recipient keys
unsigned char recipient_private[32], recipient_public[32];
nostr_generate_keypair(recipient_private, recipient_public);
if (nostr_nip44_encrypt(private_key, recipient_public, plaintext, encrypted, sizeof(encrypted)) == NOSTR_SUCCESS) {
if (nostr_nip44_decrypt(recipient_private, public_key, encrypted, decrypted, sizeof(decrypted)) == NOSTR_SUCCESS) {
if (strcmp(plaintext, decrypted) == 0) {
printf(GREEN "EXCELLENT: " RESET "NIP-44 encryption/decryption works\n");
} else {
printf(YELLOW "WARNING: " RESET "NIP-44 decryption mismatch\n");
}
} else {
printf(YELLOW "WARNING: " RESET "NIP-44 decryption failed\n");
}
} else {
printf(YELLOW "WARNING: " RESET "NIP-44 encryption failed (may not be enabled)\n");
}
nostr_cleanup();
return 1;
}
// Test 5: Library Size and Content Verification
static int test_library_size_and_content(void) {
struct stat st;
char command[512];
char output[4096];
printf("Verifying library size and content...\n");
// Check library size
if (stat("../libnostr_core.a", &st) != 0) {
printf(RED "ERROR: " RESET "Cannot stat libnostr_core.a\n");
return 0;
}
size_t lib_size = st.st_size;
printf("Library size: %zu bytes (%.2f MB)\n", lib_size, lib_size / 1024.0 / 1024.0);
// Expect "fat" library to be at least 1MB (with secp256k1 bundled)
if (lib_size < 1024 * 1024) {
printf(YELLOW "WARNING: " RESET "Library seems small (%.2f MB). May not include secp256k1.\n",
lib_size / 1024.0 / 1024.0);
} else {
printf(GREEN "GOOD: " RESET "Library size suggests secp256k1 is bundled\n");
}
// List archive contents
snprintf(command, sizeof(command), "ar -t ../libnostr_core.a | wc -l");
if (run_command(command, output, sizeof(output)) == 0) {
int object_count = atoi(output);
printf("Archive contains %d object files\n", object_count);
if (object_count > 20) {
printf(GREEN "EXCELLENT: " RESET "High object count suggests secp256k1 objects included\n");
} else {
printf(YELLOW "WARNING: " RESET "Low object count (%d). secp256k1 may not be fully bundled\n", object_count);
}
}
// Check for secp256k1-specific object files
snprintf(command, sizeof(command), "ar -t ../libnostr_core.a | grep -E '(secp256k1|ecmult)' | head -5");
if (run_command(command, output, sizeof(output)) == 0 && strlen(output) > 0) {
printf(GREEN "EXCELLENT: " RESET "Found secp256k1 object files in archive:\n");
printf("%s", output);
} else {
printf(YELLOW "WARNING: " RESET "No obvious secp256k1 object files found\n");
}
return 1;
}
// Main test runner
int main(int argc, char* argv[]) {
(void)argc;
(void)argv;
printf(BLUE "NOSTR Core Library - Static Linking Only Test\n");
printf("==============================================" RESET "\n\n");
printf("This test verifies that the library maintains its self-contained,\n");
printf("static-only design with no external cryptographic dependencies.\n\n");
// Run all tests
RUN_TEST("Library Dependency Analysis", test_library_dependency_analysis);
RUN_TEST("Symbol Resolution Verification", test_symbol_resolution_verification);
RUN_TEST("Build Process Validation", test_build_process_validation);
RUN_TEST("Runtime Independence Test", test_runtime_independence);
RUN_TEST("Library Size and Content Verification", test_library_size_and_content);
// Print summary
printf(BLUE "============================================\n");
printf("TEST SUMMARY\n");
printf("============================================" RESET "\n");
printf("Tests run: %d\n", tests_run);
printf("Tests passed: %d\n", tests_passed);
if (tests_passed == tests_run) {
printf(GREEN "ALL TESTS PASSED!" RESET "\n");
printf("✅ Library maintains static-only design\n");
printf("✅ No external crypto dependencies\n");
printf("✅ Self-contained and portable\n");
} else {
printf(RED "SOME TESTS FAILED!" RESET "\n");
printf("❌ %d out of %d tests failed\n", tests_run - tests_passed, tests_run);
printf("⚠️ Library may have external dependencies or missing components\n");
}
return (tests_passed == tests_run) ? 0 : 1;
}

View File

@@ -1,180 +0,0 @@
/*
* Synchronous Relay Query Test Program
*
* Tests the synchronous_query_relays_with_progress function
* with all three query modes: FIRST_RESULT, MOST_RECENT, ALL_RESULTS
*
* Usage: Uncomment only ONE test mode at the top of main()
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "../nostr_core/nostr_core.h"
#include "../cjson/cJSON.h"
// Helper function to get mode name for display
const char* get_mode_name(relay_query_mode_t mode) {
switch (mode) {
case RELAY_QUERY_FIRST_RESULT: return "FIRST_RESULT";
case RELAY_QUERY_MOST_RECENT: return "MOST_RECENT";
case RELAY_QUERY_ALL_RESULTS: return "ALL_RESULTS";
default: return "UNKNOWN";
}
}
// Progress callback to show raw relay activity
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) {
(void)user_data; // Unused parameter
printf("[PROGRESS] ");
if (relay_url) {
printf("%s | %s", relay_url, status);
if (event_id) {
printf(" | Event: %.12s...", event_id);
}
printf(" | Events: %d | Relays: %d/%d\n",
events_received, completed_relays, total_relays);
} else {
printf("SUMMARY | %s | Events: %d | Relays: %d/%d\n",
status, events_received, completed_relays, total_relays);
}
fflush(stdout);
}
int main() {
// Initialize NOSTR library
if (nostr_init() != NOSTR_SUCCESS) {
fprintf(stderr, "Failed to initialize NOSTR library\n");
return 1;
}
// ============================================================================
// TEST SELECTION - Uncomment only ONE test at a time
// ============================================================================
// relay_query_mode_t test_mode = RELAY_QUERY_FIRST_RESULT;
// relay_query_mode_t test_mode = RELAY_QUERY_MOST_RECENT;
relay_query_mode_t test_mode = RELAY_QUERY_ALL_RESULTS;
// ============================================================================
// Hard-coded test configuration
// ============================================================================
const char* test_relays[] = {
"ws://127.0.0.1:7777",
"wss://relay.laantungir.net",
"wss://relay.corpum.com"
};
int relay_count = 3;
// ============================================================================
// FILTER CONFIGURATION - Edit this JSON string to change the query
// ============================================================================
const char* filter_json =
"{"
" \"kinds\": [1],"
" \"limit\": 1"
"}";
// Alternative filter examples (comment out the one above, uncomment one below):
// Get kind 0 (profile) events:
// const char* filter_json = "{\"kinds\": [0], \"limit\": 5}";
// Get events from specific author (replace with real pubkey):
// const char* filter_json = "{\"authors\": [\"e88a691e98d9987c964521dff60025f60700378a4879180dcbbb4a5027850411\"], \"kinds\": [1], \"limit\": 20}";
// Get recent events with specific hashtag:
// const char* filter_json = "{\"kinds\": [1], \"#t\": [\"nostr\"], \"limit\": 15}";
// Get events since specific timestamp:
// const char* filter_json = "{\"kinds\": [1], \"since\": 1706825234, \"limit\": 10}";
// Parse the filter JSON string
cJSON* filter = cJSON_Parse(filter_json);
if (!filter) {
fprintf(stderr, "ERROR: Failed to parse filter JSON:\n%s\n", filter_json);
fprintf(stderr, "Check JSON syntax and try again.\n");
nostr_cleanup();
return 1;
}
// ============================================================================
// Run the test
// ============================================================================
printf("=== SYNCHRONOUS RELAY QUERY TEST ===\n");
printf("Mode: %s\n", get_mode_name(test_mode));
printf("Querying %d relays with 5 second timeout...\n\n", relay_count);
// Print relay list
printf("Test relays:\n");
for (int i = 0; i < relay_count; i++) {
printf(" %d. %s\n", i + 1, test_relays[i]);
}
printf("\n");
// Print filter
char* filter_str = cJSON_Print(filter);
printf("Filter: %s\n\n", filter_str);
free(filter_str);
int result_count = 0;
time_t start_time = time(NULL);
printf("Starting query...\n\n");
cJSON** results = synchronous_query_relays_with_progress(
test_relays, relay_count, filter, test_mode,
&result_count, 5, progress_callback, NULL
);
time_t end_time = time(NULL);
// ============================================================================
// Print raw results
// ============================================================================
printf("\n=== RAW RESULTS ===\n");
printf("Execution time: %ld seconds\n", end_time - start_time);
printf("Events returned: %d\n\n", result_count);
if (results && result_count > 0) {
for (int i = 0; i < result_count; i++) {
printf("--- EVENT %d ---\n", i + 1);
char* json_str = cJSON_Print(results[i]);
if (json_str) {
printf("%s\n\n", json_str);
free(json_str);
} else {
printf("ERROR: Failed to serialize event to JSON\n\n");
}
}
} else {
printf("No events returned.\n\n");
}
// ============================================================================
// Cleanup
// ============================================================================
if (results) {
for (int i = 0; i < result_count; i++) {
if (results[i]) {
cJSON_Delete(results[i]);
}
}
free(results);
}
cJSON_Delete(filter);
nostr_cleanup();
printf("Test completed.\n");
return 0;
}