Open whoabuddy opened 1 year ago
Dropping some notes from some earlier conversations and after a Discord conversation with @pradel - some good ideas here!
BIP322 text: https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki#user-content-Full_Proof_of_Funds
Electrum and Sparrow implement signatures, and this page had some resources with a timeline: https://bitcoinops.org/en/topics/generic-signmessage/
This wiki gets into the details for signing with different address types, but not sure if it's following BIP322 or an alternative to it: https://en.bitcoin.it/wiki/Message_signing
These were some use case explorations that show some good ideas toward what's possible https://hackmd.io/@bc-interns-2022/HyJC-yBt5
Here was a pull request related to two different implementations between Trezor and Electrum with some good discussion on supported formats and links to the sign message methods in bitcoinjs-message. Looks like BlueWallet adopted it as well. https://github.com/bitcoinjs/bitcoinjs-message/pull/29
...and a JS library! 🔎 https://github.com/bitcoinjs/bitcoinjs-message/
Also some talk here if the library should continue to be maintained or archived, the PR included an update to TypeScript: https://github.com/bitcoinjs/bitcoinjs-message/pull/38 https://github.com/bitcoinjs/bitcoinjs-message/issues/39
Trezor's resources here as well:
https://trezor.io/learn/a/sign-verify
sign_message.py https://github.com/trezor/trezor-firmware/blob/79632d32c79e02c7801d14c1aabd2822c8204892/core/src/apps/bitcoin/sign_message.py
verify_message.py https://github.com/trezor/trezor-firmware/blob/79632d32c79e02c7801d14c1aabd2822c8204892/core/src/apps/bitcoin/verify_message.py
There were a few mentions of AOPP but not much information following that, resources are below and may be another way to prove ownership.
https://aopp.group/ https://gitlab.com/aopp/address-ownership-proof-protocol/-/blob/master/README.md
From the website:
Adopting the digital signature standards that Bitcoin uses makes it straightforward to implement for developers.
This was the GitHub discussion about the implementation but haven't seen much more.
Using BIP-322 to prove funds:
https://nostrocket.org/ https://github.com/nostrocket
"authorship": {
"contributor": "0x12105a90a4CfeF063eDfA3Bd8b7db816087e01b6",
"signingKey": "{\"crv\":\"P-256\",\"ext\":true,\"key_ops\":[\"verify\"],\"kty\":\"EC\",\"x\":\"35OfTI7WFOVwnj-Qd-nQAp6XpJG-fCDAoOV2PpwRN7s\",\"y\":\"cbEMNrq_LTWb9YkO7soplOgEkbWI6jY28YAy3LIfo7c\"}",
"signature": "0x8da0ebe3b8009ee7978489c3f4e3bd1b81dbe88ec3dba66cbcd18133151dced0478218b68e19e9a7ae8bf2bd6fdacd06022fe4ceafa710b765319a8bff8593191b",
"signingKeySignature": "cBee8_F9SWSV0ZCE293iKTo0DwfY6XjWb8A4JknZNuxwsSZ51q_Zvs1SK_xs8PFaePr-qUJFcUFiipTvUb-kIQ",
"signingKeyMessage": "I authorize publishing on mirror.xyz from this device using:\n{\"crv\":\"P-256\",\"ext\":true,\"key_ops\":[\"verify\"],\"kty\":\"EC\",\"x\":\"35OfTI7WFOVwnj-Qd-nQAp6XpJG-fCDAoOV2PpwRN7s\",\"y\":\"cbEMNrq_LTWb9YkO7soplOgEkbWI6jY28YAy3LIfo7c\"}",
"algorithm": {
"name": "ECDSA",
"hash": "SHA-256"
}
},
There is also a digest
field shown on articles, which is a unique ID to query the different version of the post.
"digest": "QZqHyzWFJuXl3Ac_JScjLQI2AQsKIXP8JNbCKrAtOJo"
Arweave tx example: https://viewblock.io/arweave/tx/YUOCMG1EJW3vfbYYpIUcJbn0BBhL6yC2bFuSZo-CDNI
Let's start simple and iterate! Initially the signature could just be a signed message of all the other fields in the payload.
Credit to @pradel for that idea and the first signed news item on the standard: https://inscribe.news/api/news/892a90d8f022a6c329835aa0f7f7f3102a7375fe9aa7a6f672e418cf954e1c0ei0 https://inscribe.news/api/content/892a90d8f022a6c329835aa0f7f7f3102a7375fe9aa7a6f672e418cf954e1c0ei0 https://inscribe.news/api/info/892a90d8f022a6c329835aa0f7f7f3102a7375fe9aa7a6f672e418cf954e1c0ei0
Also adding Paul Miller's library for noble curves here, which was recently audited by Trail of Bits:
https://github.com/paulmillr/noble-curves https://twitter.com/paulmillr/status/1633804139472777218?s=20
secp256k1 has schnorr signature implementation which follows BIP340:
import { schnorr } from '@noble/curves/secp256k1';
const priv = schnorr.utils.randomPrivateKey();
const pub = schnorr.getPublicKey(priv);
const msg = new TextEncoder().encode('hello');
const sig = schnorr.sign(msg, priv);
const isValid = schnorr.verify(sig, msg, pub);
console.log(isValid);
Following up on this, Sigle has a working implementation for proving the authorship of a single post. :clapping:
const parsedData = {
p: 'ons',
op: 'post',
id: data.id,
author: user?.username,
authorAddress: user?.profile?.stxAddress?.mainnet,
title: data.title,
body: data.content,
url: `${appConfig.appDomain}/${user?.username}/${storyId}`,
signature: signedData ?? undefined,
};
Using the sign
method from stacks/connect for creating a SIP-018 signed message.
const handleSign = async () => {
await sign({
network: new StacksMainnet(),
message: JSON.stringify(parsedData),
onFinish: async ({ signature }) => {
setSignedData(signature);
},
});
};
Using stacks/transactions to:
Using the publicKeyFromSignatureRsv
method from .
// Call the api to get the inscription data
let data = await fetch(
`https://inscribe.news/api/content/${inscriptionId}`
);
if (!data.ok) {
return toast.error('Invalid response from api');
}
let json = await data.json();
if (json.p !== 'ons' || json.op !== 'post' || !json.signature) {
return toast.error('Invalid data');
}
const message = JSON.stringify({ ...json, signature: undefined });
// We verify the signature is valid
const recoveredPublicKey = publicKeyFromSignatureRsv(
bytesToHex(hashMessage(message)),
createMessageSignature(json.signature)
);
const recoveredAddress = getAddressFromPublicKey(recoveredPublicKey);
if (json.authorAddress !== recoveredAddress) {
console.log(json.authorAddress, recoveredAddress);
return toast.error(`address does not belong to publicKey`);
}
if (
!verifyMessageSignatureRsv({
message,
publicKey: recoveredPublicKey,
signature: json.signature,
})
) {
return toast.error(`Signature does not belong to issuer`);
}
Looking at the logic above it does prove that the authorAddress
is the one who posted, and would be curious if this same idea would be possible on the Bitcoin side, cc @yknl and @markmhx. It'd be nice to have them both work generally the same!
@pradel am I correct that this would just prove the authorAddress
but not the author
field? I think it'd be more powerful if we could make sure a BNS/BNSx name there was in fact the author, otherwise there could be some confusion if I sign from a random address claiming to be whoabuddy.btc
and it passes verification.
On that note, it'd be great to define something that works for both .btc
and .sats
so both Stacks and Bitcoin have the option to prove authorship of a single post. :thinking:
This could be helpful on the Bitcoin side! https://github.com/secretkeylabs/sats-connect
Curious if the more recently supported BIP0322 signing works for this out of the box? https://hirowallet.gitbook.io/developers/bitcoin/sign-messages
How can we prove the author is the author?
For .sats names, it'd be interesting to explore a BIP-322 or some kind of structured data signed by the wallet.
For .btc names, we could implement a similar structure using SIP-018.