amino: Copy signature encoding from launchpad

This commit is contained in:
willclarktech 2021-03-23 17:40:48 +01:00
parent d183cc1e49
commit a75b299ec5
No known key found for this signature in database
GPG Key ID: 551A86E2E398ADF7
2 changed files with 109 additions and 0 deletions

View File

@ -0,0 +1,65 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { fromBase64 } from "@cosmjs/encoding";
import { decodeSignature, encodeSecp256k1Signature, StdSignature } from "./signature";
describe("signature", () => {
describe("encodeSecp256k1Signature", () => {
it("encodes a full signature", () => {
const pubkey = fromBase64("AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP");
const signature = fromBase64(
"1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==",
);
expect(encodeSecp256k1Signature(pubkey, signature)).toEqual({
pub_key: {
type: "tendermint/PubKeySecp256k1",
value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP",
},
signature: "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==",
});
});
it("throws when getting uncompressed public keys", () => {
const pubkey = fromBase64(
"BE8EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQE7WHpoHoNswYeoFkuYpYSKK4mzFzMV/dB0DVAy4lnNU=",
);
const signature = fromBase64(
"1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==",
);
expect(() => encodeSecp256k1Signature(pubkey, signature)).toThrowError(
/public key must be compressed secp256k1/i,
);
});
it("throws if signature contains recovery byte", () => {
const pubkey = fromBase64("AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP");
const signature = Uint8Array.from([
...fromBase64(
"1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==",
),
99,
]);
expect(() => encodeSecp256k1Signature(pubkey, signature)).toThrowError(
/signature must be 64 bytes long/i,
);
});
});
describe("decodeSignature", () => {
it("works for secp256k1", () => {
const signature: StdSignature = {
pub_key: {
type: "tendermint/PubKeySecp256k1",
value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP",
},
signature: "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==",
};
expect(decodeSignature(signature)).toEqual({
pubkey: fromBase64("AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP"),
signature: fromBase64(
"1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==",
),
});
});
});
});

View File

@ -0,0 +1,44 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { fromBase64, toBase64 } from "@cosmjs/encoding";
import { encodeSecp256k1Pubkey } from "./encoding";
import { Pubkey, pubkeyType } from "./pubkeys";
export interface StdSignature {
readonly pub_key: Pubkey;
readonly signature: string;
}
/**
* Takes a binary pubkey and signature to create a signature object
*
* @param pubkey a compressed secp256k1 public key
* @param signature a 64 byte fixed length representation of secp256k1 signature components r and s
*/
export function encodeSecp256k1Signature(pubkey: Uint8Array, signature: Uint8Array): StdSignature {
if (signature.length !== 64) {
throw new Error(
"Signature must be 64 bytes long. Cosmos SDK uses a 2x32 byte fixed length encoding for the secp256k1 signature integers r and s.",
);
}
return {
pub_key: encodeSecp256k1Pubkey(pubkey),
signature: toBase64(signature),
};
}
export function decodeSignature(
signature: StdSignature,
): { readonly pubkey: Uint8Array; readonly signature: Uint8Array } {
switch (signature.pub_key.type) {
// Note: please don't add cases here without writing additional unit tests
case pubkeyType.secp256k1:
return {
pubkey: fromBase64(signature.pub_key.value),
signature: fromBase64(signature.signature),
};
default:
throw new Error("Unsupported pubkey type");
}
}