WizardConnect/packages/core/package.json

51 lines
1.5 KiB
JSON
Raw Normal View History

2026-02-26 11:19:47 +01:00
{
"name": "@wizardconnect/core",
"version": "0.2.0",
2026-02-26 11:19:47 +01:00
"type": "module",
"description": "Transport and protocol primitives for WizardConnect",
2026-03-09 16:27:24 +01:00
"repository": {
"type": "git",
"url": "https://gitlab.com/riftenlabs/lib/wizardconnect",
"directory": "packages/core"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./hdwalletv1-serialize": {
"types": "./dist/protocols/hdwalletv1-serialize.d.ts",
"default": "./dist/protocols/hdwalletv1-serialize.js"
}
},
2026-02-26 11:19:47 +01:00
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist/"
],
"scripts": {
"build": "tsc",
"test": "vitest --config vitest.config.ts --run --passWithNoTests",
feat(core): Bitcoin Signed Message primitives, checked against Electron Cash Dapps have been asking for message signing to prove key control — identity verification, SIWX-style login, and publishing a signed statement on chain. This adds the construction and the verification; the protocol wiring follows separately. The known workaround is a dummy transaction: one input with a null outpoint, its prevout script set to the P2PKH of the key being proven, one OP_RETURN output carrying a server nonce, signed but never broadcast. It covers login, but not the rest. A signature made that way is bound to a transaction, so verifying it means rebuilding that exact transaction and knowing how it was serialised — it cannot be published in an OP_RETURN and checked later by a third party holding only the message, the signature and an address. It also asks a wallet to sign a real transaction preimage, which is one bug away from signing a genuine spend. So this produces the portable form: the standard "Bitcoin Signed Message" construction. BCH wallets kept Bitcoin's magic string verbatim, so a signature made here verifies in Electron Cash, Electrum and `bitcoin-cli verifymessage`. The magic prefix also guarantees the digest can never coincide with a transaction sighash, which makes signing a message categorically safer to approve than signing a dummy transaction. Address-level API, because that is what verification actually looks like elsewhere: Electron Cash exposes only `verify_message(address, sig, message)`, and a third party pulling a proof off an explorer has an address, not a public key. verifyMessageSignatureForAddress accepts CashAddr with or without a prefix and legacy base58, and rejects P2SH — no message signature can prove control of a script hash. recoverMessageSigner returns { publicKey, compressed } rather than a bare key. The header byte declares which serialisation was used, and a key's compressed and uncompressed forms hash to DIFFERENT addresses. Dropping that bit is how a signature proving control of one address gets accepted as proof of another; message-signing.test.ts pins the case in both directions. signBitcoinMessage takes the private key as an argument and never retains it. It exists so a wallet calls one function instead of reassembling the magic string, both compactSize prefixes and the header byte — the parts third-party verifiers check, and the parts covered by the tests here. Testing: the byte layout is not asserted against our own reimplementation of the spec, because that catches a coding mistake but not a misreading of it. message-signing.vectors.json holds 32 vectors generated by a real Electron Cash 4.4.5 install (contrib/generate-message-signing-vectors.py) — two keys, both compression forms, eight messages including empty, multi-byte UTF-8, multi-line and the 252/253-byte compactSize boundary. Every preimage hash must match byte for byte, and every signature must verify. Signature bytes are NOT portable across implementations — Electron Cash and libauth derive the ECDSA nonce differently — so the reproducible quantity is the hash. message-signing.compat.test.ts drives `electron-cash verifymessage` directly, closing the loop that vectors cannot: that our OUTPUT is accepted. Not part of `npm test` (each assertion spawns a full Electron Cash process); run `npm run test:compat -w @wizardconnect/core`. Skips when Electron Cash is absent, so CI is unaffected. 77 tests, 426 in core. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 14:28:41 +02:00
"test:compat": "vitest --config vitest.compat.config.ts --run",
2026-03-06 14:01:41 +01:00
"lint:prettier": "prettier --ignore-path ../../.gitignore . --list-different",
2026-02-26 11:19:47 +01:00
"lint:eslint": "eslint .",
"lint": "npm run lint:eslint && npm run lint:prettier",
"fix": "npm run fix:eslint && npm run fix:prettier",
2026-03-06 14:01:41 +01:00
"fix:prettier": "prettier --ignore-path ../../.gitignore . --write",
2026-02-26 11:19:47 +01:00
"fix:eslint": "npm run lint:eslint -- --fix"
},
"dependencies": {
"@bch-wc2/interfaces": "^0.0.8",
"nostr-tools": "^2.23.0",
2026-02-26 11:19:47 +01:00
"@bitauth/libauth": "^3.1.0-next.2",
"eventemitter3": "^5.0.1",
"isomorphic-ws": "^5.0.0",
"lossless-json": "^4.3.0",
"ws": "^8.18.0"
},
"devDependencies": {
"typescript": "^5.6.2",
"vitest": "^3.2.3"
}
}