diff --git a/packages/common/package.json b/packages/common/package.json index d433f63..45202bd 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -13,7 +13,7 @@ "typecheck": "tsc -b" }, "dependencies": { - "js-sha512": "^0.9.0" + "@noble/hashes": "^2.0.1" }, "devDependencies": { "tsdown": "^0.18.3", diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index bb08ff5..1eff8dd 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -9,3 +9,4 @@ export * from './util/JosaUtil.js'; export * from './util/RNG.js'; export * from './util/RandUtil.js'; export * from './util/TestRNG.js'; +export * from './util/sha512.js'; diff --git a/packages/common/src/util/LiteHashDRBG.ts b/packages/common/src/util/LiteHashDRBG.ts index 096f5b3..c441221 100644 --- a/packages/common/src/util/LiteHashDRBG.ts +++ b/packages/common/src/util/LiteHashDRBG.ts @@ -1,9 +1,8 @@ import type { RNG } from './RNG.js'; -import { sha512 } from 'js-sha512'; - import { convertBytesLikeToUint8Array } from './convertBytesLikeToUint8Array.js'; import type { BytesLike } from './BytesLike.js'; +import { sha512ArrayBuffer } from './sha512.js'; const maxRngSupportBit = 53; const maxInt = 0x1f_ffff_ffff_ffff; // NOTE: b 0, 10000110011, 11...11 @@ -111,7 +110,7 @@ export class LiteHashDRBG implements RNG { protected genNextBlock(): void { this.hq.setUint32(this.hqIdxPos, this.stateIdx, true); - const digest = sha512.arrayBuffer(this.hq.buffer as ArrayBuffer); + const digest = sha512ArrayBuffer(this.hq.buffer as ArrayBuffer); this.buffer = digest; this.bufferIdx = 0; this.stateIdx += 1; diff --git a/packages/common/src/util/sha512.ts b/packages/common/src/util/sha512.ts new file mode 100644 index 0000000..4caf9fe --- /dev/null +++ b/packages/common/src/util/sha512.ts @@ -0,0 +1,49 @@ +import { sha512 as sha512Noble } from '@noble/hashes/sha2.js'; + +import type { BytesLike } from './BytesLike.js'; +import { convertBytesLikeToUint8Array } from './convertBytesLikeToUint8Array.js'; + +type NodeHash = { + update(data: Uint8Array): NodeHash; + digest(): Uint8Array; +}; + +type NodeCreateHash = (algorithm: 'sha512') => NodeHash; + +const isNode = typeof process !== 'undefined' + && typeof process.versions?.node === 'string'; + +const nodeCryptoSpecifier = 'node:crypto'; + +let nodeCreateHash: NodeCreateHash | null = null; + +if (isNode) { + const nodeCrypto = await import(nodeCryptoSpecifier) as typeof import('node:crypto'); + nodeCreateHash = nodeCrypto.createHash as NodeCreateHash; +} + +function normalizeUint8Array(bytes: Uint8Array): Uint8Array { + if ( + bytes.buffer instanceof ArrayBuffer + && bytes.byteOffset === 0 + && bytes.byteLength === bytes.buffer.byteLength + ) { + return bytes as Uint8Array; + } + const out = new Uint8Array(bytes.byteLength); + out.set(bytes); + return out as Uint8Array; +} + +export function sha512Bytes(data: BytesLike): Uint8Array { + const input = convertBytesLikeToUint8Array(data); + if (nodeCreateHash) { + const digest = nodeCreateHash('sha512').update(input).digest(); + return normalizeUint8Array(digest); + } + return normalizeUint8Array(sha512Noble(input)); +} + +export function sha512ArrayBuffer(data: BytesLike): ArrayBuffer { + return sha512Bytes(data).buffer; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3feb5ae..406c82d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -135,9 +135,9 @@ importers: packages/common: dependencies: - js-sha512: - specifier: ^0.9.0 - version: 0.9.0 + '@noble/hashes': + specifier: ^2.0.1 + version: 2.0.1 devDependencies: tsdown: specifier: ^0.18.3 @@ -459,6 +459,10 @@ packages: '@napi-rs/wasm-runtime@1.1.0': resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==} + '@noble/hashes@2.0.1': + resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} + engines: {node: '>= 20.19.0'} + '@oxc-project/types@0.103.0': resolution: {integrity: sha512-bkiYX5kaXWwUessFRSoXFkGIQTmc6dLGdxuRTrC+h8PSnIdZyuXHHlLAeTmOue5Br/a0/a7dHH0Gca6eXn9MKg==} @@ -1335,9 +1339,6 @@ packages: js-git@0.7.8: resolution: {integrity: sha512-+E5ZH/HeRnoc/LW0AmAyhU+mNcWBzAKE+30+IDMLSLbbK+Tdt02AdkOKq9u15rlJsDEGFqtgckc8ZM59LhhiUA==} - js-sha512@0.9.0: - resolution: {integrity: sha512-mirki9WS/SUahm+1TbAPkqvbCiCfOAAsyXeHxK1UkullnJVVqoJG2pL9ObvT05CN+tM7fxhfYm0NbXn+1hWoZg==} - js-yaml@4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true @@ -2284,6 +2285,8 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@noble/hashes@2.0.1': {} + '@oxc-project/types@0.103.0': {} '@pinojs/redact@0.4.0': {} @@ -3114,8 +3117,6 @@ snapshots: git-sha1: 0.1.2 pako: 0.2.9 - js-sha512@0.9.0: {} - js-yaml@4.1.1: dependencies: argparse: 2.0.1