Create addresses module
This commit is contained in:
parent
42e2fdb32c
commit
1a533fc24d
91
packages/amino/src/addresses.spec.ts
Normal file
91
packages/amino/src/addresses.spec.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import { Bech32, fromHex, toBase64 } from "@cosmjs/encoding";
|
||||
|
||||
import { pubkeyToAddress, pubkeyToRawAddress } from "./addresses";
|
||||
import { decodeBech32Pubkey } from "./encoding";
|
||||
import { MultisigThresholdPubkey } from "./pubkeys";
|
||||
|
||||
describe("addresses", () => {
|
||||
describe("pubkeyToRawAddress", () => {
|
||||
it("works for Secp256k1", () => {
|
||||
const pubkey = {
|
||||
type: "tendermint/PubKeySecp256k1",
|
||||
value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP",
|
||||
};
|
||||
expect(pubkeyToRawAddress(pubkey)).toEqual(
|
||||
Bech32.decode("cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r").data,
|
||||
);
|
||||
});
|
||||
|
||||
it("works for Ed25519", () => {
|
||||
const pubkey = {
|
||||
type: "tendermint/PubKeyEd25519",
|
||||
value: toBase64(fromHex("12ee6f581fe55673a1e9e1382a0829e32075a0aa4763c968bc526e1852e78c95")),
|
||||
};
|
||||
expect(pubkeyToRawAddress(pubkey)).toEqual(
|
||||
Bech32.decode("cosmos1pfq05em6sfkls66ut4m2257p7qwlk448h8mysz").data,
|
||||
);
|
||||
});
|
||||
|
||||
it("works for multisig", () => {
|
||||
const test1 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepqwxttx8w2sfs6d8cuzqcuau84grp8xsw95qzdjkmvc44tnckskdxw3zw2km",
|
||||
);
|
||||
const test2 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepq2gx7x7e29kge5a4ycunytyqr0u8ynql5h583s8r9wdads9m3v8ks6y0nhc",
|
||||
);
|
||||
const test3 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepq0xfx5vavxmgdkn0p6x0l9p3udttghu3qcldd7ql08wa3xy93qq0xuzvtxc",
|
||||
);
|
||||
|
||||
const testgroup1: MultisigThresholdPubkey = {
|
||||
type: "tendermint/PubKeyMultisigThreshold",
|
||||
value: {
|
||||
threshold: "2",
|
||||
pubkeys: [test1, test2, test3],
|
||||
},
|
||||
};
|
||||
expect(pubkeyToRawAddress(testgroup1)).toEqual(fromHex("0892a77fab2fa7e192c3b7b2741e6682f3abb72f"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("pubkeyToAddress", () => {
|
||||
it("works for Secp256k1", () => {
|
||||
const prefix = "cosmos";
|
||||
const pubkey = {
|
||||
type: "tendermint/PubKeySecp256k1",
|
||||
value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP",
|
||||
};
|
||||
expect(pubkeyToAddress(pubkey, prefix)).toEqual("cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r");
|
||||
});
|
||||
|
||||
it("works for Ed25519", () => {
|
||||
const prefix = "cosmos";
|
||||
const pubkey = {
|
||||
type: "tendermint/PubKeyEd25519",
|
||||
value: toBase64(fromHex("12ee6f581fe55673a1e9e1382a0829e32075a0aa4763c968bc526e1852e78c95")),
|
||||
};
|
||||
expect(pubkeyToAddress(pubkey, prefix)).toEqual("cosmos1pfq05em6sfkls66ut4m2257p7qwlk448h8mysz");
|
||||
});
|
||||
|
||||
it("works for multisig", () => {
|
||||
const test1 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepqwxttx8w2sfs6d8cuzqcuau84grp8xsw95qzdjkmvc44tnckskdxw3zw2km",
|
||||
);
|
||||
const test2 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepq2gx7x7e29kge5a4ycunytyqr0u8ynql5h583s8r9wdads9m3v8ks6y0nhc",
|
||||
);
|
||||
const test3 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepq0xfx5vavxmgdkn0p6x0l9p3udttghu3qcldd7ql08wa3xy93qq0xuzvtxc",
|
||||
);
|
||||
|
||||
const testgroup1: MultisigThresholdPubkey = {
|
||||
type: "tendermint/PubKeyMultisigThreshold",
|
||||
value: {
|
||||
threshold: "2",
|
||||
pubkeys: [test1, test2, test3],
|
||||
},
|
||||
};
|
||||
expect(pubkeyToAddress(testgroup1, "wasm")).toEqual("wasm1pzf2wlat97n7rykrk7e8g8nxste6hde0r8jqsy");
|
||||
});
|
||||
});
|
||||
});
|
||||
38
packages/amino/src/addresses.ts
Normal file
38
packages/amino/src/addresses.ts
Normal file
@ -0,0 +1,38 @@
|
||||
// See https://github.com/tendermint/tendermint/blob/f2ada0a604b4c0763bda2f64fac53d506d3beca7/docs/spec/blockchain/encoding.md#public-key-cryptography
|
||||
|
||||
import { ripemd160, sha256 } from "@cosmjs/crypto";
|
||||
import { Bech32, fromBase64 } from "@cosmjs/encoding";
|
||||
|
||||
import { encodeAminoPubkey } from "./encoding";
|
||||
import { isEd25519Pubkey, isMultisigThresholdPubkey, isSecp256k1Pubkey, Pubkey } from "./pubkeys";
|
||||
|
||||
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(pubkey: Pubkey): Uint8Array {
|
||||
if (isSecp256k1Pubkey(pubkey)) {
|
||||
const pubkeyData = fromBase64(pubkey.value);
|
||||
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);
|
||||
} else if (isMultisigThresholdPubkey(pubkey)) {
|
||||
// https://github.com/tendermint/tendermint/blob/38b401657e4ad7a7eeb3c30a3cbf512037df3740/crypto/multisig/threshold_pubkey.go#L71-L74
|
||||
const pubkeyData = encodeAminoPubkey(pubkey);
|
||||
return sha256(pubkeyData).slice(0, 20);
|
||||
} else {
|
||||
throw new Error("Unsupported public key type");
|
||||
}
|
||||
}
|
||||
|
||||
export function pubkeyToAddress(pubkey: Pubkey, prefix: string): string {
|
||||
return Bech32.encode(prefix, pubkeyToRawAddress(pubkey));
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import { Bech32, fromBase64, fromHex, toBase64 } from "@cosmjs/encoding";
|
||||
import { Bech32, fromBase64 } from "@cosmjs/encoding";
|
||||
|
||||
import {
|
||||
decodeAminoPubkey,
|
||||
@ -6,8 +6,6 @@ import {
|
||||
encodeAminoPubkey,
|
||||
encodeBech32Pubkey,
|
||||
encodeSecp256k1Pubkey,
|
||||
pubkeyToAddress,
|
||||
pubkeyToRawAddress,
|
||||
} from "./encoding";
|
||||
import { MultisigThresholdPubkey, Pubkey } from "./pubkeys";
|
||||
|
||||
@ -220,88 +218,4 @@ describe("encoding", () => {
|
||||
expect(encodeAminoPubkey(testgroup4)).toEqual(expected4);
|
||||
});
|
||||
});
|
||||
|
||||
describe("pubkeyToRawAddress", () => {
|
||||
it("works for Secp256k1", () => {
|
||||
const pubkey = {
|
||||
type: "tendermint/PubKeySecp256k1",
|
||||
value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP",
|
||||
};
|
||||
expect(pubkeyToRawAddress(pubkey)).toEqual(
|
||||
Bech32.decode("cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r").data,
|
||||
);
|
||||
});
|
||||
|
||||
it("works for Ed25519", () => {
|
||||
const pubkey = {
|
||||
type: "tendermint/PubKeyEd25519",
|
||||
value: toBase64(fromHex("12ee6f581fe55673a1e9e1382a0829e32075a0aa4763c968bc526e1852e78c95")),
|
||||
};
|
||||
expect(pubkeyToRawAddress(pubkey)).toEqual(
|
||||
Bech32.decode("cosmos1pfq05em6sfkls66ut4m2257p7qwlk448h8mysz").data,
|
||||
);
|
||||
});
|
||||
|
||||
it("works for multisig", () => {
|
||||
const test1 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepqwxttx8w2sfs6d8cuzqcuau84grp8xsw95qzdjkmvc44tnckskdxw3zw2km",
|
||||
);
|
||||
const test2 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepq2gx7x7e29kge5a4ycunytyqr0u8ynql5h583s8r9wdads9m3v8ks6y0nhc",
|
||||
);
|
||||
const test3 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepq0xfx5vavxmgdkn0p6x0l9p3udttghu3qcldd7ql08wa3xy93qq0xuzvtxc",
|
||||
);
|
||||
|
||||
const testgroup1: MultisigThresholdPubkey = {
|
||||
type: "tendermint/PubKeyMultisigThreshold",
|
||||
value: {
|
||||
threshold: "2",
|
||||
pubkeys: [test1, test2, test3],
|
||||
},
|
||||
};
|
||||
expect(pubkeyToRawAddress(testgroup1)).toEqual(fromHex("0892a77fab2fa7e192c3b7b2741e6682f3abb72f"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("pubkeyToAddress", () => {
|
||||
it("works for Secp256k1", () => {
|
||||
const prefix = "cosmos";
|
||||
const pubkey = {
|
||||
type: "tendermint/PubKeySecp256k1",
|
||||
value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP",
|
||||
};
|
||||
expect(pubkeyToAddress(pubkey, prefix)).toEqual("cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r");
|
||||
});
|
||||
|
||||
it("works for Ed25519", () => {
|
||||
const prefix = "cosmos";
|
||||
const pubkey = {
|
||||
type: "tendermint/PubKeyEd25519",
|
||||
value: toBase64(fromHex("12ee6f581fe55673a1e9e1382a0829e32075a0aa4763c968bc526e1852e78c95")),
|
||||
};
|
||||
expect(pubkeyToAddress(pubkey, prefix)).toEqual("cosmos1pfq05em6sfkls66ut4m2257p7qwlk448h8mysz");
|
||||
});
|
||||
|
||||
it("works for multisig", () => {
|
||||
const test1 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepqwxttx8w2sfs6d8cuzqcuau84grp8xsw95qzdjkmvc44tnckskdxw3zw2km",
|
||||
);
|
||||
const test2 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepq2gx7x7e29kge5a4ycunytyqr0u8ynql5h583s8r9wdads9m3v8ks6y0nhc",
|
||||
);
|
||||
const test3 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepq0xfx5vavxmgdkn0p6x0l9p3udttghu3qcldd7ql08wa3xy93qq0xuzvtxc",
|
||||
);
|
||||
|
||||
const testgroup1: MultisigThresholdPubkey = {
|
||||
type: "tendermint/PubKeyMultisigThreshold",
|
||||
value: {
|
||||
threshold: "2",
|
||||
pubkeys: [test1, test2, test3],
|
||||
},
|
||||
};
|
||||
expect(pubkeyToAddress(testgroup1, "wasm")).toEqual("wasm1pzf2wlat97n7rykrk7e8g8nxste6hde0r8jqsy");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { ripemd160, sha256 } from "@cosmjs/crypto";
|
||||
import { Bech32, fromBase64, fromHex, toBase64, toHex } from "@cosmjs/encoding";
|
||||
import { Uint53 } from "@cosmjs/math";
|
||||
import { arrayContentStartsWith } from "@cosmjs/utils";
|
||||
@ -117,38 +116,6 @@ export function encodeAminoPubkey(pubkey: Pubkey): Uint8Array {
|
||||
}
|
||||
}
|
||||
|
||||
export function rawSecp256k1PubkeyToRawAddress(pubkeyData: Uint8Array): Uint8Array {
|
||||
if (pubkeyData.length !== 33) {
|
||||
throw new Error(`Invalid Secp256k1 pubkey length (compressed): ${pubkeyData.length}`);
|
||||
}
|
||||
return ripemd160(sha256(pubkeyData));
|
||||
}
|
||||
|
||||
// See https://github.com/tendermint/tendermint/blob/f2ada0a604b4c0763bda2f64fac53d506d3beca7/docs/spec/blockchain/encoding.md#public-key-cryptography
|
||||
// For secp256k1 this assumes we already have a compressed pubkey.
|
||||
export function pubkeyToRawAddress(pubkey: Pubkey): Uint8Array {
|
||||
if (isSecp256k1Pubkey(pubkey)) {
|
||||
const pubkeyData = fromBase64(pubkey.value);
|
||||
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);
|
||||
} else if (isMultisigThresholdPubkey(pubkey)) {
|
||||
// https://github.com/tendermint/tendermint/blob/38b401657e4ad7a7eeb3c30a3cbf512037df3740/crypto/multisig/threshold_pubkey.go#L71-L74
|
||||
const pubkeyData = encodeAminoPubkey(pubkey);
|
||||
return sha256(pubkeyData).slice(0, 20);
|
||||
} else {
|
||||
throw new Error("Unsupported public key type");
|
||||
}
|
||||
}
|
||||
|
||||
export function pubkeyToAddress(pubkey: Pubkey, prefix: string): string {
|
||||
return Bech32.encode(prefix, pubkeyToRawAddress(pubkey));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a public key to binary Amino and then to bech32.
|
||||
*
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
export { pubkeyToAddress, pubkeyToRawAddress, rawSecp256k1PubkeyToRawAddress } from "./addresses";
|
||||
export {
|
||||
decodeAminoPubkey,
|
||||
decodeBech32Pubkey,
|
||||
encodeAminoPubkey,
|
||||
encodeBech32Pubkey,
|
||||
encodeSecp256k1Pubkey,
|
||||
pubkeyToAddress,
|
||||
pubkeyToRawAddress,
|
||||
rawSecp256k1PubkeyToRawAddress,
|
||||
} from "./encoding";
|
||||
export {
|
||||
MultisigThresholdPubkey,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user