Message Signing

KIP 5: Message Signing

Authors
coderofstuff
Layer
Applications
Status
Active

Motivation

Signing messages provides a mechanism for proving access to a given address without revealing your private keys. This paves the way for proving ownership of funds, native assets (not implemented yet) among many possible use-cases.

This document aims to provide a standard which applications can implement their message signing and verification functionalities.

Specifications

Signing a message

This part of the process is relevant to applications that have access to the private key and will sign some message.

Given:

  • A string of arbitrary length. We'll call this raw_message
  • A private_key

Output: signature associated with that string with some given private key

  1. Hash the message using Blake2B. To create sufficient domain separation with transaction input sighash, use a different Blake2B key PersonalMessageSigningHash (Transaction hashes uses TransactionSigningHash as key to blake2b) and a digest length of 32
  2. Schnorr sign the hashed message

In summary: schnorr_sign(blake2b(raw_message, digest_size=32, key='PersonalMessageSigningHash'), private_key)

Why hash a message?

  1. Reduces the size of some arbitrary message to a fixed length hash
  2. Prevents signing of sighashes accidentally - the raw message is hashed with a different blake2b key (PersonalMessageSigningHash) from what is used for transaction hashes (TransactionSigningHash), creating sufficient domain separation

Verifying a message signature

This part of the process is relevant to applications that is asking some public_key owner to provide evidence that they have access to the private_key of this public_key.

Given:

  • A string of arbitrary length. We'll call this raw_message
  • A public_key which the application has asked to sign the message

Output: true if the signature is valid, false otherwise

  1. Hash the raw message in the same way as above for signing
  2. Schnorr verify the signature matches the public_key you are testing for

In summary: schnorr_verify(blake2b(raw_message, digest_size=32, key='PersonalMessageSigningHash'), public_key)

Sample Implementation

Full code in /kip-0005/test-cases.py

from hashlib import blake2b
from secp256k1 import PublicKey, PrivateKey

# Assume we have a private-public key pair
# some_secret_key (private) and some_public_key (public)

def hash_message(raw_message) -> bytes:
    message_hash = blake2b(digest_size=32, key=bytes("PersonalMessageSigningHash", "ascii"))
    message_hash.update(raw_message)
    
    return message_hash.digest()

def sign_message(raw_message) -> bytes:
    message_digest = hash_message(raw_message)

    return PrivateKey(some_secret_key).schnorr_sign(message_digest, None)

def verify_message_signature(raw_message, message_signature) -> bool:    
    message_digest = hash_message(raw_message)

    return PublicKey(some_public_key).schnorr_verify(message_digest, message_signature, None)

Test Vectors

Keys taken from https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv

indexsecret keypublic keyaux_randmessage_strsignature
00000000000000000000000000000000000000000000000000000000000000003F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F90000000000000000000000000000000000000000000000000000000000000000Hello Kaspa!40B9BB2BE0AE02607279EDA64015A8D86E3763279170340B8243F7CE5344D77AFF1191598BAF2FD26149CAC3B4B12C2C433261C00834DB6098CB172AA48EF522
1B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEFDFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA6590000000000000000000000000000000000000000000000000000000000000001Hello Kaspa!EB9E8A3C547EB91B6A7592644F328F0648BDD21ABA3CD44787D429D4D790AA8B962745691F3B472ED8D65F3B770ECB4F777BD17B1D309100919B53E0E206B4C6
2B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEFDFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA6590000000000000000000000000000000000000000000000000000000000000001こんにちは世界810653D5F80206DB519672362ADD6C98DAD378844E5BA4D89A22C9F0C7092E8CECBA734FFF7922B656B4BE3F4B1F098899C95CB5C1023DCE3519208AFAFB59BC
3B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEFDFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA6590000000000000000000000000000000000000000000000000000000000000001(See Test CAse 3 Full Text section)40CBBD3938867B10076BB14835557C062F5BF6A4682995FC8B0A1CD2ED986EEDAAA00CFE04F6C9E5A9546B860732E5B903CC82780228647D5375BEC3D2A4983A

Test Case 3 Full Text

Lorem ipsum dolor sit amet. Aut omnis amet id voluptatem eligendi sit accusantium dolorem 33 corrupti necessitatibus hic consequatur quod et maiores alias non molestias suscipit? Est voluptatem magni qui odit eius est eveniet cupiditate id eius quae aut molestiae nihil eum excepturi voluptatem qui nisi architecto?

Et aliquid ipsa ut quas enim et dolorem deleniti ut eius dicta non praesentium neque est velit numquam. Ut consectetur amet ut error veniam et officia laudantium ea velit nesciunt est explicabo laudantium sit totam aperiam.

Ut omnis magnam et accusamus earum rem impedit provident eum commodi repellat qui dolores quis et voluptate labore et adipisci deleniti. Est nostrum explicabo aut quibusdam labore et molestiae voluptate. Qui omnis nostrum At libero deleniti et quod quia.