Loading...
Loading...
Message signing and verification — SIP-018 structured Clarity data signing (on-chain verifiable), Stacks plain-text message signing (SIWS-compatible), Bitcoin message signing (BIP-137 for legacy/wrapped-SegWit, BIP-322 for native SegWit bc1q and Taproot bc1p), BIP-340 Schnorr signing for Taproot multisig, and Nostr event signing using NIP-06 key derivation. All signing requires an unlocked wallet; hash and verify operations do not.
npx skill4agent add aibtcdev/skills signingsecp256k1-recover?m/44'/1237'/0'/0/0keySourcebun run signing/signing.ts <subcommand> [options]bun run signing/signing.ts sip018-sign \
--message '{"amount":{"type":"uint","value":100}}' \
--domain-name "My App" \
--domain-version "1.0.0"--message{"type":"uint","value":100}uint{"type":"int","value":-50}int{"type":"principal","value":"SP..."}principal{"type":"ascii","value":"hello"}string-ascii{"type":"utf8","value":"hello"}string-utf8{"type":"buff","value":"0x1234"}buff{"type":"bool","value":true}bool{"type":"none"}none{"type":"some","value":...}(some ...){"type":"list","value":[...]}list{"type":"tuple","value":{...}}tuplestring → string-utf8number → intboolean → boolnull → none--domain-name--domain-version--domain{"name":"My App","version":"1.0.0"}chainId{
"success": true,
"signature": "abc123...",
"signatureFormat": "RSV (65 bytes hex)",
"signer": "SP...",
"network": "testnet",
"chainId": 2147483648,
"hashes": {
"message": "...",
"domain": "...",
"encoded": "...",
"verification": "...",
"prefix": "0x534950303138"
},
"domain": { "name": "My App", "version": "1.0.0", "chainId": 2147483648 },
"verificationNote": "Use sip018-verify with the 'verification' hash..."
}verificationsip018-signsip018-hashbun run signing/signing.ts sip018-verify \
--message-hash <verificationHash> \
--signature <rsv65BytesHex> \
[--expected-signer <address>]--message-hashsip018-signsip018-hash--signature--expected-signer{
"success": true,
"recoveredPublicKey": "03...",
"recoveredAddress": "SP...",
"network": "testnet",
"verification": {
"expectedSigner": "SP...",
"isValid": true,
"message": "Signature is valid for the expected signer"
}
}bun run signing/signing.ts sip018-hash \
--message '{"amount":{"type":"uint","value":100}}' \
--domain-name "My App" \
--domain-version "1.0.0" \
[--chain-id <id>]--message--domain-name--domain-version--domain{"name":"My App","version":"1.0.0"}chainId--chain-iddomain.chainId{
"success": true,
"hashes": {
"message": "...",
"domain": "...",
"encoded": "...",
"verification": "..."
},
"hashConstruction": {
"prefix": "0x534950303138",
"formula": "verification = sha256(prefix || domainHash || messageHash)"
},
"domain": { "name": "My App", "version": "1.0.0", "chainId": 2147483648 },
"clarityVerification": {
"example": "(secp256k1-recover? (sha256 encoded-data) signature)"
}
}\x17Stacks Signed Message:\nbun run signing/signing.ts stacks-sign --message "Hello, Stacks!"--message{
"success": true,
"signature": "abc123...",
"signatureFormat": "RSV (65 bytes hex)",
"signer": "SP...",
"network": "testnet",
"message": {
"original": "Hello, Stacks!",
"prefix": "\u0017Stacks Signed Message:\n",
"prefixHex": "...",
"hash": "..."
},
"verificationNote": "Use stacks-verify with the original message and signature to verify."
}bun run signing/signing.ts stacks-verify \
--message "Hello, Stacks!" \
--signature <rsv65BytesHex> \
[--expected-signer <address>]--message--signature--expected-signer{
"success": true,
"signatureValid": true,
"recoveredPublicKey": "03...",
"recoveredAddress": "SP...",
"network": "testnet",
"message": {
"original": "Hello, Stacks!",
"prefix": "\u0017Stacks Signed Message:\n",
"hash": "..."
},
"verification": {
"expectedSigner": "SP...",
"signerMatches": true,
"isFullyValid": true,
"message": "Signature is valid and matches expected signer"
}
}bun run signing/signing.ts btc-sign --message "Hello, Bitcoin!"--message{
"success": true,
"signature": "abc123...",
"signatureBase64": "...",
"signatureFormat": "BIP-137 (65 bytes: 1 header + 32 r + 32 s)",
"signer": "bc1q...",
"network": "mainnet",
"addressType": "P2WPKH (native SegWit)",
"message": {
"original": "Hello, Bitcoin!",
"prefix": "\u0018Bitcoin Signed Message:\n",
"prefixHex": "...",
"formattedHex": "...",
"hash": "..."
},
"header": { "value": 39, "recoveryId": 0, "addressType": "P2WPKH (native SegWit)" },
"verificationNote": "Use btc-verify with the original message and signature to verify."
}bun run signing/signing.ts btc-verify \
--message "Hello, Bitcoin!" \
--signature <hexOrBase64Sig> \
[--expected-signer <btcAddress>]--message--signature--expected-signer{
"success": true,
"signatureValid": true,
"recoveredPublicKey": "03...",
"recoveredAddress": "bc1q...",
"network": "mainnet",
"message": { "original": "Hello, Bitcoin!", "prefix": "...", "hash": "..." },
"header": { "value": 39, "recoveryId": 0, "addressType": "P2WPKH (native SegWit)" },
"verification": {
"expectedSigner": "bc1q...",
"signerMatches": true,
"isFullyValid": true,
"message": "Signature is valid and matches expected signer"
}
}--confirm-blind-signbun run signing/signing.ts schnorr-sign-digest \
--digest <64-char-hex> \
[--aux-rand <64-char-hex>] \
[--confirm-blind-sign]--digest--aux-rand--confirm-blind-sign--confirm-blind-sign{
"warning": "schnorr-sign-digest signs a raw 32-byte digest...",
"digestToReview": "abc123...",
"instructions": "Review the digest above. If you trust its origin..."
}--confirm-blind-sign{
"success": true,
"signature": "abc123...",
"publicKey": "def456...",
"address": "bc1p...",
"network": "mainnet",
"signatureFormat": "BIP-340 Schnorr (64 bytes)",
"publicKeyFormat": "x-only (32 bytes)",
"note": "For Taproot script-path spending, append sighash type byte..."
}bun run signing/signing.ts schnorr-verify-digest \
--digest <64-char-hex> \
--signature <128-char-hex> \
--public-key <64-char-hex>--digest--signature--public-key{
"success": true,
"isValid": true,
"digest": "abc123...",
"signature": "def456...",
"publicKey": "789abc...",
"message": "Signature is valid for the given digest and public key",
"note": "BIP-340 Schnorr verification. Use for validating signatures in Taproot multisig coordination."
}m/44'/1237'/0'/0/0npubbun run signing/signing.ts nostr-sign-event \
--event '{"kind":1,"created_at":1700000000,"tags":[],"content":"Hello, Nostr!"}' \
[--key-source nostr|taproot|segwit]--eventidpubkeysig--key-source"nostr""nostr"m/44'/1237'/0'/0/0"taproot"m/86'/0'/0'/0/0"segwit"m/84'/0'/0'/0/0{
"success": true,
"event": {
"id": "abc123...",
"pubkey": "def456...",
"created_at": 1700000000,
"kind": 1,
"tags": [],
"content": "Hello, Nostr!",
"sig": "789abc..."
},
"npub": "npub1...",
"keySource": "nostr",
"derivationPath": "m/44'/1237'/0'/0/0",
"note": "Key derived via NIP-06. npub matches NIP-06 compliant Nostr clients."
}"nostr"m/44'/1237'/0'/0/0keySource| Standard | Prefix | Use Case | On-Chain Verifiable? |
|---|---|---|---|
| SIP-018 | | Structured Clarity data | Yes ( |
| Stacks | | Auth, ownership proof | No (off-chain only) |
| BIP-137 / BIP-322 | | Bitcoin auth, ownership proof (BIP-137 for 1.../3...; BIP-322 for bc1q/bc1p) | No (off-chain only) |
| BIP-340 | None (raw digest) | Taproot multisig, script-path spending | Yes (OP_CHECKSIG/OP_CHECKSIGADD) |
| NIP-06 (Nostr) | None (event hash) | Nostr event signing (NIP-01) | No (Nostr network only) |
bun run wallet/wallet.ts unlocksip018-hash*-verifyschnorr-verify-digest