Let's create a Byron address:
$ cardano-cli byron key keygen --secret test.skey
$ cardano-cli byron key signing-key-public --secret test.skey
public key hash: 7e5078fa6e2a8308
public key (base64): RNbpyp7dquTkVJJ5hXxs4hLjtVCynfQvuVTi5gicU55McTshDzVSGQdNfJHN995WVWsPYpaAyIQ8omBBR8uagA==
public key (hex): 44d6e9ca9eddaae4e4549279857c6ce212e3b550b29df42fb954e2e6089c539e4c713b210f355219074d7c91cdf7de56556b0f629680c8843ca2604147cb9a80
$ cardano-cli byron key signing-key-address --mainnet --secret test.skey
Ae2tdPwUPEZHvh7P2QsxENNDeHZ9K4vw4Pfk3LY9gxkrAVVLSTmXaCvxxFf
VerKey address with root d3a912bbc69d18f9f8754c4f79adcbaed373aa6703444d465fd31047, attributes: AddrAttributes { derivation path: {} }
To start with, let's state some facts about the address:
- The address is
Ae2tdPwUPEZHvh7P2QsxENNDeHZ9K4vw4Pfk3LY9gxkrAVVLSTmXaCvxxFf
in base58 encoding - The address root hash in hex is
d3a912bbc69d18f9f8754c4f79adcbaed373aa6703444d465fd31047
- The public key in hex is
44d6e9ca9eddaae4e4549279857c6ce212e3b550b29df42fb954e2e6089c539e4c713b210f355219074d7c91cdf7de56556b0f629680c8843ca2604147cb9a80
a. The first 32-bytes are the Ed25519 public key44d6e9ca9eddaae4e4549279857c6ce212e3b550b29df42fb954e2e6089c539e
b. The second 32-bytes are the BIP-32 chain code4c713b210f355219074d7c91cdf7de56556b0f629680c8843ca2604147cb9a80
Now, suppose all we have is the address root hash. Given:
- the 64-byte public key
- the address attributes as a CBOR blob
- a serialized message
- a signature over the message We want to verify:
- The signature was signed by the owner of the public key
- The public key is associated with the address root hash we have record of
Verifying the signature is relatively straightforward:
ed25519PubKey <- pubKey[0..32]
verifyEd25519Signature ed25519PubKey message signature
Checking the address root hash is a bit more involved. The goal is to reconstruct the address root CBOR bytes, hash it, and check it against the hash we have record of. The CDDL for the address root is here https://raw.githubusercontent.com/cardano-foundation/CIPs/master/CIP-0019/CIP-0019-byron-addresses.cddl. Unfortunately, the schema is somewhat ambiguous and trying to use a tool like https://cbor.me will not produce the correct sequence of bytes. Here is how to serialize the address root with the given information:
writeByte(buffer, 0x83) // array(3) - ADDRESS_ROOT
writeByte(buffer, 0x00) // byte(0) - BYRON_ADDRESS_TYPE = Public-key
writeByte(buffer, 0x82) // array(2) - BYRON_ADDRESS_SPENDING_DATA
writeByte(buffer, 0x00) // byte(0) - indicates public-key spending data
writeByte(buffer, 0x58) // bytes
writeByte(buffer, 0x40) // length 64
write(buffer, pubKey) // Ed25519 public key + BIP-32 chain code
write(buffer, attributes) // map(?) - BYRON_ADDRESS_ATTRIBUTES
For our example address, this results in the following CBOR bytes:
83
00
82
00
58 40
44d6e9ca9eddaae4e4549279857c6ce212e3b550b29df42fb954e2e6089c539e4c713b210f355219074d7c91cdf7de56556b0f629680c8843ca2604147cb9a80
a0
Now we have our address root. We now need to double-hash it - first with SHA3-256, then with Blake2b-224:
blake2b_224(sha3_256(buffer))
which results in d3a912bbc69d18f9f8754c4f79adcbaed373aa6703444d465fd31047
, our original root hash.
The hashes match, the message was signed by the owner of the address.