Skip to content

Commit 19d968f

Browse files
authored
Merge pull request #1893 from cosmos/uint8array-arraybuffer
Return Uint8Array<ArrayBuffer> whenever we create an Uint8Array
2 parents fc7857e + 1c153c1 commit 19d968f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+299
-154
lines changed

CHANGELOG.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,48 @@ and this project adheres to
66

77
## [Unreleased]
88

9+
### Added
10+
11+
- @cosmjs/encoding: Add `fixUint8Array` which takes an
12+
`Uint8Array<ArrayBufferLike>` and returns `Uint8Array<ArrayBuffer>`. This can
13+
be used in cases where a data source returns an `Uint8Array` without
14+
specifying the buffer type but you need an `ArrayBuffer`. Internally it might
15+
perform a copy but in the vast majority of cases it will just change the type
16+
after ensuring `ArrayBuffer` is used. ([#1883])
17+
18+
[#1883]: https://github.com/cosmos/cosmjs/issues/1883
19+
20+
### Changed
21+
22+
- all: return `Uint8Array<ArrayBuffer>` instead of
23+
`Uint8Array = Uint8Array<ArrayBufferLike>` whenever CosmJS creates binary data
24+
for users. This allows users to stick it into APIs that require `ArrayBuffer`
25+
such as many APIs from Subtle crypto. You can still assign
26+
`Uint8Array<ArrayBuffer>` to any `Uint8Array` in an existing codebase like
27+
this:
28+
29+
```ts
30+
const myVar: Uint8Array = fromHex("aabb");
31+
```
32+
33+
That's the easy way and probably good for many use cases. However, this way
34+
you lose information which buffer type is in use and you cannot trivially pass
35+
it to an API requiring `Uint8Array<ArrayBuffer>` later on.
36+
37+
The other option is to preserve the information you are getting from CosmJS by
38+
using `Uint8Array<ArrayBuffer>` too:
39+
40+
```ts
41+
const myVar: Uint8Array<ArrayBuffer> = fromHex("aabb");
42+
43+
// or inferred
44+
const myVar = fromHex("aabb"); // Uint8Array<ArrayBuffer>
45+
```
46+
47+
This change requires users to use TypeScript 5.7 or newer. ([#1883])
48+
49+
[#1883]: https://github.com/cosmos/cosmjs/issues/1883
50+
951
## [0.37.0] - 2025-10-29
1052

1153
### Added

packages/amino/src/addresses.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,22 @@ import { fromBase64, toBech32 } from "@cosmjs/encoding";
66
import { encodeAminoPubkey } from "./encoding";
77
import { isEd25519Pubkey, isMultisigThresholdPubkey, isSecp256k1Pubkey, Pubkey } from "./pubkeys";
88

9-
export function rawEd25519PubkeyToRawAddress(pubkeyData: Uint8Array): Uint8Array {
9+
export function rawEd25519PubkeyToRawAddress(pubkeyData: Uint8Array): Uint8Array<ArrayBuffer> {
1010
if (pubkeyData.length !== 32) {
1111
throw new Error(`Invalid Ed25519 pubkey length: ${pubkeyData.length}`);
1212
}
1313
return sha256(pubkeyData).slice(0, 20);
1414
}
1515

16-
export function rawSecp256k1PubkeyToRawAddress(pubkeyData: Uint8Array): Uint8Array {
16+
export function rawSecp256k1PubkeyToRawAddress(pubkeyData: Uint8Array): Uint8Array<ArrayBuffer> {
1717
if (pubkeyData.length !== 33) {
1818
throw new Error(`Invalid Secp256k1 pubkey length (compressed): ${pubkeyData.length}`);
1919
}
2020
return ripemd160(sha256(pubkeyData));
2121
}
2222

2323
// For secp256k1 this assumes we already have a compressed pubkey.
24-
export function pubkeyToRawAddress(pubkey: Pubkey): Uint8Array {
24+
export function pubkeyToRawAddress(pubkey: Pubkey): Uint8Array<ArrayBuffer> {
2525
if (isSecp256k1Pubkey(pubkey)) {
2626
const pubkeyData = fromBase64(pubkey.value);
2727
return rawSecp256k1PubkeyToRawAddress(pubkeyData);

packages/amino/src/encoding.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ function encodeUvarint(value: number | string): number[] {
192192
/**
193193
* Encodes a public key to binary Amino.
194194
*/
195-
export function encodeAminoPubkey(pubkey: Pubkey): Uint8Array {
195+
export function encodeAminoPubkey(pubkey: Pubkey): Uint8Array<ArrayBuffer> {
196196
if (isMultisigThresholdPubkey(pubkey)) {
197197
const out = Array.from(pubkeyAminoPrefixMultisigThreshold);
198198
out.push(0x08); // TODO: What is this?

packages/amino/src/signdoc.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export function escapeCharacters(input: string): string {
9696
return input.replace(amp, "\\u0026").replace(lt, "\\u003c").replace(gt, "\\u003e");
9797
}
9898

99-
export function serializeSignDoc(signDoc: StdSignDoc): Uint8Array {
99+
export function serializeSignDoc(signDoc: StdSignDoc): Uint8Array<ArrayBuffer> {
100100
const serialized = escapeCharacters(sortedJsonStringify(signDoc));
101101
return toUtf8(serialized);
102102
}

packages/amino/src/wallet.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { sleep } from "@cosmjs/utils";
1313
* This reduces the scope of a potential rainbow attack to all CosmJS users.
1414
* Must be 16 bytes due to implementation limitations.
1515
*/
16-
export const cosmjsSalt: Uint8Array = toAscii("The CosmJS salt.");
16+
export const cosmjsSalt: Uint8Array<ArrayBuffer> = toAscii("The CosmJS salt.");
1717

1818
export interface KdfConfiguration {
1919
/**

packages/cosmwasm-stargate/src/cosmwasmclient.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { fromUtf8, toHex } from "@cosmjs/encoding";
1+
import { fixUint8Array, fromUtf8, toHex } from "@cosmjs/encoding";
22
import { Uint53 } from "@cosmjs/math";
33
import {
44
Account,
@@ -496,7 +496,10 @@ export class CosmWasmClient {
496496
events: tx.result.events.map(fromTendermintEvent),
497497
rawLog: tx.result.log || "",
498498
tx: tx.tx,
499-
msgResponses: txMsgData.msgResponses,
499+
msgResponses: txMsgData.msgResponses.map((mr) => ({
500+
typeUrl: mr.typeUrl,
501+
value: fixUint8Array(mr.value),
502+
})),
500503
gasUsed: tx.result.gasUsed,
501504
gasWanted: tx.result.gasWanted,
502505
};

packages/cosmwasm-stargate/src/instantiate2.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import { assert } from "@cosmjs/utils";
77
* The "Basic Address" Hash from
88
* https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/docs/architecture/adr-028-public-key-addresses.md
99
*/
10-
function hash(type: string, key: Uint8Array): Uint8Array {
10+
function hash(type: string, key: Uint8Array): Uint8Array<ArrayBuffer> {
1111
return new Sha256(sha256(toAscii(type))).update(key).digest();
1212
}
1313

1414
/**
1515
* Takes an integer [0, 2**64-1] and returns a one-byte encoding of it.
1616
*/
17-
function toUint64(int: number): Uint8Array {
17+
function toUint64(int: number): Uint8Array<ArrayBuffer> {
1818
return Uint64.fromNumber(int).toBytesBigEndian();
1919
}
2020

packages/crypto/src/bip39.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { fixUint8Array } from "@cosmjs/encoding";
12
import { entropyToMnemonic, mnemonicToEntropy, mnemonicToSeed } from "@scure/bip39";
23
import { wordlist } from "@scure/bip39/wordlists/english";
34

@@ -38,8 +39,8 @@ export class Bip39 {
3839
return new EnglishMnemonic(entropyToMnemonic(entropy, wordlist));
3940
}
4041

41-
public static decode(mnemonic: EnglishMnemonic): Uint8Array {
42-
return mnemonicToEntropy(mnemonic.toString(), wordlist);
42+
public static decode(mnemonic: EnglishMnemonic): Uint8Array<ArrayBuffer> {
43+
return fixUint8Array(mnemonicToEntropy(mnemonic.toString(), wordlist));
4344
}
4445

4546
public static async mnemonicToSeed(mnemonic: EnglishMnemonic, password?: string): Promise<Uint8Array> {

packages/crypto/src/hmac.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { fixUint8Array } from "@cosmjs/encoding";
2+
13
import { HashFunction } from "./hash";
24

35
export class Hmac<H extends HashFunction> implements HashFunction {
@@ -6,7 +8,7 @@ export class Hmac<H extends HashFunction> implements HashFunction {
68
private readonly messageHasher: H;
79
private readonly oKeyPad: Uint8Array;
810
private readonly iKeyPad: Uint8Array;
9-
private readonly hash: (data: Uint8Array) => Uint8Array;
11+
private readonly hash: (data: Uint8Array) => Uint8Array<ArrayBuffer>;
1012

1113
public constructor(hashFunctionConstructor: new () => H, originalKey: Uint8Array) {
1214
// This implementation is based on https://en.wikipedia.org/wiki/HMAC#Implementation
@@ -15,7 +17,7 @@ export class Hmac<H extends HashFunction> implements HashFunction {
1517

1618
const blockSize = new hashFunctionConstructor().blockSize;
1719

18-
this.hash = (data) => new hashFunctionConstructor().update(data).digest();
20+
this.hash = (data) => fixUint8Array(new hashFunctionConstructor().update(data).digest());
1921

2022
let key = originalKey;
2123
if (key.length > blockSize) {
@@ -42,7 +44,7 @@ export class Hmac<H extends HashFunction> implements HashFunction {
4244
return this;
4345
}
4446

45-
public digest(): Uint8Array {
47+
public digest(): Uint8Array<ArrayBuffer> {
4648
const innerHash = this.messageHasher.digest();
4749
return this.hash(new Uint8Array([...this.oKeyPad, ...innerHash]));
4850
}

packages/crypto/src/keccak.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { fixUint8Array } from "@cosmjs/encoding";
12
import { keccak_256 } from "@noble/hashes/sha3.js";
23

34
import { HashFunction } from "./hash";
@@ -19,12 +20,12 @@ export class Keccak256 implements HashFunction {
1920
return this;
2021
}
2122

22-
public digest(): Uint8Array {
23-
return this.impl.digest();
23+
public digest(): Uint8Array<ArrayBuffer> {
24+
return fixUint8Array(this.impl.digest());
2425
}
2526
}
2627

2728
/** Convenience function equivalent to `new Keccak256(data).digest()` */
28-
export function keccak256(data: Uint8Array): Uint8Array {
29+
export function keccak256(data: Uint8Array): Uint8Array<ArrayBuffer> {
2930
return new Keccak256(data).digest();
3031
}

0 commit comments

Comments
 (0)