Add Secpk256k1 offline key signer

Renamed Secp256k1Wallet -> Secp256k1HdWallet

Renamed Secp256k1Key -> Secp256k1Wallet

Renamed fromPrivateKey function

Fixed linter issues

Rename Secp256k1Wallet.fromMnemonic everywhere

Revert "Rename Secp256k1Wallet.fromMnemonic everywhere"

This reverts commit 18c52968bc1a234755c61d1d5c67850222239bd7.

Revert "Fixed linter issues"

This reverts commit 8e6fce93d809f160e8dafa9478f56f9effcf561a.

Revert "Renamed fromPrivateKey function"

This reverts commit d628f186bb126d4fc2b205dbc0b95b3198af02df.

Revert "Renamed Secp256k1Key -> Secp256k1Wallet"

This reverts commit 35a082701de9bd2c8cf89b25a168f12212d4ba8a.

Revert "Renamed Secp256k1Wallet -> Secp256k1HdWallet"

This reverts commit bd69f293e1ae7d96ad0afd295af360de70863e13.

Ran linter

Renamed fromPrivateKey

Updated Typescript definitions
This commit is contained in:
Shane Vitarana 2020-10-07 12:03:07 -04:00 committed by Simon Warta
parent 4e52a89175
commit 04a74aac83
3 changed files with 128 additions and 0 deletions

View File

@ -0,0 +1,54 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { Secp256k1, Secp256k1Signature, Sha256 } from "@cosmjs/crypto";
import { fromBase64, fromHex } from "@cosmjs/encoding";
import { serializeSignDoc, StdSignDoc } from "./encoding";
import { Secp256k1Key } from "./secp256k1key";
describe("Secp256k1Key", () => {
const defaultPrivkey = fromHex("b8c462d2bb0c1a92edf44f735021f16c270f28ee2c3d1cb49943a5e70a3c763e");
const defaultAddress = "cosmos1kxt5x5q2l57ma2d434pqpafxdm0mgeg9c8cvtx";
const defaultPubkey = fromHex("03f146c27639179e5b67b8646108f48e1a78b146c74939e34afaa5414ad5c93f8a");
describe("fromPrivkey", () => {
it("works", async () => {
const signer = await Secp256k1Key.fromPrivkey(defaultPrivkey);
expect(signer).toBeTruthy();
});
});
describe("getAccounts", () => {
it("resolves to a list of accounts", async () => {
const signer = await Secp256k1Key.fromPrivkey(defaultPrivkey);
const accounts = await signer.getAccounts();
expect(accounts.length).toEqual(1);
expect(accounts[0]).toEqual({
address: defaultAddress,
algo: "secp256k1",
pubkey: defaultPubkey,
});
});
});
describe("sign", () => {
it("resolves to valid signature if enabled", async () => {
const signer = await Secp256k1Key.fromPrivkey(defaultPrivkey);
const signDoc: StdSignDoc = {
msgs: [],
fee: { amount: [], gas: "23" },
chain_id: "foochain",
memo: "hello, world",
account_number: "7",
sequence: "54",
};
const { signed, signature } = await signer.sign(defaultAddress, signDoc);
expect(signed).toEqual(signDoc);
const valid = await Secp256k1.verifySignature(
Secp256k1Signature.fromFixedLength(fromBase64(signature.signature)),
new Sha256(serializeSignDoc(signed)).digest(),
defaultPubkey,
);
expect(valid).toEqual(true);
});
});
});

View File

@ -0,0 +1,56 @@
import { Secp256k1, Sha256 } from "@cosmjs/crypto";
import { rawSecp256k1PubkeyToAddress } from "./address";
import { serializeSignDoc, StdSignDoc } from "./encoding";
import { encodeSecp256k1Signature } from "./signature";
import { AccountData, OfflineSigner, SignResponse } from "./signer";
export class Secp256k1Key implements OfflineSigner {
/**
* Creates a Secp256k1 key signer from the given private key
*
* @param privkey The private key.
* @param prefix The bech32 address prefix (human readable part). Defaults to "cosmos".
*/
public static async fromPrivkey(privkey: Uint8Array, prefix = "cosmos"): Promise<Secp256k1Key> {
const uncompressed = (await Secp256k1.makeKeypair(privkey)).pubkey;
return new Secp256k1Key(privkey, Secp256k1.compressPubkey(uncompressed), prefix);
}
private readonly pubkey: Uint8Array;
private readonly privkey: Uint8Array;
private readonly prefix: string;
private constructor(privkey: Uint8Array, pubkey: Uint8Array, prefix: string) {
this.privkey = privkey;
this.pubkey = pubkey;
this.prefix = prefix;
}
private get address(): string {
return rawSecp256k1PubkeyToAddress(this.pubkey, this.prefix);
}
public async getAccounts(): Promise<readonly AccountData[]> {
return [
{
algo: "secp256k1",
address: this.address,
pubkey: this.pubkey,
},
];
}
public async sign(signerAddress: string, signDoc: StdSignDoc): Promise<SignResponse> {
if (signerAddress !== this.address) {
throw new Error(`Address ${signerAddress} not found in wallet`);
}
const message = new Sha256(serializeSignDoc(signDoc)).digest();
const signature = await Secp256k1.createSignature(message, this.privkey);
const signatureBytes = new Uint8Array([...signature.r(32), ...signature.s(32)]);
return {
signed: signDoc,
signature: encodeSecp256k1Signature(this.pubkey, signatureBytes),
};
}
}

View File

@ -0,0 +1,18 @@
import { StdSignDoc } from "./encoding";
import { AccountData, OfflineSigner, SignResponse } from "./signer";
export declare class Secp256k1Key implements OfflineSigner {
/**
* Creates a Secp256k1 key signer from the given private key
*
* @param privkey The private key.
* @param prefix The bech32 address prefix (human readable part). Defaults to "cosmos".
*/
static fromPrivkey(privkey: Uint8Array, prefix?: string): Promise<Secp256k1Key>;
private readonly pubkey;
private readonly privkey;
private readonly prefix;
private constructor();
private get address();
getAccounts(): Promise<readonly AccountData[]>;
sign(signerAddress: string, signDoc: StdSignDoc): Promise<SignResponse>;
}