nostr_core_lib/tests/nip44_test.c

394 lines
13 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* NIP-44 Encryption/Decryption Test
*
* Test suite for NIP-44 versioned encryption functionality
* Uses known test vectors and cross-implementation compatibility tests
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#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;
}
}