bitcoin-sv / ts-sdk

Other
51 stars 12 forks source link

[BUG] electrum decrypt with counterparty, and your own private key #124

Closed rohenaz closed 1 month ago

rohenaz commented 2 months ago

Bug Description

electrumDecrypt can encrypt with a counterparty public key identically to existing libraries, but fails to decrypt when providing your own private key and the counterparty public key.

Steps to Reproduce

This code sample illustrates the problem compared to bsv v1.5.6 in detail:

// bsv
import bsv from "bsv";
import ECIES from "bsv/ecies";

import Message from 'bsv/message'
// @bsv/sdk
import { BSM, PrivateKey, PublicKey, ECIES as sdkECIES } from "@bsv/sdk"
import { Utils } from "@bsv/sdk"
const { toArray, toHex, toUTF8 } = Utils
const { electrumEncrypt, electrumDecrypt } = sdkECIES;

const wif = "L211enC224G1kV8pyyq7bjVd9SxZebnRYEzzM3i7ZHCc1c5E7dQu"

const bsvSdkPk = PrivateKey.fromWif(wif)
const bsvPk = bsv.PrivateKey.fromWIF(wif)
const msgStr = "hello world"

// Create a random counterparty public key for bsv and ts-sdk
const randomCounterparty = bsv.PrivateKey.fromRandom().toPublicKey()
const counterpartySdk = PublicKey.fromString(randomCounterparty.toString())

// Encrypt in bsv & ts-sdk is identical with random counterparty public key
const encryptedBsv = ECIES().publicKey(randomCounterparty).privateKey(bsvPk).encrypt(msgStr);
const encryptedSdk = electrumEncrypt(toArray(msgStr), counterpartySdk, bsvSdkPk)

console.log({ encryptedBsv: encryptedBsv.toString('hex'), length: encryptedBsv.length })
console.log({ encryptedSdk: toHex(encryptedSdk), length: encryptedSdk.length })

// In bsv v1.5.6 you can decrypt with that counterparty's public key only, and your private key
const ecies2 = ECIES();
ecies2.privateKey(bsvPk);
ecies2.publicKey(randomCounterparty);
const decryptedBsv = ecies2.decrypt(Buffer.from(encryptedBsv, 'hex')).toString()
// success!

// But this fails in ts-sdk with "error: buf length must be a multiple of 4"
const decryptedSdk = toUTF8(electrumDecrypt([...encryptedBsv], bsvSdkPk, counterpartySdk))

Expected Behavior

Should decrypt successfully

Actual Behavior

Error with stack strace:

Stack Traces or Screenshots

188 |         const messageBuf = AESWrapper.words2Buf(message);
189 |         return messageBuf;
190 |     }
191 |     static buf2Words(buf) {
192 |         if (buf.length % 4) {
193 |             throw new Error('buf length must be a multiple of 4');
                        ^
error: buf length must be a multiple of 4
      at buf2Words (/Users/satchmo/Downloads/bsv-sdk-bsm-compare/node_modules/@bsv/sdk/dist/esm/src/compat/ECIES.js:193:19)
      at decrypt (/Users/satchmo/Downloads/bsv-sdk-bsm-compare/node_modules/@bsv/sdk/dist/esm/src/compat/ECIES.js:184:32)
      at decryptBlock (/Users/satchmo/Downloads/bsv-sdk-bsm-compare/node_modules/@bsv/sdk/dist/esm/src/compat/ECIES.js:260:36)
      at decryptBlocks (/Users/satchmo/Downloads/bsv-sdk-bsm-compare/node_modules/@bsv/sdk/dist/esm/src/compat/ECIES.js:278:34)
      at decrypt (/Users/satchmo/Downloads/bsv-sdk-bsm-compare/node_modules/@bsv/sdk/dist/esm/src/compat/ECIES.js:250:31)
      at /Users/satchmo/Downloads/bsv-sdk-bsm-compare/index.ts:47:29

Environment

Additional information

For additional reference, the go implementation does this successfully. See this test case: https://github.com/bitcoin-sv/go-sdk/blob/master/compat/ecies/ecies_test.go#L104