250 lines
10 KiB
C
250 lines
10 KiB
C
/*
|
|
* NIP-44 Debug Test - Step-by-step comparison with nostr-tools vectors
|
|
*
|
|
* This test prints intermediate values for comparison with nostr-tools
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include "../nostr_core/nostr_core.h"
|
|
|
|
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';
|
|
}
|
|
|
|
// Test a specific vector from nostr-tools
|
|
static int test_vector_step_by_step(const char* name,
|
|
const char* sec1_hex,
|
|
const char* sec2_hex,
|
|
const char* expected_conversation_key_hex,
|
|
const char* nonce_hex,
|
|
const char* plaintext,
|
|
const char* expected_payload) {
|
|
|
|
printf("\n🔍 Testing Vector: %s\n", name);
|
|
printf("=====================================\n");
|
|
|
|
// Step 1: Parse keys
|
|
unsigned char sec1[32], sec2[32];
|
|
if (hex_to_bytes(sec1_hex, sec1, 32) != 0 || hex_to_bytes(sec2_hex, sec2, 32) != 0) {
|
|
printf("❌ Failed to parse private keys\n");
|
|
return -1;
|
|
}
|
|
|
|
printf("📝 sec1: %s\n", sec1_hex);
|
|
printf("📝 sec2: %s\n", sec2_hex);
|
|
|
|
// Step 2: Generate public keys
|
|
unsigned char pub1[32], pub2[32];
|
|
if (nostr_ec_public_key_from_private_key(sec1, pub1) != 0 ||
|
|
nostr_ec_public_key_from_private_key(sec2, pub2) != 0) {
|
|
printf("❌ Failed to derive public keys\n");
|
|
return -1;
|
|
}
|
|
|
|
char pub1_hex[65], pub2_hex[65];
|
|
bytes_to_hex(pub1, 32, pub1_hex);
|
|
bytes_to_hex(pub2, 32, pub2_hex);
|
|
printf("📝 pub1: %s\n", pub1_hex);
|
|
printf("📝 pub2: %s\n", pub2_hex);
|
|
|
|
// Step 3: Calculate ECDH shared secret (our raw implementation)
|
|
unsigned char shared_secret[32];
|
|
if (ecdh_shared_secret(sec1, pub2, shared_secret) != 0) {
|
|
printf("❌ Failed to compute ECDH shared secret\n");
|
|
return -1;
|
|
}
|
|
|
|
char shared_hex[65];
|
|
bytes_to_hex(shared_secret, 32, shared_hex);
|
|
printf("🔗 ECDH shared secret: %s\n", shared_hex);
|
|
|
|
// Step 4: Calculate conversation key using HKDF-extract
|
|
unsigned char conversation_key[32];
|
|
const char* salt_str = "nip44-v2";
|
|
if (nostr_hkdf_extract((const unsigned char*)salt_str, strlen(salt_str),
|
|
shared_secret, 32, conversation_key) != 0) {
|
|
printf("❌ Failed to derive conversation key\n");
|
|
return -1;
|
|
}
|
|
|
|
char conv_key_hex[65];
|
|
bytes_to_hex(conversation_key, 32, conv_key_hex);
|
|
printf("🗝️ Our conversation key: %s\n", conv_key_hex);
|
|
printf("🎯 Expected conv key: %s\n", expected_conversation_key_hex);
|
|
|
|
if (strcmp(conv_key_hex, expected_conversation_key_hex) == 0) {
|
|
printf("✅ Conversation key matches!\n");
|
|
} else {
|
|
printf("❌ Conversation key MISMATCH!\n");
|
|
return -1;
|
|
}
|
|
|
|
// Step 5: Parse nonce
|
|
unsigned char nonce[32];
|
|
if (hex_to_bytes(nonce_hex, nonce, 32) != 0) {
|
|
printf("❌ Failed to parse nonce\n");
|
|
return -1;
|
|
}
|
|
printf("🎲 Nonce: %s\n", nonce_hex);
|
|
|
|
// Step 6: Derive message keys using HKDF-expand
|
|
unsigned char message_keys[76]; // 32 chacha_key + 12 chacha_nonce + 32 hmac_key
|
|
if (nostr_hkdf_expand(conversation_key, 32, nonce, 32, message_keys, 76) != 0) {
|
|
printf("❌ Failed to derive message keys\n");
|
|
return -1;
|
|
}
|
|
|
|
char chacha_key_hex[65], chacha_nonce_hex[25], hmac_key_hex[65];
|
|
bytes_to_hex(message_keys, 32, chacha_key_hex);
|
|
bytes_to_hex(message_keys + 32, 12, chacha_nonce_hex);
|
|
bytes_to_hex(message_keys + 44, 32, hmac_key_hex);
|
|
|
|
printf("🔐 ChaCha key: %s\n", chacha_key_hex);
|
|
printf("🔐 ChaCha nonce: %s\n", chacha_nonce_hex);
|
|
printf("🔐 HMAC key: %s\n", hmac_key_hex);
|
|
|
|
// Step 7: Test encryption with known nonce
|
|
char our_payload[8192];
|
|
int encrypt_result = nostr_nip44_encrypt_with_nonce(sec1, pub2, plaintext, nonce, our_payload, sizeof(our_payload));
|
|
|
|
if (encrypt_result == NOSTR_SUCCESS) {
|
|
printf("🔒 Our payload: %s\n", our_payload);
|
|
printf("🎯 Expected payload: %s\n", expected_payload);
|
|
|
|
if (strcmp(our_payload, expected_payload) == 0) {
|
|
printf("✅ Payload matches perfectly!\n");
|
|
} else {
|
|
printf("❌ Payload MISMATCH!\n");
|
|
|
|
// Try to decrypt expected payload with our conversation key
|
|
printf("\n🔍 Debugging: Trying to decrypt expected payload...\n");
|
|
char decrypted[8192];
|
|
int decrypt_result = nostr_nip44_decrypt(sec2, pub1, expected_payload, decrypted, sizeof(decrypted));
|
|
|
|
if (decrypt_result == NOSTR_SUCCESS) {
|
|
printf("✅ Successfully decrypted expected payload!\n");
|
|
printf("📝 Decrypted text: \"%s\"\n", decrypted);
|
|
if (strcmp(decrypted, plaintext) == 0) {
|
|
printf("✅ Decrypted text matches original!\n");
|
|
} else {
|
|
printf("❌ Decrypted text doesn't match original!\n");
|
|
}
|
|
} else {
|
|
printf("❌ Failed to decrypt expected payload (error: %d)\n", decrypt_result);
|
|
}
|
|
}
|
|
} else {
|
|
printf("❌ Encryption failed with error: %d\n", encrypt_result);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main() {
|
|
printf("🧪 NIP-44 Debug Test - Step-by-step Vector Comparison\n");
|
|
printf("======================================================\n");
|
|
|
|
// Initialize the library
|
|
if (nostr_init() != NOSTR_SUCCESS) {
|
|
printf("❌ Failed to initialize NOSTR library\n");
|
|
return 1;
|
|
}
|
|
|
|
// Test the simple "a" vector
|
|
test_vector_step_by_step(
|
|
"Single char 'a'",
|
|
"0000000000000000000000000000000000000000000000000000000000000001",
|
|
"0000000000000000000000000000000000000000000000000000000000000002",
|
|
"c41c775356fd92eadc63ff5a0dc1da211b268cbea22316767095b2871ea1412d",
|
|
"0000000000000000000000000000000000000000000000000000000000000001",
|
|
"a",
|
|
"AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABee0G5VSK0/9YypIObAtDKfYEAjD35uVkHyB0F4DwrcNaCXlCWZKaArsGrY6M9wnuTMxWfp1RTN9Xga8no+kF5Vsb"
|
|
);
|
|
|
|
// Test the emoji vector
|
|
test_vector_step_by_step(
|
|
"Emoji 🍕🫃",
|
|
"0000000000000000000000000000000000000000000000000000000000000002",
|
|
"0000000000000000000000000000000000000000000000000000000000000001",
|
|
"c41c775356fd92eadc63ff5a0dc1da211b268cbea22316767095b2871ea1412d",
|
|
"f00000000000000000000000000000f00000000000000000000000000000000f",
|
|
"🍕🫃",
|
|
"AvAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAPSKSK6is9ngkX2+cSq85Th16oRTISAOfhStnixqZziKMDvB0QQzgFZdjLTPicCJaV8nDITO+QfaQ61+KbWQIOO2Yj"
|
|
);
|
|
|
|
// Test with get_message_keys test vector to verify HKDF-expand
|
|
printf("\n🔍 Testing get_message_keys vector from nostr-tools:\n");
|
|
printf("===========================================\n");
|
|
|
|
unsigned char conv_key[32];
|
|
if (hex_to_bytes("a1a3d60f3470a8612633924e91febf96dc5366ce130f658b1f0fc652c20b3b54", conv_key, 32) == 0) {
|
|
unsigned char test_nonce[32];
|
|
if (hex_to_bytes("e1e6f880560d6d149ed83dcc7e5861ee62a5ee051f7fde9975fe5d25d2a02d72", test_nonce, 32) == 0) {
|
|
|
|
unsigned char message_keys[76];
|
|
if (nostr_hkdf_expand(conv_key, 32, test_nonce, 32, message_keys, 76) == 0) {
|
|
|
|
char chacha_key_hex[65], chacha_nonce_hex[25], hmac_key_hex[65];
|
|
bytes_to_hex(message_keys, 32, chacha_key_hex);
|
|
bytes_to_hex(message_keys + 32, 12, chacha_nonce_hex);
|
|
bytes_to_hex(message_keys + 44, 32, hmac_key_hex);
|
|
|
|
printf("📝 Conv key: a1a3d60f3470a8612633924e91febf96dc5366ce130f658b1f0fc652c20b3b54\n");
|
|
printf("📝 Nonce: e1e6f880560d6d149ed83dcc7e5861ee62a5ee051f7fde9975fe5d25d2a02d72\n");
|
|
printf("🔐 Our ChaCha key: %s\n", chacha_key_hex);
|
|
printf("🎯 Expected ChaCha key: f145f3bed47cb70dbeaac07f3a3fe683e822b3715edb7c4fe310829014ce7d76\n");
|
|
printf("🔐 Our ChaCha nonce: %s\n", chacha_nonce_hex);
|
|
printf("🎯 Expected ChaCha nonce: c4ad129bb01180c0933a160c\n");
|
|
printf("🔐 Our HMAC key: %s\n", hmac_key_hex);
|
|
printf("🎯 Expected HMAC key: 027c1db445f05e2eee864a0975b0ddef5b7110583c8c192de3732571ca5838c4\n");
|
|
|
|
if (strcmp(chacha_key_hex, "f145f3bed47cb70dbeaac07f3a3fe683e822b3715edb7c4fe310829014ce7d76") == 0) {
|
|
printf("✅ ChaCha key matches!\n");
|
|
} else {
|
|
printf("❌ ChaCha key MISMATCH!\n");
|
|
}
|
|
|
|
if (strcmp(chacha_nonce_hex, "c4ad129bb01180c0933a160c") == 0) {
|
|
printf("✅ ChaCha nonce matches!\n");
|
|
} else {
|
|
printf("❌ ChaCha nonce MISMATCH!\n");
|
|
}
|
|
|
|
if (strcmp(hmac_key_hex, "027c1db445f05e2eee864a0975b0ddef5b7110583c8c192de3732571ca5838c4") == 0) {
|
|
printf("✅ HMAC key matches!\n");
|
|
} else {
|
|
printf("❌ HMAC key MISMATCH!\n");
|
|
}
|
|
} else {
|
|
printf("❌ Failed to expand message keys\n");
|
|
}
|
|
} else {
|
|
printf("❌ Failed to parse test nonce\n");
|
|
}
|
|
} else {
|
|
printf("❌ Failed to parse conversation key\n");
|
|
}
|
|
|
|
nostr_cleanup();
|
|
printf("\n🏁 Debug test completed\n");
|
|
return 0;
|
|
}
|