Merge pull request #79 from confio/pen-sign

Let Pen.sign return full StdSignature
This commit is contained in:
Simon Warta 2020-02-12 00:09:16 +01:00 committed by GitHub
commit ff57e8d2a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 180 additions and 132 deletions

View File

@ -67,8 +67,8 @@ describe("encode", () => {
},
];
describe("encodePubKey", () => {
it("encodes a Secp256k1 pubkey", () => {
describe("encodePubkey", () => {
it("works for compressed public key", () => {
expect(encodePubkey(defaultPubkey)).toEqual({
type: "tendermint/PubKeySecp256k1",
value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP",

View File

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/camelcase */
import { encodeSecp256k1Signature, types } from "@cosmwasm/sdk";
import { encodeSecp256k1Pubkey, encodeSecp256k1Signature, types } from "@cosmwasm/sdk";
import {
Algorithm,
Amount,
@ -10,19 +10,18 @@ import {
SignedTransaction,
UnsignedTransaction,
} from "@iov/bcp";
import { Secp256k1 } from "@iov/crypto";
import { Encoding } from "@iov/encoding";
import { BankTokens, Erc20Token } from "./types";
const { toBase64 } = Encoding;
// TODO: This function seems to be unused and is not well tested (e.g. uncompressed secp256k1 or ed25519)
export function encodePubkey(pubkey: PubkeyBundle): types.PubKey {
switch (pubkey.algo) {
case Algorithm.Secp256k1:
return {
type: types.pubkeyType.secp256k1,
value: toBase64(pubkey.data),
};
return encodeSecp256k1Pubkey(pubkey.data);
case Algorithm.Ed25519:
return {
type: types.pubkeyType.ed25519,
@ -70,8 +69,11 @@ export function encodeFee(fee: Fee, tokens: BankTokens): types.StdFee {
export function encodeFullSignature(fullSignature: FullSignature): types.StdSignature {
switch (fullSignature.pubkey.algo) {
case Algorithm.Secp256k1:
return encodeSecp256k1Signature(fullSignature.pubkey.data, fullSignature.signature);
case Algorithm.Secp256k1: {
const compressedPubkey = Secp256k1.compressPubkey(fullSignature.pubkey.data);
const normalizedSignature = Secp256k1.trimRecoveryByte(fullSignature.signature);
return encodeSecp256k1Signature(compressedPubkey, normalizedSignature);
}
default:
throw new Error("Unsupported signing algorithm");
}

View File

@ -65,7 +65,7 @@ const sendTokensMsg: types.MsgSend = {
};
const signBytes = makeSignBytes([sendTokensMsg], defaultFee, defaultNetworkId, memo, account_number, sequence);
const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
const signature = await pen.sign(signBytes);
const signedTx: types.StdTx = {
msg: [sendTokensMsg],
fee: defaultFee,

View File

@ -40,7 +40,7 @@ const instantiateContract = async (initClient: RestClient, initPen: Secp256k1Pen
};
const account = (await initClient.authAccounts(faucetAddress)).result.value;
const signBytes = makeSignBytes([instantiateContractMsg], defaultFee, networkId, memo, account);
const signature = encodeSecp256k1Signature(initPen.pubkey, await initPen.createSignature(signBytes));
const signature = await initPen.sign(signBytes);
const signedTx = {
msg: [instantiateContractMsg],
fee: defaultFee,
@ -71,7 +71,7 @@ const executeContract = async (execClient: RestClient, execPen: Secp256k1Pen, co
};
const account = (await execClient.authAccounts(faucetAddress)).result.value;
const signBytes = makeSignBytes([instantiateContractMsg], defaultFee, networkId, memo, account);
const signature = encodeSecp256k1Signature(execPen.pubkey, await execPen.createSignature(signBytes));
const signature = await execPen.sign(signBytes);
const signedTx = {
msg: [instantiateContractMsg],
fee: defaultFee,

View File

@ -136,7 +136,7 @@ export function main(originalArgs: readonly string[]): void {
const pubkey = encodeSecp256k1Pubkey(pen.pubkey);
const address = encodeAddress(pubkey, "cosmos");
const data = Encoding.toAscii("foo bar");
const signature = await pen.createSignature(data);
const signature = await pen.sign(data);
console.info("Done testing, will exit now.");
process.exit(0);

View File

@ -1,5 +1,5 @@
import { CosmWasmClient } from "./cosmwasmclient";
import { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding";
import { makeSignBytes, marshalTx } from "./encoding";
import { findAttribute } from "./logs";
import { Secp256k1Pen } from "./pen";
import { RestClient } from "./restclient";
@ -95,7 +95,7 @@ describe("CosmWasmClient", () => {
const chainId = await client.chainId();
const { accountNumber, sequence } = await client.getNonce(faucet.address);
const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence);
const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
const signature = await pen.sign(signBytes);
const signedTx = {
msg: [sendMsg],
fee: fee,
@ -113,9 +113,7 @@ describe("CosmWasmClient", () => {
it("works", async () => {
pendingWithoutCosmos();
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
const client = CosmWasmClient.makeWritable(httpUrl, faucet.address, async signBytes => {
return encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
});
const client = CosmWasmClient.makeWritable(httpUrl, faucet.address, signBytes => pen.sign(signBytes));
const codeId = await client.upload(getRandomizedHackatom());
expect(codeId).toBeGreaterThanOrEqual(1);
});
@ -125,9 +123,7 @@ describe("CosmWasmClient", () => {
it("works with transfer amount", async () => {
pendingWithoutCosmos();
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
const client = CosmWasmClient.makeWritable(httpUrl, faucet.address, async signBytes => {
return encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
});
const client = CosmWasmClient.makeWritable(httpUrl, faucet.address, signBytes => pen.sign(signBytes));
const codeId = await client.upload(getRandomizedHackatom());
const transferAmount: readonly Coin[] = [
@ -159,9 +155,7 @@ describe("CosmWasmClient", () => {
it("can instantiate one code multiple times", async () => {
pendingWithoutCosmos();
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
const client = CosmWasmClient.makeWritable(httpUrl, faucet.address, async signBytes => {
return encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
});
const client = CosmWasmClient.makeWritable(httpUrl, faucet.address, signBytes => pen.sign(signBytes));
const codeId = await client.upload(getRandomizedHackatom());
const contractAddress1 = await client.instantiate(codeId, {
@ -180,9 +174,7 @@ describe("CosmWasmClient", () => {
it("works", async () => {
pendingWithoutCosmos();
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
const client = CosmWasmClient.makeWritable(httpUrl, faucet.address, async signBytes => {
return encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
});
const client = CosmWasmClient.makeWritable(httpUrl, faucet.address, signBytes => pen.sign(signBytes));
const codeId = await client.upload(getRandomizedHackatom());
// instantiate

View File

@ -1,59 +1 @@
import { Encoding } from "@iov/encoding";
import { encodeSecp256k1Signature } from "./encoding";
const { fromBase64 } = Encoding;
describe("encoding", () => {
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({
// eslint-disable-next-line @typescript-eslint/camelcase
pub_key: {
type: "tendermint/PubKeySecp256k1",
value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP",
},
signature: "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==",
});
});
it("compresses uncompressed public keys", () => {
const pubkey = fromBase64(
"BE8EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQE7WHpoHoNswYeoFkuYpYSKK4mzFzMV/dB0DVAy4lnNU=",
);
const signature = fromBase64(
"1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==",
);
expect(encodeSecp256k1Signature(pubkey, signature)).toEqual({
// eslint-disable-next-line @typescript-eslint/camelcase
pub_key: {
type: "tendermint/PubKeySecp256k1",
value: "A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ",
},
signature: "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==",
});
});
it("removes recovery values from signature data", () => {
const pubkey = fromBase64("AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP");
const signature = Uint8Array.from([
...fromBase64(
"1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==",
),
99,
]);
expect(encodeSecp256k1Signature(pubkey, signature)).toEqual({
// eslint-disable-next-line @typescript-eslint/camelcase
pub_key: {
type: "tendermint/PubKeySecp256k1",
value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP",
},
signature: "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==",
});
});
});
});
describe("encoding", () => {});

View File

@ -1,10 +1,8 @@
import { Secp256k1 } from "@iov/crypto";
import { Encoding } from "@iov/encoding";
import { encodeSecp256k1Pubkey } from "./pubkey";
import { Msg, StdFee, StdSignature, StdTx } from "./types";
import { Msg, StdFee, StdTx } from "./types";
const { toBase64, toUtf8 } = Encoding;
const { toUtf8 } = Encoding;
function sortJson(json: any): any {
if (typeof json !== "object" || json === null) {
@ -59,12 +57,3 @@ export function makeSignBytes(
const signMsg = sortJson(signJson);
return toUtf8(JSON.stringify(signMsg));
}
export function encodeSecp256k1Signature(pubkey: Uint8Array, signature: Uint8Array): StdSignature {
return {
// eslint-disable-next-line @typescript-eslint/camelcase
pub_key: encodeSecp256k1Pubkey(pubkey),
// Recovery seems to be unused
signature: toBase64(Secp256k1.trimRecoveryByte(signature)),
};
}

View File

@ -4,8 +4,9 @@ export { logs, types };
export { CosmosAddressBech32Prefix, encodeAddress, isValidAddress } from "./address";
export { unmarshalTx } from "./decoding";
export { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding";
export { makeSignBytes, marshalTx } from "./encoding";
export { RestClient, TxsResponse } from "./restclient";
export { encodeSecp256k1Signature } from "./signature";
export { CosmWasmClient, ExecuteResult, GetNonceResult, PostTxResult } from "./cosmwasmclient";
export { makeCosmoshubPath, Pen, PrehashType, Secp256k1Pen } from "./pen";
export {

View File

@ -2,6 +2,7 @@ import { Secp256k1, Secp256k1Signature, Sha256 } from "@iov/crypto";
import { Encoding } from "@iov/encoding";
import { Secp256k1Pen } from "./pen";
import { decodeSignature } from "./signature";
const { fromHex } = Encoding;
@ -33,12 +34,12 @@ describe("Sec256k1Pen", () => {
"special sign fit simple patrol salute grocery chicken wheat radar tonight ceiling",
);
const data = Encoding.toAscii("foo bar");
const signature = await pen.createSignature(data);
const { pubkey, signature } = decodeSignature(await pen.sign(data));
const valid = await Secp256k1.verifySignature(
new Secp256k1Signature(signature.slice(0, 32), signature.slice(32, 64)),
new Sha256(data).digest(),
pen.pubkey,
pubkey,
);
expect(valid).toEqual(true);
});

View File

@ -9,6 +9,9 @@ import {
Slip10RawIndex,
} from "@iov/crypto";
import { encodeSecp256k1Signature } from "./signature";
import { StdSignature } from "./types";
export type PrehashType = "sha256" | "sha512" | null;
/**
@ -23,7 +26,7 @@ export type PrehashType = "sha256" | "sha512" | null;
*/
export interface Pen {
readonly pubkey: Uint8Array;
readonly createSignature: (signBytes: Uint8Array, prehashType?: PrehashType) => Promise<Uint8Array>;
readonly sign: (signBytes: Uint8Array, prehashType?: PrehashType) => Promise<StdSignature>;
}
function prehash(bytes: Uint8Array, type: PrehashType): Uint8Array {
@ -73,14 +76,12 @@ export class Secp256k1Pen implements Pen {
}
/**
* Creates a fixed length encoding of the signature parameters r (32 bytes) and s (32 bytes).
* Creates and returns a signature
*/
public async createSignature(
signBytes: Uint8Array,
prehashType: PrehashType = "sha256",
): Promise<Uint8Array> {
public async sign(signBytes: Uint8Array, prehashType: PrehashType = "sha256"): Promise<StdSignature> {
const message = prehash(signBytes, prehashType);
const signature = await Secp256k1.createSignature(message, this.privkey);
return new Uint8Array([...signature.r(32), ...signature.s(32)]);
const fixedLengthSignature = new Uint8Array([...signature.r(32), ...signature.s(32)]);
return encodeSecp256k1Signature(this.pubkey, fixedLengthSignature);
}
}

View File

@ -7,7 +7,7 @@ const { fromBase64 } = Encoding;
describe("pubkey", () => {
describe("encodeSecp256k1Pubkey", () => {
it("encodes a full signature", () => {
it("encodes a compresed pubkey", () => {
const pubkey = fromBase64("AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP");
expect(encodeSecp256k1Pubkey(pubkey)).toEqual({
type: "tendermint/PubKeySecp256k1",
@ -15,14 +15,11 @@ describe("pubkey", () => {
});
});
it("compresses uncompressed public keys", () => {
it("throws for uncompressed public keys", () => {
const pubkey = fromBase64(
"BE8EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQE7WHpoHoNswYeoFkuYpYSKK4mzFzMV/dB0DVAy4lnNU=",
);
expect(encodeSecp256k1Pubkey(pubkey)).toEqual({
type: "tendermint/PubKeySecp256k1",
value: "A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ",
});
expect(() => encodeSecp256k1Pubkey(pubkey)).toThrowError(/public key must be compressed secp256k1/i);
});
});

View File

@ -1,13 +1,15 @@
import { Secp256k1 } from "@iov/crypto";
import { Bech32, Encoding } from "@iov/encoding";
import equal from "fast-deep-equal";
import { Bech32PubKey, PubKey, pubkeyType } from "./types";
export function encodeSecp256k1Pubkey(pubkey: Uint8Array): PubKey {
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");
}
return {
type: pubkeyType.secp256k1,
value: Encoding.toBase64(Secp256k1.compressPubkey(pubkey)),
value: Encoding.toBase64(pubkey),
};
}

View File

@ -3,7 +3,7 @@ import { Sha256 } from "@iov/crypto";
import { Encoding } from "@iov/encoding";
import { assert } from "@iov/utils";
import { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding";
import { makeSignBytes, marshalTx } from "./encoding";
import { findAttribute, parseLogs } from "./logs";
import { Pen, Secp256k1Pen } from "./pen";
import { encodeBech32Pubkey } from "./pubkey";
@ -86,7 +86,7 @@ async function uploadCustomContract(
const { account_number, sequence } = (await client.authAccounts(faucet.address)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account_number, sequence);
const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
const signature = await pen.sign(signBytes);
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
return client.postTx(marshalTx(signedTx));
}
@ -127,7 +127,7 @@ async function instantiateContract(
const { account_number, sequence } = (await client.authAccounts(faucet.address)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account_number, sequence);
const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
const signature = await pen.sign(signBytes);
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
return client.postTx(marshalTx(signedTx));
}
@ -159,7 +159,7 @@ async function executeContract(
const { account_number, sequence } = (await client.authAccounts(faucet.address)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account_number, sequence);
const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
const signature = await pen.sign(signBytes);
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
return client.postTx(marshalTx(signedTx));
}
@ -261,7 +261,7 @@ describe("RestClient", () => {
const { account_number, sequence } = (await client.authAccounts(faucet.address)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account_number, sequence);
const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
const signature = await pen.sign(signBytes);
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
const result = await client.postTx(marshalTx(signedTx));
// console.log("Raw log:", result.raw_log);

View File

@ -0,0 +1,69 @@
import { Encoding } from "@iov/encoding";
import { decodeSignature, encodeSecp256k1Signature } from "./signature";
import { StdSignature } from "./types";
const { fromBase64 } = Encoding;
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({
// eslint-disable-next-line @typescript-eslint/camelcase
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 = {
// eslint-disable-next-line @typescript-eslint/camelcase
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,39 @@
import { Encoding } from "@iov/encoding";
import { encodeSecp256k1Pubkey } from "./pubkey";
import { pubkeyType, StdSignature } from "./types";
/**
* 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 {
// eslint-disable-next-line @typescript-eslint/camelcase
pub_key: encodeSecp256k1Pubkey(pubkey),
signature: Encoding.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: Encoding.fromBase64(signature.pub_key.value),
signature: Encoding.fromBase64(signature.signature),
};
default:
throw new Error("Unsupported pubkey type");
}
}

View File

@ -1,4 +1,4 @@
import { Msg, StdFee, StdSignature, StdTx } from "./types";
import { Msg, StdFee, StdTx } from "./types";
export declare function marshalTx(tx: StdTx): Uint8Array;
export declare function makeSignBytes(
msgs: readonly Msg[],
@ -8,4 +8,3 @@ export declare function makeSignBytes(
accountNumber: number,
sequence: number,
): Uint8Array;
export declare function encodeSecp256k1Signature(pubkey: Uint8Array, signature: Uint8Array): StdSignature;

View File

@ -3,8 +3,9 @@ import * as types from "./types";
export { logs, types };
export { CosmosAddressBech32Prefix, encodeAddress, isValidAddress } from "./address";
export { unmarshalTx } from "./decoding";
export { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding";
export { makeSignBytes, marshalTx } from "./encoding";
export { RestClient, TxsResponse } from "./restclient";
export { encodeSecp256k1Signature } from "./signature";
export { CosmWasmClient, ExecuteResult, GetNonceResult, PostTxResult } from "./cosmwasmclient";
export { makeCosmoshubPath, Pen, PrehashType, Secp256k1Pen } from "./pen";
export {

View File

@ -1,4 +1,5 @@
import { Slip10RawIndex } from "@iov/crypto";
import { StdSignature } from "./types";
export declare type PrehashType = "sha256" | "sha512" | null;
/**
* A pen is the most basic tool you can think of for signing. It works
@ -12,7 +13,7 @@ export declare type PrehashType = "sha256" | "sha512" | null;
*/
export interface Pen {
readonly pubkey: Uint8Array;
readonly createSignature: (signBytes: Uint8Array, prehashType?: PrehashType) => Promise<Uint8Array>;
readonly sign: (signBytes: Uint8Array, prehashType?: PrehashType) => Promise<StdSignature>;
}
/**
* The Cosmoshub derivation path in the form `m/44'/118'/0'/0/a`
@ -25,7 +26,7 @@ export declare class Secp256k1Pen implements Pen {
private readonly privkey;
private constructor();
/**
* Creates a fixed length encoding of the signature parameters r (32 bytes) and s (32 bytes).
* Creates and returns a signature
*/
createSignature(signBytes: Uint8Array, prehashType?: PrehashType): Promise<Uint8Array>;
sign(signBytes: Uint8Array, prehashType?: PrehashType): Promise<StdSignature>;
}

14
packages/sdk/types/signature.d.ts vendored Normal file
View File

@ -0,0 +1,14 @@
import { StdSignature } from "./types";
/**
* 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 declare function encodeSecp256k1Signature(pubkey: Uint8Array, signature: Uint8Array): StdSignature;
export declare function decodeSignature(
signature: StdSignature,
): {
readonly pubkey: Uint8Array;
readonly signature: Uint8Array;
};

View File

@ -1,7 +1,7 @@
#!/usr/bin/env node
/* eslint-disable @typescript-eslint/camelcase */
const { CosmWasmClient, encodeSecp256k1Signature, Secp256k1Pen } = require("@cosmwasm/sdk");
const { CosmWasmClient, Secp256k1Pen } = require("@cosmwasm/sdk");
const fs = require("fs");
const httpUrl = "http://localhost:1317";
@ -56,9 +56,7 @@ const initMsgCash = {
async function main() {
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
const client = CosmWasmClient.makeWritable(httpUrl, faucet.address, async signBytes => {
return encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
});
const client = CosmWasmClient.makeWritable(httpUrl, faucet.address, signBytes => pen.sign(signBytes));
const wasm = fs.readFileSync(__dirname + "/contracts/cw-erc20.wasm");
const codeId = await client.upload(wasm, "Upload ERC20 contract");