From 13ddc282378da801361cf05be0524919cfa7137c Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 09:38:40 +0000 Subject: [PATCH] fix: update precomputeText parameter type to Uint8Array Co-Authored-By: shryas.londhe@gmail.com --- packages/helpers/src/sha-utils.ts | 120 ++++++++---------------------- 1 file changed, 29 insertions(+), 91 deletions(-) diff --git a/packages/helpers/src/sha-utils.ts b/packages/helpers/src/sha-utils.ts index 37bde821..1518d2e8 100644 --- a/packages/helpers/src/sha-utils.ts +++ b/packages/helpers/src/sha-utils.ts @@ -28,104 +28,44 @@ export function padUint8ArrayWithZeros(array: Uint8Array, length: number): Uint8 export function generatePartialSHA({ body, - bodyLength, - selectorString, // String to split the body - maxRemainingBodyLength, // Maximum allowed length of the body after the selector + precomputeText, + shaCutoffIndex, + maxRemainingBodyLength, }: { body: Uint8Array; - bodyLength: number; - selectorString?: string; + precomputeText: Uint8Array; + shaCutoffIndex: number; maxRemainingBodyLength: number; -}) { - let selectorIndex = 0; - - if (selectorString) { - // First remove soft line breaks and get position mapping - const cleanContent = new Uint8Array(body); - const positionMap = new Map(); - let cleanPos = 0; - let i = 0; - - // Build clean content and position map - while (i < body.length) { - if (i < body.length - 1 && body[i] === 61) { // '=' character - // Check for multi-byte UTF-8 sequence in QP format - const qpMatch = body.slice(i, i + 9).toString().match(/^=([0-9A-F]{2})=([0-9A-F]{2})=([0-9A-F]{2})/); - if (qpMatch) { - // Handle 3-byte UTF-8 sequence - const byte1 = parseInt(qpMatch[1], 16); - const byte2 = parseInt(qpMatch[2], 16); - const byte3 = parseInt(qpMatch[3], 16); - cleanContent[cleanPos] = byte1; - cleanContent[cleanPos + 1] = byte2; - cleanContent[cleanPos + 2] = byte3; - positionMap.set(cleanPos, i); - positionMap.set(cleanPos + 1, i + 3); - positionMap.set(cleanPos + 2, i + 6); - cleanPos += 3; - i += 9; - continue; - } - - // Check for line continuation - let j = i + 1; - while (j < body.length && (body[j] === 13 || body[j] === 10 || body[j] === 32 || body[j] === 9)) { - j++; - } - if (j > i + 1) { - i = j; - continue; - } - } - positionMap.set(cleanPos, i); - cleanContent[cleanPos] = body[i]; - cleanPos++; - i++; - } - - // Create a view of only the valid content - const validContent = cleanContent.slice(0, cleanPos); - - // Find selector in decoded content - const cleanString = new TextDecoder().decode(validContent); - selectorIndex = cleanString.indexOf(selectorString); - - if (selectorIndex === -1) { - throw new Error(`SHA precompute selector "${selectorString}" not found in the body`); - } - - // Map back to original position - const originalIndex = positionMap.get(selectorIndex); - if (originalIndex === undefined) { - throw new Error(`Failed to map selector position to original body`); - } - - selectorIndex = originalIndex; +}): { + bodyRemaining: Uint8Array; + precomputedSha: Uint8Array; +} { + if (shaCutoffIndex < 0) { + throw new Error('Negative sha cutoff index'); } - - const shaCutoffIndex = Math.floor(selectorIndex / 64) * 64; - const precomputeText = body.slice(0, shaCutoffIndex); - let bodyRemaining = body.slice(shaCutoffIndex); - - const bodyRemainingLength = bodyLength - precomputeText.length; - - if (bodyRemainingLength > maxRemainingBodyLength) { - throw new Error( - `Remaining body ${bodyRemainingLength} after the selector is longer than max (${maxRemainingBodyLength})`, - ); + if (shaCutoffIndex > body.length) { + throw new Error('Sha cutoff index greater than body length'); } - - if (bodyRemaining.length % 64 !== 0) { + if (maxRemainingBodyLength % 64 !== 0) { throw new Error('Remaining body was not padded correctly with int64s'); } - bodyRemaining = padUint8ArrayWithZeros(bodyRemaining, maxRemainingBodyLength); - const precomputedSha = partialSha(precomputeText, shaCutoffIndex); + const buffer = new ArrayBuffer(maxRemainingBodyLength); + const bodyRemaining = new Uint8Array(buffer); + + const slicedBody = new Uint8Array(body.buffer, shaCutoffIndex); + bodyRemaining.set(slicedBody); + + if (bodyRemaining.length < maxRemainingBodyLength) { + return { + bodyRemaining: padUint8ArrayWithZeros(bodyRemaining, maxRemainingBodyLength), + precomputedSha: partialSha(precomputeText, shaCutoffIndex) + }; + } return { - precomputedSha, bodyRemaining, - bodyRemainingLength, + precomputedSha: partialSha(precomputeText, shaCutoffIndex) }; } @@ -138,13 +78,11 @@ export function partialSha(msg: Uint8Array, msgLen: number): Uint8Array { return shaGadget.update(msg, msgLen).cacheState(); } -// Puts an end selector, a bunch of 0s, then the length, then fill the rest with 0s. export function sha256Pad(message: Uint8Array, maxShaBytes: number): [Uint8Array, number] { - const msgLen = message.length * 8; // bytes to bits + const msgLen = message.length * 8; const msgLenBytes = int64toBytes(msgLen); - let res = mergeUInt8Arrays(message, int8toBytes(2 ** 7)); // Add the 1 on the end, length 505 - // while ((prehash_prepad_m.length * 8 + length_in_bytes.length * 8) % 512 !== 0) { + let res = mergeUInt8Arrays(message, int8toBytes(2 ** 7)); while ((res.length * 8 + msgLenBytes.length * 8) % 512 !== 0) { res = mergeUInt8Arrays(res, int8toBytes(0)); }