OrdinalNews / docs

Documentation for the Ordinal News Standard
https://docs.inscribe.news
4 stars 0 forks source link

Optional Field: Author Proof #2

Open whoabuddy opened 1 year ago

whoabuddy commented 1 year ago

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.

whoabuddy commented 1 year ago

Dropping some notes from some earlier conversations and after a Discord conversation with @pradel - some good ideas here!

BIP322 Proof of UTXO and related signing ideas:

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

Address Ownership Proof Protocol

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.

Other Implementations

Nostrocket: micro-dao funding for projects

Using BIP-322 to prove funds:

https://nostrocket.org/ https://github.com/nostrocket

Mirror format for signatures:

 "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

whoabuddy commented 1 year ago

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

whoabuddy commented 1 year ago

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);
whoabuddy commented 1 year ago

Following up on this, Sigle has a working implementation for proving the authorship of a single post. :clapping:

Fields Used

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,
};

Signing Method

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);
    },
  });
};

Verification Method

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`);
}
whoabuddy commented 1 year ago

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:

whoabuddy commented 1 year ago

This could be helpful on the Bitcoin side! https://github.com/secretkeylabs/sats-connect

markmhendrickson commented 1 year ago

Curious if the more recently supported BIP0322 signing works for this out of the box? https://hirowallet.gitbook.io/developers/bitcoin/sign-messages