Skip to content

Commit 1a18a3f

Browse files
committed
fix fast: add token_type to tokenresponse on batched tok ens
1 parent 4add513 commit 1a18a3f

2 files changed

Lines changed: 62 additions & 38 deletions

File tree

src/generic_batched_token.ts

Lines changed: 61 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@ import {
1010
tokenEntryToSerializedLength,
1111
tokenRequestToTokenTypeEntry,
1212
} from './index.js';
13-
import { Issuer as Type1Issuer, TokenRequest as Type1TokenRequest } from './priv_verif_token.js';
1413
import {
15-
TokenResponse,
14+
Issuer as Type1Issuer,
15+
TokenRequest as Type1TokenRequest,
16+
TokenResponse as Type1TokenResponse,
17+
} from './priv_verif_token.js';
18+
import {
19+
TokenResponse as Type2TokenResponse,
1620
Issuer as Type2Issuer,
1721
TokenRequest as Type2TokenRequest,
1822
} from './pub_verif_token.js';
@@ -133,31 +137,50 @@ export class BatchedTokenRequest {
133137

134138
export class OptionalTokenResponse {
135139
// struct {
136-
// optional<GenericTokenResponse> generic_token_response; /* Defined by token_type */
140+
// uint8 present;
141+
// select (present) {
142+
// case 0: ; /* empty */
143+
// case 1:
144+
// uint16 token_type;
145+
// GenericTokenResponse generic_token_response; /* Defined by token_type */
146+
// }
137147
// } OptionalTokenResponse;
138148
constructor(
149+
public readonly tokenType: 1 | 2,
139150
public readonly tokenResponse:
140151
| null
141152
| publicVerif.TokenResponse
142153
| privateVerif.TokenResponse,
143154
) {}
144155

145-
static deserialize(bytes: Uint8Array, type: 1 | 2): OptionalTokenResponse {
156+
static deserialize(bytes: Uint8Array): OptionalTokenResponse {
146157
if (bytes.length === 0) {
147158
throw new Error('OptionalTokenResponse MUST be of length strictly greater than 0');
148159
}
149160
switch (bytes[0]) {
150161
case TokenStatus.ABSENT:
151-
return new OptionalTokenResponse(null);
152-
case TokenStatus.PRESENT:
153-
switch (type) {
154-
case TOKEN_TYPES.VOPRF.value:
155-
return new OptionalTokenResponse(TokenResponse.deserialize(bytes.slice(1)));
156-
case TOKEN_TYPES.BLIND_RSA.value:
157-
return new OptionalTokenResponse(TokenResponse.deserialize(bytes.slice(1)));
158-
default:
159-
throw new Error('unsupported token type');
162+
// For absent responses, we still need a token type but it doesn't matter
163+
// We use 1 as a placeholder since the response is null
164+
return new OptionalTokenResponse(1, null);
165+
case TokenStatus.PRESENT: {
166+
if (bytes.length < 3) {
167+
throw new Error('OptionalTokenResponse PRESENT requires at least 3 bytes');
168+
}
169+
// Parse token_type from bytes[1:3] big-endian
170+
const tokenType = (bytes[1] << 8) | bytes[2];
171+
if (
172+
tokenType !== TOKEN_TYPES.VOPRF.value &&
173+
tokenType !== TOKEN_TYPES.BLIND_RSA.value
174+
) {
175+
throw new Error(`unsupported token type: ${tokenType}`);
160176
}
177+
const responseBytes = bytes.slice(3);
178+
const response =
179+
tokenType === TOKEN_TYPES.VOPRF.value
180+
? Type1TokenResponse.deserialize(responseBytes)
181+
: Type2TokenResponse.deserialize(responseBytes);
182+
return new OptionalTokenResponse(tokenType as 1 | 2, response);
183+
}
161184
default:
162185
throw new Error('OptionalTokenResponse MUST start with either 0x00 or 0x01');
163186
}
@@ -168,7 +191,21 @@ export class OptionalTokenResponse {
168191
return new Uint8Array([TokenStatus.ABSENT]);
169192
}
170193
const serialized = this.tokenResponse.serialize();
171-
return new Uint8Array([TokenStatus.PRESENT, ...serialized]);
194+
// Format: [present:1][token_type:2 big-endian][response_data]
195+
const result = new Uint8Array(1 + 2 + serialized.length);
196+
result[0] = TokenStatus.PRESENT;
197+
result[1] = (this.tokenType >> 8) & 0xff;
198+
result[2] = this.tokenType & 0xff;
199+
result.set(serialized, 3);
200+
return result;
201+
}
202+
203+
/** Returns the serialized length of this response */
204+
length(): number {
205+
if (this.tokenResponse === null) {
206+
return 1; // just the ABSENT byte
207+
}
208+
return 1 + 2 + this.tokenResponse.length(); // present + token_type + response
172209
}
173210
}
174211

@@ -178,7 +215,7 @@ export class GenericBatchTokenResponse {
178215
// } GenericBatchTokenResponse
179216
constructor(public readonly tokenResponses: OptionalTokenResponse[]) {}
180217

181-
static deserialize(bytes: Uint8Array, types: (1 | 2)[]): GenericBatchTokenResponse {
218+
static deserialize(bytes: Uint8Array): GenericBatchTokenResponse {
182219
let offset = 0;
183220
const input = new DataView(bytes.buffer);
184221

@@ -191,15 +228,9 @@ export class GenericBatchTokenResponse {
191228

192229
const batchedTokenResponses: OptionalTokenResponse[] = [];
193230

194-
let i = 0;
195231
while (offset < bytes.length) {
196-
const type = types[i++];
197-
const otr = OptionalTokenResponse.deserialize(bytes.slice(offset), type);
198-
if (otr.tokenResponse === null) {
199-
offset += 1;
200-
} else {
201-
offset += otr.tokenResponse.length() + 1;
202-
}
232+
const otr = OptionalTokenResponse.deserialize(bytes.slice(offset));
233+
offset += otr.length();
203234
batchedTokenResponses.push(otr);
204235
}
205236

@@ -276,17 +307,15 @@ export class Issuer {
276307
async issue(tokenRequests: BatchedTokenRequest): Promise<GenericBatchTokenResponse> {
277308
const tokenResponses: OptionalTokenResponse[] = [];
278309
for (const tokenRequest of tokenRequests) {
310+
const tokenType = tokenRequest.tokenType as 1 | 2;
279311
try {
280-
const issuer = await this.issuer(
281-
tokenRequest.tokenType,
282-
tokenRequest.truncatedTokenKeyId,
283-
);
284-
const response = (await issuer.issue(tokenRequest.tokenRequest)).serialize();
285-
tokenResponses.push(new OptionalTokenResponse(TokenResponse.deserialize(response)));
312+
const issuer = await this.issuer(tokenType, tokenRequest.truncatedTokenKeyId);
313+
const response = await issuer.issue(tokenRequest.tokenRequest);
314+
tokenResponses.push(new OptionalTokenResponse(tokenType, response));
286315
// eslint-disable-next-line @typescript-eslint/no-unused-vars
287316
} catch (e) {
288317
console.log(e);
289-
tokenResponses.push(new OptionalTokenResponse(null));
318+
tokenResponses.push(new OptionalTokenResponse(tokenType, null));
290319
}
291320
}
292321

@@ -326,7 +355,7 @@ export class Client {
326355
return new BatchedTokenRequest(tokenRequests);
327356
}
328357

329-
deserializeTokenResponse(bytes: Uint8Array, types: (1 | 2)[]): GenericBatchTokenResponse {
330-
return GenericBatchTokenResponse.deserialize(bytes, types);
358+
deserializeTokenResponse(bytes: Uint8Array): GenericBatchTokenResponse {
359+
return GenericBatchTokenResponse.deserialize(bytes);
331360
}
332361
}

test/generic_batched_token.test.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,10 @@ describe.each(vectors)('GenericBatched-Vector-%#', (v: Vectors) => {
134134

135135
const issuer = new Issuer(...issuers);
136136

137-
console.log(tokReq);
138137
const tokRes = await issuer.issue(tokReq);
139138
const bytes = tokRes.serialize();
140-
const got = GenericBatchTokenResponse.deserialize(
141-
bytes,
142-
tokReq.tokenRequests.map((r) => r.tokenType) as (1 | 2)[],
143-
);
139+
const got = GenericBatchTokenResponse.deserialize(bytes);
144140
expect(got).toStrictEqual(tokRes);
145-
console.log(tokRes);
146141

147142
for (let i = 0; i < v.issuance.length; i += 1) {
148143
const issuance = v.issuance[i];

0 commit comments

Comments
 (0)