mima-kit
Version:
mima-kit is a cryptographic suite implemented in TypeScript. The goal is to provide an easy-to-use cryptographic library. mima-kit 是一个使用 TypeScript 实现的密码学套件。目标是提供一个简单易用的密码学库。
1 lines • 652 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","sources":["../../src/core/utils.ts","../../src/core/prime.ts","../../src/core/codec.ts","../../src/core/hash.ts","../../src/hash/sm3.ts","../../src/hash/md5.ts","../../src/hash/sha1.ts","../../src/hash/sha256.ts","../../src/hash/sha512.ts","../../src/hash/keccak1600.ts","../../src/hash/sha3.ts","../../src/hash/sha3Derived.ts","../../src/hash/turboSHAKE.ts","../../src/hash/kangaroo12.ts","../../src/hash/hmac.ts","../../src/hash/totp.ts","../../src/core/cipher.ts","../../src/cipher/streamCipher/arc4.ts","../../src/cipher/streamCipher/rabbit.ts","../../src/cipher/streamCipher/salsa20.ts","../../src/cipher/streamCipher/zuc.ts","../../src/cipher/blockCipher/aes.ts","../../src/cipher/blockCipher/arc5.ts","../../src/cipher/blockCipher/aria.ts","../../src/cipher/blockCipher/blowfish.ts","../../src/cipher/blockCipher/camellia.ts","../../src/cipher/blockCipher/des.ts","../../src/cipher/blockCipher/sm4.ts","../../src/cipher/blockCipher/tea.ts","../../src/cipher/blockCipher/twofish.ts","../../src/core/asn1.ts","../../src/cipher/pkcs/rsa.ts","../../src/cipher/pkcs/pkcs1.ts","../../src/core/kdf.ts","../../src/core/galois_field.ts","../../src/core/coordinate_system.ts","../../src/core/ec.ts","../../src/cipher/ecc/ecc.ts","../../src/core/ec_params.ts","../../src/cipher/ecc/x25519_448.ts","../../src/cipher/ecc/sm2.ts"],"sourcesContent":["import type { Codec } from './codec';\r\n\r\n// * Math Utility Functions\r\n\r\n/**\r\n * 32-bit 循环左移 / 32-bit Rotate Left\r\n *\r\n * @param {number | bigint} x - 数值 / value\r\n * @param {number | bigint} n - 位移 / shift\r\n */\r\nexport function rotateL32(x: number, n: number) {\r\n return ((x << n) | (x >>> (32 - n))) >>> 0;\r\n}\r\n\r\n/**\r\n * 32-bit 循环右移 / 32-bit Rotate Right\r\n *\r\n * @param {number | bigint} x - 数值 / value\r\n * @param {number | bigint} n - 位移 / shift\r\n */\r\nexport function rotateR32(x: number, n: number) {\r\n return (x >>> n) | ((x << (32 - n)) >>> 0);\r\n}\r\n\r\n/**\r\n * 位循环左移 / Rotate Left\r\n *\r\n * @param {number} bit - 限制位数 / limit bit\r\n * @param {number | bigint} x - 数值 / value\r\n * @param {number | bigint} n - 位移 / shift\r\n * @param {bigint} [mask] - 位掩码 / bit mask\r\n */\r\nexport function rotateL(bit: number | bigint, x: number | bigint, n: number | bigint, mask?: bigint) {\r\n bit = BigInt(bit);\r\n mask ??= genBitMask(bit);\r\n x = BigInt(x);\r\n n = BigInt(n);\r\n x &= mask;\r\n n %= bit;\r\n x = (x << n) | (x >> (bit - n));\r\n return x & mask;\r\n}\r\n\r\n/**\r\n * 位循环右移 / Rotate Right\r\n *\r\n * @param {number} bit - 限制位数 / limit bit\r\n * @param {number | bigint} x - 数值 / value\r\n * @param {number | bigint} n - 位移 / shift\r\n * @param {bigint} [mask] - 位掩码 / bit mask\r\n */\r\nexport function rotateR(bit: number | bigint, x: number | bigint, n: number | bigint, mask?: bigint) {\r\n bit = BigInt(bit);\r\n mask ??= genBitMask(bit);\r\n x = BigInt(x);\r\n n = BigInt(n);\r\n x &= mask;\r\n n %= bit;\r\n x = (x >> n) | (x << (bit - n));\r\n return x & mask;\r\n}\r\n\r\n/**\r\n * 在指定缓存区长度内生成随机大整数 / Generate random BigInt within specified buffer length\r\n *\r\n * @param {bigint} max - 最大值 (不包含) / maximum value (exclusive)\r\n * @param {number} byte - 缓存区长度 / buffer length in byte\r\n * @param {number} [max_attempts] - 最大尝试次数 / maximum attempts (default: 1000)\r\n *\r\n * @returns\r\n * - buffer: 生成的随机缓存区 / generated random buffer\r\n * - result: 生成的随机大整数 / generated random bigint\r\n */\r\nexport function genRandomBI(max: bigint, byte: number, max_attempts: number = 1000) {\r\n if (max <= 1n) throw new KitError('Max must be greater than 1');\r\n\r\n // 创建缓存区\r\n const buffer = new U8(byte);\r\n\r\n // 生成随机数直到小于 max\r\n let result = 0n;\r\n let attempts = 0;\r\n while (attempts < max_attempts) {\r\n crypto.getRandomValues(buffer);\r\n result = buffer.toBI();\r\n if (result < max) return { buffer, result };\r\n attempts++;\r\n }\r\n\r\n throw new KitError('Failed to generate random bigint within max attempts');\r\n}\r\n\r\n/**\r\n * 获取大整数的比特长度\r\n *\r\n * Get the bit length of a BigInt\r\n */\r\nexport function getBIBits(n: bigint) {\r\n return n === 0n ? 0 : n.toString(2).length;\r\n}\r\n\r\n/**\r\n * 生成位掩码 / Generate Bit Mask\r\n *\r\n * @param {number} w - 位数 / bit\r\n *\r\n * ```ts\r\n * const mask = genBitMask(8) // 0xFFn\r\n * ```\r\n */\r\nexport function genBitMask(w: number | bigint) {\r\n w = BigInt(w);\r\n let mask = 0x0n;\r\n for (let i = 0; i < w; i++) {\r\n mask = (mask << 1n) | 1n;\r\n }\r\n return mask;\r\n}\r\n\r\n/**\r\n * 扩展欧几里得算法\r\n *\r\n * Extended Euclidean Algorithm\r\n *\r\n * @returns\r\n * - gcd: 最大公约数 / greatest common divisor\r\n * - x: a 的贝祖系数 / Bézout coefficient of a\r\n */\r\nexport function extendedEuclidean(a: bigint, b: bigint) {\r\n let [s0, s1, t0, t1, r0, r1] = [1n, 0n, 0n, 1n, a, b];\r\n\r\n if (b === 0n) {\r\n return {\r\n gcd: a,\r\n x: 1n,\r\n };\r\n }\r\n\r\n while (r1 !== 0n) {\r\n const q = r0 / r1;\r\n [r0, r1] = [r1, r0 - q * r1];\r\n [s0, s1] = [s1, s0 - q * s1];\r\n [t0, t1] = [t1, t0 - q * t1];\r\n }\r\n\r\n return {\r\n gcd: r0,\r\n x: s0,\r\n };\r\n}\r\n\r\n/**\r\n * 勒让德符号\r\n *\r\n * Legendre Symbol\r\n */\r\nexport function legendreSymbol(a: bigint, p: bigint): bigint {\r\n return modPow(a, (p - 1n) >> 1n, p);\r\n}\r\n\r\n/**\r\n * 托内利-香克斯算法\r\n *\r\n * Tonelli-Shanks Algorithm\r\n */\r\nexport function tonelliShanks(a: bigint, p: bigint): bigint {\r\n if (legendreSymbol(a, p) !== 1n) {\r\n throw new KitError('There is no square root');\r\n }\r\n if (a === 0n) {\r\n return 0n;\r\n }\r\n if (p === 2n) {\r\n return a;\r\n }\r\n if (p % 4n === 3n) {\r\n return modPow(a, (p + 1n) >> 2n, p);\r\n }\r\n\r\n let q = p - 1n;\r\n let s = 0n;\r\n while (mod(q, 2n) === 0n) {\r\n q >>= 1n;\r\n s++;\r\n }\r\n\r\n let z = 2n;\r\n while (legendreSymbol(z, p) !== p - 1n) {\r\n z++;\r\n }\r\n\r\n let m = s;\r\n let c = modPow(z, q, p);\r\n let t = modPow(a, q, p);\r\n let r = modPow(a, (q + 1n) >> 1n, p);\r\n\r\n while (t !== 0n && t !== 1n) {\r\n let t2i = t;\r\n let i = 1n;\r\n for (; i < m; i++) {\r\n t2i = modPow(t2i, 2n, p);\r\n if (t2i === 1n) {\r\n break;\r\n }\r\n }\r\n\r\n const b = modPow(c, 1n << (m - i - 1n), p);\r\n m = i;\r\n c = modPow(b, 2n, p);\r\n t = (t * c) % p;\r\n r = (r * b) % p;\r\n }\r\n\r\n return r;\r\n}\r\n\r\n/**\r\n * 最大公约数\r\n *\r\n * Greatest Common Divisor\r\n */\r\nexport function gcd(a: bigint, b: bigint): bigint {\r\n return extendedEuclidean(a, b).gcd;\r\n}\r\n\r\n/**\r\n * 最小公倍数\r\n *\r\n * Least Common Multiple\r\n */\r\nexport function lcm(a: bigint, b: bigint): bigint {\r\n return (a * b) / gcd(a, b);\r\n}\r\n\r\n/**\r\n * 求模: a mod b\r\n *\r\n * Modulo operation: a mod b\r\n *\r\n * @param {bigint} a - 被除数 / dividend\r\n * @param {bigint} b - 除数 / divisor\r\n */\r\nexport function mod(a: bigint, b: bigint): bigint {\r\n const r = a % b;\r\n return r < 0n ? r + b : r;\r\n}\r\n\r\n/**\r\n * 模幂运算: x ^ y mod n\r\n *\r\n * Modular exponentiation: x ^ y mod n\r\n *\r\n * @param {bigint} x - base\r\n * @param {bigint} y - exponent\r\n * @param {bigint} n - modulus\r\n */\r\nexport function modPow(x: bigint, y: bigint, n: bigint): bigint {\r\n x %= n;\r\n let r = 1n;\r\n while (y > 0n) {\r\n if (y & 1n) r = (r * x) % n;\r\n x = (x * x) % n;\r\n y >>= 1n;\r\n }\r\n return r;\r\n}\r\n\r\n/**\r\n * 模逆运算: e ≡ x ^ -1 (mod n)\r\n *\r\n * Modular inverse operation: e ≡ x ^ -1 (mod n)\r\n *\r\n * @param {bigint} x - base\r\n * @param {bigint} n - modulus\r\n */\r\nexport function modInverse(x: bigint, n: bigint): bigint {\r\n const { gcd, x: _x } = extendedEuclidean(x, n);\r\n if (gcd !== 1n) throw new KitError('Modular inverse does not exist');\r\n\r\n return mod(_x, n);\r\n}\r\n\r\n/**\r\n * 模素平方根运算: n ^ 0.5 (mod p)\r\n *\r\n * Modular prime square operation: n ^ 0.5 (mod p)\r\n */\r\nexport function modPrimeSquareRoot(n: bigint, p: bigint): bigint {\r\n n = mod(n, p);\r\n if (n === 0n) return 0n;\r\n const r1 = tonelliShanks(n, p);\r\n const r2 = mod(p - r1, p);\r\n return r1 <= r2 ? r1 : r2;\r\n}\r\n\r\n// * Buffer Utility Functions\r\n\r\n/**\r\n * @extends Uint8Array\r\n */\r\nexport class U8 extends Uint8Array {\r\n /**\r\n * 从 U8 中获取一个字 / Get a word from U8\r\n *\r\n * @param {number} word_size - 字长 / word size (byte)\r\n * @param {number} index - 字索引 / word index\r\n * @param {boolean} [little_endian] - 是否为小端序 / little-endian (default: false)\r\n */\r\n getWord(word_size: number, index: number, little_endian = false): bigint {\r\n const offset = index * word_size;\r\n const buffer = this.subarray(offset, offset + word_size);\r\n return little_endian ? buffer.toBI(true) : buffer.toBI();\r\n }\r\n\r\n /**\r\n * 将一个字写入 U8 / Set a word to U8\r\n *\r\n * @param {number} word_size - 字长 / word size (byte)\r\n * @param {number} index - 字索引 / word index\r\n * @param {bigint | Uint8Array} word - 字 / word\r\n * @param {boolean} [little_endian] - 是否为小端序 / little-endian (default: false)\r\n */\r\n setWord(word_size: number, index: number, word: bigint | Uint8Array, little_endian = false) {\r\n const offset = index * word_size;\r\n const buffer = typeof word === 'bigint' ? U8.fromBI(word, word_size) : word;\r\n this.set(little_endian ? buffer.toReversed() : buffer, offset);\r\n }\r\n\r\n /**\r\n * U8 视图 / U8 view\r\n *\r\n * @param {number} word_size - 字长 / word size (byte)\r\n */\r\n view(word_size: number) {\r\n const length = Math.floor(this.length / word_size);\r\n const get = (index: number, little_endian = false) => this.getWord(word_size, index, little_endian);\r\n const set = (index: number, word: bigint | Uint8Array, little_endian = false) =>\r\n this.setWord(word_size, index, word, little_endian);\r\n return { get, set, length };\r\n }\r\n\r\n /**\r\n * 将 U8 编码为字符串 / stringify U8 to encoded string\r\n */\r\n to(codec: Codec) {\r\n return codec(this);\r\n }\r\n\r\n /**\r\n * 将 U8 转换为 BigInt / Convert U8 to BigInt\r\n *\r\n * @param {boolean} [little_endian] - 是否为小端序 / little-endian (default: false)\r\n */\r\n toBI(little_endian = false) {\r\n const buffer = little_endian ? this.toReversed() : this;\r\n let bigint = 0n;\r\n buffer.forEach((byte) => {\r\n bigint = (bigint << 8n) | BigInt(byte);\r\n });\r\n return bigint;\r\n }\r\n\r\n /**\r\n * Convert U8 to Uint8Array\r\n *\r\n * 将 U8 转换为 Uint8Array\r\n */\r\n toUint8Array() {\r\n return new Uint8Array(this);\r\n }\r\n\r\n /**\r\n * Convert string to U8\r\n *\r\n * 将 字符串 转换为 U8\r\n */\r\n static fromString(input: string, codec: Codec): U8 {\r\n return codec(input);\r\n }\r\n\r\n /**\r\n * Convert BigInt to U8\r\n *\r\n * 将 BigInt 转换为 U8\r\n */\r\n static fromBI(bigint: bigint, length?: number, little_endian = false): U8 {\r\n length = length || (getBIBits(bigint) + 7) >> 3;\r\n const buffer = new U8(length);\r\n if (little_endian) {\r\n for (let i = 0; i < buffer.length; i++) {\r\n buffer[i] = Number(bigint & 0xffn);\r\n bigint >>= 8n;\r\n }\r\n } else {\r\n for (let i = buffer.length - 1; i >= 0; i--) {\r\n buffer[i] = Number(bigint & 0xffn);\r\n bigint >>= 8n;\r\n }\r\n }\r\n return buffer;\r\n }\r\n\r\n /**\r\n * Returns the elements of an array that meet the condition specified in a callback function.\r\n * @param predicate A function that accepts up to three arguments. The filter method calls\r\n * the predicate function one time for each element in the array.\r\n * @param thisArg An object to which the this keyword can refer in the predicate function.\r\n * If thisArg is omitted, undefined is used as the this value.\r\n */\r\n filter(predicate: (value: number, index: number, array: this) => any, thisArg?: any): U8 {\r\n const _ = super.filter(predicate, thisArg);\r\n return new U8(_.buffer, _.byteOffset, _.byteLength);\r\n }\r\n\r\n /**\r\n * Returns a new array from a set of elements.\r\n * @param items A set of elements to include in the new array object.\r\n */\r\n static of(...items: number[]): U8 {\r\n const _ = Uint8Array.of(...items);\r\n return new U8(_.buffer, _.byteOffset, _.byteLength);\r\n }\r\n\r\n /**\r\n * Creates an array from an array-like or iterable object.\r\n * @param elements An iterable object to convert to an array.\r\n */\r\n static from(elements: Iterable<number>): U8;\r\n /**\r\n * Creates an array from an array-like or iterable object.\r\n * @param elements An iterable object to convert to an array.\r\n * @param mapfn A mapping function to call on every element of the array.\r\n * @param thisArg Value of 'this' used to invoke the mapfn.\r\n */\r\n static from<T>(elements: Iterable<T>, mapfn?: (v: T, k: number) => number, thisArg?: any): U8;\r\n /**\r\n * Creates an array from an array-like or iterable object.\r\n * @param arrayLike An array-like object to convert to an array.\r\n */\r\n static from(arrayLike: ArrayLike<number>): U8;\r\n /**\r\n * Creates an array from an array-like or iterable object.\r\n * @param arrayLike An array-like object to convert to an array.\r\n * @param mapfn A mapping function to call on every element of the array.\r\n * @param thisArg Value of 'this' used to invoke the mapfn.\r\n */\r\n static from<T>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => number, thisArg?: any): U8;\r\n static from(array_like: any, mapfn?: any, this_arg?: any): U8 {\r\n const _ = Uint8Array.from(array_like, mapfn, this_arg);\r\n return new U8(_.buffer, _.byteOffset, _.byteLength);\r\n }\r\n\r\n /**\r\n * Calls a defined callback function on each element of an array, and returns an array that\r\n * contains the results.\r\n * @param callbackfn A function that accepts up to three arguments. The map method calls the\r\n * callbackfn function one time for each element in the array.\r\n * @param thisArg An object to which the this keyword can refer in the callbackfn function.\r\n * If thisArg is omitted, undefined is used as the this value.\r\n */\r\n map(callbackfn: (value: number, index: number, array: this) => number, thisArg?: any): U8 {\r\n const _ = super.map(callbackfn, thisArg);\r\n return new U8(_.buffer, _.byteOffset, _.byteLength);\r\n }\r\n\r\n /**\r\n * Returns a section of an array.\r\n * @param start The beginning of the specified portion of the array.\r\n * @param end The end of the specified portion of the array. This is exclusive of the element at the index 'end'.\r\n */\r\n slice(start?: number, end?: number): U8 {\r\n const _ = super.slice(start, end);\r\n return new U8(_.buffer, _.byteOffset, _.byteLength);\r\n }\r\n\r\n /**\r\n * Gets a new Uint8Array view of the ArrayBuffer store for this array, referencing the elements\r\n * at begin, inclusive, up to end, exclusive.\r\n * @param begin The index of the beginning of the array.\r\n * @param end The index of the end of the array.\r\n */\r\n subarray(begin?: number, end?: number): U8 {\r\n const _ = super.subarray(begin, end);\r\n return new U8(_.buffer, _.byteOffset, _.byteLength);\r\n }\r\n\r\n /**\r\n * Copies the array and returns the copy with the elements in reverse order.\r\n */\r\n toReversed(): U8 {\r\n const _ = super.toReversed();\r\n return new U8(_.buffer, _.byteOffset, _.byteLength);\r\n }\r\n\r\n /**\r\n * Copies and sorts the array.\r\n * @param compareFn Function used to determine the order of the elements. It is expected to return\r\n * a negative value if the first argument is less than the second argument, zero if they're equal, and a positive\r\n * value otherwise. If omitted, the elements are sorted in ascending order.\r\n * ```ts\r\n * const myNums = Uint8Array.from([11, 2, 22, 1]);\r\n * myNums.toSorted((a, b) => a - b) // Uint8Array(4) [1, 2, 11, 22]\r\n * ```\r\n */\r\n toSorted(compareFn?: (a: number, b: number) => number): U8 {\r\n const _ = super.toSorted(compareFn);\r\n return new U8(_.buffer, _.byteOffset, _.byteLength);\r\n }\r\n\r\n /**\r\n * Copies the array and inserts the given number at the provided index.\r\n * @param index The index of the value to overwrite. If the index is\r\n * negative, then it replaces from the end of the array.\r\n * @param value The value to insert into the copied array.\r\n * @returns A copy of the original array with the inserted value.\r\n */\r\n with(index: number, value: number): U8 {\r\n const _ = super.with(index, value);\r\n return new U8(_.buffer, _.byteOffset, _.byteLength);\r\n }\r\n}\r\n\r\ntype TypedArray = Uint8Array | Int8Array | Uint8ClampedArray | Uint16Array | Int16Array | Uint32Array | Int32Array;\r\n\r\n/**\r\n * Convert TypedArray to Uint8Array\r\n *\r\n * 将 TypedArray 转换为 Uint8Array\r\n */\r\nexport function u8(source: TypedArray): U8 {\r\n return new U8(source.buffer as ArrayBuffer, source.byteOffset, source.byteLength);\r\n}\r\n\r\n/**\r\n * Convert TypedArray to Uint16Array\r\n *\r\n * 将 TypedArray 转换为 Uint16Array\r\n */\r\nexport function u16(source: TypedArray): Uint16Array {\r\n return new Uint16Array(source.buffer, source.byteOffset, source.byteLength >> 1);\r\n}\r\n\r\n/**\r\n * Convert TypedArray to Uint32Array\r\n *\r\n * 将 TypedArray 转换为 Uint32Array\r\n */\r\nexport function u32(source: TypedArray): Uint32Array {\r\n return new Uint32Array(source.buffer, source.byteOffset, source.byteLength >> 2);\r\n}\r\n\r\n/**\r\n * Merging multiple ArrayBuffers\r\n *\r\n * 合并多个 ArrayBuffer\r\n */\r\nexport function joinBuffer(...buffers: Uint8Array[]) {\r\n const byte_total = buffers.reduce((acc, cur) => acc + cur.byteLength, 0);\r\n const result = new U8(byte_total);\r\n let offset = 0;\r\n for (const buffer of buffers) {\r\n result.set(new U8(buffer), offset);\r\n offset += buffer.byteLength;\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * resize ArrayBuffer\r\n *\r\n * 调整 ArrayBuffer 大小\r\n *\r\n * @param {ArrayBuffer} buffer\r\n * @param {number} size - byte\r\n */\r\nexport function resizeBuffer(buffer: Uint8Array, size: number) {\r\n const b = new U8(size);\r\n b.set(buffer);\r\n return b;\r\n}\r\n\r\nconst nibble_reverse_map = [\r\n 0x0n,\r\n 0x8n,\r\n 0x4n,\r\n 0xcn,\r\n 0x2n,\r\n 0xan,\r\n 0x6n,\r\n 0xen,\r\n 0x1n,\r\n 0x9n,\r\n 0x5n,\r\n 0xdn,\r\n 0x3n,\r\n 0xbn,\r\n 0x7n,\r\n 0xfn,\r\n];\r\n\r\n/**\r\n * 快速翻转字节位序 / Fast Reverse Byte's Bit Order\r\n *\r\n * @param {number} byte - 字节 / byte\r\n */\r\nexport function reverseBit(byte: number) {\r\n byte &= 0xff;\r\n const b_h = nibble_reverse_map[byte >> 4];\r\n const b_l = nibble_reverse_map[byte & 0xf];\r\n return (b_l << 4n) | b_h;\r\n}\r\n\r\nexport class Counter extends U8 {\r\n /**\r\n * @param {number} offset - 计数器偏移 / counter offset\r\n * @param {number} length - 计数器长度 / counter length\r\n */\r\n inc(offset?: number, length?: number, little_endian = false) {\r\n // 如果不提供偏移,则默认计数器从 0 开始\r\n offset = offset || 0;\r\n if (offset < 0 || offset >= this.length) {\r\n throw new KitError('Invalid counter offset');\r\n }\r\n // 如果不提供长度,则默认计数器长度为剩余长度\r\n length = length || this.length - offset;\r\n if (length < 0 || offset + length > this.length) {\r\n throw new KitError('Invalid counter length');\r\n }\r\n if (little_endian) {\r\n for (let i = offset; i < offset + length; i++) {\r\n if (this[i] < 0xff) {\r\n this[i] += 1;\r\n break;\r\n }\r\n this[i] = 0;\r\n }\r\n } else {\r\n for (let i = offset + length - 1; i >= offset; i--) {\r\n if (this[i] < 0xff) {\r\n this[i] += 1;\r\n break;\r\n }\r\n this[i] = 0;\r\n }\r\n }\r\n }\r\n}\r\n\r\n// * Other Utility Functions\r\n\r\nexport function trying<T>(fn: () => T): [Error, null] | [null, T] {\r\n try {\r\n const result = fn();\r\n return [null, result];\r\n } catch (error) {\r\n return error instanceof Error ? [error, null] : [new KitError('Unknown error'), null];\r\n }\r\n}\r\n\r\nexport function wrap<T = any>(...args: any[]): T {\r\n // @ts-expect-error Object assign\r\n return Object.assign(...args);\r\n}\r\n\r\nexport class KitError extends Error {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = 'mima-kit Error';\r\n }\r\n}\r\n","import { modPow, U8 } from './utils';\r\n\r\n// * Interfaces\r\n\r\n/** 随机素数生成器 / Random Prime Generator */\r\nexport interface RandomPrimeGenerator {\r\n /**\r\n * @param {bigint} b - 位数 / Bits\r\n */\r\n (b: number): bigint;\r\n}\r\n\r\n// * Constants\r\n\r\n/** deterministic >= 1 - 0.5^t */\r\nconst T = 40;\r\nconst LOW_PRIMES = [\r\n 2n,\r\n 3n,\r\n 5n,\r\n 7n,\r\n 11n,\r\n 13n,\r\n 17n,\r\n 19n,\r\n 23n,\r\n 29n,\r\n 31n,\r\n 37n,\r\n 41n,\r\n 43n,\r\n 47n,\r\n 53n,\r\n 59n,\r\n 61n,\r\n 67n,\r\n 71n,\r\n 73n,\r\n 79n,\r\n 83n,\r\n 89n,\r\n 97n,\r\n 101n,\r\n 103n,\r\n 107n,\r\n 109n,\r\n 113n,\r\n 127n,\r\n 131n,\r\n 137n,\r\n 139n,\r\n 149n,\r\n 151n,\r\n 157n,\r\n 163n,\r\n 167n,\r\n 173n,\r\n 179n,\r\n 181n,\r\n 191n,\r\n 193n,\r\n 197n,\r\n 199n,\r\n 211n,\r\n 223n,\r\n 227n,\r\n 229n,\r\n 233n,\r\n 239n,\r\n 241n,\r\n 251n,\r\n 257n,\r\n 263n,\r\n 269n,\r\n 271n,\r\n 277n,\r\n 281n,\r\n 283n,\r\n 293n,\r\n 307n,\r\n 311n,\r\n 313n,\r\n 317n,\r\n 331n,\r\n 337n,\r\n 347n,\r\n 349n,\r\n 353n,\r\n 359n,\r\n 367n,\r\n 373n,\r\n 379n,\r\n 383n,\r\n 389n,\r\n 397n,\r\n 401n,\r\n 409n,\r\n 419n,\r\n 421n,\r\n 431n,\r\n 433n,\r\n 439n,\r\n 443n,\r\n 449n,\r\n 457n,\r\n 461n,\r\n 463n,\r\n 467n,\r\n 479n,\r\n 487n,\r\n 491n,\r\n 499n,\r\n 503n,\r\n 509n,\r\n 521n,\r\n 523n,\r\n 541n,\r\n 547n,\r\n 557n,\r\n 563n,\r\n 569n,\r\n 571n,\r\n 577n,\r\n 587n,\r\n 593n,\r\n 599n,\r\n 601n,\r\n 607n,\r\n 613n,\r\n 617n,\r\n 619n,\r\n 631n,\r\n 641n,\r\n 643n,\r\n 647n,\r\n 653n,\r\n 659n,\r\n 661n,\r\n 673n,\r\n 677n,\r\n 683n,\r\n 691n,\r\n 701n,\r\n 709n,\r\n 719n,\r\n 727n,\r\n 733n,\r\n 739n,\r\n 743n,\r\n 751n,\r\n 757n,\r\n 761n,\r\n 769n,\r\n 773n,\r\n 787n,\r\n 797n,\r\n 809n,\r\n 811n,\r\n 821n,\r\n 823n,\r\n 827n,\r\n 829n,\r\n 839n,\r\n 853n,\r\n 857n,\r\n 859n,\r\n 863n,\r\n 877n,\r\n 881n,\r\n 883n,\r\n 887n,\r\n 907n,\r\n 911n,\r\n 919n,\r\n 929n,\r\n 937n,\r\n 941n,\r\n 947n,\r\n 953n,\r\n 967n,\r\n 971n,\r\n 977n,\r\n 983n,\r\n 991n,\r\n 997n,\r\n];\r\nconst LOW_PRIMES_LIMIT = (1n << 26n) / LOW_PRIMES[LOW_PRIMES.length - 1];\r\n\r\n// * Functions\r\n\r\n/**\r\n * Miller-Rabin 素性测试 / Primality Test\r\n *\r\n * @param {bigint} n - 待测试的数 / Number to be tested\r\n * @param {number} t - 测试轮数 / Number of tests\r\n */\r\nfunction MillerRabin(n: bigint, t: number): boolean {\r\n const n_1 = n - 1n;\r\n let s = 0n;\r\n let d = n_1;\r\n while ((d & 1n) === 0n) {\r\n d >>= 1n;\r\n s++;\r\n }\r\n\r\n t = (t + 1) >> 1;\r\n if (t > LOW_PRIMES.length) t = LOW_PRIMES.length;\r\n\r\n const tested: bigint[] = [2n];\r\n for (let i = 0; i < t; ++i) {\r\n // Pick bases at random\r\n let base: bigint;\r\n do {\r\n base = LOW_PRIMES[Math.floor(Math.random() * LOW_PRIMES.length)];\r\n } while (tested.includes(base));\r\n tested.push(base);\r\n if (StrongPseudoPrime(n, n_1, s, d, base) === false) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n}\r\n\r\n/**\r\n * 根据费马小定理: `base^(n-1) ≡ 1 (mod n)` 时 `n` 可能是素数,\r\n * 通过将 `n-1` 分解为 `2^s * d` 优化计算\r\n *\r\n * According to Fermat's Little Theorem: `base^(n-1) ≡ 1 (mod n)` when `n` may be a prime,\r\n * optimize the calculation by decomposing `n-1` into `2^s * d`\r\n *\r\n * @param {bigint} n - 待测试的数 / Number to be tested\r\n * @param {bigint} n_1 - n - 1\r\n * @param {bigint} s - n - 1 = 2^s * d\r\n * @param {bigint} d - n - 1 = 2^s * d\r\n * @param {bigint} base - 测试基数 / Test base\r\n */\r\nfunction StrongPseudoPrime(n: bigint, n_1: bigint, s: bigint, d: bigint, base: bigint): boolean {\r\n let x = modPow(base, d, n);\r\n if (x === 1n || x === n_1) return true;\r\n\r\n let y = 0n;\r\n for (let i = 1; i < s; i++) {\r\n y = modPow(x, 2n, n);\r\n if (y === 1n && x !== 1n && x !== n_1) return false;\r\n x = y;\r\n }\r\n return y === 1n;\r\n}\r\n\r\n/**\r\n * 高级素性测试: 确定性 >= 1-.5^t\r\n *\r\n * Advanced primality test: deterministic >= 1-.5^t\r\n */\r\nfunction _isProbablePrime(n: bigint, t: number = T): boolean {\r\n // 低素数倍数\r\n for (let i = 1; i < LOW_PRIMES.length; ) {\r\n let m = LOW_PRIMES[i];\r\n let j = i + 1;\r\n while (j < LOW_PRIMES.length && m < LOW_PRIMES_LIMIT) {\r\n m *= LOW_PRIMES[j++];\r\n }\r\n m = n % m;\r\n while (i < j) {\r\n if (m % LOW_PRIMES[i++] === 0n) return false;\r\n }\r\n }\r\n\r\n return MillerRabin(n, t);\r\n}\r\n\r\nfunction genPrimeCandidate(buffer: U8) {\r\n crypto.getRandomValues(buffer);\r\n buffer[0] |= 0x80;\r\n let n = buffer.toBI() | 1n;\r\n const n_mod_6 = n % 6n;\r\n if (n_mod_6 !== 1n && n_mod_6 !== 5n) n += 4n;\r\n\r\n return n;\r\n}\r\n\r\n/**\r\n * 随机素数生成器 / Random Prime Generator\r\n *\r\n * @param {bigint} b - 位数 / Bits\r\n */\r\nexport const genPrime: RandomPrimeGenerator = (b: number): bigint => {\r\n const buffer = new U8(b >> 3);\r\n let n: bigint;\r\n do {\r\n n = genPrimeCandidate(buffer);\r\n } while (!_isProbablePrime(n));\r\n return n;\r\n};\r\n\r\n/**\r\n * 素性测试: 确定性 >= 1-.5^t\r\n *\r\n * Primality test: deterministic >= 1-.5^t\r\n *\r\n * @param {bigint} n - 待测试的数 / Number to be tested\r\n * @param {number} t - 测试轮数 / Number of tests\r\n */\r\nexport function isProbablePrime(n: bigint, t: number = T): boolean {\r\n if (t <= 0) return false;\r\n // 偶数\r\n if ((n & 1n) === 0n) return false;\r\n // 六倍原理\r\n const n_mod_6 = n % 6n;\r\n if (n_mod_6 !== 1n && n_mod_6 !== 5n) return false;\r\n // 小素数\r\n if (n <= LOW_PRIMES[LOW_PRIMES.length - 1]) return LOW_PRIMES.includes(n);\r\n\r\n return _isProbablePrime(n, t);\r\n}\r\n","import { KitError, trying, U8, u8, wrap } from './utils';\r\n\r\n/** 字符编解码器 / String Codec */\r\nexport interface Codec {\r\n /**\r\n * 将编码字符串解析为 Uint8Array\r\n *\r\n * Parse encoded string to Uint8Array\r\n */\r\n (input: string): U8;\r\n /**\r\n * 将 Uint8Array 编码为字符串\r\n *\r\n * Stringify Uint8Array to encoded string\r\n */\r\n (input: Uint8Array): string;\r\n FORMAT: string;\r\n}\r\nfunction createCodec(\r\n parse: (input: string) => U8,\r\n stringify: (input: Uint8Array) => string,\r\n format: string,\r\n): Codec {\r\n function codec(input: string): U8;\r\n function codec(input: Uint8Array): string;\r\n function codec(input: string | Uint8Array) {\r\n return typeof input === 'string' ? parse(input) : stringify(input);\r\n }\r\n return wrap(codec, { FORMAT: format });\r\n}\r\n\r\nfunction UTF8ToU8(input: string) {\r\n /**\r\n * 尝试使用 TextEncoder 编码\r\n * 否则使用自定义编码器\r\n */\r\n const [error, result] = trying(() => new TextEncoder().encode(input));\r\n if (!error) return u8(result);\r\n\r\n /** provided by xingluo233 */\r\n const buffer: number[] = [];\r\n for (let i = 0; i < input.length; i++) {\r\n const char_code = input.codePointAt(i);\r\n if (char_code === undefined) {\r\n } else if (char_code < 0x80) {\r\n buffer.push(char_code);\r\n } else if (char_code < 0x800) {\r\n buffer.push(0xc0 | (char_code >> 6));\r\n buffer.push(0x80 | (char_code & 0x3f));\r\n } else if (char_code < 0x10000) {\r\n buffer.push(0xe0 | (char_code >> 12));\r\n buffer.push(0x80 | ((char_code >> 6) & 0x3f));\r\n buffer.push(0x80 | (char_code & 0x3f));\r\n } else if (char_code < 0x110000) {\r\n buffer.push(0xf0 | (char_code >> 18));\r\n buffer.push(0x80 | ((char_code >> 12) & 0x3f));\r\n buffer.push(0x80 | ((char_code >> 6) & 0x3f));\r\n buffer.push(0x80 | (char_code & 0x3f));\r\n i++;\r\n }\r\n }\r\n return U8.from(buffer);\r\n}\r\nfunction U8ToUTF8(input: Uint8Array) {\r\n /**\r\n * 尝试使用 TextDecoder 解码\r\n * 否则使用自定义解码器\r\n */\r\n const [error, result] = trying(() => new TextDecoder().decode(input));\r\n if (!error) return result;\r\n\r\n /** provided by xingluo233 */\r\n const str = [];\r\n for (let i = 0; i < input.length; ) {\r\n const byte1 = input[i++];\r\n if (byte1 < 0x80) {\r\n str.push(String.fromCharCode(byte1));\r\n } else if (byte1 >= 0xc0 && byte1 < 0xe0) {\r\n const byte2 = input[i++];\r\n const char_code = ((byte1 & 0x1f) << 6) | (byte2 & 0x3f);\r\n str.push(String.fromCharCode(char_code));\r\n } else if (byte1 >= 0xe0 && byte1 < 0xf0) {\r\n const byte2 = input[i++];\r\n const byte3 = input[i++];\r\n const char_code = ((byte1 & 0x0f) << 12) | ((byte2 & 0x3f) << 6) | (byte3 & 0x3f);\r\n str.push(String.fromCharCode(char_code));\r\n } else if (byte1 >= 0xf0 && byte1 < 0xf8) {\r\n const byte2 = input[i++];\r\n const byte3 = input[i++];\r\n const byte4 = input[i++];\r\n const char_code =\r\n ((byte1 & 0x07) << 18) | ((byte2 & 0x3f) << 12) | ((byte3 & 0x3f) << 6) | (byte4 & 0x3f);\r\n str.push(String.fromCodePoint(char_code));\r\n } else {\r\n console.warn('Included an invalid UTF-8 byte');\r\n }\r\n }\r\n return str.join('');\r\n}\r\n/** UTF-8 编解码器 / Codec */\r\nexport const UTF8 = createCodec(UTF8ToU8, U8ToUTF8, 'utf-8');\r\n\r\nfunction HEXToU8(input: string) {\r\n input = input.replace(/^0x/, '');\r\n // eslint-disable-next-line node/prefer-global/buffer\r\n const [error, result] = trying(() => Buffer.from(input.replace(/[^0-9a-f]/gi, ''), 'hex'));\r\n if (!error) return u8(result);\r\n\r\n const arr = input.match(/[\\da-f]{2}/gi);\r\n if (arr == null) {\r\n return new U8();\r\n }\r\n return new U8(arr.map((h) => Number.parseInt(h, 16)));\r\n}\r\nfunction U8ToHEX(input: Uint8Array) {\r\n // eslint-disable-next-line node/prefer-global/buffer\r\n const [error, result] = trying(() => Buffer.from(input).toString('hex'));\r\n if (!error) return result;\r\n\r\n let str = '';\r\n for (let i = 0; i < input.length; i++) {\r\n str += input[i].toString(16).padStart(2, '0');\r\n }\r\n return str;\r\n}\r\n/** hex 编解码器 / Codec */\r\nexport const HEX = createCodec(HEXToU8, U8ToHEX, 'hex');\r\n\r\nfunction B64ToU8(input: string) {\r\n // eslint-disable-next-line node/prefer-global/buffer\r\n const [error, result] = trying(() => Buffer.from(input.replace(/[^A-Z0-9+/]/gi, ''), 'base64'));\r\n if (!error) return u8(result);\r\n\r\n return B64CommonParse(input);\r\n}\r\nfunction U8ToB64(input: Uint8Array) {\r\n // eslint-disable-next-line node/prefer-global/buffer\r\n const [error, result] = trying(() => Buffer.from(input).toString('base64'));\r\n if (!error) return result;\r\n\r\n return B64CommonStringify(input, false);\r\n}\r\n/** base64 编解码器 / Codec */\r\nexport const B64 = createCodec(B64ToU8, U8ToB64, 'base64');\r\n\r\nfunction B64URLToU8(input: string) {\r\n // eslint-disable-next-line node/prefer-global/buffer\r\n const [error, result] = trying(() => Buffer.from(input.replace(/[^\\w-]/g, ''), 'base64url'));\r\n if (!error) return u8(result);\r\n\r\n return B64CommonParse(input);\r\n}\r\nfunction U8ToB64URL(input: Uint8Array) {\r\n // eslint-disable-next-line node/prefer-global/buffer\r\n const [error, result] = trying(() => Buffer.from(input).toString('base64url'));\r\n if (!error) return result;\r\n\r\n return B64(input).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\r\n}\r\n/** base64url 编解码器 / Codec */\r\nexport const B64URL = createCodec(B64URLToU8, U8ToB64URL, 'base64url');\r\n\r\n/**\r\n * provided by xingluo233\r\n *\r\n * B64CommonParse can parse B64 or B64url string to Uint8Array\r\n *\r\n * B64CommonParse 可以将 B64 或者 B64url 字符串解析为 Uint8Array\r\n *\r\n * @param {string} input - B64 或 B64url 字符串\r\n */\r\nfunction B64CommonParse(input: string) {\r\n const map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\r\n input = input\r\n .replace(/-/g, '+')\r\n .replace(/_/g, '/')\r\n .replace(/[^A-Z0-9+/]/gi, '');\r\n const length = input.length * 0.75;\r\n const result = new U8(length);\r\n\r\n let i = 0;\r\n let j = 0;\r\n while (i < input.length) {\r\n const a = map.indexOf(input.charAt(i++));\r\n const b = map.indexOf(input.charAt(i++));\r\n const c = map.indexOf(input.charAt(i++));\r\n const d = map.indexOf(input.charAt(i++));\r\n\r\n const combined = (a << 18) | (b << 12) | (c << 6) | d;\r\n\r\n result[j++] = (combined >> 16) & 0xff;\r\n result[j++] = (combined >> 8) & 0xff;\r\n result[j++] = combined & 0xff;\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * B64CommonStringify can stringify Uint8Array to B64 or B64url string\r\n *\r\n * B64CommonStringify 可以将 Uint8Array 编码为 B64 或 B64url 字符串\r\n *\r\n * @param {Uint8Array} input - Uint8Array\r\n * @param {boolean} url - 是否是 B64url 字符串\r\n */\r\nfunction B64CommonStringify(input: Uint8Array, url: boolean) {\r\n let map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\r\n map += url ? '-_' : '+/';\r\n let result = '';\r\n let i: number;\r\n for (i = 0; i < input.length - 2; i += 3) {\r\n result += map[input[i] >> 2];\r\n result += map[((input[i] & 3) << 4) | (input[i + 1] >> 4)];\r\n result += map[((input[i + 1] & 15) << 2) | (input[i + 2] >> 6)];\r\n result += map[input[i + 2] & 63];\r\n }\r\n\r\n if (i === input.length - 2) {\r\n result += map[input[i] >> 2];\r\n result += map[((input[i] & 3) << 4) | (input[i + 1] >> 4)];\r\n result += map[(input[i + 1] & 15) << 2];\r\n result += url ? '' : '=';\r\n } else if (i === input.length - 1) {\r\n result += map[input[i] >> 2];\r\n result += map[(input[i] & 3) << 4];\r\n result += url ? '' : '==';\r\n }\r\n return result;\r\n}\r\n\r\ninterface B32Params {\r\n variant?: 'rfc4648' | 'rfc4648-hex' | 'crockford';\r\n padding?: boolean;\r\n}\r\ninterface B32Codec extends Codec {\r\n /**\r\n * 创建一个 base32 编解码器\r\n *\r\n * Create a base32 codec\r\n */\r\n (params: B32Params): Codec;\r\n}\r\n\r\nfunction TheB32Codec(input: string): U8;\r\nfunction TheB32Codec(input: Uint8Array): string;\r\nfunction TheB32Codec(params: B32Params): Codec;\r\nfunction TheB32Codec(args: string | Uint8Array | B32Params) {\r\n // 使用默认配置处理 B32 编解码\r\n\r\n const RFC4648_B32_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';\r\n if (typeof args === 'string') {\r\n const input = args.toUpperCase().replace(/[^A-Z2-7]/g, '');\r\n return B32CommonParse(input, RFC4648_B32_MAP);\r\n } else if (args instanceof Uint8Array) {\r\n return B32CommonStringify(args, RFC4648_B32_MAP, false);\r\n }\r\n\r\n // 创建 B32 变体\r\n\r\n const { variant = 'rfc4648', padding = false } = args;\r\n if (variant === 'rfc4648') {\r\n function B32ToU8(input: string) {\r\n input = input.toUpperCase().replace(/[^A-Z2-7]/g, '');\r\n return B32CommonParse(input, RFC4648_B32_MAP);\r\n }\r\n function U8ToB32(input: Uint8Array) {\r\n return B32CommonStringify(input, RFC4648_B32_MAP, padding);\r\n }\r\n return createCodec(B32ToU8, U8ToB32, 'base32');\r\n } else if (variant === 'rfc4648-hex') {\r\n const RFC4648_B32_HEX_MAP = '0123456789ABCDEFGHIJKLMNOPQRSTUV';\r\n function B32HexToU8(input: string) {\r\n input = input.toUpperCase().replace(/[^0-9A-V]/g, '');\r\n return B32CommonParse(input, RFC4648_B32_HEX_MAP);\r\n }\r\n function U8ToB32Hex(input: Uint8Array) {\r\n return B32CommonStringify(input, RFC4648_B32_HEX_MAP, padding);\r\n }\r\n return createCodec(B32HexToU8, U8ToB32Hex, 'base32-hex');\r\n } else if (variant === 'crockford') {\r\n const RFC4648_B32_CROCKFORD_MAP = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';\r\n function B32CrockfordToU8(input: string) {\r\n input = input\r\n .toUpperCase()\r\n .replace(/O/g, '0')\r\n .replace(/[IL]/g, '1')\r\n .replace(/[^0-9A-HJKMNP-TV-Z]/g, '');\r\n return B32CommonParse(input, RFC4648_B32_CROCKFORD_MAP);\r\n }\r\n function U8ToB32Crockford(input: Uint8Array) {\r\n return B32CommonStringify(input, RFC4648_B32_CROCKFORD_MAP, padding);\r\n }\r\n return createCodec(B32CrockfordToU8, U8ToB32Crockford, 'base32-crockford');\r\n }\r\n}\r\n/** base32 编解码器 / Codec */\r\nexport const B32: B32Codec = wrap(TheB32Codec, { FORMAT: 'base32' });\r\n\r\n/**\r\n * B32CommonParse can parse B32 string to Uint8Array\r\n *\r\n * B32CommonParse 可以将 B32 字符串解析为 Uint8Array\r\n *\r\n * @param {string} input - B32 或 B32url 字符串\r\n * @param {string} map - 字符表\r\n */\r\nfunction B32CommonParse(input: string, map: string) {\r\n const length = input.length * 0.625;\r\n const result = new U8(length);\r\n\r\n let i = 0;\r\n let j = 0;\r\n while (i < input.length) {\r\n const a = map.indexOf(input.charAt(i++));\r\n const b = map.indexOf(input.charAt(i++));\r\n const c = map.indexOf(input.charAt(i++));\r\n const d = map.indexOf(input.charAt(i++));\r\n const e = map.indexOf(input.charAt(i++));\r\n const f = map.indexOf(input.charAt(i++));\r\n const g = map.indexOf(input.charAt(i++));\r\n const h = map.indexOf(input.charAt(i++));\r\n\r\n result[j++] = (a << 3) | (b >> 2);\r\n result[j++] = ((b & 0b11) << 6) | (c << 1) | (d >> 4);\r\n result[j++] = ((d & 0b1111) << 4) | (e >> 1);\r\n result[j++] = ((e & 0b1) << 7) | (f << 2) | (g >> 3);\r\n result[j++] = ((g & 0b111) << 5) | h;\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * B32CommonStringify can stringify Uint8Array to B32 string\r\n *\r\n * B32CommonStringify 可以将 Uint8Array 编码为 B32 字符串\r\n *\r\n * @param {Uint8Array} input - Uint8Array\r\n * @param {string} map - 字符表\r\n * @param {boolean} pad - 是否填充\r\n */\r\nfunction B32CommonStringify(input: Uint8Array, map: string, pad: boolean) {\r\n let result = '';\r\n let i: number;\r\n for (i = 0; i < input.length - 4; i += 5) {\r\n const E0 = input[i];\r\n const E1 = input[i + 1];\r\n const E2 = input[i + 2];\r\n const E3 = input[i + 3];\r\n const E4 = input[i + 4];\r\n\r\n result += map[E0 >> 3];\r\n result += map[((E0 & 0b111) << 2) | (E1 >> 6)];\r\n result += map[(E1 >> 1) & 0b11111];\r\n result += map[((E1 & 0b1) << 4) | (E2 >> 4)];\r\n result += map[((E2 & 0b1111) << 1) | (E3 >> 7)];\r\n result += map[(E3 >> 2) & 0b11111];\r\n result += map[((E3 & 0b11) << 3) | (E4 >> 5)];\r\n result += map[E4 & 0b11111];\r\n }\r\n\r\n if (i === input.length - 4) {\r\n const E0 = input[i];\r\n const E1 = input[i + 1];\r\n const E2 = input[i + 2];\r\n const E3 = input[i + 3];\r\n\r\n result += map[E0 >> 3];\r\n result += map[((E0 & 0b111) << 2) | (E1 >> 6)];\r\n result += map[(E1 >> 1) & 0b11111];\r\n result += map[((E1 & 0b1) << 4) | (E2 >> 4)];\r\n result += map[((E2 & 0b1111) << 1) | (E3 >> 7)];\r\n result += map[(E3 >> 2) & 0b11111];\r\n result += map[(E3 & 0b11) << 3];\r\n result += pad ? '=' : '';\r\n } else if (i === input.length - 3) {\r\n const E0 = input[i];\r\n const E1 = input[i + 1];\r\n const E2 = input[i + 2];\r\n\r\n result += map[E0 >> 3];\r\n result += map[((E0 & 0b111) << 2) | (E1 >> 6)];\r\n result += map[(E1 >> 1) & 0b11111];\r\n result += map[((E1 & 0b1) << 4) | (E2 >> 4)];\r\n result += map[(E2 & 0b1111) << 1];\r\n result += pad ? '===' : '';\r\n } else if (i === input.length - 2) {\r\n const E0 = input[i];\r\n const E1 = input[i + 1];\r\n\r\n result += map[E0 >> 3];\r\n result += map[((E0 & 0b111) << 2) | (E1 >> 6)];\r\n result += map[(E1 >> 1) & 0b11111];\r\n result += map[(E1 & 0b1) << 4];\r\n result += pad ? '====' : '';\r\n } else if (i === input.length - 1) {\r\n const E0 = input[i];\r\n\r\n result += map[E0 >> 3];\r\n result += map[(E0 & 0b111) << 2];\r\n result += pad ? '======' : '';\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction CSVToU8(input: string) {\r\n const coreValueMap = new Map<string, number>();\r\n coreValueMap.set('富强', 0);\r\n coreValueMap.set('民主', 1);\r\n coreValueMap.set('文明', 2);\r\n coreValueMap.set('和谐', 3);\r\n coreValueMap.set('自由', 4);\r\n coreValueMap.set('平等', 5);\r\n coreValueMap.set('公正', 6);\r\n coreValueMap.set('法治', 7);\r\n coreValueMap.set('爱国', 8);\r\n coreValueMap.set('敬业', 9);\r\n coreValueMap.set('诚信', 10);\r\n coreValueMap.set('友善', 11);\r\n\r\n const from = (value: string) => {\r\n const nibble = coreValueMap.get(value);\r\n if (nibble === undefined) {\r\n throw new KitError('你竟然在社会主义核心价值观里夹带私货!');\r\n }\r\n return nibble;\r\n };\r\n\r\n const coreValues = input.match(/(\\S){2}/g);\r\n if (coreValues == null) return new U8();\r\n\r\n let h = 0;\r\n let l = 0;\r\n let count = 0;\r\n const result: number[] = [];\r\n for (let i = 0; i < coreValues.length; i++) {\r\n const isHigh = count % 2 === 0;\r\n\r\n let nibble = from(coreValues[i]);\r\n if (nibble === 10 || nibble === 11) {\r\n i++;\r\n if (i === coreValues.length) {\r\n throw new KitError('你的社会主义核心价值观破碎了!');\r\n }\r\n nibble = nibble === 10 ? 10 + from(coreValues[i]) : 6 + from(coreValues[i]);\r\n }\r\n if (isHigh) {\r\n h = nibble;\r\n } else {\r\n l = nibble;\r\n }\r\n\r\n if (!isHigh) {\r\n result.push(((h << 4) | l) & 0xff);\r\n }\r\n count++;\r\n }\r\n\r\n return new U8(result);\r\n}\r\nfunction U8ToCSV(input: Uint8Array) {\r\n const rand = () => Math.random() >= 0.5;\r\n const map = [\r\n '富强',\r\n '民主',\r\n '文明',\r\n '和谐',\r\n '自由',\r\n '平等',\r\n '公正',\r\n '法治',\r\n '爱国',\r\n '敬业',\r\n '诚信',\r\n '友善',\r\n ];\r\n\r\n let result = '';\r\n input.forEach((byte) => {\r\n const h = (byte >> 4) & 0xf;\r\n const l = byte & 0xf;\r\n if (h < 10) {\r\n result += map[h];\r\n } else if (rand()) {\r\n result += map[11] + map[h - 6];\r\n } else {\r\n result += map[11] + map[h - 6];\r\n }\r\n\r\n if (l < 10) {\r\n result += map[l];\r\n } else if (rand()) {\r\n result += map[10] + map[l - 10];\r\n } else {\r\n result += map[11] + map[l - 6];\r\n }\r\n });\r\n\r\n return result;\r\n}\r\n/** 社会主义核心价值观编解码器 / Core Socialist Values Codec */\r\nexport const CSV = createCodec(CSVToU8, U8ToCSV, 'core-socialist-values');\r\n","import type { U8 } from './utils';\r\nimport { wrap } from './utils';\r\n\r\n// * 散列函数包装器\r\n\r\nexport interface Digest {\r\n /**\r\n * @param {Uint8Array} M - 消息 / message\r\n */\r\n (M: Uint8Array): U8;\r\n}\r\nexport interface HashDescription {\r\n /** 算法名称 / Algorithm name */\r\n ALGORITHM: string;\r\n /** 分块大小 / Block size (byte) */\r\n BLOCK_SIZE: number;\r\n /** 摘要大小 / Digest size (byte) */\r\n DIGEST_SIZE: number;\r\n OID?: string;\r\n}\r\nexport interface Hash extends Digest, HashDescription {}\r\n/**\r\n * 散列算法包装器,\r\n * 提供散列算法描述, 以实现 `HMAC` 等拓展算法.\r\n *\r\n * Hash algorithm wrapper,\r\n * provide hash algorithm description to implement extended algorithms such as `HMAC`.\r\n *\r\n * @param {Digest} digest - 摘要函数 / digest function\r\n * @param {HashDescription} description - 算法描述 / algorithm description\r\n *\r\n * ```ts\r\n * const digest: Digest = (M: Uint8Array): U8 => { ... }\r\n * const description: HashDescription = { ... }\r\n * const hash = createHash(digest, description)\r\n * ```\r\n */\r\nexport const createHash = (digest: Digest, description: HashDescription): Hash => wrap(digest, description);\r\n\r\n// * 元组散列函数包装器\r\n\r\nexport interface TupleDigest {\r\n /**\r\n * @param {Uint8Array[]} M - 消息 / message\r\n */\r\n (M: Uint8Array[]): U8;\r\n}\r\nexport interface TupleHashDescription extends HashDescription {}\r\nexport interface TupleHash extends TupleDigest, TupleHashDescription {}\r\n/**\r\n * 元组散列算法包装器\r\n *\r\n * Tuple hash algorithm wrapper\r\n *\r\n * @param {TupleDigest} digest - 元组摘要函数 / tuple digest function\r\n * @param {TupleHashDescription} description - 算法描述 / algorithm description\r\n *\r\n * ```ts\r\n * const digest: TupleDigest = (M: Uint8Array[]): U8 => { ... }\r\n * const description: TupleHashDescription = { ... }\r\n * const hash = createTupleHash(digest, description)\r\n * ```\r\n */\r\nexport const createTupleHash = (digest: TupleDigest, description: TupleHashDescription): TupleHash =>\r\n wrap(digest, description);\r\n\r\n// * 密钥散列函数\r\n\r\nexport interface KeyDigest {\r\n /**\r\n * @param {Uint8Array} K - 密钥 / key\r\n * @param {Uint8Array} M - 消息 / message\r\n */\r\n (K: Uint8Array, M: Uint8Array): U8;\r\n}\r\nexport interface KeyHashDescription extends HashDescription {\r\n /** 推荐的密钥大小 / Recommended key size (byte) */\r\n KEY_SIZE: number;\r\n}\r\n/** 密钥散列函数 / Keyed hash function */\r\nexport interface KeyHash extends KeyDigest, KeyHashDescription {}\r\nexport const createKeyHash = (digest: KeyDigest, description: KeyHashDescription): KeyHash => wrap(digest, description);\r\n","import { createHash } from '../core/hash';\r\nimport { rotateL32, U8 } from '../core/utils';\r\n\r\n// * Function\r\n\r\nconst FF = (X: number, Y: number, Z: number, j: number) =>\r\n j < 16 ? X ^ Y ^ Z : (X & Y) | (X & Z) | (Y & Z);\r\nconst GG = (X: number, Y: number, Z: number, j: number) =>\r\n j < 16 ? X ^ Y ^ Z : (X & Y) | (~X & Z);\r\nconst P0 = (X: number) => X ^ rotateL32(X, 9) ^ rotateL32(X, 17);\r\nconst P1 = (X: number) => X ^ rotateL32(X, 15) ^ rotateL32(X, 23);\r\n\r\n// * Algorithm\r\n\r\nfunction digest(message: Uint8Array) {\r\n // * 初始化\r\n const state = new U8(32);\r\n const state_view = state.view(4);\r\n state_view.set(0, 0x7380166fn);\r\n state_view.set(1, 0x4914b2b9n);\r\n state_view.set(2, 0x172442d7n);\r\n state_view.set(3, 0xda8a0600n);\r\n state_view.set(4, 0xa96f30bcn);\r\n state_view.set(5, 0x163138aan);\r\n state_view.set(6, 0xe38dee4dn);\r\n state_view.set(7, 0xb0fb0e4en);\r\n\r\n const m_byte = message.length;\r\n const m_bit = BigInt(m_byte) << 3n;\r\n const block_size = 64;\r\n // ceil((M_BYTE + 9) / 64)\r\n const block_total = (m_byte + 9 + 63) >> 6;\r\n\r\n // * 填充\r\n const p = new U8(block_total * block_size);\r\n p.set(message);\r\n\r\n // appending the bit '1' to the message\r\n p[m_byte] = 0x80;\r\n\r\n // appending length\r\n const p_view = new DataView(p.buffer, p.byteOffset, p.byteLength);\r\n p_view.setBigUint64(p.length - 8, m_bit, false);\r\n\r\n // * 迭代压缩\r\n for (let offset = 0; offset < p.length; offset += block_size) {\r\n /** B(n) = p[offset:offset + block_size] */\r\n\r\n // 准备状态字\r\n const H0 = Number(state_view.get(0));\r\n const H1 = Number(state_view.get(1));\r\n const H2 = Number(state_view.get(2));\r\n const H3 = Number(state_view.get(3));\r\n const H4 = Number(state_view.get(4));\r\n const H5 = Number(state_view.get(5));\r\n const H6 = Number(state_view.get(6));\r\n const H7 = Number(state_view.get(7));\r\n let A = H0;\r\n let B = H1;\r\n let C = H2;\r\n let D = H3;\r\n let E = H4;\r\n let F = H5;\r\n let G = H6;\r\n let H = H7;\r\n\r\n // 合并执行 扩展 & 压缩\r\n const W = new Uint32Array(68);\r\n const W1 = new Uint32Array(64);\r\n for (let i = 0; i < 68; i++) {\r\n // 拓展 W\r\n if (i < 16) {\r\n // W[i] = B(n)[i]\r\n W[i] = p_view.getUint32(offset + (i << 2), false);\r\n } else {\r\n W[i] =\r\n P1(W[i - 16] ^ W[i - 9] ^ rotateL32(W[i - 3], 15)) ^ rotateL32(W[i - 13], 7) ^ W[i - 6];\r\n }\r\n\r\n // W1 拓展 & 压缩\r\n if (i > 3) {\r\n // W1 拓展\r\n const j = i - 4;\r\n // W1[j] = W[j] ^ W[j + 4]\r\n W1[j] = W[j] ^ W[i];\r\n\r\n // 压缩\r\n const T = j < 16 ? 0x79cc4519 : 0x7a879d8a;\r\n const SS1 = rotateL32(rotateL32(A, 12) + E + rotateL32(T, j), 7);\r\n const SS2 = SS1 ^ rotateL32(A, 12);\r\n const TT1 = FF(A, B, C, j) + D + SS2 + W1[j];\r\n const TT2 = GG(E, F, G, j) + H + SS1 + W[j];\r\n D = C;\r\n C = rotateL32(B, 9);\r\n B = A;\r\n A = TT1;\r\n H = G;\r\n G = rotateL32(F, 19);\r\n F = E;\r\n E = P0(TT2);\r\n }\r\n }\r\n\r\n // 更新状态字\r\n state_view.set(0, BigInt(H0 ^ A));\r\n state_view.set(1, BigInt(H1 ^ B));\r\n state_view.set(2, BigInt(H2 ^ C));\r\n state_view.set(3, BigInt(H3 ^ D));\r\n state_view.set(4, BigInt(H4 ^ E));\r\n state_view.set(5, BigInt(H5 ^ F));\r\n state_view.set(6, BigInt(H6 ^ G));\r\n state_view.set(7, BigInt(H7 ^ H));\r\n }\r\n\r\n // * 截断输出\r\n return state;\r\n}\r\n\r\nexport const sm3 = createHash(digest, {\r\n ALGORITHM: 'SM3',\r\n BLOCK_SIZE: 64,\r\n DIGEST_SIZE: 32,\r\n OID: '1.2.156.10197.1.401',\r\n});\r\n","import { createHash } from '../core/hash';\r\nimport { rotateL32, U8 } from '../core/utils';\r\n\r\n// * Constants\r\n\r\n/**\r\n * 轮常量列表 K 由 64 个 32 位无符号整数组成, 使用 1 到 64 的正弦函数生成.\r\n *\r\n * The round constants K is a list of 64 32-bit unsigned integers,\r\n * generated by the sine function from 1 to 64.\r\n *\r\n * ```ts\r\n * const K: number[] = []\r\n * for (let i = 0; i < 64; i++) {\r\n * K[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) >>> 0\r\n * }\r\n * ```\r\n */\r\nconst K = new Uint32Array([\r\n 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,\r\n 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,\r\n 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,\r\n 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,\r\n 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde53