idlize

Форк
0
353 строки · 11.1 Кб
1
/*
2
 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3
 * Licensed under the Apache License, Version 2.0 (the "License");
4
 * you may not use this file except in compliance with the License.
5
 * You may obtain a copy of the License at
6
 *
7
 * http://www.apache.org/licenses/LICENSE-2.0
8
 *
9
 * Unless required by applicable law or agreed to in writing, software
10
 * distributed under the License is distributed on an "AS IS" BASIS,
11
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
 * See the License for the specific language governing permissions and
13
 * limitations under the License.
14
 */
15

16
import { CustomTextDecoder } from "@koalaui/compat"
17
import { int32 } from "@koalaui/compat"
18

19
const K = [
20
    (0x5a827999 | 0) as int32,
21
    (0x6ed9eba1 | 0) as int32,
22
    (0x8f1bbcdc | 0) as int32,
23
    (0xca62c1d6 | 0) as int32,
24
]
25

26
const inputBytes = 64
27
const inputWords = inputBytes / 4
28
const highIndex = inputWords - 2
29
const lowIndex = inputWords - 1
30
const workWords = 80
31
const allocBytes = 80
32
const allocWords = allocBytes / 4
33
const allocTotal = allocBytes * 100
34

35
export function createSha1(): SHA1Hash {
36
   return new SHA1Hash()
37
}
38

39
export class SHA1Hash {
40
    private A = (0x67452301 | 0) as int32
41
    private B = (0xefcdab89 | 0) as int32
42
    private C = (0x98badcfe | 0) as int32
43
    private D = (0x10325476 | 0) as int32
44
    private E = (0xc3d2e1f0 | 0) as int32
45
    private readonly _byte: Uint8Array
46
    private readonly _word: Int32Array
47
    private _size = 0
48
    private _sp = 0 // surrogate pair
49

50
    constructor() {
51
        if (!sharedBuffer || sharedOffset >= allocTotal) {
52
            sharedBuffer = new ArrayBuffer(allocTotal)
53
            sharedOffset = 0
54
        }
55

56
        this._byte = new Uint8Array(sharedBuffer, sharedOffset, allocBytes)
57
        this._word = new Int32Array(sharedBuffer, sharedOffset, allocWords)
58
        sharedOffset += allocBytes
59
    }
60

61
    updateString(data: string, encoding?: string): SHA1Hash {
62
        return this._utf8(data)
63
    }
64
    updateInt32(data: int32): SHA1Hash {
65
        const buffer = new Int32Array(1)
66
        buffer[0] = data
67
        return this.update(buffer)
68
    }
69

70
    update(data: Int32Array | Float32Array | Uint32Array | Uint8Array): SHA1Hash {
71
        if (data == null) {
72
            throw new TypeError("SHA1Hash expected non-null data: ")
73
        }
74

75
        let byteOffset: int32 = 0
76
        let length: int32 = 0
77
        let buffer: ArrayBufferLike | undefined = undefined
78

79
        // TODO: an attempt to wrie this in a generic form causes
80
        // es2panda to segfault.
81
        if (data instanceof Int32Array) {
82
            byteOffset = data.byteOffset as int32
83
            length = data.byteLength as int32
84
            buffer = data.buffer
85
        } else if (data instanceof Uint32Array) {
86
            byteOffset = data.byteOffset as int32
87
            length = data.byteLength as int32
88
            buffer = data.buffer
89
        } else if (data instanceof Float32Array) {
90
            byteOffset = data.byteOffset as int32
91
            length = data.byteLength as int32
92
            buffer = data.buffer
93
        } else if (data instanceof Uint8Array) {
94
            byteOffset = data.byteOffset as int32
95
            length = data.byteLength as int32
96
            buffer = data.buffer
97
        }
98

99
        let blocks: int32 = ((length / inputBytes) | 0) as int32
100
        let offset: int32 = 0
101

102
        // longer than 1 block
103
        if ((blocks != 0) && !(byteOffset & 3) && !(this._size % inputBytes)) {
104
            const block = new Int32Array(buffer!, byteOffset, blocks * inputWords)
105
            while (blocks--) {
106
                this._int32(block, offset >> 2)
107
                offset += inputBytes
108
            }
109
            this._size += offset
110
        }
111

112
        // data: TypedArray | DataView
113
        const BYTES_PER_ELEMENT = (data as Uint8Array).BYTES_PER_ELEMENT as int32
114
        if ((BYTES_PER_ELEMENT != 1) && buffer != undefined) {
115
            const rest = new Uint8Array(buffer, byteOffset + offset, length - offset)
116
            return this._uint8(rest)
117
        }
118

119
        // no more bytes
120
        if (offset == length) return this
121

122
        return this._uint8(new Uint8Array(buffer!), offset)
123
    }
124

125
    private _uint8(data: Uint8Array, offset?: int32): SHA1Hash {
126
        const _byte = this._byte
127
        const _word = this._word
128
        const length = data.length
129
        offset = ((offset ?? 0) | 0) as int32
130

131
        while (offset < length) {
132
            const start = this._size % inputBytes
133
            let index = start
134

135
            while (offset < length && index < inputBytes) {
136
                _byte[index++] = data[offset++]
137
            }
138

139
            if (index >= inputBytes) {
140
                this._int32(_word)
141
            }
142

143
            this._size += index - start
144
        }
145

146
        return this
147
    }
148

149
    private _utf8(text: string): SHA1Hash {
150
        const _byte = this._byte
151
        const _word = this._word
152
        const length = text.length
153
        let surrogate = this._sp
154

155
        for (let offset = 0; offset < length; ) {
156
            const start = this._size % inputBytes
157
            let index = start
158

159
            while (offset < length && index < inputBytes) {
160
                let code = text.charCodeAt(offset++) | 0
161
                if (code < 0x80) {
162
                    // ASCII characters
163
                    _byte[index++] = code
164
                } else if (code < 0x800) {
165
                    // 2 bytes
166
                    _byte[index++] = 0xC0 | (code >>> 6)
167
                    _byte[index++] = 0x80 | (code & 0x3F)
168
                } else if (code < 0xD800 || code > 0xDFFF) {
169
                    // 3 bytes
170
                    _byte[index++] = 0xE0 | (code >>> 12)
171
                    _byte[index++] = 0x80 | ((code >>> 6) & 0x3F)
172
                    _byte[index++] = 0x80 | (code & 0x3F)
173
                } else if (surrogate) {
174
                    // 4 bytes - surrogate pair
175
                    code = ((surrogate & 0x3FF) << 10) + (code & 0x3FF) + 0x10000
176
                    _byte[index++] = 0xF0 | (code >>> 18)
177
                    _byte[index++] = 0x80 | ((code >>> 12) & 0x3F)
178
                    _byte[index++] = 0x80 | ((code >>> 6) & 0x3F)
179
                    _byte[index++] = 0x80 | (code & 0x3F)
180
                    surrogate = 0
181
                } else {
182
                    surrogate = code
183
                }
184
            }
185

186
            if (index >= inputBytes) {
187
                this._int32(_word)
188
                _word[0] = _word[inputWords]
189
            }
190

191
            this._size += index - start
192
        }
193

194
        this._sp = surrogate
195
        return this
196
    }
197

198
    private _int32(data: Int32Array, offset?: int32): void {
199
        let A = this.A
200
        let B = this.B
201
        let C = this.C
202
        let D = this.D
203
        let E = this.E
204
        let i = 0
205
        offset = ((offset ??  0) | 0) as int32
206

207
        while (i < inputWords) {
208
            W[i++] = swap32(data[offset++] as int32)
209
        }
210

211
        for (i = inputWords; i < workWords; i++) {
212
            W[i] = rotate1((W[i - 3] as int32) ^ (W[i - 8] as int32) ^ (W[i - 14] as int32) ^ (W[i - 16] as int32))
213
        }
214

215
        for (i = 0; i < workWords; i++) {
216
            const S = (i / 20) | 0
217
            const T = ((rotate5(A) + ft(S, B, C, D) + E + W[i] + K[S]) as int32) | 0
218
            E = D
219
            D = C
220
            C = rotate30(B)
221
            B = A
222
            A = T
223
        }
224

225
        this.A = (A + this.A) | 0
226
        this.B = (B + this.B) | 0
227
        this.C = (C + this.C) | 0
228
        this.D = (D + this.D) | 0
229
        this.E = (E + this.E) | 0
230
    }
231

232
    // digest(): Uint8Array
233
    // digest(encoding: string): string
234
    digest(encoding?: string): Uint8Array | string {
235
        const _byte = this._byte
236
        const _word = this._word
237
        let i = (this._size % inputBytes) | 0
238
        _byte[i++] = 0x80
239

240
        // pad 0 for current word
241
        while (i & 3) {
242
            _byte[i++] = 0
243
        }
244
        i >>= 2
245

246
        if (i > highIndex) {
247
            while (i < inputWords) {
248
                _word[i++] = 0
249
            }
250
            i = 0
251
            this._int32(_word)
252
        }
253

254
        // pad 0 for rest words
255
        while (i < inputWords) {
256
            _word[i++] = 0
257
        }
258

259
        // input size
260
        const bits64: int32 = this._size * 8
261
        const low32: int32 = ((bits64 & 0xffffffff) as int32 >>> 0) as int32
262
        const high32: int32 = ((bits64 - low32) as int32 / 0x100000000) as int32
263
        if (high32) _word[highIndex] = swap32(high32) as int32
264
        if (low32) _word[lowIndex] = swap32(low32) as int32
265

266
        this._int32(_word)
267

268
        return (encoding === "hex") ? this._hex() : this._bin()
269
    }
270

271
    private _hex(): string {
272
        let A = this.A
273
        let B = this.B
274
        let C = this.C
275
        let D = this.D
276
        let E = this.E
277

278
        return hex32Str(A, B, C, D, E)
279
    }
280

281
    private _bin(): Uint8Array {
282
        let A = this.A
283
        let B = this.B
284
        let C = this.C
285
        let D = this.D
286
        let E = this.E
287
        const _byte = this._byte
288
        const _word = this._word
289

290
        _word[0] = swap32(A)
291
        _word[1] = swap32(B)
292
        _word[2] = swap32(C)
293
        _word[3] = swap32(D)
294
        _word[4] = swap32(E)
295

296
        return _byte.slice(0, 20)
297
    }
298
}
299

300
type NS = (num: int32) => string
301
type NN = (num: int32) => int32
302

303
const W = new Int32Array(workWords)
304

305
let sharedBuffer: ArrayBuffer
306
let sharedOffset: int32 = 0
307

308
const swapLE: NN = ((c:int32):int32 => (((c << 24) & 0xff000000) | ((c << 8) & 0xff0000) | ((c >> 8) & 0xff00) | ((c >> 24) & 0xff)))
309
const swapBE: NN = ((c:int32):int32 => c)
310
const swap32: NN = isBE() ? swapBE : swapLE
311
const rotate1: NN = (num: int32): int32 => (num << 1) | (num >>> 31)
312
const rotate5: NN = (num: int32): int32 => (num << 5) | (num >>> 27)
313
const rotate30: NN = (num: int32): int32 => (num << 30) | (num >>> 2)
314

315
function isBE(): boolean {
316
    let a16 = new Uint16Array(1)
317
    a16[0] = 0xFEFF
318
    let a8 = new Uint8Array(a16.buffer)
319
    return a8[0] == 0xFE // BOM
320
}
321

322

323
function ft(s: int32, b: int32, c: int32, d: int32) {
324
    if (s == 0) return (b & c) | ((~b) & d)
325
    if (s == 2) return (b & c) | (b & d) | (c & d)
326
    return b ^ c ^ d
327
}
328

329
const hex32Decoder = new CustomTextDecoder()
330
const hex32DecodeBuffer = new Uint8Array(40)
331
function hex32Str(A: int32, B: int32, C: int32, D: int32, E: int32): string {
332
    writeIntAsHexUTF8(A, hex32DecodeBuffer, 0)
333
    writeIntAsHexUTF8(B, hex32DecodeBuffer, 8)
334
    writeIntAsHexUTF8(C, hex32DecodeBuffer, 16)
335
    writeIntAsHexUTF8(D, hex32DecodeBuffer, 24)
336
    writeIntAsHexUTF8(E, hex32DecodeBuffer, 32)
337
    return hex32Decoder.decode(hex32DecodeBuffer)
338
}
339

340
function writeIntAsHexUTF8(value: int32, buffer: Uint8Array, byteOffset: int32) {
341
    buffer[byteOffset++] = nibbleToHexCode((value >> 28) & 0xF)
342
    buffer[byteOffset++] = nibbleToHexCode((value >> 24) & 0xF)
343
    buffer[byteOffset++] = nibbleToHexCode((value >> 20) & 0xF)
344
    buffer[byteOffset++] = nibbleToHexCode((value >> 16) & 0xF)
345
    buffer[byteOffset++] = nibbleToHexCode((value >> 12) & 0xF)
346
    buffer[byteOffset++] = nibbleToHexCode((value >> 8 ) & 0xF)
347
    buffer[byteOffset++] = nibbleToHexCode((value >> 4 ) & 0xF)
348
    buffer[byteOffset++] = nibbleToHexCode((value >> 0 ) & 0xF)
349
}
350

351
function nibbleToHexCode(nibble: int32) {
352
    return nibble > 9 ? nibble + 87 : nibble + 48
353
}
354

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.