1
1
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
+ // 100 lines of code in the file are duplicated from noble-hashes (utils).
3
+ // This is OK: `abstract` directory does not use noble-hashes.
4
+ // User may opt-in into using different hashing library. This way, noble-hashes
5
+ // won't be included into their bundle.
2
6
const _0n = BigInt ( 0 ) ;
3
7
const _1n = BigInt ( 1 ) ;
4
8
const _2n = BigInt ( 2 ) ;
5
9
const u8a = ( a : any ) : a is Uint8Array => a instanceof Uint8Array ;
6
-
7
- // We accept hex strings besides Uint8Array for simplicity
8
- export type Hex = Uint8Array | string ;
9
- // Very few implementations accept numbers, we do it to ease learning curve
10
- export type PrivKey = Hex | bigint ;
10
+ export type Hex = Uint8Array | string ; // hex strings are accepted for simplicity
11
+ export type PrivKey = Hex | bigint ; // bigints are accepted to ease learning curve
11
12
export type CHash = {
12
13
( message : Uint8Array | string ) : Uint8Array ;
13
14
blockLen : number ;
@@ -17,6 +18,9 @@ export type CHash = {
17
18
export type FHash = ( message : Uint8Array | string ) => Uint8Array ;
18
19
19
20
const hexes = Array . from ( { length : 256 } , ( v , i ) => i . toString ( 16 ) . padStart ( 2 , '0' ) ) ;
21
+ /**
22
+ * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
23
+ */
20
24
export function bytesToHex ( bytes : Uint8Array ) : string {
21
25
if ( ! u8a ( bytes ) ) throw new Error ( 'Uint8Array expected' ) ;
22
26
// pre-caching improves the speed 6x
@@ -38,22 +42,25 @@ export function hexToNumber(hex: string): bigint {
38
42
return BigInt ( hex === '' ? '0' : `0x${ hex } ` ) ;
39
43
}
40
44
41
- // Caching slows it down 2-3x
45
+ /**
46
+ * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])
47
+ */
42
48
export function hexToBytes ( hex : string ) : Uint8Array {
43
49
if ( typeof hex !== 'string' ) throw new Error ( 'hex string expected, got ' + typeof hex ) ;
44
- if ( hex . length % 2 ) throw new Error ( 'hex string is invalid: unpadded ' + hex . length ) ;
45
- const array = new Uint8Array ( hex . length / 2 ) ;
50
+ const len = hex . length ;
51
+ if ( len % 2 ) throw new Error ( 'padded hex string expected, got unpadded hex of length ' + len ) ;
52
+ const array = new Uint8Array ( len / 2 ) ;
46
53
for ( let i = 0 ; i < array . length ; i ++ ) {
47
54
const j = i * 2 ;
48
55
const hexByte = hex . slice ( j , j + 2 ) ;
49
56
const byte = Number . parseInt ( hexByte , 16 ) ;
50
- if ( Number . isNaN ( byte ) || byte < 0 ) throw new Error ( 'invalid byte sequence' ) ;
57
+ if ( Number . isNaN ( byte ) || byte < 0 ) throw new Error ( 'Invalid byte sequence' ) ;
51
58
array [ i ] = byte ;
52
59
}
53
60
return array ;
54
61
}
55
62
56
- // Big Endian
63
+ // BE: Big Endian, LE: Little Endian
57
64
export function bytesToNumberBE ( bytes : Uint8Array ) : bigint {
58
65
return hexToNumber ( bytesToHex ( bytes ) ) ;
59
66
}
@@ -62,12 +69,26 @@ export function bytesToNumberLE(bytes: Uint8Array): bigint {
62
69
return hexToNumber ( bytesToHex ( Uint8Array . from ( bytes ) . reverse ( ) ) ) ;
63
70
}
64
71
65
- export const numberToBytesBE = ( n : bigint , len : number ) =>
66
- hexToBytes ( n . toString ( 16 ) . padStart ( len * 2 , '0' ) ) ;
67
- export const numberToBytesLE = ( n : bigint , len : number ) => numberToBytesBE ( n , len ) . reverse ( ) ;
68
- // Returns variable number bytes (minimal bigint encoding?)
69
- export const numberToVarBytesBE = ( n : bigint ) => hexToBytes ( numberToHexUnpadded ( n ) ) ;
72
+ export function numberToBytesBE ( n : number | bigint , len : number ) : Uint8Array {
73
+ return hexToBytes ( n . toString ( 16 ) . padStart ( len * 2 , '0' ) ) ;
74
+ }
75
+ export function numberToBytesLE ( n : number | bigint , len : number ) : Uint8Array {
76
+ return numberToBytesBE ( n , len ) . reverse ( ) ;
77
+ }
78
+ // Unpadded, rarely used
79
+ export function numberToVarBytesBE ( n : number | bigint ) : Uint8Array {
80
+ return hexToBytes ( numberToHexUnpadded ( n ) ) ;
81
+ }
70
82
83
+ /**
84
+ * Takes hex string or Uint8Array, converts to Uint8Array.
85
+ * Validates output length.
86
+ * Will throw error for other types.
87
+ * @param title descriptive title for an error e.g. 'private key'
88
+ * @param hex hex string or Uint8Array
89
+ * @param expectedLength optional, will compare to result array's length
90
+ * @returns
91
+ */
71
92
export function ensureBytes ( title : string , hex : Hex , expectedLength ?: number ) : Uint8Array {
72
93
let res : Uint8Array ;
73
94
if ( typeof hex === 'string' ) {
@@ -89,11 +110,13 @@ export function ensureBytes(title: string, hex: Hex, expectedLength?: number): U
89
110
return res ;
90
111
}
91
112
92
- // Copies several Uint8Arrays into one.
93
- export function concatBytes ( ...arrs : Uint8Array [ ] ) : Uint8Array {
94
- const r = new Uint8Array ( arrs . reduce ( ( sum , a ) => sum + a . length , 0 ) ) ;
113
+ /**
114
+ * Copies several Uint8Arrays into one.
115
+ */
116
+ export function concatBytes ( ...arrays : Uint8Array [ ] ) : Uint8Array {
117
+ const r = new Uint8Array ( arrays . reduce ( ( sum , a ) => sum + a . length , 0 ) ) ;
95
118
let pad = 0 ; // walk through each item, ensure they have proper type
96
- arrs . forEach ( ( a ) => {
119
+ arrays . forEach ( ( a ) => {
97
120
if ( ! u8a ( a ) ) throw new Error ( 'Uint8Array expected' ) ;
98
121
r . set ( a , pad ) ;
99
122
pad += a . length ;
@@ -111,29 +134,47 @@ export function equalBytes(b1: Uint8Array, b2: Uint8Array) {
111
134
// Global symbols in both browsers and Node.js since v11
112
135
// See https://github.com/microsoft/TypeScript/issues/31535
113
136
declare const TextEncoder : any ;
137
+
138
+ /**
139
+ * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
140
+ */
114
141
export function utf8ToBytes ( str : string ) : Uint8Array {
115
- if ( typeof str !== 'string' ) {
116
- throw new Error ( `utf8ToBytes expected string, got ${ typeof str } ` ) ;
117
- }
142
+ if ( typeof str !== 'string' ) throw new Error ( `utf8ToBytes expected string, got ${ typeof str } ` ) ;
118
143
return new TextEncoder ( ) . encode ( str ) ;
119
144
}
120
145
121
146
// Bit operations
122
147
123
- // Amount of bits inside bigint (Same as n.toString(2).length)
148
+ /**
149
+ * Calculates amount of bits in a bigint.
150
+ * Same as `n.toString(2).length`
151
+ */
124
152
export function bitLen ( n : bigint ) {
125
153
let len ;
126
154
for ( len = 0 ; n > _0n ; n >>= _1n , len += 1 ) ;
127
155
return len ;
128
156
}
129
- // Gets single bit at position. NOTE: first bit position is 0 (same as arrays)
130
- // Same as !!+Array.from(n.toString(2)).reverse()[pos]
131
- export const bitGet = ( n : bigint , pos : number ) => ( n >> BigInt ( pos ) ) & _1n ;
132
- // Sets single bit at position
133
- export const bitSet = ( n : bigint , pos : number , value : boolean ) =>
134
- n | ( ( value ? _1n : _0n ) << BigInt ( pos ) ) ;
135
- // Return mask for N bits (Same as BigInt(`0b${Array(i).fill('1').join('')}`))
136
- // Not using ** operator with bigints for old engines.
157
+
158
+ /**
159
+ * Gets single bit at position.
160
+ * NOTE: first bit position is 0 (same as arrays)
161
+ * Same as `!!+Array.from(n.toString(2)).reverse()[pos]`
162
+ */
163
+ export function bitGet ( n : bigint , pos : number ) {
164
+ return ( n >> BigInt ( pos ) ) & _1n ;
165
+ }
166
+
167
+ /**
168
+ * Sets single bit at position.
169
+ */
170
+ export const bitSet = ( n : bigint , pos : number , value : boolean ) => {
171
+ return n | ( ( value ? _1n : _0n ) << BigInt ( pos ) ) ;
172
+ } ;
173
+
174
+ /**
175
+ * Calculate mask for N bits. Not using ** operator with bigints because of old engines.
176
+ * Same as BigInt(`0b${Array(i).fill('1').join('')}`)
177
+ */
137
178
export const bitMask = ( n : number ) => ( _2n << BigInt ( n - 1 ) ) - _1n ;
138
179
139
180
// DRBG
0 commit comments