@@ -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' ;
1413import {
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
134138export 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}
0 commit comments