Self-hosted wallets: proof of ownership
Based on the AOPP protocol
Mission Statement
The AOPP streamlines and automates address ownership proofs, which are required in interactions between self-hosted wallets and virtual asset service providers (VASPs), for example in virtual asset withdrawal.
Specification
Link on the "Address Ownership Proof" web page of a VASP:
<a href="aopp:?v=0&msg=vasp-chosen-msg&asset=btc&format=p2xxx&callback=https://vasp.com/proofs/vasp-chosen-token">verify address</a>
Required parameters in version 0:
v: version number, always 0
msg: a vasp-chosen message up to 1024 ASCII characters; it is recommended to contain a nonce value
asset: a virtual asset identifier (as defined in SLIP-0044)
format: specifies a wallet address type the VASP expects in a callback;
for "btc" asset it is:
- p2pkh
- p2wpkh
- p2sh
- p2tr
- any
for "eth" asset it is:
- standard
callback: a VASP chosen URL endpoint where the client wallet sends the response to.
When a wallet encounters an unknown version number or other unrecognised or invalid values in required parameters, it should display an error and abort signing. Wallets should ignore parameters not listed above.
On click, a desktop app shows up. The user confirms the message. The app sends a response to the server:
Response:
POST <callback URL> Content-Type: application/json; utf-8 { "version": 0, "address": "bc1000000000000000000000000", "signature": "<Bitcoin Signed Message Signature>" }
Response from the Server:
- HTTP 204: Signature is valid.
- HTTP 400: Bad Request.
- HTTP 404: The
vasp-chosen-token
in the callback URL doesn't exist.
Compressed Keys Only
Uncompressed keys are considered legacy and are not supported.
Bitcoin Message Signatures
For bitcoin, the signatures are constructed following the algorithm in Citcoin Core. Special attention should be brought to the encoding of the recovery byte that does not indicate information about witness addresses in its encoding. This is the main difference between bitcoin core's message signatures and other, less popular ones.
Please refer to the wallet guide for further implementation hints.
Ethereum Message Signatures
For ethereum, the signatures are constructed following the same algorithm as in bitcoin core with the notable exception that the recovery byte is appended to the signature instead of prepended.
Recommendations
- Choose
any
for the address format if your VASP supports all possible address formats. Certain wallets (e.g. Electrum) have a fixed address format and therefore letting them pick the address format will increase interoperability. - Choose a small message to improve UX using hardware wallets (small screens). Also, URIs have an implementation-defined limit so smaller URIs will have better interoperability in general.
- [Add SRO approved message style here]
FAQ
Why is there a format specifier?
A format specifier allows a VASP to hint to a wallet what address format it can accept. Historically, certain VASPs have had poor support for various address formats.
How to deal with p2sh addresses?
For p2sh addresses we need to presume that it's a p2wpkh address wrapped in a p2sh.
Why is the wallet choosing the address?
Certain wallet types, such as hardware wallets, are limited in how they can handle specific workflows. To facilitate the adoption in all kinds of wallets, the protocol lets the wallet choose the address.
Why is there a limit on the
msg
parameter?Some wallets have a hard limit on the size of the message, hence the 1024 character limit in AOPP.
Test vectors
Bitcoin
- p2pkh
- private key: L4MSJRS7EZNoinjUXJAKrtSgvA6epQDAmwgo5B2LJdVCcjEapPE1
- address: 13LiZwTMfowMo5KsWHf5TNLmK78WSxVQCG
- message: hello
- signature: IFwh9XVPb8vvNUsbuuQU1Xk1jT652JD/6HN3cqnFn/MMBDziPbM8cOi83D29LRGSwMF3ZcjytD7nfNdn5dI0/50=
- p2sh (wrapped SegWit)
- private key: L5fETAwYWGRA1eWCHk8AgH2FX2rxLp64winwoAoRGpz1aQMp3Rai
- address: 3JvVkfeKrrJstF66haNpFepfhxzQuBB78h
- message: hello
- signature: H1oYVmDaWxZBPEk2ou4myn1SRC20ycBUPPD5fLS+SmQ1e04Bi1J9mIJ5fNhe3khDhJRUX2fU+VHGKlJdAjYIvBU=
- p2wpkh
- private key: L5fETAwYWGRA1eWCHk8AgH2FX2rxLp64winwoAoRGpz1aQMp3Rai
- address: bc1qnshsvhrfl28g03k0vxdez6vua56r0c72xy9e93
- message: hello
- signature: H1oYVmDaWxZBPEk2ou4myn1SRC20ycBUPPD5fLS+SmQ1e04Bi1J9mIJ5fNhe3khDhJRUX2fU+VHGKlJdAjYIvBU=
Ethereum
- private key: 4142e80a872531fd1055f52ccab713d4c7f1eee28c33415558e74faeb516de2b
- address: 0x270402aeB8f4dAc8203915fC26F0768feA61b532
- message: hello
- signature: vbyudz7PM/tUdVjlL0wEtCnvn3PVYv8eCqCf/aLeVj8JwAsUVuyMMwbIInXAj7EtmZIUwlem7AOH0da8ygXmQBs=