/* * NIP-04 Encryption DEBUG Test * This test shows intermediate values to compare with JavaScript implementation */ #include #include #include #include "../nostr_core/nip004.h" #include "../nostr_core/nostr_common.h" #include "../nostr_core/crypto/nostr_secp256k1.h" #include "../nostr_core/utils.h" void print_hex_debug(const char* label, const unsigned char* data, size_t len) { printf("%s (%zu bytes): ", label, len); for (size_t i = 0; i < len; i++) { printf("%02x", data[i]); } printf("\n"); } 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 test_ecdh_debug(void) { printf("\n=== ECDH DEBUG TEST ===\n"); // Test vector from JavaScript debug output const char* sk1_hex = "91ba716fa9e7ea2fcbad360cf4f8e0d312f73984da63d90f524ad61a6a1e7dbe"; const char* pk2_hex = "dcb33a629560280a0ee3b6b99b68c044fe8914ad8a984001ebf6099a9b474dc3"; // Expected values from JavaScript: // Shared Secret (33 bytes): 037ce22696eb0e303ddaa491bdf2a56b79d249f2d861b8e012a933e01dc4beba81 // Normalized Key (32 bytes): 7ce22696eb0e303ddaa491bdf2a56b79d249f2d861b8e012a933e01dc4beba81 unsigned char sk1[32], pk2[32]; hex_to_bytes(sk1_hex, sk1); hex_to_bytes(pk2_hex, pk2); printf("Private Key: %s\n", sk1_hex); printf("Public Key: %s\n", pk2_hex); print_hex_debug("SK1", sk1, 32); print_hex_debug("PK2", pk2, 32); // Test ECDH shared secret computation unsigned char shared_secret[32]; printf("\nCalling ecdh_shared_secret...\n"); int result = ecdh_shared_secret(sk1, pk2, shared_secret); printf("ecdh_shared_secret returned: %d\n", result); if (result == 0) { print_hex_debug("C Shared Secret", shared_secret, 32); printf("Expected: 7ce22696eb0e303ddaa491bdf2a56b79d249f2d861b8e012a933e01dc4beba81\n"); // Check if it matches expected const char* expected_hex = "7ce22696eb0e303ddaa491bdf2a56b79d249f2d861b8e012a933e01dc4beba81"; unsigned char expected[32]; hex_to_bytes(expected_hex, expected); if (memcmp(shared_secret, expected, 32) == 0) { printf("✅ ECDH matches expected value!\n"); return 1; } else { printf("❌ ECDH does NOT match expected value\n"); print_hex_debug("Expected", expected, 32); return 0; } } else { printf("❌ ECDH computation failed with error code: %d\n", result); return 0; } } int test_encryption_step_by_step(void) { printf("\n=== STEP-BY-STEP ENCRYPTION DEBUG ===\n"); // Test vector 1 data const char* sk1_hex = "91ba716fa9e7ea2fcbad360cf4f8e0d312f73984da63d90f524ad61a6a1e7dbe"; const char* pk2_hex = "dcb33a629560280a0ee3b6b99b68c044fe8914ad8a984001ebf6099a9b474dc3"; const char* plaintext = "nanana"; // Known IV from JavaScript test (to get deterministic results) const char* fixed_iv_hex = "115e5b52371ce0e5f62a6ff33e9e2775"; printf("Private Key: %s\n", sk1_hex); printf("Public Key: %s\n", pk2_hex); printf("Plaintext: \"%s\"\n", plaintext); printf("Fixed IV: %s\n", fixed_iv_hex); unsigned char sk1[32], pk2[32], fixed_iv[16]; hex_to_bytes(sk1_hex, sk1); hex_to_bytes(pk2_hex, pk2); hex_to_bytes(fixed_iv_hex, fixed_iv); // Step 1: ECDH printf("\n--- Step 1: ECDH Shared Secret ---\n"); unsigned char shared_secret[32]; if (ecdh_shared_secret(sk1, pk2, shared_secret) != 0) { printf("❌ ECDH failed\n"); return 0; } print_hex_debug("Shared Secret", shared_secret, 32); printf("Expected: 7ce22696eb0e303ddaa491bdf2a56b79d249f2d861b8e012a933e01dc4beba81\n"); // Step 2: Convert plaintext to bytes printf("\n--- Step 2: Plaintext to UTF-8 bytes ---\n"); size_t plaintext_len = strlen(plaintext); printf("UTF-8 Plaintext (%zu bytes): ", plaintext_len); for (size_t i = 0; i < plaintext_len; i++) { printf("%02x", (unsigned char)plaintext[i]); } printf("\n"); printf("Expected: 6e616e616e61\n"); // Step 3: PKCS#7 padding printf("\n--- Step 3: PKCS#7 Padding ---\n"); size_t padded_len = ((plaintext_len / 16) + 1) * 16; unsigned char* padded_data = malloc(padded_len); if (!padded_data) { printf("❌ Memory allocation failed\n"); return 0; } memcpy(padded_data, plaintext, plaintext_len); // Manual PKCS#7 padding for debugging size_t padding_needed = 16 - (plaintext_len % 16); for (size_t i = 0; i < padding_needed; i++) { padded_data[plaintext_len + i] = (unsigned char)padding_needed; } size_t actual_padded_len = plaintext_len + padding_needed; print_hex_debug("Padded Data", padded_data, actual_padded_len); printf("Padding bytes added: %zu (value: 0x%02x)\n", padding_needed, (unsigned char)padding_needed); // Step 4: Try calling the full encryption function printf("\n--- Step 4: Full Encryption Function ---\n"); char* encrypted = malloc(NOSTR_NIP04_MAX_ENCRYPTED_SIZE); if (!encrypted) { printf("❌ Memory allocation failed\n"); free(padded_data); return 0; } printf("Calling nostr_nip04_encrypt...\n"); int result = nostr_nip04_encrypt(sk1, pk2, plaintext, encrypted, NOSTR_NIP04_MAX_ENCRYPTED_SIZE); printf("nostr_nip04_encrypt returned: %d (%s)\n", result, nostr_strerror(result)); if (result == NOSTR_SUCCESS) { printf("✅ Encryption succeeded!\n"); printf("Result: %s\n", encrypted); printf("Expected: zJxfaJ32rN5Dg1ODjOlEew==?iv=EV5bUjcc4OX2Km/zPp4ndQ==\n"); } else { printf("❌ Encryption failed with error: %s\n", nostr_strerror(result)); } free(padded_data); free(encrypted); return result == NOSTR_SUCCESS ? 1 : 0; } int main(void) { printf("=== NIP-04 DEBUG TEST ===\n"); printf("This test shows intermediate values for comparison with JavaScript implementation\n\n"); // Initialize secp256k1 context printf("Initializing secp256k1 context...\n"); if (!nostr_secp256k1_context_create()) { printf("❌ Failed to initialize secp256k1 context!\n"); return 1; } printf("✅ secp256k1 context initialized successfully\n\n"); int all_passed = 1; // Test 1: ECDH computation if (!test_ecdh_debug()) { all_passed = 0; printf("❌ ECDH test failed - this is likely the root cause!\n"); } // Test 2: Step by step encryption if (!test_encryption_step_by_step()) { all_passed = 0; } // Summary printf("\n=== SUMMARY ===\n"); if (all_passed) { printf("✅ All debug tests passed!\n"); } else { printf("❌ Some debug tests failed - compare values with JavaScript output\n"); } // Clean up secp256k1 context nostr_secp256k1_context_destroy(); return all_passed ? 0 : 1; }