diff --git a/package.json b/package.json index 92327f0..a3eff97 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ }, "dependencies": { "@emailjs/browser": "^4.4.1", + "@noble/hashes": "^2.0.1", "@noble/post-quantum": "^0.5.2", "@scure/bip39": "^2.0.1", "axios": "^1.11.0", diff --git a/src/constants.ts b/src/constants.ts index ab6e643..8376f72 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -14,7 +14,6 @@ export const CONTEXT_ENC_KEYSTORE = 'CRYPTO library 2025-07-30 16:18:03 key for export const CONTEXT_RECOVERY = 'CRYPTO library 2025-07-30 16:20:00 key for account recovery'; export const CONTEXT_INDEX = 'CRYPTO library 2025-07-30 17:20:00 key for protecting current search indices'; export const CONTEXT_DERIVE = 'CRYPTO library 2025-08-27 17:08:00 derive one key from two keys'; -export const CONTEXT_RATCHET = 'CRYPTO library 2025-08-28 18:27:00 ratchet media key'; export const PREFIX_MEDIA_KEY_COMMITMENT = 'CRYPTO library 2025-08-26 18:29:00 prefix for commitment to media keys'; export const PREFIX_PUBLIC_KEY_COMMITMENT = 'CRYPTO library 2025-08-26 18:30:00 prefix for commitment to public keys'; diff --git a/src/derive-key/deriveKeyFromTwoKeys.ts b/src/derive-key/deriveKeyFromTwoKeys.ts deleted file mode 100644 index bc8d0da..0000000 --- a/src/derive-key/deriveKeyFromTwoKeys.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { CONTEXT_DERIVE } from '../constants'; -import { deriveKeyFromTwoKeysAndContext } from './deriveKeysFromKey'; - -import { importSymmetricCryptoKey } from '../symmetric-crypto'; - -/** - * Derives a symmetric key from two keys - * - * @param key1 - The 32-bytes key - * @param key2 - The 32-bytes key - * @returns The derived secret key - */ -export async function deriveSymmetricKeyFromTwoKeys(key1: Uint8Array, key2: Uint8Array): Promise { - return await deriveKeyFromTwoKeysAndContext(key1, key2, CONTEXT_DERIVE); -} - -/** - * Derives a symmetric CryptoKey from two keys - * - * @param key1 - The 32-bytes key - * @param key2 - The 32-bytes key - * @returns The derived secret CryptoKey - */ -export async function deriveSymmetricCryptoKeyFromTwoKeys(key1: Uint8Array, key2: Uint8Array): Promise { - try { - const keyBytes = await deriveSymmetricKeyFromTwoKeys(key1, key2); - const key = await importSymmetricCryptoKey(keyBytes); - return key; - } catch (error) { - throw new Error('Failed to derive symmetric CryptoKey from two keys', { cause: error }); - } -} diff --git a/src/derive-key/deriveKeysFromKey.ts b/src/derive-key/deriveKeysFromKey.ts index cd4cc95..1c7d0f2 100644 --- a/src/derive-key/deriveKeysFromKey.ts +++ b/src/derive-key/deriveKeysFromKey.ts @@ -1,6 +1,6 @@ -import { blake3 } from 'hash-wasm'; -import { AES_KEY_BIT_LENGTH, HASH_BIT_LEN } from '../constants'; -import { hexToUint8Array } from '../utils'; +import { blake3 } from '@noble/hashes/blake3.js'; +import { AES_KEY_BIT_LENGTH, CONTEXT_DERIVE } from '../constants'; +import { UTF8ToUint8 } from '../utils'; import { importSymmetricCryptoKey } from '../symmetric-crypto'; /** @@ -11,18 +11,8 @@ import { importSymmetricCryptoKey } from '../symmetric-crypto'; * @param baseKey - The base key (NOT PASSWORD!) * @returns The derived secret key */ -export async function deriveSymmetricKeyFromContext( - context: string, - baseKey: Uint8Array | string, -): Promise { - try { - const context_key = await blake3(context); - const buffer_context_key = hexToUint8Array(context_key); - const result = await blake3(baseKey, AES_KEY_BIT_LENGTH, buffer_context_key); - return hexToUint8Array(result); - } catch (error) { - throw new Error('Failed to derive key from base key and context', { cause: error }); - } +export function deriveSymmetricKeyFromContext(context: string, baseKey: Uint8Array): Uint8Array { + return blake3(baseKey, { context: UTF8ToUint8(context) }); } /** @@ -41,7 +31,7 @@ export async function deriveSymmetricCryptoKeyFromContext(context: string, baseK if (!context) { throw new Error('Context is empry'); } - const keyBytes = await deriveSymmetricKeyFromContext(context, baseKey); + const keyBytes = deriveSymmetricKeyFromContext(context, baseKey); const key = await importSymmetricCryptoKey(keyBytes); return key; @@ -57,19 +47,43 @@ export async function deriveSymmetricCryptoKeyFromContext(context: string, baseK * @param key2 - The 32-bytes key * @returns The derived secret key */ -export async function deriveKeyFromTwoKeysAndContext( - key1: Uint8Array, - key2: Uint8Array, - context: string, -): Promise { +export function deriveSymmetricKeyFromTwoKeys(key1: Uint8Array, key2: Uint8Array): Uint8Array { + return deriveKeyFromTwoKeysAndContext(key1, key2, CONTEXT_DERIVE); +} + +/** + * Derives a symmetric CryptoKey from two keys + * + * @param key1 - The 32-bytes key + * @param key2 - The 32-bytes key + * @returns The derived secret CryptoKey + */ +export async function deriveSymmetricCryptoKeyFromTwoKeys(key1: Uint8Array, key2: Uint8Array): Promise { + try { + const keyBytes = deriveSymmetricKeyFromTwoKeys(key1, key2); + const key = await importSymmetricCryptoKey(keyBytes); + return key; + } catch (error) { + throw new Error('Failed to derive symmetric CryptoKey from two keys', { cause: error }); + } +} + +/** + * Derives a symmetric key from two keys and context + * + * @param key1 - The 32-bytes key + * @param key2 - The 32-bytes key + * @param context - The context string + * @returns The derived symmetric key + */ +export function deriveKeyFromTwoKeysAndContext(key1: Uint8Array, key2: Uint8Array, context: string): Uint8Array { try { if (key2.length != AES_KEY_BIT_LENGTH / 8 || key1.length != AES_KEY_BIT_LENGTH / 8) { throw new Error(`Input key length must be exactly ${AES_KEY_BIT_LENGTH / 8} bytes`); } - const combined_key = await blake3(key1, HASH_BIT_LEN, key2); - const result = await deriveSymmetricKeyFromContext(context, combined_key); - return result; + const key = blake3(key1, { key: key2 }); + return blake3(key, { context: UTF8ToUint8(context) }); } catch (error) { - throw new Error('Failed to derive symmetric key from two keys', { cause: error }); + throw new Error('Failed to derive symmetric key from two keys and context', { cause: error }); } } diff --git a/src/derive-key/index.ts b/src/derive-key/index.ts index 327dc11..7aee5a6 100644 --- a/src/derive-key/index.ts +++ b/src/derive-key/index.ts @@ -1,3 +1,2 @@ export * from './deriveKeysFromKey'; export * from './deriveKeysFromPassword'; -export * from './deriveKeyFromTwoKeys'; diff --git a/src/hash/blake3.ts b/src/hash/blake3.ts index 0a37410..2bc8afd 100644 --- a/src/hash/blake3.ts +++ b/src/hash/blake3.ts @@ -1,49 +1,113 @@ -import { computeHash } from './core'; -import { HASH_BIT_LEN } from '../constants'; +import { blake3 } from '@noble/hashes/blake3.js'; +import { utf8ToBytes, bytesToHex } from '@noble/hashes/utils.js'; /** * Hashes the given array of data * * @param data - The data to hash - * @returns The resulting hash hex string + * @returns The resulting hash array */ -export async function hashData(data: string[] | Uint8Array[]): Promise { +export function hashData(data: Uint8Array[]): Uint8Array { try { - const hasher = await computeHash(HASH_BIT_LEN, data); + const hasher = blake3.create(); + for (const d of data) { + hasher.update(d); + } return hasher.digest(); } catch (error) { throw new Error('Failed to compute hash', { cause: error }); } } +export function keyedHashHex(hashKey: Uint8Array, data: Uint8Array[]): string { + try { + const hash = keyedHash(hashKey, data); + return bytesToHex(hash); + } catch (error) { + throw new Error('Failed to compute hash hex', { cause: error }); + } +} + +export function keyedHash(hashKey: Uint8Array, data: Uint8Array[]): Uint8Array { + try { + const hasher = blake3.create({ key: hashKey }); + for (const d of data) { + hasher.update(d); + } + return hasher.digest(); + } catch (error) { + throw new Error('Failed to compute hash', { cause: error }); + } +} + +/** + * Hashes the given array of data + * + * @param data - The data to hash + * @returns The resulting hash hex string + */ +export function hashDataHex(data: Uint8Array[]): string { + try { + const hash = hashData(data); + return bytesToHex(hash); + } catch (error) { + throw new Error('Failed to compute hash', { cause: error }); + } +} + /** * Hashes the given array of data using blake3 algorithm * - * @param bits - The desired output bit-length, must be multiple of 8 + * @param bytes - The desired output byte-length * @param data - The data to hash * @returns The resulting hash value */ -export async function getBitsFromData(bits: number, data: string[] | Uint8Array[]): Promise { +export function getBytesFromData(bytes: number, data: Uint8Array[]): Uint8Array { try { - const hasher = await computeHash(bits, data); - return hasher.digest('binary'); + const hasher = blake3.create({ dkLen: bytes }); + for (const chunk of data) { + hasher.update(chunk); + } + return hasher.digest(); } catch (error) { - throw new Error('Failed to get bits from data', { cause: error }); + throw new Error('Failed to get bytes from data', { cause: error }); } } /** - * Hashes the given string using blake3 algorithm + * Hashes the given array of data using blake3 algorithm * - * @param bits - The desired output bit-length, must be multiple of 8 - * @param value - The string to hash + * @param bytes - The desired output byte-length + * @param data - The data to hash * @returns The resulting hash value */ -export async function getBitsFromString(bits: number, value: string): Promise { +export function getBytesFromDataHex(bytes: number, data: Uint8Array[]): string { try { - const hasher = await computeHash(bits, [value]); - return hasher.digest('binary'); + const hash = getBytesFromData(bytes, data); + return bytesToHex(hash); } catch (error) { - throw new Error('Failed to get bits from string', { cause: error }); + throw new Error('Failed to get bytes from data', { cause: error }); } } + +/** + * Hashes the given string using blake3 algorithm + * + * @param bytes - The desired output byte-length + * @param value - The string to hash + * @returns The resulting hash value + */ +export function getBytesFromString(bytes: number, value: string): Uint8Array { + return blake3(utf8ToBytes(value), { dkLen: bytes }); +} + +/** + * Hashes the given string using blake3 algorithm + * + * @param bytes - The desired output byte-length + * @param value - The string to hash + * @returns The resulting hash value + */ +export function getBytesFromStrinHex(bytes: number, value: string): string { + return bytesToHex(getBytesFromString(bytes, value)); +} diff --git a/src/hash/core.ts b/src/hash/core.ts deleted file mode 100644 index 0004009..0000000 --- a/src/hash/core.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { createBLAKE3, IHasher } from 'hash-wasm'; - -/** - * Hashes the given array of data using blake3 algorithm - * - * @param bits - The desired output bit-length, must be multiple of 8 - * @param data - The given data to hash - * @returns The resulting hash value - */ -export async function computeHash(bits: number, data: string[] | Uint8Array[]): Promise { - try { - const hasher = await createBLAKE3(bits); - hasher.init(); - for (const chunk of data) { - hasher.update(chunk); - } - return hasher; - } catch (error) { - throw new Error('Failed to compute hash', { cause: error }); - } -} - -/** - * Computes keyed hash of the given array of data using blake3 algorithm - * - * @param bits - The desired output bit-length, must be multiple of 8 - * @param key - The key - * @param data - The given data to hash - * @returns The resulting keyed hash value - */ -export async function computeKeyedHash(bits: number, key: Uint8Array, data: string[] | Uint8Array[]): Promise { - try { - const hasher = await createBLAKE3(bits, key); - hasher.init(); - for (const chunk of data) { - hasher.update(chunk); - } - return hasher; - } catch (error) { - throw new Error('Failed to compute keyed hash', { cause: error }); - } -} diff --git a/src/hash/mac.ts b/src/hash/mac.ts index ef32893..1c8b487 100644 --- a/src/hash/mac.ts +++ b/src/hash/mac.ts @@ -1,6 +1,6 @@ -import { computeKeyedHash } from './core'; -import { HASH_BIT_LEN, AES_KEY_BIT_LENGTH } from '../constants'; -import { getBitsFromString } from './blake3'; +import { bytesToHex } from '@noble/hashes/utils.js'; +import { AES_KEY_BIT_LENGTH } from '../constants'; +import { getBytesFromString, keyedHash } from './blake3'; /** * Computes mac for the given key material and data @@ -9,11 +9,11 @@ import { getBitsFromString } from './blake3'; * @param data - The data to hash * @returns The resulting hash hex string */ -export async function computeMac(keyMaterial: string, data: string[]): Promise { +export function computeMac(keyMaterial: string, data: Uint8Array[]): string { try { - const key = await getBitsFromString(AES_KEY_BIT_LENGTH, keyMaterial); - const hasher = await computeKeyedHash(HASH_BIT_LEN, key, data); - return hasher.digest(); + const key = getBytesFromString(AES_KEY_BIT_LENGTH / 8, keyMaterial); + const hash = keyedHash(key, data); + return bytesToHex(hash); } catch (error) { throw new Error('Failed to compute mac', { cause: error }); } diff --git a/src/keystore-crypto/core.ts b/src/keystore-crypto/core.ts index 6bac826..5b22274 100644 --- a/src/keystore-crypto/core.ts +++ b/src/keystore-crypto/core.ts @@ -4,7 +4,7 @@ import { SymmetricCiphertext } from '../types'; import sessionStorageService from '../storage-service/sessionStorageService'; import { deriveSymmetricCryptoKeyFromContext } from '../derive-key'; import { CONTEXT_LOGIN, CONTEXT_ENC_KEYSTORE, AES_KEY_BIT_LENGTH, CONTEXT_RECOVERY } from '../constants'; -import { getBitsFromString } from '../hash'; +import { getBytesFromString } from '../hash'; /** * Encrypts the keystore content using symmetric encryption @@ -107,7 +107,7 @@ export async function deriveIdentityKeystoreKey(baseKey: Uint8Array): Promise { - const recoveryCodesBuffer = await getBitsFromString(AES_KEY_BIT_LENGTH, recoveryCodes); + const recoveryCodesBuffer = getBytesFromString(AES_KEY_BIT_LENGTH / 8, recoveryCodes); return deriveSymmetricCryptoKeyFromContext(CONTEXT_RECOVERY, recoveryCodesBuffer); } diff --git a/src/symmetric-crypto/aes.ts b/src/symmetric-crypto/aes.ts index bf0d620..67bf8b1 100644 --- a/src/symmetric-crypto/aes.ts +++ b/src/symmetric-crypto/aes.ts @@ -17,7 +17,7 @@ export async function encryptSymmetrically( freeField?: string, ): Promise { try { - const iv = await createNISTbasedIV(freeField); + const iv = createNISTbasedIV(freeField); const additionalData = await makeAuxFixedLength(aux); const ciphertext = await encryptMessage(message, encryptionKey, iv, additionalData); return { ciphertext, iv }; diff --git a/src/symmetric-crypto/core.ts b/src/symmetric-crypto/core.ts index f51aa64..1f6bf01 100644 --- a/src/symmetric-crypto/core.ts +++ b/src/symmetric-crypto/core.ts @@ -1,5 +1,5 @@ import { randomBytes } from '@noble/post-quantum/utils.js'; -import { getBitsFromString } from '../hash'; +import { getBytesFromString } from '../hash'; import { AUX_LEN, AES_ALGORITHM, IV_LEN_BYTES } from '../constants'; /** @@ -10,7 +10,7 @@ import { AUX_LEN, AES_ALGORITHM, IV_LEN_BYTES } from '../constants'; * @param freeFiled - The string with an unrestricted content. Can be a device identifier, etc. * @returns The resulting 128-bits initialization vector. */ -export async function createNISTbasedIV(freeField?: string): Promise { +export function createNISTbasedIV(freeField?: string): Uint8Array { try { if (!freeField) { return randomBytes(IV_LEN_BYTES); @@ -21,7 +21,7 @@ export async function createNISTbasedIV(freeField?: string): Promise const randFiled = randomBytes(12); iv.set(randFiled, 0); - const freeFiledFixedLength = await getBitsFromString(32, freeField); + const freeFiledFixedLength = getBytesFromString(4, freeField); iv.set(freeFiledFixedLength, 12); return iv; @@ -37,7 +37,7 @@ export async function createNISTbasedIV(freeField?: string): Promise * @returns The resulting fixed-length auxilary string. */ export async function makeAuxFixedLength(aux: string): Promise { - return getBitsFromString(AUX_LEN, aux); + return getBytesFromString(AUX_LEN / 8, aux); } /** diff --git a/src/symmetric-crypto/keys.ts b/src/symmetric-crypto/keys.ts index 8edc8a2..0e74409 100644 --- a/src/symmetric-crypto/keys.ts +++ b/src/symmetric-crypto/keys.ts @@ -1,5 +1,5 @@ import { AES_ALGORITHM, AES_KEY_BIT_LENGTH, KEY_FORMAT } from '../constants'; -import { getBitsFromString } from '../hash'; +import { getBytesFromString } from '../hash'; /** * Converts Uint8Array into CryptoKey @@ -73,7 +73,7 @@ export function genSymmetricKey(): Uint8Array { */ export async function deriveSymmetricCryptoKey(keyMaterial: string): Promise { try { - const hashBuffer = await getBitsFromString(AES_KEY_BIT_LENGTH, keyMaterial); + const hashBuffer = getBytesFromString(AES_KEY_BIT_LENGTH / 8, keyMaterial); return importSymmetricCryptoKey(hashBuffer); } catch (error) { throw new Error('Failed to derive CryptoKey from the given key material', { cause: error }); diff --git a/src/utils/converters.ts b/src/utils/converters.ts index e49f9f5..f20eadf 100644 --- a/src/utils/converters.ts +++ b/src/utils/converters.ts @@ -1,4 +1,4 @@ -import { Buffer } from 'buffer'; +import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'; /** * Converts a Uint8Array into a hexadecimal string. @@ -7,7 +7,7 @@ import { Buffer } from 'buffer'; * @returns The hexadecimal string representation of the array. */ export function uint8ArrayToHex(array: Uint8Array): string { - return Buffer.from(array).toString('hex'); + return bytesToHex(array); } /** @@ -37,7 +37,7 @@ export function uint8ToUTF8(array: Uint8Array): string { * @returns A Uint8Array created from the hex string. */ export function hexToUint8Array(hex: string): Uint8Array { - return new Uint8Array(Buffer.from(hex, 'hex')); + return hexToBytes(hex); } /** @@ -46,8 +46,10 @@ export function hexToUint8Array(hex: string): Uint8Array { * @param array - The Uint8Array to convert. * @returns The base64 string representation of the array. */ -export function uint8ArrayToBase64(array: Uint8Array): string { - return Buffer.from(array).toString('base64'); +export function uint8ArrayToBase64(buffer: Uint8Array): string { + const array = Uint16Array.from(buffer); + const binaryString = new TextDecoder('UTF-16').decode(array); + return btoa(binaryString); } /** @@ -57,5 +59,11 @@ export function uint8ArrayToBase64(array: Uint8Array): string { * @returns A Uint8Array created from the base64 string. */ export function base64ToUint8Array(str: string): Uint8Array { - return new Uint8Array(Buffer.from(str, 'base64')); + const binaryString = atob(str); + const len = binaryString.length; + const array = new Uint8Array(len); + for (let i = 0; i < len; i++) { + array[i] = binaryString.codePointAt(i)!; + } + return new Uint8Array(array.buffer); } diff --git a/tests/derive-keys/deriveKeys.test.ts b/tests/derive-keys/deriveKeys.test.ts index bd6a1bc..6d0601a 100644 --- a/tests/derive-keys/deriveKeys.test.ts +++ b/tests/derive-keys/deriveKeys.test.ts @@ -62,10 +62,10 @@ describe('Test derive key', () => { it('derive symmetric key from two keys should fail for small key', async () => { const short_key = new Uint8Array([1, 2, 3]); const key2 = genSymmetricKey(); - await expect(deriveSymmetricKeyFromTwoKeys(short_key, key2)).rejects.toThrowError( + expect(() => deriveSymmetricKeyFromTwoKeys(short_key, key2)).toThrowError( /Failed to derive symmetric key from two keys/, ); - await expect(deriveSymmetricKeyFromTwoKeys(key2, short_key)).rejects.toThrowError( + expect(() => deriveSymmetricKeyFromTwoKeys(key2, short_key)).toThrowError( /Failed to derive symmetric key from two keys/, ); diff --git a/tests/hash/blake3.test.ts b/tests/hash/blake3.test.ts index 03a74d4..fe68a65 100644 --- a/tests/hash/blake3.test.ts +++ b/tests/hash/blake3.test.ts @@ -1,102 +1,90 @@ import { describe, expect, it } from 'vitest'; -import { getBitsFromData, hashData, getBitsFromString } from '../../src/hash'; -import { hexToUint8Array } from '../../src/utils'; +import { getBytesFromDataHex, hashDataHex, getBytesFromStrinHex } from '../../src/hash'; describe('Test hash module with blake3 test vectors', () => { - it('should throw an error if bits are not multiple of 8', async () => { - const message = ''; - await expect(getBitsFromString(66, message)).rejects.toThrow(/Failed to get bits from string/); - await expect(getBitsFromData(66, [message])).rejects.toThrow(/Failed to get bits from data/); - }); + function getBuffer(length: number) { + const result = new Uint8Array(length); + let byte = 0; + for (let i = 0; i < length; i++) { + result[i] = byte; + byte += 1; + if (byte > 250) { + byte = 0; + } + } + return result; + } + const expectedLen = 131; - it('should compute correct hash value', async () => { - const message = ''; - const result = await hashData([message]); + it('should compute correct hash value', () => { + const message = new Uint8Array(); + const result = hashDataHex([message]); const testResult = 'af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262'; expect(result).toStrictEqual(testResult); }); - it('should pass test with input length 0 from blake3 team', async () => { + it('should pass test with input length 0 from blake3 team', () => { const message = ''; - const result = await getBitsFromData(1048, [message]); - const result_string = await getBitsFromString(1048, message); + const result = getBytesFromDataHex(expectedLen, [new Uint8Array()]); + const result_string = getBytesFromStrinHex(expectedLen, message); - const testResult = hexToUint8Array( - 'af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262e00f03e7b69af26b7faaf09fcd333050338ddfe085b8cc869ca98b206c08243a26f5487789e8f660afe6c99ef9e0c52b92e7393024a80459cf91f476f9ffdbda7001c22e159b402631f277ca96f2defdf1078282314e763699a31c5363165421cce14d', - ); + const testResult = + 'af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262e00f03e7b69af26b7faaf09fcd333050338ddfe085b8cc869ca98b206c08243a26f5487789e8f660afe6c99ef9e0c52b92e7393024a80459cf91f476f9ffdbda7001c22e159b402631f277ca96f2defdf1078282314e763699a31c5363165421cce14d'; expect(result).toStrictEqual(result_string); expect(result).toStrictEqual(testResult); }); - it('should pass test with input length 1 from blake3 team', async () => { + it('should pass test with input length 1 from blake3 team', () => { const message = new Uint8Array([0]); - const result = await getBitsFromData(1048, [message]); + const result = getBytesFromDataHex(expectedLen, [message]); - const testResult = hexToUint8Array( - '2d3adedff11b61f14c886e35afa036736dcd87a74d27b5c1510225d0f592e213c3a6cb8bf623e20cdb535f8d1a5ffb86342d9c0b64aca3bce1d31f60adfa137b358ad4d79f97b47c3d5e79f179df87a3b9776ef8325f8329886ba42f07fb138bb502f4081cbcec3195c5871e6c23e2cc97d3c69a613eba131e5f1351f3f1da786545e5', - ); + const testResult = + '2d3adedff11b61f14c886e35afa036736dcd87a74d27b5c1510225d0f592e213c3a6cb8bf623e20cdb535f8d1a5ffb86342d9c0b64aca3bce1d31f60adfa137b358ad4d79f97b47c3d5e79f179df87a3b9776ef8325f8329886ba42f07fb138bb502f4081cbcec3195c5871e6c23e2cc97d3c69a613eba131e5f1351f3f1da786545e5'; expect(result).toStrictEqual(testResult); }); - it('should pass test with input length 2 from blake3 team', async () => { + it('should pass test with input length 2 from blake3 team', () => { const message = new Uint8Array([0, 1]); - const result = await getBitsFromData(1048, [message]); + const result = getBytesFromDataHex(expectedLen, [message]); - const testResult = hexToUint8Array( - '7b7015bb92cf0b318037702a6cdd81dee41224f734684c2c122cd6359cb1ee63d8386b22e2ddc05836b7c1bb693d92af006deb5ffbc4c70fb44d0195d0c6f252faac61659ef86523aa16517f87cb5f1340e723756ab65efb2f91964e14391de2a432263a6faf1d146937b35a33621c12d00be8223a7f1919cec0acd12097ff3ab00ab1', - ); + const testResult = + '7b7015bb92cf0b318037702a6cdd81dee41224f734684c2c122cd6359cb1ee63d8386b22e2ddc05836b7c1bb693d92af006deb5ffbc4c70fb44d0195d0c6f252faac61659ef86523aa16517f87cb5f1340e723756ab65efb2f91964e14391de2a432263a6faf1d146937b35a33621c12d00be8223a7f1919cec0acd12097ff3ab00ab1'; expect(result).toStrictEqual(testResult); }); - function getBuffer(length: number) { - const result = new Uint8Array(length); - let byte = 0; - for (let i = 0; i < length; i++) { - result[i] = byte; - byte += 1; - if (byte > 250) { - byte = 0; - } - } - return result; - } it('should pass test with input length 7 from blake3 team', async () => { const message = getBuffer(7); - const result = await getBitsFromData(1048, [message]); + const result = await getBytesFromDataHex(expectedLen, [message]); - const testResult = hexToUint8Array( - '3f8770f387faad08faa9d8414e9f449ac68e6ff0417f673f602a646a891419fe66036ef6e6d1a8f54baa9fed1fc11c77cfb9cff65bae915045027046ebe0c01bf5a941f3bb0f73791d3fc0b84370f9f30af0cd5b0fc334dd61f70feb60dad785f070fef1f343ed933b49a5ca0d16a503f599a365a4296739248b28d1a20b0e2cc8975c', - ); + const testResult = + '3f8770f387faad08faa9d8414e9f449ac68e6ff0417f673f602a646a891419fe66036ef6e6d1a8f54baa9fed1fc11c77cfb9cff65bae915045027046ebe0c01bf5a941f3bb0f73791d3fc0b84370f9f30af0cd5b0fc334dd61f70feb60dad785f070fef1f343ed933b49a5ca0d16a503f599a365a4296739248b28d1a20b0e2cc8975c'; expect(result).toStrictEqual(testResult); }); it('should pass test with input length 63 from blake3 team', async () => { const message = getBuffer(63); - const result = await getBitsFromData(1048, [message]); + const result = await getBytesFromDataHex(expectedLen, [message]); - const testResult = hexToUint8Array( - 'e9bc37a594daad83be9470df7f7b3798297c3d834ce80ba85d6e207627b7db7b1197012b1e7d9af4d7cb7bdd1f3bb49a90a9b5dec3ea2bbc6eaebce77f4e470cbf4687093b5352f04e4a4570fba233164e6acc36900e35d185886a827f7ea9bdc1e5c3ce88b095a200e62c10c043b3e9bc6cb9b6ac4dfa51794b02ace9f98779040755', - ); + const testResult = + 'e9bc37a594daad83be9470df7f7b3798297c3d834ce80ba85d6e207627b7db7b1197012b1e7d9af4d7cb7bdd1f3bb49a90a9b5dec3ea2bbc6eaebce77f4e470cbf4687093b5352f04e4a4570fba233164e6acc36900e35d185886a827f7ea9bdc1e5c3ce88b095a200e62c10c043b3e9bc6cb9b6ac4dfa51794b02ace9f98779040755'; expect(result).toStrictEqual(testResult); }); it('should pass test with input length 1023 from blake3 team', async () => { const message = getBuffer(1023); - const result = await getBitsFromData(1048, [message]); + const result = await getBytesFromDataHex(expectedLen, [message]); - const testResult = hexToUint8Array( - '10108970eeda3eb932baac1428c7a2163b0e924c9a9e25b35bba72b28f70bd11a182d27a591b05592b15607500e1e8dd56bc6c7fc063715b7a1d737df5bad3339c56778957d870eb9717b57ea3d9fb68d1b55127bba6a906a4a24bbd5acb2d123a37b28f9e9a81bbaae360d58f85e5fc9d75f7c370a0cc09b6522d9c8d822f2f28f485', - ); + const testResult = + '10108970eeda3eb932baac1428c7a2163b0e924c9a9e25b35bba72b28f70bd11a182d27a591b05592b15607500e1e8dd56bc6c7fc063715b7a1d737df5bad3339c56778957d870eb9717b57ea3d9fb68d1b55127bba6a906a4a24bbd5acb2d123a37b28f9e9a81bbaae360d58f85e5fc9d75f7c370a0cc09b6522d9c8d822f2f28f485'; expect(result).toStrictEqual(testResult); }); it('should pass test with input length 102400 from blake3 team', async () => { const message = getBuffer(102400); - const result = await getBitsFromData(1048, [message]); + const result = await getBytesFromDataHex(expectedLen, [message]); - const testResult = hexToUint8Array( - 'bc3e3d41a1146b069abffad3c0d44860cf664390afce4d9661f7902e7943e085e01c59dab908c04c3342b816941a26d69c2605ebee5ec5291cc55e15b76146e6745f0601156c3596cb75065a9c57f35585a52e1ac70f69131c23d611ce11ee4ab1ec2c009012d236648e77be9295dd0426f29b764d65de58eb7d01dd42248204f45f8e', - ); + const testResult = + 'bc3e3d41a1146b069abffad3c0d44860cf664390afce4d9661f7902e7943e085e01c59dab908c04c3342b816941a26d69c2605ebee5ec5291cc55e15b76146e6745f0601156c3596cb75065a9c57f35585a52e1ac70f69131c23d611ce11ee4ab1ec2c009012d236648e77be9295dd0426f29b764d65de58eb7d01dd42248204f45f8e'; expect(result).toStrictEqual(testResult); }); }); diff --git a/tests/hash/mac.test.ts b/tests/hash/mac.test.ts index cb0bb00..56766f9 100644 --- a/tests/hash/mac.test.ts +++ b/tests/hash/mac.test.ts @@ -1,19 +1,19 @@ import { describe, expect, it } from 'vitest'; import { computeMac } from '../../src/hash'; -import { computeKeyedHash } from '../../src/hash/core'; +import { keyedHashHex } from '../../src/hash'; describe('Test mac via blake3 test vectors', () => { it('keyed hash should work with blake 3 test vector', async () => { const key = new TextEncoder().encode('whats the Elvish word for friend'); const data = new Uint8Array([0, 1, 2, 3, 4, 5, 6]); - const mac = (await computeKeyedHash(256, key, [data])).digest(); + const mac = keyedHashHex(key, [data]); expect(mac).toEqual('af0a7ec382aedc0cfd626e49e7628bc7a353a4cb108855541a5651bf64fbb28a'); }); it('compute should work', async () => { const key = 'Srp6AzybbyludWuaVwGoHa1C2H0Qtv7JR0sKGLSWe8Ho8_q9hezfYD2RYb9IUrW999pH4VlABgDLse484zAapg'; - const data = ['test', 'this', 'mac']; - const mac = await computeMac(key, data); + const data = [new TextEncoder().encode('test'), new TextEncoder().encode('this'), new TextEncoder().encode('mac')]; + const mac = computeMac(key, data); expect(mac).toEqual('69e61015d45f1d2e33e380952cada43dd293e45188bfee5e35635e6d12edd815'); }); }); diff --git a/tests/symmetric-crypto/core.test.ts b/tests/symmetric-crypto/core.test.ts index 651e928..811272c 100644 --- a/tests/symmetric-crypto/core.test.ts +++ b/tests/symmetric-crypto/core.test.ts @@ -3,15 +3,15 @@ import { createNISTbasedIV } from '../../src/symmetric-crypto/core'; import { genSymmetricCryptoKey, encryptSymmetrically } from '../../src/symmetric-crypto'; import { base64ToCiphertext, ciphertextToBase64 } from '../../src/utils'; import { SymmetricCiphertext } from '../../src/types'; -import { getBitsFromString } from '../../src/hash'; +import { getBytesFromString } from '../../src/hash'; describe('Test symmetric functions', () => { it('should generate iv as expected', async () => { const freeField = '4'; - const iv = await createNISTbasedIV(freeField); + const iv = createNISTbasedIV(freeField); const number = iv.slice(12); - const hash = await getBitsFromString(32, freeField); + const hash = getBytesFromString(4, freeField); expect(number).toStrictEqual(hash); expect(iv.length).toBe(16); diff --git a/yarn.lock b/yarn.lock index 881c827..15b382b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -425,7 +425,7 @@ dependencies: "@noble/hashes" "2.0.1" -"@noble/hashes@2.0.1", "@noble/hashes@~2.0.0": +"@noble/hashes@2.0.1", "@noble/hashes@^2.0.1", "@noble/hashes@~2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-2.0.1.tgz#fc1a928061d1232b0a52bb754393c37a5216c89e" integrity sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==