or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

base-encodings.mdbase58-encodings.mdbech32-encodings.mdindex.mdutils.md

utils.mddocs/

0

# Utility Functions

1

2

Low-level utility functions for building custom encoders using functional composition. These utilities enable creating domain-specific encoders by chaining simple operations together, following the same patterns used internally by @scure/base.

3

4

## Capabilities

5

6

### Chain Function

7

8

Composes multiple coders together in functional style, ensuring encode/decode operations maintain proper order.

9

10

```typescript { .api }

11

/**

12

* Chains multiple coders together in functional composition

13

* Automatically handles proper order for encode/decode operations

14

* @param args - Sequence of coders to chain together

15

* @returns Single coder combining all operations

16

*/

17

function chain<T extends Chain & AsChain<T>>(

18

...args: T

19

): Coder<Input<First<T>>, Output<Last<T>>>;

20

21

type Chain = [Coder<any, any>, ...Coder<any, any>[]];

22

```

23

24

**Usage Examples:**

25

26

```typescript

27

import { utils } from "@scure/base";

28

29

// Create custom base32 encoder by chaining operations

30

const customBase32 = utils.chain(

31

utils.radix2(5), // Convert bytes to 5-bit values

32

utils.alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'), // Map to base32 alphabet

33

utils.padding(5), // Add padding

34

utils.join('') // Join to string

35

);

36

37

const data = new Uint8Array([0x12, 0x34]);

38

const encoded = customBase32.encode(data); // Works like base32.encode()

39

const decoded = customBase32.decode(encoded); // Works like base32.decode()

40

```

41

42

### Alphabet Function

43

44

Maps between number arrays and string arrays using a custom alphabet.

45

46

```typescript { .api }

47

/**

48

* Creates encoder for number array to string array mapping using custom alphabet

49

* @param letters - Alphabet as string or array of strings

50

* @returns Coder mapping number indices to alphabet characters

51

*/

52

function alphabet(letters: string | string[]): Coder<number[], string[]>;

53

```

54

55

**Usage Examples:**

56

57

```typescript

58

import { utils } from "@scure/base";

59

60

// Create alphabet mapper

61

const hexAlphabet = utils.alphabet('0123456789abcdef');

62

63

const digits = [15, 14, 13, 12]; // Indices into alphabet

64

const letters = hexAlphabet.encode(digits); // ['f', 'e', 'd', 'c']

65

const restored = hexAlphabet.decode(letters); // [15, 14, 13, 12]

66

67

// Can also use string array

68

const customAlphabet = utils.alphabet(['zero', 'one', 'two']);

69

const words = customAlphabet.encode([0, 2, 1]); // ['zero', 'two', 'one']

70

```

71

72

### Radix Conversion

73

74

Convert between arbitrary numeric bases. Note: O(n^2) complexity for non-power-of-2 bases.

75

76

```typescript { .api }

77

/**

78

* Converts bytes to arbitrary radix representation

79

* @param num - Target radix/base number

80

* @returns Coder converting bytes to number array in specified radix

81

*/

82

function radix(num: number): Coder<Uint8Array, number[]>;

83

84

/**

85

* Optimized radix conversion for power-of-2 bases

86

* @param bits - Number of bits per output digit (must be ≤32)

87

* @param revPadding - Reverse padding direction

88

* @returns Coder for efficient power-of-2 base conversion

89

*/

90

function radix2(bits: number, revPadding?: boolean): Coder<Uint8Array, number[]>;

91

```

92

93

**Usage Examples:**

94

95

```typescript

96

import { utils } from "@scure/base";

97

98

// Convert to base 58 (O(n^2) - use sparingly)

99

const base58Radix = utils.radix(58);

100

const data = new Uint8Array([0x12, 0x34]);

101

const base58Digits = base58Radix.encode(data); // Array of base58 digit values

102

103

// Convert to base 32 (power of 2 - efficient)

104

const base32Radix = utils.radix2(5); // 2^5 = 32

105

const base32Digits = base32Radix.encode(data); // Array of 5-bit values

106

```

107

108

### String Operations

109

110

Join and split string arrays with configurable separators.

111

112

```typescript { .api }

113

/**

114

* Joins string arrays into single strings and splits them back

115

* @param separator - String to use for joining (default: empty string)

116

* @returns Coder for joining/splitting string arrays

117

*/

118

function join(separator?: string): Coder<string[], string>;

119

```

120

121

**Usage Examples:**

122

123

```typescript

124

import { utils } from "@scure/base";

125

126

// Join without separator (default)

127

const joiner = utils.join();

128

const joined = joiner.encode(['a', 'b', 'c']); // "abc"

129

const split = joiner.decode('abc'); // ['a', 'b', 'c'] - splits into chars

130

131

// Join with separator

132

const dashedJoiner = utils.join('-');

133

const dashed = dashedJoiner.encode(['hello', 'world']); // "hello-world"

134

const unDashed = dashedJoiner.decode('hello-world'); // ['hello', 'world']

135

```

136

137

### Padding Operations

138

139

Add and remove padding from string arrays to ensure proper bit alignment.

140

141

```typescript { .api }

142

/**

143

* Adds/removes padding to ensure string array represents whole number of bits

144

* @param bits - Number of bits per character in the encoding

145

* @param chr - Padding character (default: '=')

146

* @returns Coder for adding/removing padding

147

*/

148

function padding(bits: number, chr?: string): Coder<string[], string[]>;

149

```

150

151

**Usage Examples:**

152

153

```typescript

154

import { utils } from "@scure/base";

155

156

// Base64 uses 6 bits per character, padded with '='

157

const base64Padding = utils.padding(6, '=');

158

const data = ['Q', 'W']; // Incomplete group

159

const padded = base64Padding.encode(data); // ['Q', 'W', '=', '=']

160

const unpadded = base64Padding.decode(padded); // ['Q', 'W']

161

162

// Base32 uses 5 bits per character

163

const base32Padding = utils.padding(5);

164

const base32Data = ['A', 'B', 'C'];

165

const paddedB32 = base32Padding.encode(base32Data); // Adds padding if needed

166

```

167

168

### Checksum Validation

169

170

Add checksum validation to any encoder for error detection.

171

172

```typescript { .api }

173

/**

174

* Adds checksum validation using provided hash function

175

* @param len - Number of checksum bytes to append

176

* @param fn - Hash function for generating checksum

177

* @returns Coder that appends/validates checksum

178

*/

179

function checksum(

180

len: number,

181

fn: (data: Uint8Array) => Uint8Array

182

): Coder<Uint8Array, Uint8Array>;

183

```

184

185

**Usage Examples:**

186

187

```typescript

188

import { utils } from "@scure/base";

189

import { sha256 } from "@noble/hashes/sha2";

190

191

// Create checksum validator using SHA-256 (like base58check)

192

const sha256Checksum = utils.checksum(4, (data) => sha256(sha256(data)));

193

194

const originalData = new Uint8Array([0x12, 0x34, 0x56]);

195

const withChecksum = sha256Checksum.encode(originalData); // Appends 4-byte checksum

196

const verified = sha256Checksum.decode(withChecksum); // Validates and removes checksum

197

198

// Error on invalid checksum

199

try {

200

const corrupted = new Uint8Array([...withChecksum]);

201

corrupted[corrupted.length - 1] = 0; // Corrupt checksum

202

sha256Checksum.decode(corrupted); // Throws "Invalid checksum"

203

} catch (error) {

204

console.log("Checksum validation failed");

205

}

206

```

207

208

### Normalization

209

210

Apply transformation functions during decode operations for input sanitization.

211

212

```typescript { .api }

213

/**

214

* Applies normalization function during decode operation

215

* @param fn - Function to transform input during decode

216

* @returns Coder that applies transformation on decode

217

*/

218

function normalize<T>(fn: (val: T) => T): Coder<T, T>;

219

```

220

221

**Usage Examples:**

222

223

```typescript

224

import { utils } from "@scure/base";

225

226

// Create case-insensitive decoder (like base32crockford)

227

const caseNormalizer = utils.normalize((s: string) => s.toUpperCase());

228

const encoded = caseNormalizer.encode("Hello"); // "Hello" (no change on encode)

229

const decoded = caseNormalizer.decode("hello"); // "HELLO" (normalized on decode)

230

231

// Create character substitution (like base32crockford)

232

const charNormalizer = utils.normalize((s: string) =>

233

s.toUpperCase().replace(/O/g, '0').replace(/[IL]/g, '1')

234

);

235

const normalized = charNormalizer.decode("hel1O"); // "HEL10" (O->0, I/L->1)

236

```

237

238

### Direct Radix Conversion

239

240

Low-level radix conversion functions for direct use.

241

242

```typescript { .api }

243

/**

244

* Direct radix conversion between arbitrary bases (O(n^2) complexity)

245

* @param data - Input digits in source base

246

* @param from - Source radix

247

* @param to - Target radix

248

* @returns Digits in target radix

249

*/

250

function convertRadix(data: number[], from: number, to: number): number[];

251

252

/**

253

* Optimized radix conversion for power-of-2 bases

254

* @param data - Input digits

255

* @param from - Source radix (power of 2, ≤32)

256

* @param to - Target radix (power of 2, ≤32)

257

* @param padding - Whether to add padding

258

* @returns Converted digits

259

*/

260

function convertRadix2(

261

data: number[],

262

from: number,

263

to: number,

264

padding: boolean

265

): number[];

266

```

267

268

**Usage Examples:**

269

270

```typescript

271

import { utils } from "@scure/base";

272

273

// Convert from base 10 to base 16

274

const decimal = [1, 2, 3]; // Represents 123 in base 10

275

const hex = utils.convertRadix(decimal, 10, 16); // Convert to base 16

276

277

// Efficient binary to base32 conversion

278

const binary = [1, 0, 1, 1, 0]; // 5 bits

279

const base32 = utils.convertRadix2(binary, 2, 32, true); // Convert 2^1 to 2^5

280

```

281

282

## Building Custom Encoders

283

284

Combine utilities to create domain-specific encoders:

285

286

```typescript

287

import { utils } from "@scure/base";

288

import { sha256 } from "@noble/hashes/sha2";

289

290

// Example: Custom cryptocurrency address encoder

291

const cryptoAddress = utils.chain(

292

utils.checksum(4, (data) => sha256(sha256(data))), // Double SHA-256 checksum

293

utils.radix(58), // Convert to base58 digits

294

utils.alphabet('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'),

295

utils.join('') // Join to string

296

);

297

298

// Example: Custom data format with metadata

299

const dataFormat = utils.chain(

300

utils.radix2(6), // 6-bit encoding like base64

301

utils.alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'),

302

utils.padding(6, '='), // Base64-style padding

303

utils.join('-'), // Use dashes as separators

304

utils.normalize((s: string) => s.toLowerCase()) // Normalize to lowercase

305

);

306

307

// Example: Compact binary encoding

308

const compactBinary = utils.chain(

309

utils.radix2(8), // Keep as bytes

310

utils.alphabet('0123456789ABCDEF'), // Hex alphabet

311

utils.join('') // Standard hex string

312

);

313

```

314

315

## Performance Notes

316

317

- `radix()` has O(n^2) complexity - use only with small inputs

318

- `radix2()` has O(n) complexity - preferred for power-of-2 bases

319

- `convertRadix()` and `convertRadix2()` are the underlying conversion functions

320

- Built-in encoders (base64, hex) use optimized implementations when available

321

322

## Error Handling

323

324

All utility functions validate inputs and provide descriptive errors:

325

326

```typescript

327

import { utils } from "@scure/base";

328

329

try {

330

utils.radix(1); // Base must be ≥ 2

331

} catch (error) {

332

console.log(error.message); // "convertRadix: invalid from=1, base cannot be less than 2"

333

}

334

335

try {

336

utils.alphabet('ABC').decode(['D']); // Invalid character

337

} catch (error) {

338

console.log(error.message); // "Unknown letter: D. Allowed: ABC"

339

}

340

341

try {

342

utils.padding(6).decode(['A', 'B', '=', '=', '=']); // Too much padding

343

} catch (error) {

344

console.log(error.message); // "padding: invalid, string has too much padding"

345

}

346

```