diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c1fad21..2ce58ea2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to ### Added +- @cosmjs/amino: Add `encodeEd25519Pubkey` analogue to the existing + `encodeSecp256k1Pubkey`. - @cosmjs/utils: Add `isDefined` which checks for `undefined` in a TypeScript-friendly way. diff --git a/packages/amino/src/encoding.spec.ts b/packages/amino/src/encoding.spec.ts index 3813e6ca..0a056e98 100644 --- a/packages/amino/src/encoding.spec.ts +++ b/packages/amino/src/encoding.spec.ts @@ -1,3 +1,4 @@ +import { Random } from "@cosmjs/crypto"; import { fromBase64, fromBech32, fromHex } from "@cosmjs/encoding"; import { @@ -5,6 +6,7 @@ import { decodeBech32Pubkey, encodeAminoPubkey, encodeBech32Pubkey, + encodeEd25519Pubkey, encodeSecp256k1Pubkey, } from "./encoding"; import { Pubkey } from "./pubkeys"; @@ -37,6 +39,25 @@ describe("encoding", () => { }); }); + describe("encodeEd25519Pubkey", () => { + it("encodes a compressed pubkey", () => { + const pubkey = fromBase64("ICKLJPyWYIF35GpOclg0gu957WYJe4PHzyn2scCZoek="); + expect(encodeEd25519Pubkey(pubkey)).toEqual({ + type: "tendermint/PubKeyEd25519", + value: "ICKLJPyWYIF35GpOclg0gu957WYJe4PHzyn2scCZoek=", + }); + }); + + it("throws for wrong pubkey lengths", () => { + expect(() => encodeEd25519Pubkey(Random.getBytes(31))).toThrowError( + /ed25519 public key must be 32 bytes long/i, + ); + expect(() => encodeEd25519Pubkey(Random.getBytes(64))).toThrowError( + /ed25519 public key must be 32 bytes long/i, + ); + }); + }); + describe("decodeAminoPubkey", () => { it("works for secp256k1", () => { const amino = fromBech32( diff --git a/packages/amino/src/encoding.ts b/packages/amino/src/encoding.ts index fa0b35ba..0b069bca 100644 --- a/packages/amino/src/encoding.ts +++ b/packages/amino/src/encoding.ts @@ -3,6 +3,7 @@ import { Uint53 } from "@cosmjs/math"; import { arrayContentStartsWith } from "@cosmjs/utils"; import { + Ed25519Pubkey, isEd25519Pubkey, isMultisigThresholdPubkey, isSecp256k1Pubkey, @@ -12,6 +13,10 @@ import { Secp256k1Pubkey, } from "./pubkeys"; +/** + * Takes a Secp256k1 public key as raw bytes and returns the Amino JSON + * representation of it (the type/value wrapper object). + */ export function encodeSecp256k1Pubkey(pubkey: Uint8Array): Secp256k1Pubkey { if (pubkey.length !== 33 || (pubkey[0] !== 0x02 && pubkey[0] !== 0x03)) { throw new Error("Public key must be compressed secp256k1, i.e. 33 bytes starting with 0x02 or 0x03"); @@ -22,6 +27,20 @@ export function encodeSecp256k1Pubkey(pubkey: Uint8Array): Secp256k1Pubkey { }; } +/** + * Takes an Edd25519 public key as raw bytes and returns the Amino JSON + * representation of it (the type/value wrapper object). + */ +export function encodeEd25519Pubkey(pubkey: Uint8Array): Ed25519Pubkey { + if (pubkey.length !== 32) { + throw new Error("Ed25519 public key must be 32 bytes long"); + } + return { + type: pubkeyType.ed25519, + value: toBase64(pubkey), + }; +} + // As discussed in https://github.com/binance-chain/javascript-sdk/issues/163 // Prefixes listed here: https://github.com/tendermint/tendermint/blob/d419fffe18531317c28c29a292ad7d253f6cafdf/docs/spec/blockchain/encoding.md#public-key-cryptography // Last bytes is varint-encoded length prefix diff --git a/packages/amino/src/index.ts b/packages/amino/src/index.ts index d273be77..2edbb2db 100644 --- a/packages/amino/src/index.ts +++ b/packages/amino/src/index.ts @@ -10,6 +10,7 @@ export { decodeBech32Pubkey, encodeAminoPubkey, encodeBech32Pubkey, + encodeEd25519Pubkey, encodeSecp256k1Pubkey, } from "./encoding"; export { createMultisigThresholdPubkey } from "./multisig";