import { sha256 as SHA256 } from "js-sha256" import { blobToArrayBuffer, isBlob } from "../../bit" import { base64 } from "../funcs/base64" import { base58 } from "./base58" /** 计算数据的 SHA256 哈希值 */ export function sha256( data: Blob, options?: { outBase64?: boolean; outBase58?: boolean; arrayBuffer: ArrayBuffer } ): Promise export function sha256( data: Blob, options: { outMore: true } ): Promise<{ base64: string; base58: string; hex: string; arrayBuffer: ArrayBuffer }> export function sha256( data: string | ArrayBuffer | Uint8Array, options?: { outBase64?: boolean; outBase58?: boolean } ): string export function sha256( data: string | ArrayBuffer| Uint8Array, options: { outMore: true } ): { base64: string; base58: string; hex: string; arrayBuffer: ArrayBuffer } export function sha256( data: string | ArrayBuffer | Blob | Uint8Array, options?: { outMore?: boolean; outBase64?: boolean; outBase58?: boolean } ) { if (isBlob(data)) { if (typeof crypto !== "undefined" && !!crypto?.subtle?.digest) { return sha256Native(data, options) } else { return blobToArrayBuffer(data).then((arrayBuffer) => { return sha256(arrayBuffer, options) }) } } else { if (options?.outBase64) { return base64.encode((SHA256 as any).arrayBuffer(data)) } else if (options?.outBase58) { return base58.encode((SHA256 as any).array(data)) } else if (options?.outMore) { var hash_sha256 = SHA256.create() hash_sha256.update(data) let arrayBuffer = hash_sha256.arrayBuffer() return { base64: base64.encode(arrayBuffer), base58: base58.encode(arrayBuffer), hex: hash_sha256.hex(), arrayBuffer, } } else { return (SHA256 as any).hex(data) } } } /** 使用浏览器原生 crypto 计算 sha256 */ export async function sha256Native( data: string | ArrayBuffer | Blob, options: { outMore: true } ): Promise<{ base64: string; base58: string; hex: string; arrayBuffer: ArrayBuffer }> export async function sha256Native( data: string | ArrayBuffer | Blob, options?: { outBase64?: boolean; outBase58?: boolean } ): Promise export async function sha256Native( data: string | ArrayBuffer | Blob, options?: { outBase64?: boolean; outBase58?: boolean; outMore?: boolean } ) { if (isBlob(data)) { return blobToArrayBuffer(data).then((arrayBuffer) => { return sha256Native(arrayBuffer, options) }) } let input: string | ArrayBuffer | Uint8Array = data if (typeof data === "string") input = new TextEncoder().encode(data) let hash_arrayBuffer = await crypto.subtle.digest("SHA-256", input) if (options?.outBase64) { return base64.encode(hash_arrayBuffer) } else if (options?.outBase58) { return base58.encode(hash_arrayBuffer) } else if (options?.outMore) { return { base64: base64.encode(hash_arrayBuffer), base58: base58.encode(hash_arrayBuffer), hex: hex(hash_arrayBuffer), arrayBuffer: hash_arrayBuffer, } } else { return hex(hash_arrayBuffer) } } function hex(buffer: ArrayBuffer) { var digest = "" var view = new DataView(buffer) for (var i = 0; i < view.byteLength; i += 4) { // We use getUint32 to reduce the number of iterations (notice the `i += 4`) var value = view.getUint32(i) // toString(16) will transform the integer into the corresponding hex string // but will remove any initial "0" var stringValue = value.toString(16) // One Uint32 element is 4 bytes or 8 hex chars (it would also work with 4 // chars for Uint16 and 2 chars for Uint8) var padding = "00000000" var paddedValue = (padding + stringValue).slice(-padding.length) digest += paddedValue } return digest }