Merge pull request #757 from cosmos/753-tm-address-helpers

Add address helpers to tendermint-rpc
This commit is contained in:
Simon Warta 2021-04-07 14:12:05 +02:00 committed by GitHub
commit 10ddc6282d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 92 additions and 5 deletions

View File

@ -61,6 +61,10 @@ and this project adheres to
- @cosmjs/proto-signing: Export `DirectSecp256k1HdWalletOptions` interface.
- @cosmjs/proto-signing: Add `bip39Password` option to `DirectSecp256k1HdWallet`
options.
- @cosmjs/amino: Add `rawEd25519PubkeyToRawAddress` helper function.
- @cosmjs/tendermint-rpc: Add `pubkeyToAddress`, `pubkeyToRawAddress`,
`rawEd25519PubkeyToRawAddress`, and `rawSecp256k1PubkeyToRawAddress` helper
functions.
### Changed

View File

@ -6,6 +6,13 @@ import { Bech32, fromBase64 } from "@cosmjs/encoding";
import { encodeAminoPubkey } from "./encoding";
import { isEd25519Pubkey, isMultisigThresholdPubkey, isSecp256k1Pubkey, Pubkey } from "./pubkeys";
export function rawEd25519PubkeyToRawAddress(pubkeyData: Uint8Array): Uint8Array {
if (pubkeyData.length !== 32) {
throw new Error(`Invalid Ed25519 pubkey length: ${pubkeyData.length}`);
}
return sha256(pubkeyData).slice(0, 20);
}
export function rawSecp256k1PubkeyToRawAddress(pubkeyData: Uint8Array): Uint8Array {
if (pubkeyData.length !== 33) {
throw new Error(`Invalid Secp256k1 pubkey length (compressed): ${pubkeyData.length}`);
@ -20,10 +27,7 @@ export function pubkeyToRawAddress(pubkey: Pubkey): Uint8Array {
return rawSecp256k1PubkeyToRawAddress(pubkeyData);
} else if (isEd25519Pubkey(pubkey)) {
const pubkeyData = fromBase64(pubkey.value);
if (pubkeyData.length !== 32) {
throw new Error(`Invalid Ed25519 pubkey length: ${pubkeyData.length}`);
}
return sha256(pubkeyData).slice(0, 20);
return rawEd25519PubkeyToRawAddress(pubkeyData);
} else if (isMultisigThresholdPubkey(pubkey)) {
// https://github.com/tendermint/tendermint/blob/38b401657e4ad7a7eeb3c30a3cbf512037df3740/crypto/multisig/threshold_pubkey.go#L71-L74
const pubkeyData = encodeAminoPubkey(pubkey);

View File

@ -1,4 +1,9 @@
export { pubkeyToAddress, pubkeyToRawAddress, rawSecp256k1PubkeyToRawAddress } from "./addresses";
export {
pubkeyToAddress,
pubkeyToRawAddress,
rawEd25519PubkeyToRawAddress,
rawSecp256k1PubkeyToRawAddress,
} from "./addresses";
export { Coin, coin, coins, parseCoins } from "./coins";
export {
decodeAminoPubkey,

View File

@ -0,0 +1,35 @@
import { fromHex } from "@cosmjs/encoding";
import { pubkeyToAddress, pubkeyToRawAddress } from "./addresses";
// Test values from https://github.com/informalsystems/tendermint-rs/blob/v0.18.1/tendermint/src/account.rs#L153-L192
describe("addresses", () => {
describe("pubkeyToRawAddress", () => {
it("works for Secp256k1", () => {
const pubkey = fromHex("02950E1CDFCB133D6024109FD489F734EEB4502418E538C28481F22BCE276F248C");
expect(pubkeyToRawAddress("secp256k1", pubkey)).toEqual(
fromHex("7C2BB42A8BE69791EC763E51F5A49BCD41E82237"),
);
});
it("works for Ed25519", () => {
const pubkey = fromHex("14253D61EF42D166D02E68D540D07FDF8D65A9AF0ACAA46302688E788A8521E2");
expect(pubkeyToRawAddress("ed25519", pubkey)).toEqual(
fromHex("0CDA3F47EF3C4906693B170EF650EB968C5F4B2C"),
);
});
});
describe("pubkeyToAddress", () => {
it("works for Secp256k1", () => {
const pubkey = fromHex("02950E1CDFCB133D6024109FD489F734EEB4502418E538C28481F22BCE276F248C");
expect(pubkeyToAddress("secp256k1", pubkey)).toEqual("7C2BB42A8BE69791EC763E51F5A49BCD41E82237");
});
it("works for Ed25519", () => {
const pubkey = fromHex("14253D61EF42D166D02E68D540D07FDF8D65A9AF0ACAA46302688E788A8521E2");
expect(pubkeyToAddress("ed25519", pubkey)).toEqual("0CDA3F47EF3C4906693B170EF650EB968C5F4B2C");
});
});
});

View File

@ -0,0 +1,33 @@
import { ripemd160, sha256 } from "@cosmjs/crypto";
import { toHex } from "@cosmjs/encoding";
export function rawEd25519PubkeyToRawAddress(pubkeyData: Uint8Array): Uint8Array {
if (pubkeyData.length !== 32) {
throw new Error(`Invalid Ed25519 pubkey length: ${pubkeyData.length}`);
}
return sha256(pubkeyData).slice(0, 20);
}
export function rawSecp256k1PubkeyToRawAddress(pubkeyData: Uint8Array): Uint8Array {
if (pubkeyData.length !== 33) {
throw new Error(`Invalid Secp256k1 pubkey length (compressed): ${pubkeyData.length}`);
}
return ripemd160(sha256(pubkeyData));
}
// For secp256k1 this assumes we already have a compressed pubkey.
export function pubkeyToRawAddress(type: "ed25519" | "secp256k1", data: Uint8Array): Uint8Array {
switch (type) {
case "ed25519":
return rawEd25519PubkeyToRawAddress(data);
case "secp256k1":
return rawSecp256k1PubkeyToRawAddress(data);
default:
// Keep this case here to guard against new types being added but not handled
throw new Error(`Pubkey type ${type} not supported`);
}
}
export function pubkeyToAddress(type: "ed25519" | "secp256k1", data: Uint8Array): string {
return toHex(pubkeyToRawAddress(type, data)).toUpperCase();
}

View File

@ -1,3 +1,9 @@
export {
pubkeyToAddress,
pubkeyToRawAddress,
rawEd25519PubkeyToRawAddress,
rawSecp256k1PubkeyToRawAddress,
} from "./addresses";
export {
adaptor33,
adaptor34,