From 243eecbee16568ca33a5a1623618d1a547146116 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 14 Jul 2026 22:18:59 +0100 Subject: [PATCH] refactor(reef): use Noble byte utilities --- extensions/reef/protocol/audit.ts | 12 +++--------- extensions/reef/protocol/encoding.ts | 22 ++-------------------- extensions/reef/protocol/node.ts | 7 ++----- 3 files changed, 7 insertions(+), 34 deletions(-) diff --git a/extensions/reef/protocol/audit.ts b/extensions/reef/protocol/audit.ts index c14326a3167a..14dba2ea25b5 100644 --- a/extensions/reef/protocol/audit.ts +++ b/extensions/reef/protocol/audit.ts @@ -1,7 +1,7 @@ import { gcm } from "@noble/ciphers/aes.js"; import { ed25519 } from "@noble/curves/ed25519.js"; import { sha256 } from "@noble/hashes/sha2.js"; -import { randomBytes } from "@noble/hashes/utils.js"; +import { concatBytes, randomBytes } from "@noble/hashes/utils.js"; import { canonicalBytes, canonicalJson } from "./canonical.js"; import { base64, base64url, decodeUtf8, fromBase64, fromBase64url, hex, utf8 } from "./encoding.js"; @@ -187,10 +187,7 @@ function encryptSensitive( throw new Error("invalid audit nonce"); } const ciphertext = gcm(key, nonce).encrypt(utf8(child)); - const combined = new Uint8Array(nonce.length + ciphertext.length); - combined.set(nonce); - combined.set(ciphertext, nonce.length); - output[field] = { enc: base64(combined) }; + output[field] = { enc: base64(concatBytes(nonce, ciphertext)) }; } else { output[field] = encryptSensitive(child, key, rng); } @@ -230,10 +227,7 @@ function decryptSensitive(value: unknown, key: Uint8Array, field?: string): unkn function hashEntry(previous: string, event: AuditEvent): string { const previousBytes = previous === "" ? new Uint8Array() : fromHex(previous); const eventBytes = canonicalBytes(event); - const combined = new Uint8Array(previousBytes.length + eventBytes.length); - combined.set(previousBytes); - combined.set(eventBytes, previousBytes.length); - return hex(sha256(combined)); + return hex(sha256(concatBytes(previousBytes, eventBytes))); } function validateAuditKey(key: Uint8Array): Uint8Array { diff --git a/extensions/reef/protocol/encoding.ts b/extensions/reef/protocol/encoding.ts index 3939f64c4d17..ffff02981f72 100644 --- a/extensions/reef/protocol/encoding.ts +++ b/extensions/reef/protocol/encoding.ts @@ -1,13 +1,10 @@ -const encoder = new TextEncoder(); +export { bytesToHex as hex, equalBytes, utf8ToBytes as utf8 } from "@noble/ciphers/utils.js"; + const decoder = new TextDecoder("utf-8", { fatal: true }); const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; const base64Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -export function utf8(value: string): Uint8Array { - return encoder.encode(value); -} - export function decodeUtf8(value: Uint8Array): string { return decoder.decode(value); } @@ -99,18 +96,3 @@ export function fromBase64(value: string): Uint8Array { } return output; } - -export function hex(value: Uint8Array): string { - return Array.from(value, (byte) => byte.toString(16).padStart(2, "0")).join(""); -} - -export function equalBytes(a: Uint8Array, b: Uint8Array): boolean { - if (a.length !== b.length) { - return false; - } - let difference = 0; - for (let index = 0; index < a.length; index++) { - difference |= a[index]! ^ b[index]!; - } - return difference === 0; -} diff --git a/extensions/reef/protocol/node.ts b/extensions/reef/protocol/node.ts index 6eec851d638f..3b2b82a10722 100644 --- a/extensions/reef/protocol/node.ts +++ b/extensions/reef/protocol/node.ts @@ -1,7 +1,7 @@ import { mkdir, open as openFile, readFile } from "node:fs/promises"; import { dirname } from "node:path"; import { gcm } from "@noble/ciphers/aes.js"; -import { randomBytes } from "@noble/hashes/utils.js"; +import { concatBytes, randomBytes } from "@noble/hashes/utils.js"; import { createAuditEntry, verifyChain, type AuditEntry, type AuditStore } from "./audit.js"; import { canonicalBytes } from "./canonical.js"; import { base64, decodeUtf8, fromBase64 } from "./encoding.js"; @@ -293,10 +293,7 @@ function encryptReplayBody( throw new Error("replay body rng returned invalid nonce"); } const ciphertext = gcm(key, nonce).encrypt(canonicalBytes(body)); - const packed = new Uint8Array(nonce.length + ciphertext.length); - packed.set(nonce); - packed.set(ciphertext, nonce.length); - return { enc: base64(packed) }; + return { enc: base64(concatBytes(nonce, ciphertext)) }; } function decryptReplayBody(body: EncryptedReplayBody, key: Uint8Array): MessageBody {