From daa59903e23548d3017b926639b03dedc5b0b626 Mon Sep 17 00:00:00 2001 From: Karl-Johan Alm Date: Wed, 24 Jul 2019 13:27:48 +0900 Subject: BIP-322 update to remove ProveFunds purpose (with a note about extensibility) and to fix the serialization format --- bip-0322.mediawiki | 71 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 30 deletions(-) (limited to 'bip-0322.mediawiki') diff --git a/bip-0322.mediawiki b/bip-0322.mediawiki index 5191143..71959f1 100644 --- a/bip-0322.mediawiki +++ b/bip-0322.mediawiki @@ -23,7 +23,7 @@ The current message signing standard only works for P2PKH (1...) addresses. By e A new structure SignatureProof is added, which is a simple serializable scriptSig & witness container. -Two actions "Sign" and "Verify" are defined along with two *purposes* "SignMessage" and "ProveFunds". +Two actions "Sign" and "Verify" are defined along with one ''purpose'', "SignMessage", with the ability to expand in the future to add a potential "ProveFunds" purpose. === SignatureProof container === @@ -36,11 +36,7 @@ Two actions "Sign" and "Verify" are defined along with two *purposes* "SignMessa |- |Uint32||4||flags||standard flags (1-to-1 with standard flags in Bitcoin Core) |- -|VarInt||1-8||msglen||Number of bytes in message string, excluding NUL termination -|- -|Char*||[msglen]||msg||The message being signed for all subjects, excluding NUL termination -|- -|Uint8||1||entries||Number of proof entriesWhy support multiple proofs? In particular with proof of funds, it is non-trivial to check a large number of individual proofs (one per UTXO) for duplicates. Software could be written to do so, but it seems more efficient to build this check into the specification itself. +|Uint8||1||entries||number of proof entriesWhy support multiple proofs? It is non-trivial to check a large number of individual proofs for duplicates. Software could be written to do so, but it seems more efficient to build this check into the specification itself. |} The above is followed by [entries] number of signature entries: @@ -56,9 +52,9 @@ The above is followed by [entries] number of signature entries: |- |Uint8*||[scriptsiglen]||scriptsig||ScriptSig data |- -|VarInt||1-8||witlen||Number of bytes in witness data +|VarInt||1-8||witlen||Number of entries in witness stack |- -|Uint8*||[witlen]||wit||Witness +|Uint8[]*||[witlen]||wit||Witness stack, as [witlen] uint8* vectors, each one prepended with a varint of its size |} In some cases, the scriptsig or wit may be empty. If both are empty, the proof is incomplete. @@ -80,36 +76,24 @@ A verification call will return a result code according to the table below. |- |INVALID||One or more of the given proofs were invalid |- -|SPENT||One or more of the claimed UTXO:s has been spent -|- |ERROR||An error was encountered |} == Signing and Verifying == -Let there be an empty set `inputs` which is populated and tested at each call to one of the actions below. +If the challenge consists of a single address and the address is in the P2PK(H) (legacy) format, sign using the legacy format (further information below). Otherwise continue as stated below. + +Let there be an empty set inputs which is populated and tested at each call to one of the actions below. === Purpose: SignMessage === The "SignMessage" purpose generates a sighash based on a scriptPubKey and a message. It emits a VALID verification result code unless otherwise stated. -# Return INVALID if scriptPubKey already exists in `inputs` set, otherwise insert itWhy track duplicates? Because a 3-entry proof is not proving 3 inputs unless they are all distinct +# Return INVALID if scriptPubKey already exists in inputs set, otherwise insert itWhy track duplicates? Because a 3-entry proof is not proving 3 entries unless they are all distinct # Define the message pre-image as the sequence "Bitcoin Message:" concatenated with the message, encoded in UTF-8 using Normalization Form Compatibility Decomposition (NFKD) # Let sighash = sha256(sha256(scriptPubKey || pre-image)) -=== Purpose: ProveFunds === - -The "ProveFunds" purpose generates a sighash and a scriptPubKey from a transaction, an output index, and a message. For multiple simultaneous proofs, it also requires access to the ordered list of proofs. It emits a VALID verification result code unless otherwise stated. - -# Let txid be the transaction ID of the transaction, and vout be the output index corresponding to the index of the output being spent -# Return INVALID if the txid:vout pair already exists in `inputs` set, otherwise insert it -# Return SPENT if the txid/vout is not a valid UTXO according to a Bitcoin nodeSynced up or not? A normal verifier would use a synced up node. An auditor checking records from a client that were submitted in the past want to use a node that is synced up to the block corresponding to the proof, or the proof will fail, even if it may have been valid at the time of creation. -# Extract scriptPubKey from transaction output -# Define the message pre-image as the concatenation of the following components:Why not just the UTXO data? We want the verifier to be able to challenge the prover with a custom message to sign, or anyone can reuse the POF proof for a set of UTXO:s once they have seen it, and the funds have not yet been spent -#* the string "POF:" -#* the message, encoded in UTF-8 using Normalization Form Compatibility Decomposition (NFKD), including the null terminating character (i.e. write strlen(message) + 1 bytes, for a C string) -#* all transactions being proven for, as binary txid (little endian uint256) followed by index (little endian uint32), each separated by a single `0x00` byte -# Let sighash = sha256(sha256(scriptPubKey || pre-image)) +A private key may be used directly to sign a message. In this case, its P2WPKH bech32 address shall be derived, and used as the input. === Action: Sign === @@ -119,6 +103,8 @@ The "Sign" action takes as input a purpose. It returns a signature or fails. # Derive the private key privkey for the scriptPubKey; FAIL if not VALID # Generate and return a signature sig with privkey=privkey, sighash=sighash +The resulting signature proof should be encoded using base64 encoding. + === Action: Verify === The "Verify" action takes as input a standard flags value, a script sig, an optional witness, and a purpose. @@ -139,13 +125,39 @@ Note that the order of the entries in the proof must match the order of the entr * If a verification call returns ERROR or INVALID, return ERROR or INVALID immediately, ignoring as yet unverified entries * After all verifications complete, ** return INCONCLUSIVE if any verification call returned INCONCLUSIVE -** return SPENT if any verification call returned SPENT ** return INCOMPLETE if the INCOMPLETE flag is set ** return VALID +== Legacy format == + +The legacy format is restricted to the legacy P2PK(H) address format, and restricted to one single challenge (address). + +Any other input (e.g. multiple addresses, or non-P2PK(H) address format(s)) must be signed using the new format described above. + +=== Signing === + +Given the P2PK(H) address a and the message m: +# let p be the pubkey-hash contained in a +# let x be the private key associated with p +# let digest be SHA56d("Bitcoin Signed Message:\n"||m) +# create a compact signature sig (aka "recoverable ECDSA signature") using x on digest + +The resulting proof is sig, serialized using the base64 encoding. + +=== Verifying === + +Given the P2PK(H) address a, the message m, and the compact signature sig: + +# let p be the pubkey-hash contained in a +# let digest be SHA56d("Bitcoin Signed Message:\n"||m) +# attempt pubkey recovery for digest using the signature sig and store the resulting pubkey into Q +## fail verification if pubkey recovery above fails +# let q be the pubkey-hash of Q +# if p == q, the proof is valid, otherwise it is invalid + == Compatibility == -This specification is not backwards compatible with the legacy signmessage/verifymessage specification. However, legacy addresses (1...) may be used in this implementation without any problems. +This specification is backwards compatible with the legacy signmessage/verifymessage specification through the special case as described above. == Rationale == @@ -153,16 +165,15 @@ This specification is not backwards compatible with the legacy signmessage/verif == Reference implementation == -To do. +# Pull request to Bitcoin Core: https://github.com/bitcoin/bitcoin/pull/16440 == Acknowledgements == -TODO +Thanks to David Harding, Jim Posen, Kalle Rosenbaum, Pieter Wuille, and many others for their feedback on the specification. == References == # Original mailing list thread: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-March/015818.html -# Pull request, with comments: https://github.com/bitcoin/bips/pull/725 == Copyright == -- cgit v1.2.3