33import { bcs , fromBase64 , fromHex , toBase64 , toHex } from '@mysten/bcs' ;
44import { bls12_381 } from '@noble/curves/bls12-381' ;
55
6- import { KeyServerMove , KeyServerMoveV1 } from './bcs.js' ;
7- import { InvalidKeyServerError , InvalidKeyServerVersionError , SealAPIError } from './error.js' ;
6+ import { KeyServerMove , KeyServerMoveV1 , KeyServerMoveV2 } from './bcs.js' ;
7+ import {
8+ InvalidClientOptionsError ,
9+ InvalidKeyServerError ,
10+ InvalidKeyServerVersionError ,
11+ SealAPIError ,
12+ } from './error.js' ;
813import { DST_POP } from './ibe.js' ;
914import { PACKAGE_VERSION } from './version.js' ;
10- import type { SealCompatibleClient } from './types.js' ;
15+ import type { KeyServerConfig , SealCompatibleClient } from './types.js' ;
1116import type { G1Element } from './bls12381.js' ;
1217import { flatten , Version } from './utils.js' ;
1318import { elgamalDecrypt } from './elgamal.js' ;
1419import type { Certificate } from './session-key.js' ;
1520
16- const EXPECTED_SERVER_VERSION = 1 ;
21+ const SUPPORTED_SERVER_VERSIONS = [ 2 , 1 ] ; // Must be configured in descending order.
22+
23+ export type ServerType = 'Independent' | 'Committee' ;
1724
1825export type KeyServer = {
1926 objectId : string ;
2027 name : string ;
2128 url : string ;
22- keyType : KeyServerType ;
29+ keyType : KeyType ;
2330 pk : Uint8Array < ArrayBuffer > ;
31+ serverType : ServerType ;
2432} ;
2533
26- export enum KeyServerType {
34+ export enum KeyType {
2735 BonehFranklinBLS12381 = 0 ,
2836}
2937
@@ -33,16 +41,22 @@ export const SERVER_VERSION_REQUIREMENT = new Version('0.4.1');
3341 * Given a list of key server object IDs, returns a list of SealKeyServer
3442 * from onchain state containing name, objectId, URL and pk.
3543 *
44+ * Supports both V1 (independent servers) and V2 (independent + committee servers).
45+ * For V2 committee servers, returns the aggregator URL from the config.
46+ *
3647 * @param objectIds - The key server object IDs.
3748 * @param client - The SuiClient to use.
49+ * @param configs - The key server configurations containing aggregator URLs.
3850 * @returns - An array of SealKeyServer.
3951 */
4052export async function retrieveKeyServers ( {
4153 objectIds,
4254 client,
55+ configs,
4356} : {
4457 objectIds : string [ ] ;
4558 client : SealCompatibleClient ;
59+ configs : Map < string , KeyServerConfig > ;
4660} ) : Promise < KeyServer [ ] > {
4761 return await Promise . all (
4862 objectIds . map ( async ( objectId ) => {
@@ -51,39 +65,89 @@ export async function retrieveKeyServers({
5165 objectId,
5266 } ) ;
5367 const ks = KeyServerMove . parse ( await res . object . content ) ;
54- if (
55- EXPECTED_SERVER_VERSION < Number ( ks . firstVersion ) ||
56- EXPECTED_SERVER_VERSION > Number ( ks . lastVersion )
57- ) {
68+
69+ // Find the highest supported version.
70+ const firstVersion = Number ( ks . firstVersion ) ;
71+ const lastVersion = Number ( ks . lastVersion ) ;
72+ const version = SUPPORTED_SERVER_VERSIONS . find ( ( v ) => v >= firstVersion && v <= lastVersion ) ;
73+
74+ if ( version === undefined ) {
5875 throw new InvalidKeyServerVersionError (
59- `Key server ${ objectId } supports versions between ${ ks . firstVersion } and ${ ks . lastVersion } (inclusive), but SDK expects version ${ EXPECTED_SERVER_VERSION } ` ,
76+ `Key server ${ objectId } supports versions between ${ ks . firstVersion } and ${ ks . lastVersion } (inclusive), but SDK expects one of ${ SUPPORTED_SERVER_VERSIONS . join ( ', ' ) } ` ,
6077 ) ;
6178 }
6279
63- // Then fetch the expected versioned object and parse it .
64- const resVersionedKs = await client . core . getDynamicField ( {
80+ // Fetch the versioned object.
81+ const versionedKeyServer = await client . core . getDynamicField ( {
6582 parentId : objectId ,
6683 name : {
6784 type : 'u64' ,
68- bcs : bcs . u64 ( ) . serialize ( EXPECTED_SERVER_VERSION ) . toBytes ( ) ,
85+ bcs : bcs . u64 ( ) . serialize ( version ) . toBytes ( ) ,
6986 } ,
7087 } ) ;
7188
72- const ksVersioned = KeyServerMoveV1 . parse ( resVersionedKs . dynamicField . value . bcs ) ;
89+ // Parse based on version.
90+ switch ( version ) {
91+ case 2 : {
92+ const ksV2 = KeyServerMoveV2 . parse ( versionedKeyServer . dynamicField . value . bcs ) ;
93+ if ( ksV2 . keyType !== KeyType . BonehFranklinBLS12381 ) {
94+ throw new InvalidKeyServerError (
95+ `Server ${ objectId } has invalid key type: ${ ksV2 . keyType } ` ,
96+ ) ;
97+ }
7398
74- if ( ksVersioned . keyType !== KeyServerType . BonehFranklinBLS12381 ) {
75- throw new InvalidKeyServerError (
76- `Server ${ objectId } has invalid key type: ${ ksVersioned . keyType } ` ,
77- ) ;
78- }
99+ // Return based on server type.
100+ switch ( ksV2 . serverType . $kind ) {
101+ case 'Independent' :
102+ return {
103+ objectId,
104+ name : ksV2 . name ,
105+ url : ksV2 . serverType . Independent . url ,
106+ keyType : ksV2 . keyType ,
107+ pk : new Uint8Array ( ksV2 . pk ) ,
108+ serverType : 'Independent' ,
109+ } ;
110+ case 'Committee' : {
111+ // For committee mode, get aggregator URL from config
112+ const config = configs . get ( objectId ) ;
113+ if ( ! config ?. aggregatorUrl ) {
114+ throw new InvalidClientOptionsError (
115+ `Committee server ${ objectId } requires aggregatorUrl in config` ,
116+ ) ;
117+ }
118+ return {
119+ objectId,
120+ name : ksV2 . name ,
121+ url : config . aggregatorUrl ,
122+ keyType : ksV2 . keyType ,
123+ pk : new Uint8Array ( ksV2 . pk ) ,
124+ serverType : 'Committee' ,
125+ } ;
126+ }
127+ default :
128+ throw new InvalidKeyServerError ( `Unknown server type for ${ objectId } ` ) ;
129+ }
130+ }
131+ case 1 : {
132+ const ksV1 = KeyServerMoveV1 . parse ( versionedKeyServer . dynamicField . value . bcs ) ;
133+ if ( ksV1 . keyType !== KeyType . BonehFranklinBLS12381 ) {
134+ throw new InvalidKeyServerError (
135+ `Server ${ objectId } has invalid key type: ${ ksV1 . keyType } ` ,
136+ ) ;
137+ }
79138
80- return {
81- objectId,
82- name : ksVersioned . name ,
83- url : ksVersioned . url ,
84- keyType : ksVersioned . keyType ,
85- pk : new Uint8Array ( ksVersioned . pk ) ,
86- } ;
139+ return {
140+ objectId,
141+ name : ksV1 . name ,
142+ url : ksV1 . url ,
143+ keyType : ksV1 . keyType ,
144+ pk : new Uint8Array ( ksV1 . pk ) ,
145+ serverType : 'Independent' ,
146+ } ;
147+ }
148+ default :
149+ throw new InvalidKeyServerVersionError ( `Unsupported key server version: ${ version } ` ) ;
150+ }
87151 } ) ,
88152 ) ;
89153}
0 commit comments