GitHub Logo HIP-222: Support ECDSA(secp256k1) keys

Author Michael Tinker
Discussions-To https://github.com/hashgraph/hedera-improvement-proposal/discussions/221
Status Final
Needs Council Approval Yes
Review period ends Mon, 29 Nov 2021 07:00:00 +0000
Type Standards Track
Category Service
Created 2021-11-15
Updated 2022-04-26
Release v0.21.0

Abstract

The only kind of public key that may currently appear in a Hedera key structure is a Ed25519 public key. It follows that users can only secure their transactions using Ed25519 signatures.

We propose to enable support for ECDSA(secp256k1) cryptography by,

  • Extending the Hedera API protobufs with new fields for ECDSA(secp256k1) keys and signatures.
  • Clearly documenting how users will populate these new protobuf fields.
  • Updating the node software to support ECDSA(secp256k1) keys and signatures wherever their Ed25519 equivalents are currently supported.

There are three design proposals in this HIP that, while fairly standard, deserve emphasis:

  1. Public keys are to be given in their compressed 33-byte form.
  2. The signing algorithm is to be keccak256-with-ECDSA; that is, clients will sign the keccak256 hash of the bytes in their SignedTrasaction#bodyBytes field.
  3. The signature bytes in the SignaturePair for a ECDSA(secp256k1) key are to be the raw 64-byte encoding of the (r, s) values of the ECDSA signature.

Motivation

Some users might prefer to use ECDSA(secp256k1) keys as on the Bitcoin and Ethereum networks; for example, to simplify reuse of existing client code and tooling.

Rationale

The protobuf specification below is the only natural extension of the existing Hedera API protobufs. We propose using 33-byte compressed public keys instead of uncompressed keys because the compressed form reduces both network usage and state size. We propose using the keccak256-with-ECDSA signing algorithm because this is standard on the Ethereum network.

User stories

  • As a smart contract developer, I want to use existing tools that assume ECDSA(secp256k1) keys.
  • As an owner of a Hedera account, I want to secure transactions involving my account with a ECDSA(secp256k1) key.
  • As the creator of a Hedera token, I want the supply manager role to be controlled by a ECDSA(secp256k1) keys.

Specification

Only two protobuf changes are required. To the Key message type, we need to extend the oneof key with a new choice:

message Key {
    oneof key {
        ...
        /**
         * Compressed ECDSA(secp256k1) public key bytes
         */
        bytes ECDSA_secp256k1 = 7;

To the SignaturePair message type, we need to extend the oneof signature with a new choice:

message SignaturePair {
    ...
    oneof signature {
        ...
        /**
         * The 64-byte ECDSA(secp256k1) signature of the keccak256 hash of the body bytes, with
         * the (r, s) values of the signature concatenated in unsigned big-endian form.
         */
        bytes ECDSA_secp256k1 = 6;

When a user is creating or updating a Hedera key structure to include a ECDSA(secp256k1) public key, they should set the bytes of the Key.ECDSA_secp256k1 field to the compressed form of the public key. (That is, the first byte should be 0x02 if the y-coordinate of the key is even, and 0x03 if the y-coordinate is odd; and the following 32 bytes should be the x-coordinate as an unsigned 256-bit integer.)

For example, if the uncompressed public key of the user’s key pair is,

0x043232a86a9f267290db881b82547ae53eb4d7a917324a494e4f938a7092be4924e9c4e57a4469664ec57d4688a1c100945f8772308701739b86bc2745d2dbb0f6

Then the hex-encoded bytes of the Key.ECDSA_secp256k1 field should be,

0x023232a86a9f267290db881b82547ae53eb4d7a917324a494e4f938a7092be4924

When a user is providing an ECDSA(secp256k1) signature in a SignaturePair.ECDSA_secp256k1 field, it should be the 64-byte “raw” encoding of the (r, s) values that result from from signing the keccak256 hash of the SignedTransaction.bodyBytes from the top-level Transaction with the relevant ECDSA(secp256k1) private key. (That is, the signature bytes should be the concatentation of the r and s values in unsigned big-endian form.)

For example, if the user is signing the keccak256 digest,

0x744c77a7af70b3a522009f0a963384eccfa77662a594d6e0247dfba095eb48d5

with the private key,

0x7f327369608f973b63ab29cfebd9de54ffc39cc060c1bdae9ba79bfb7ef5028c

Then the signature bytes should be,

0x60498ba4ae336e76924d8d047c9991f873ebd21ee6d8672681273d6633d8044a7ce0d3f0203587f085fcd3d5a9c3ba72cbf7eef5a4771cfb14415f01618cc831

Backwards Compatibility

This HIP does not make any breaking changes. Clients that continue to use Ed25519 keys and signatures will be unaffected.

Security Implications

If we observe a significant performance impact when verifying ECDSA(secp256k1) signatures compared to Ed25519 signatures, we will need to throttle transactions with ECDSA(secp256k1) signatures at a lower TPS.

How to Teach This

In one sentence: “Allow Hedera entities to be secured using ECDSA(secp256k1) keys and signatures.”

Reference Implementation

Ongoing.

Rejected Ideas

No other designs seemed natural.

Open Issues

Signature verification is done through the Platform SDK, so the node software depends on the SDK being updated to also verify ECDSA(secp256k1) signatures with acceptable performance.

References

Copyright/license

This document is licensed under the Apache License, Version 2.0 – see LICENSE or (https://www.apache.org/licenses/LICENSE-2.0)

Citation

Please cite this document as: