user20778175
user20778175

Reputation: 21

Cosmos: Convert pubkey to consensus address

I need to do a conversion using the cosmrs library, but I couldn't do it. Can anyone who has experience with this help with a sample code? Also I have a note to complete it:

Take the address from the pubkey and bech32 encode it using the correct HRP prefix

Cosmrs lib: https://docs.rs/cosmrs/latest/cosmrs/crypto/struct.PublicKey.html

Basically, a prefix should be determined and the relevant conversion process should be performed in this way. this seems a bit over my head. but for the example below, the prefix to use is cosmosvalcons

Example pubkey:

"consensus_pubkey".
{
    "consensus_pubkey": {
      "@type": "/cosmos.crypto.ed25519.PubKey",
      "key": "bDO9bUrbyg0f1pTpmjjZU5cgsweCWdwL6HUVnsKJi7k="
    }
}

I need to get an address with cosmosvalcons... prefixed from pubkey, but all I get is nothing.

Upvotes: 2

Views: 972

Answers (2)

Farkhod Abdukodirov
Farkhod Abdukodirov

Reputation: 938

Following test code was done in MacOS.

# I call the sample project as the key-test
cargo new key-test
  • Update dependencies in ./key-test/Cargo.toml file:
[package]
name = "key-test"
version = "0.1.0"
edition = "2021"

[dependencies]
cosmrs = "0.15"
bech32 = "0.9"
sha2 = "0.10"
base64 = "0.21"
  • Then use the following sample code in ./key-test/src/main.rs:
use bech32::{self, ToBase32, Variant};
use sha2::{Digest, Sha256};
use base64::{Engine as _, engine::general_purpose};
use cosmrs::crypto::PublicKey;
use cosmrs::tendermint;

fn main() {
    let base64_pubkey = "bDO9bUrbyg0f1pTpmjjZU5cgsweCWdwL6HUVnsKJi7k=";

    // Decode base64 public key
    let decoded_bytes = general_purpose::STANDARD.decode(base64_pubkey)
        .expect("Failed to decode base64");

    // Convert raw bytes into Tendermint PublicKey (Ed25519)
    let tendermint_pubkey = tendermint::PublicKey::from_raw_ed25519(&decoded_bytes)
        .expect("Invalid public key");

    // Convert Tendermint PublicKey to CosmRS PublicKey
    let pubkey = PublicKey::from(tendermint_pubkey);

    // Compute the address (SHA-256 hash of the pubkey)
    let pubkey_bytes = pubkey.to_bytes();
    let hash = Sha256::digest(pubkey_bytes);
    let truncated_address = &hash[..20]; // Take first 20 bytes

    // Encode in Bech32 with the prefix "cosmosvalcons"
    let bech32_address = bech32::encode("cosmosvalcons", truncated_address.to_base32(), Variant::Bech32)
        .expect("Bech32 encoding failed");

    println!("Cosmos Validator Address: {}", bech32_address);
}
  • Then run the code
cargo run
  • Expected output:
   Compiling key-test v0.1.0 (/Users/farkhodabdukodirov/Development/temp/key-test)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.38s
     Running `target/debug/key-test`
Cosmos Validator Address: cosmosvalcons1lth4cv5tkn2fc5yuy4xx6rj7wvzrpxkkqg3my5

Sample code running image capture

Explanation:

  • Decode the base64 key
  • Convert it into tendermint pub key
  • Extract the pub key bytes
  • Compute the sha-256 hash and derive the val consensus address
  • Encode in bech32 with cosmosvalcons prefix

Upvotes: 0

amorfati
amorfati

Reputation: 13

I was struggling to convert pub key to consensus address on Axelar ecosystem but I found a solution. Here is the solution:

import { sha256 } from "@cosmjs/crypto"; 
import { toBech32, fromBase64 } from "@cosmjs/encoding";


const pubKey = {
  consensus_pubkey: {
    "@type": "/cosmos.crypto.ed25519.PubKey",
    key: "ijzDoMl+TKz06uaK5H+V3IgpuvPjqeAyc/HMW4wgsy8=",
  },
};


const ed25519PubkeyRaw = fromBase64(pubKey.consensus_pubkey.key);
const addressData = sha256(ed25519PubkeyRaw).slice(0, 20);
const bech32Address = toBech32("axelarvalcons", addressData);
logger.info(bech32Address);

Upvotes: 0

Related Questions