Working in the mines
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user