nostr_core_lib/debug_nip04_comparison.js

107 lines
3.8 KiB
JavaScript

import { bytesToHex, hexToBytes, randomBytes } from '@noble/hashes/utils'
import { secp256k1 } from '@noble/curves/secp256k1'
import { cbc } from '@noble/ciphers/aes'
import { base64 } from '@scure/base'
// UTF-8 encoder/decoder
const utf8Encoder = new TextEncoder()
const utf8Decoder = new TextDecoder()
function getNormalizedX(key) {
return key.slice(1, 33)
}
function encrypt(secretKey, pubkey, text) {
console.log(`[JS] Encrypting "${text}" using sk1 -> pk2`)
console.log(`[JS] Private Key: ${secretKey}`)
console.log(`[JS] Public Key: ${pubkey}`)
// Step 1: Get shared secret
const key = secp256k1.getSharedSecret(secretKey, '02' + pubkey)
console.log(`[JS] Shared Secret: ${bytesToHex(key)}`)
// Step 2: Normalize key (remove first byte, keep next 32)
const normalizedKey = getNormalizedX(key)
console.log(`[JS] Normalized Key: ${bytesToHex(normalizedKey)}`)
// Step 3: Generate random IV
const iv = randomBytes(16)
console.log(`[JS] IV: ${bytesToHex(iv)}`)
// Step 4: Encode plaintext to UTF-8
const plaintext = utf8Encoder.encode(text)
console.log(`[JS] UTF-8 Plaintext: ${bytesToHex(plaintext)}`)
// Step 5: AES-CBC encryption
const ciphertext = cbc(normalizedKey, iv).encrypt(plaintext)
console.log(`[JS] Raw Ciphertext: ${bytesToHex(new Uint8Array(ciphertext))}`)
// Step 6: Base64 encoding
const ctb64 = base64.encode(new Uint8Array(ciphertext))
const ivb64 = base64.encode(new Uint8Array(iv.buffer))
const result = `${ctb64}?iv=${ivb64}`
console.log(`[JS] Encrypted Result: ${result}`)
return result
}
function decrypt(secretKey, pubkey, data) {
console.log(`[JS] Decrypting "${data}" using sk2 + pk1`)
console.log(`[JS] Private Key: ${secretKey}`)
console.log(`[JS] Public Key: ${pubkey}`)
// Step 1: Parse format
const [ctb64, ivb64] = data.split('?iv=')
// Step 2: Get shared secret
const key = secp256k1.getSharedSecret(secretKey, '02' + pubkey)
console.log(`[JS] Shared Secret: ${bytesToHex(key)}`)
// Step 3: Normalize key
const normalizedKey = getNormalizedX(key)
console.log(`[JS] Normalized Key: ${bytesToHex(normalizedKey)}`)
// Step 4: Base64 decode
const iv = base64.decode(ivb64)
const ciphertext = base64.decode(ctb64)
console.log(`[JS] IV: ${bytesToHex(iv)}`)
console.log(`[JS] Raw Ciphertext: ${bytesToHex(ciphertext)}`)
// Step 5: AES-CBC decryption
const plaintext = cbc(normalizedKey, iv).decrypt(ciphertext)
console.log(`[JS] Decrypted Plaintext: ${bytesToHex(plaintext)}`)
// Step 6: UTF-8 decode
const result = utf8Decoder.decode(plaintext)
console.log(`[JS] UTF-8 Decoded: "${result}"`)
return result
}
// Test with exact vectors
async function main() {
console.log("=== NIP-04 DEBUG COMPARISON (JavaScript) ===")
const sk1 = "91ba716fa9e7ea2fcbad360cf4f8e0d312f73984da63d90f524ad61a6a1e7dbe"
const pk1 = "b38ce15d3d9874ee710dfabb7ff9801b1e0e20aace6e9a1a05fa7482a04387d1"
const sk2 = "96f6fa197aa07477ab88f6981118466ae3a982faab8ad5db9d5426870c73d220"
const pk2 = "dcb33a629560280a0ee3b6b99b68c044fe8914ad8a984001ebf6099a9b474dc3"
const plaintext = "nanana"
const expectedCiphertext = "d6Joav5EciPI9hdHw31vmQ==?iv=fWs5rfv2+532arG/k83kcA=="
console.log("\n--- ENCRYPTION TEST ---")
const encrypted = encrypt(sk1, pk2, plaintext)
console.log("\n--- DECRYPTION TEST ---")
const decrypted = decrypt(sk2, pk1, expectedCiphertext)
console.log("\n--- RESULTS ---")
console.log(`Encryption Success: Generated ciphertext`)
console.log(`Decryption Success: ${decrypted === plaintext}`)
console.log(`Expected: "${plaintext}"`)
console.log(`Got: "${decrypted}"`)
}
main().catch(console.error)