GitHub Logo HIP-632: Hedera Account Service (HAS) System Contract

Author Nana Essilfie-Conduah, Luke Lee
Working Group Danno Ferrin <@shemnon>, Richard Bair <@rbair23>, Ashe Oro <@ashe-oro>, Atul Mahamuni <@atul-hedera>, David Bakin <@david-bakin-sl>
Status Accepted
Needs Council Approval Yes
Review period ends Tue, 10 Jan 2023 07:00:00 +0000
Type Standards Track
Category Service
Created 2022-11-28
Updated 2022-12-13, 2022-12-20, 2023-01-03, 2023-01-18
Requires 631


Virtual Addresses introduced a list of ECDSA public addresses that are stored in the account entity and serve as the account identifier on the EVM for transactions. This is in addition to the Hedera Account ID that is used by default when no virtual addresses exist.

One result of this change is that accounts now have an organized presentation of different address formats that support historical formats and EVM equivalent formats. These addresses may be stored within smart contract state but their usefulness is limited without the ability to differentiate addresses.


Prior to HIP 631, deployed smart contracts may have stored an account with a Hedera Account ID or the extracted public address from an ECDSA public key. Subsequent to HIP 631, when a virtual address is added to an account it will now present itself as the virtual address and no longer use the Hedera Account ID. To avoid issues of lossed balance and permissions it is important that developers can distinguish between Hedera Account IDs and virtual addresses and translate easily between the them.

Additionally, many smart contracts utilize ECRECOVER as part of their authorization process in smart contracts. However, this is limited to ECDSA based signatures, which leaves E25519 and complex key types not supported in Hedera. To provide good user experience and to allow Hedera users to enjoy additional feature benefits over EVM equivalanece, it is important to provide authorization options within smart contract for non-ECDSA keys.


In smart contract executions the EVM will provide msg.sender values as either Hedera Account ID or virtual addresses. To support authorization flows that check addresses explicitly in smart contract code, the network should support smart contract distinguishing operations that allow smart contract to distinguish between the two forms. Additionally, to support standard implicit checks the network should support system contract checks in a manner similar ECRECOVER for easy developer support.

User stories

  1. As a developer I want to be able to distinguish between Hedera Account ID and virtual addresses within a smart contract so I can resolve address mappings in balance, permission or similar scenarios.
  2. As a developer I want to be able to confirm account authorization within a contract using simple ECDSA/ED2519 key raw signatures as I would on Ethereum using ECRECOVER.
  3. As a developer I want to be able to confirm account authorization for ECDSA accounts within a contract without being limited to ECRECOVER.
  4. As a developer I want to be able to confirm account authorization for accounts within a contract using protobuf signature maps in a similar fashion as I would on Ethereum using ECRECOVER.


A new system contract with functions to support address (Hedera Account ID and virtual) mapping reconciliation and authorization is proposed.

This will aid developers to support smart contract migration logic for cases where Hedera Account ID or virtual address values are encountered. Additionally, EVM developers who were limited to ECRECOVER authorization flows will be able to expand authorization checks to other key types.

hash signature return description
  getVirtualAddresses(address) address[] returns an array of virtual addresses for a given Hedera Account ID
  getHederaAddress(address) address returns the top level Hedera Account ID if applicable
  isVirtualAddress(address) bool true if valid virtual address, false if long-zero or non existing account
  isAuthorized(address, messageHash, signatureBlob) bool true if account is authorized to carry out transaction execution on account. Accepts protobuf key signature blobs. May be used for ECDSA, ED25519 and complex key flows
  isAuthorizedRaw(address, messageHash, signatureBlob) bool true if account is authorized to carry out transaction execution on account. Accepts single key raw signature blobs (ECDSA and ED25519). This provides similar logic to ECRECOVER.

isAuthorizedRaw(address, messageHash, signatureBlob) Function Usage

This function is similar to using the ECRECOVER precompile function. Ethereum uses the secp256k1 curve to produce signatures which are 65 bytes in length (length of v = 1 byte and length of r and s = 32 bytes each). ED25519 signatures are 64 bytes in length. The address given can be either a Hedera Account ID or an Ethereum virtual address. The isAuthorizedRaw function call will perform the following steps to determine its result:

  1. Call isVirtualAddress if the address is not a Hedera Account ID. Return false if not a virtual address.
  2. Determine if the length of the signatureBlob is 65 bytes in length
    • If true, extract v, r and s and run ECRECOVER(messageHash, v, r, s) and determine if the result matches any of the virtual address on the account. Return true if any matching address is found if given a Hedera Account ID. If given an Ethereum address, the recovered address must match the given address.
  3. If length of signatureBlob is 64 bytes in length
    • Retrieve the Hedera address. Determine if there is a single key associated with the Hedera Accound ID. If not return false.
    • If there is a single key, sign the messageHash and return true if the signature matches the signatureBlob.

isAuthorized(address, messageHash, signatureBlob) Function Usage

This function is used for Hedera account (non Ethereum) signature validation. It handles the more complex signature types which are available with Hedera accounts. One or more signatures will be encoded in protobuf format into the signatureBlob. The precompile function will look up the keys for the account and determine if the signatures passed in via the signatureBlob satisfy the signing requirements for the account. For example, if the account has a threshhold key of needing 3 out of 4 signatures,the precompile function will sign the messageHash with each key on the account and determine if at least 3 signatures in the signatureBlob matches.

The signatureBlob could be limited to encoding the following protobuf schema definitions

message SignatureMap {
     * Each signature pair corresponds to a unique Key required to sign the transaction.
    repeated SignaturePair sigPair = 1;

message SignaturePair {
     * First few bytes of the public key
    bytes pubKeyPrefix = 1;

    oneof signature {
         * smart contract virtual signature (always length zero)
        bytes contract = 2;

         * ed25519 signature
        bytes ed25519 = 3;

         * RSA-3072 signature
        bytes RSA_3072 = 4;

         * ECDSA p-384 signature
        bytes ECDSA_384 = 5;

         * ECDSA(secp256k1) signature
        bytes ECDSA_secp256k1 = 6;

Backwards Compatibility

This functionality is newly proposed and thus does not overwrite or alter existing functionality.

Security Implications

The ledger and the EVM maintain their authorization capabilities. In fact, it may be argued security is enhanced by the precompile support for contracts to verify both raw and protocol formatted signatures.

As always users and developers are responsible for key hygiene and proper storage of keys.

How to Teach This

Give example of using each function in context to show how they can be used to duplicate and enhance existing functionality available in Ethereum.

Reference Implementation

Rejected Ideas

Open Issues



This document is licensed under the Apache License, Version 2.0 – see LICENSE or (


Please cite this document as: