diff --git a/README.md b/README.md index 364c0d3de32eef0f07e8b4418a1dc1dd5266c049..d4f2026443275e506c72dca6473a58fbb3ff571a 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ All documents should be implementation agnostic, as specific documentations shou * RFC_0008: [Duniter Messages Encryption and Signature](https://git.duniter.org/documents/rfcs/blob/messages_encryption_and_signature/rfc/0008%20Messages%20Encryption%20and%20Signature.md) * RFC_0013: [Duniter Encrypted Wallet Import Format](https://git.duniter.org/documents/rfcs/blob/dewif/rfc/0013_Duniter_Encrypted_Wallet_Import_Format.md) * RFC_0014: [DUBP Mnemonic](https://git.duniter.org/documents/rfcs/blob/dubp-mnemonic/rfc/0014_Dubp_Mnemonic.md) +* RFC_0016: [Checksum for Duniter public keys](rfc/0016_public_key_checksum.md) ### Drafts RFCs diff --git a/rfc/0016_public_key_checksum.md b/rfc/0016_public_key_checksum.md new file mode 100644 index 0000000000000000000000000000000000000000..9cd96ed9aa9a267d4f8899b3072b15ed2f8b8c0f --- /dev/null +++ b/rfc/0016_public_key_checksum.md @@ -0,0 +1,108 @@ +# 0016 Checksum for Duniter public keys + +```txt +RFC: 0016 +Title: Checksum for Duniter public keys +Type: Convention +Status: Proposed Standard +Author: matograine <matograine@zaclys.net> +Created: 2021-03-07 +Last edited: 2021-03-07 +License: AGPL-3 +``` + +## Sources + +This document proposes an enhancement on Tortue's standard for public key checksum: +https://github.com/Tortue95/Duniter_Paper_Wallet/blob/master/Duniter_Auth_Protocol.md + +## Public key format + +A public key is to be understood as an Ed25519 public key. +It is represented as a Base58 string which length ranges {43,44} characters. + +Example of a public key: +``` +J4c8CARmP9vAFNGtHRuzx14zvxojyRWHW2darguVqjtX +``` + +Example of two valid public keys referring to the same Ed25519 binary public key: +``` +12BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx +2BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx +``` + +When converting a public key to its binary representation, the length of the bytes array MUST be verified. +If the length of the array is inferior to 32, zero-bytes MUST be prepended. + +```python +# convert public key string to bytes +pubkey_byte = bytearray(base58.b58decode(pubkey)) +# prepend zero-bytes until the public key is 32 bytes long +while len(pubkey_byte) < 32: + pubkey_byte = bytearray(b"\x00") + pubkey_byte +``` + +## Checksum display + +The checksum aims at verifying the consistency of the public key. +It consists in three (3) base58 characters. +It is displayed after the public key, separated by a colon `:`. + +Example of two valid representations of a public key with their checksum: +``` +12BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx:8pQ +2BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx:8pQ +``` + +This function is used when a public key is typed manually on the keyboard (or issue on QRcode reader) +to avoid sending coins to the wrong public key. Because no control exist on the Duniter protocol. + +This technique is better than adding only some checksum bytes at the end of the key, before the base58.encode because: +- The public key visible for the user is the same. +- If the user miss some characters, the software client can detect it. +- The checksum is not mandatory + +### Short form + +When displaying a public key on little space, a short form can be used for public keys. +This short form consists in: + +* the 4 first characters of the public key +* the ellipsis character `…` +* the 4 last characters of the public key +* a colon `:` +* the checksum + +Example of short-form public keys with checksum: +``` +12Bj…v2nx:8pQ +2Bjy…v2nx:8pQ +``` + +Short form CAN be used for user input, only in research fields. +In that case, users will probably use three points `...` instead of an ellipsis `…`. +Short form MUST NOT be used as a direct input of a public key. + +For accessibility, a color CAN be used to display the checksum. +In that case, the same color MUST be used for the separating colon. + +## Compute the checksum + +To compute the checksum: + +0) use the binary representation of the public key : +`pubkey = bytearray(base58.b58decode("J4c8CARmP9vAFNGtHRuzx14zvxojyRWHW2darguVqjtX"))` + +1) `sha256(pubkey)` +`0x47c7aee49dfb9bea99949d04623281d8ad6188be8f6a698b0eb5994fa44d0a67` + +2) `sha256(sha256(pubkey))` +`0x04a7ad22fbe357fbf5f58b2996fe5840fa2f977b9f6aa4c62575e68f75882672` + +3) `Base58.encode(sha256(sha256(pubkey))` +`KAvdGW7rpV68WDQPVN2TCrCoyvAHqMK1nSTS8y68bmB` + +4) We only take the 3 first characters of this value to get the checksum +`KAv` +