/* * NIP-44 Encryption/Decryption Test * * Test suite for NIP-44 versioned encryption functionality * Uses known test vectors and cross-implementation compatibility tests */ #include #include #include #include #include "../nostr_core/nostr_core.h" // Test vectors for NIP-44 with proper key pairs typedef struct { const char* name; const char* sender_private_key_hex; const char* recipient_private_key_hex; // FIX: Need proper private key, not public key const char* plaintext; const char* expected_encrypted; // Optional - for known test vectors } nip44_test_vector_t; // Known test vectors from nostr-tools nip44.vectors.json static nip44_test_vector_t known_test_vectors[] = { { "Known vector: single char 'a'", "0000000000000000000000000000000000000000000000000000000000000001", // sec1 "0000000000000000000000000000000000000000000000000000000000000002", // sec2 "a", "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABee0G5VSK0/9YypIObAtDKfYEAjD35uVkHyB0F4DwrcNaCXlCWZKaArsGrY6M9wnuTMxWfp1RTN9Xga8no+kF5Vsb" }, { "Known vector: emoji", "0000000000000000000000000000000000000000000000000000000000000002", // sec1 "0000000000000000000000000000000000000000000000000000000000000001", // sec2 "πŸ•πŸ«ƒ", "AvAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAPSKSK6is9ngkX2+cSq85Th16oRTISAOfhStnixqZziKMDvB0QQzgFZdjLTPicCJaV8nDITO+QfaQ61+KbWQIOO2Yj" }, { "Known vector: wide unicode", "5c0c523f52a5b6fad39ed2403092df8cebc36318b39383bca6c00808626fab3a", // sec1 "4b22aa260e4acb7021e32f38a6cdf4b673c6a277755bfce287e370c924dc936d", // sec2 "葨ポあAι·—Ε’Γ©οΌ’ι€ΓœΓŸΒͺąñ丂㐀𠀀", "ArY1I2xC2yDwIbuNHN/1ynXdGgzHLqdCrXUPMwELJPc7s7JqlCMJBAIIjfkpHReBPXeoMCyuClwgbT419jUWU1PwaNl4FEQYKCDKVJz+97Mp3K+Q2YGa77B6gpxB/lr1QgoqpDf7wDVrDmOqGoiPjWDqy8KzLueKDcm9BVP8xeTJIxs=" } }; // Round-trip test vectors with proper key pairs static nip44_test_vector_t test_vectors[] = { { "Basic short message", "91ba716fa9e7ea2fcbad360cf4f8e0d312f73984da63d90f524ad61a6a1e7dbe", // Working keys from simple_nip44_test "96f6fa197aa07477ab88f6981118466ae3a982faab8ad5db9d5426870c73d220", "Hello, NIP-44!", NULL }, { "Unicode message", "1111111111111111111111111111111111111111111111111111111111111111", "2222222222222222222222222222222222222222222222222222222222222222", "Hello 🌍 World! πŸš€", NULL }, { "Empty message", "3333333333333333333333333333333333333333333333333333333333333333", "4444444444444444444444444444444444444444444444444444444444444444", "", NULL } }; static int hex_to_bytes(const char* hex, unsigned char* bytes, size_t len) { if (strlen(hex) != len * 2) return -1; for (size_t i = 0; i < len; i++) { if (sscanf(hex + i * 2, "%2hhx", &bytes[i]) != 1) { return -1; } } return 0; } static void bytes_to_hex(const unsigned char* bytes, size_t len, char* hex) { for (size_t i = 0; i < len; i++) { sprintf(hex + i * 2, "%02x", bytes[i]); } hex[len * 2] = '\0'; } static int test_nip44_round_trip(const nip44_test_vector_t* tv) { printf("Testing: %s\n", tv->name); // Parse keys - both private keys unsigned char sender_private_key[32]; unsigned char recipient_private_key[32]; if (hex_to_bytes(tv->sender_private_key_hex, sender_private_key, 32) != 0) { printf(" ❌ Failed to parse sender private key\n"); return -1; } if (hex_to_bytes(tv->recipient_private_key_hex, recipient_private_key, 32) != 0) { printf(" ❌ Failed to parse recipient private key\n"); return -1; } // Generate the public keys from the private keys unsigned char sender_public_key[32]; unsigned char recipient_public_key[32]; if (nostr_ec_public_key_from_private_key(sender_private_key, sender_public_key) != 0) { printf(" ❌ Failed to derive sender public key\n"); return -1; } if (nostr_ec_public_key_from_private_key(recipient_private_key, recipient_public_key) != 0) { printf(" ❌ Failed to derive recipient public key\n"); return -1; } // Test encryption char encrypted[8192]; // Large buffer for encrypted data int encrypt_result = nostr_nip44_encrypt( sender_private_key, recipient_public_key, tv->plaintext, encrypted, sizeof(encrypted) ); if (encrypt_result != NOSTR_SUCCESS) { printf(" ❌ Encryption failed with error: %d\n", encrypt_result); return -1; } printf(" βœ… Encryption successful\n"); printf(" πŸ“¦ Encrypted length: %zu bytes\n", strlen(encrypted)); // Test decryption - use recipient private key + sender public key char decrypted[8192]; // Large buffer for decrypted data int decrypt_result = nostr_nip44_decrypt( recipient_private_key, sender_public_key, encrypted, decrypted, sizeof(decrypted) ); if (decrypt_result != NOSTR_SUCCESS) { printf(" ❌ Decryption failed with error: %d\n", decrypt_result); return -1; } // Verify round-trip if (strcmp(tv->plaintext, decrypted) != 0) { printf(" ❌ Round-trip failed!\n"); printf(" πŸ“ Original: \"%s\"\n", tv->plaintext); printf(" πŸ“ Decrypted: \"%s\"\n", decrypted); return -1; } printf(" βœ… Round-trip successful!\n"); printf(" πŸ“ Message: \"%s\"\n", tv->plaintext); printf("\n"); return 0; } static int test_nip44_error_conditions() { printf("Testing NIP-44 error conditions:\n"); // Use proper valid secp256k1 private keys unsigned char valid_sender_key[32]; unsigned char valid_recipient_key[32]; unsigned char valid_recipient_pubkey[32]; hex_to_bytes("0000000000000000000000000000000000000000000000000000000000000001", valid_sender_key, 32); hex_to_bytes("0000000000000000000000000000000000000000000000000000000000000002", valid_recipient_key, 32); // Generate the recipient's public key if (nostr_ec_public_key_from_private_key(valid_recipient_key, valid_recipient_pubkey) != 0) { printf(" ❌ Failed to generate recipient public key\n"); return -1; } char output[1024]; // Test NULL parameters int result = nostr_nip44_encrypt(NULL, valid_recipient_pubkey, "test", output, sizeof(output)); if (result != NOSTR_ERROR_INVALID_INPUT) { printf(" ❌ Should reject NULL sender key\n"); return -1; } result = nostr_nip44_encrypt(valid_sender_key, NULL, "test", output, sizeof(output)); if (result != NOSTR_ERROR_INVALID_INPUT) { printf(" ❌ Should reject NULL recipient key\n"); return -1; } result = nostr_nip44_encrypt(valid_sender_key, valid_recipient_pubkey, NULL, output, sizeof(output)); if (result != NOSTR_ERROR_INVALID_INPUT) { printf(" ❌ Should reject NULL plaintext\n"); return -1; } result = nostr_nip44_encrypt(valid_sender_key, valid_recipient_pubkey, "test", NULL, sizeof(output)); if (result != NOSTR_ERROR_INVALID_INPUT) { printf(" ❌ Should reject NULL output buffer\n"); return -1; } // Test buffer too small char small_buffer[10]; result = nostr_nip44_encrypt(valid_sender_key, valid_recipient_pubkey, "test message", small_buffer, sizeof(small_buffer)); if (result != NOSTR_ERROR_NIP44_BUFFER_TOO_SMALL) { printf(" ❌ Should detect buffer too small, got error: %d\n", result); return -1; } printf(" βœ… All error conditions handled correctly\n\n"); return 0; } static int test_nip44_known_vector(const nip44_test_vector_t* tv) { printf("Testing known vector: %s\n", tv->name); // Parse keys unsigned char sender_private_key[32]; unsigned char recipient_private_key[32]; if (hex_to_bytes(tv->sender_private_key_hex, sender_private_key, 32) != 0) { printf(" ❌ Failed to parse sender private key\n"); return -1; } if (hex_to_bytes(tv->recipient_private_key_hex, recipient_private_key, 32) != 0) { printf(" ❌ Failed to parse recipient private key\n"); return -1; } // Generate the public keys from the private keys unsigned char sender_public_key[32]; if (nostr_ec_public_key_from_private_key(sender_private_key, sender_public_key) != 0) { printf(" ❌ Failed to derive sender public key\n"); return -1; } // Test decryption of known vector char decrypted[8192]; int decrypt_result = nostr_nip44_decrypt( recipient_private_key, sender_public_key, tv->expected_encrypted, decrypted, sizeof(decrypted) ); if (decrypt_result != NOSTR_SUCCESS) { printf(" ❌ Decryption of known vector failed with error: %d\n", decrypt_result); printf(" πŸ“¦ Expected payload: %.80s...\n", tv->expected_encrypted); return -1; } // Verify decrypted plaintext matches expected if (strcmp(tv->plaintext, decrypted) != 0) { printf(" ❌ Decrypted plaintext doesn't match!\n"); printf(" πŸ“ Expected: \"%s\"\n", tv->plaintext); printf(" πŸ“ Got: \"%s\"\n", decrypted); return -1; } printf(" βœ… Known vector decryption successful!\n"); printf(" πŸ“ Message: \"%s\"\n", tv->plaintext); printf("\n"); return 0; } static int test_nip44_vs_nip04_comparison() { printf("Testing NIP-44 vs NIP-04 comparison:\n"); const char* test_message = "This is a test message for comparing NIP-04 and NIP-44 encryption methods."; unsigned char sender_key[32], recipient_key[32]; memset(sender_key, 0x11, 32); memset(recipient_key, 0x22, 32); // Generate proper public keys unsigned char sender_pubkey[32], recipient_pubkey[32]; if (nostr_ec_public_key_from_private_key(sender_key, sender_pubkey) != 0 || nostr_ec_public_key_from_private_key(recipient_key, recipient_pubkey) != 0) { printf(" ❌ Failed to generate public keys\n"); return -1; } // Test NIP-04 encryption char nip04_encrypted[8192]; int nip04_result = nostr_nip04_encrypt(sender_key, recipient_pubkey, test_message, nip04_encrypted, sizeof(nip04_encrypted)); // Test NIP-44 encryption char nip44_encrypted[8192]; int nip44_result = nostr_nip44_encrypt(sender_key, recipient_pubkey, test_message, nip44_encrypted, sizeof(nip44_encrypted)); if (nip04_result == NOSTR_SUCCESS && nip44_result == NOSTR_SUCCESS) { printf(" βœ… Both NIP-04 and NIP-44 encryption successful\n"); printf(" πŸ“Š NIP-04 output length: %zu bytes\n", strlen(nip04_encrypted)); printf(" πŸ“Š NIP-44 output length: %zu bytes\n", strlen(nip44_encrypted)); printf(" πŸ“Š Size difference: %+ld bytes\n", (long)strlen(nip44_encrypted) - (long)strlen(nip04_encrypted)); // Verify they produce different outputs (they use different algorithms) if (strcmp(nip04_encrypted, nip44_encrypted) == 0) { printf(" ⚠️ Warning: NIP-04 and NIP-44 produced identical output (unexpected)\n"); } else { printf(" βœ… NIP-04 and NIP-44 produce different outputs (expected)\n"); } } else { if (nip04_result != NOSTR_SUCCESS) { printf(" ❌ NIP-04 encryption failed: %d\n", nip04_result); } if (nip44_result != NOSTR_SUCCESS) { printf(" ❌ NIP-44 encryption failed: %d\n", nip44_result); } return -1; } printf("\n"); return 0; } int main() { printf("πŸ§ͺ NIP-44 Encryption Test Suite\n"); printf("================================\n\n"); // Initialize the library if (nostr_init() != NOSTR_SUCCESS) { printf("❌ Failed to initialize NOSTR library\n"); return 1; } int total_tests = 0; int passed_tests = 0; // Test all vectors size_t num_vectors = sizeof(test_vectors) / sizeof(test_vectors[0]); for (size_t i = 0; i < num_vectors; i++) { total_tests++; if (test_nip44_round_trip(&test_vectors[i]) == 0) { passed_tests++; } } // Test known vectors size_t num_known_vectors = sizeof(known_test_vectors) / sizeof(known_test_vectors[0]); for (size_t i = 0; i < num_known_vectors; i++) { total_tests++; if (test_nip44_known_vector(&known_test_vectors[i]) == 0) { passed_tests++; } } // Test error conditions total_tests++; if (test_nip44_error_conditions() == 0) { passed_tests++; } // Test comparison with NIP-04 total_tests++; if (test_nip44_vs_nip04_comparison() == 0) { passed_tests++; } // Final results printf("🏁 Test Results:\n"); printf("================\n"); printf("Tests passed: %d/%d\n", passed_tests, total_tests); if (passed_tests == total_tests) { printf("βœ… All NIP-44 tests PASSED! πŸŽ‰\n"); nostr_cleanup(); return 0; } else { printf("❌ Some tests FAILED! 😞\n"); nostr_cleanup(); return 1; } }