Skip to content

Fix byte offset bugs when working with Uint8Array subarrays - #62

Merged
lbaquerofierro merged 1 commit into
cloudflare:mainfrom
lbaquerofierro:fix/byte-offset-bugs-0.8.1
Feb 11, 2026
Merged

Fix byte offset bugs when working with Uint8Array subarrays#62
lbaquerofierro merged 1 commit into
cloudflare:mainfrom
lbaquerofierro:fix/byte-offset-bugs-0.8.1

Conversation

@lbaquerofierro

@lbaquerofierro lbaquerofierro commented Feb 10, 2026

Copy link
Copy Markdown
Contributor

Summary

When using Uint8Array.subarray(), the .buffer property still points to the original ArrayBuffer, not just the slice. This was causing issues in two places:

  1. DataView constructors weren't accounting for byteOffset when parsing subarrays
  2. serialize() methods were using .buffer directly, which included extra bytes

Changes

  • DataView constructors now use (bytes.buffer, bytes.byteOffset, bytes.byteLength)
  • serialize() methods now use buffer.slice(byteOffset, byteOffset + byteLength)
  • Fixed tokenEntryToSerializedLength() which was missing the 3 byte header (token_type + truncated_token_key_id)

Files changed

  • src/generic_batched_token.ts
  • src/index.ts
  • src/priv_verif_token.ts
  • src/pub_verif_token.ts

Testing

  • All 144 tests pass in privacypass-ts
  • Verified working with privacypass-issuer (all 35 tests pass using npm pack)

When using Uint8Array.subarray(), the .buffer property still points to the
original ArrayBuffer, not just the slice. This was causing issues in two places:

1. DataView constructors weren't accounting for byteOffset when parsing subarrays
2. serialize() methods were using .buffer directly, which included extra bytes

Added proper byteOffset/byteLength handling to DataView calls and buffer.slice()
in serialize methods. Also fixed tokenEntryToSerializedLength() which was missing
the 3 byte header (token_type + truncated_token_key_id) in its calculation.

Verified working with privacypass-issuer (all 35 tests pass).
Comment thread src/index.ts
switch (tokenType.value) {
case TOKEN_TYPES.VOPRF.value:
return VOPRF.Ne + 2 * VOPRF.Nk;
return headerLen + VOPRF.Ne;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the blinded_msg size is Ne

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly. For VOPRF the blinded_msg is Ne bytes per Section 5.1 of the spec (v16). The fix adds the 3 byte header (token_type + truncated_token_key_id) that was missing from the original calculation

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's add this test in this line:
https://github.com/cloudflare/privacypass-ts/blob/main/test/generic_batched_token.test.ts#L134

        // check BatchedTokenRequest deserialization.
        const token_request_bytes = hexToUint8(v.token_request);
        const tokReqGot = BatchedTokenRequest.deserialize(token_request_bytes);
        expect(tokReq.tokenRequests.length).toBe(tokReqGot.tokenRequests.length);
        for (let i = 0; i < tokReq.tokenRequests.length; i += 1) {
            expect(tokReq.tokenRequests[i].tokenType).toBe(tokReqGot.tokenRequests[i].tokenType);
            expect(tokReq.tokenRequests[i].truncatedTokenKeyId).toBe(
                tokReqGot.tokenRequests[i].truncatedTokenKeyId,
            );
            expect(tokReq.tokenRequests[i].blindMsg).toStrictEqual(
                tokReqGot.tokenRequests[i].blindMsg,
            );
        }

@armfazh armfazh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it works, let's add a test for BatchedTokenRequest.deserialize, see my comment above

@lbaquerofierro
lbaquerofierro merged commit ed2342e into cloudflare:main Feb 11, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants