@mysten/seal 1.3.7 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/client.d.mts.map +1 -1
- package/dist/client.mjs +5 -2
- package/dist/client.mjs.map +1 -1
- package/dist/key-server.d.mts.map +1 -1
- package/dist/key-server.mjs +4 -4
- package/dist/key-server.mjs.map +1 -1
- package/dist/types.d.mts +6 -0
- package/dist/types.d.mts.map +1 -1
- package/dist/version.mjs +1 -1
- package/dist/version.mjs.map +1 -1
- package/docs/index.md +3 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @mysten/seal
|
|
2
2
|
|
|
3
|
+
## 1.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 5b147a2: Add an optional `fetch` option to `SealClient`, used for all key server requests. This
|
|
8
|
+
lets callers customize how requests are sent — for example send cookies with
|
|
9
|
+
`credentials: 'include'` or attach your own headers — mirroring the `fetch` option of
|
|
10
|
+
`SuiHTTPTransport`.
|
|
11
|
+
|
|
12
|
+
## 1.3.8
|
|
13
|
+
|
|
3
14
|
## 1.3.7
|
|
4
15
|
|
|
5
16
|
## 1.3.6
|
package/dist/client.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.mts","names":[],"sources":["../src/client.ts"],"mappings":";;;;;cAmDa,UAAA;EAAA;
|
|
1
|
+
{"version":3,"file":"client.d.mts","names":[],"sources":["../src/client.ts"],"mappings":";;;;;cAmDa,UAAA;EAAA;cAYA,OAAA,EAAS,iBAAA;EA0CpB;;;;;;;;;;;;;EAFK,OAAA,CAAA;IACL,OAAA;IACA,OAAA;IACA,SAAA;IACA,SAAA;IACA,EAAA;IACA,IAAA;IACA;EAAA,GACE,cAAA,GAAc,OAAA;;;;EAyDd;;;;;;;;;;;;;;;;;;EANG,OAAA,CAAA;IACL,IAAA;IACA,UAAA;IACA,OAAA;IACA,qBAAA;IACA;EAAA,GACE,cAAA,GAAc,OAAA,CAAA,UAAA,CAAA,eAAA;EAqDX,aAAA,CAAA,GAAiB,OAAA,CAAQ,GAAA,SAAY,SAAA;EAgOxC;;;;;;;EA/MG,aAAA,CAAc,QAAA,aAAqB,OAAA,CAAQ,SAAA;EA/K5B;;;;;;;;;;;;EA6Qf,SAAA,CAAA;IAAY,GAAA;IAAK,OAAA;IAAS,UAAA;IAAY;EAAA,GAAa,gBAAA,GAAgB,OAAA;EA/NxE;;;;;;;;;EA0UK,cAAA,CAAA;IACL,OAAA;IACA,EAAA;IACA,OAAA;IACA,UAAA;IACA;EAAA,GACE,qBAAA,GAAwB,OAAA,CAAQ,GAAA,SAAY,UAAA;AAAA"}
|
package/dist/client.mjs
CHANGED
|
@@ -18,6 +18,7 @@ var SealClient = class {
|
|
|
18
18
|
#cachedPublicKeys = /* @__PURE__ */ new Map();
|
|
19
19
|
#timeout;
|
|
20
20
|
#totalWeight;
|
|
21
|
+
#fetch;
|
|
21
22
|
constructor(options) {
|
|
22
23
|
this.#suiClient = options.suiClient;
|
|
23
24
|
if (new Set(options.serverConfigs.map((s) => s.objectId)).size !== options.serverConfigs.length) throw new InvalidClientOptionsError("Duplicate object IDs");
|
|
@@ -26,6 +27,7 @@ var SealClient = class {
|
|
|
26
27
|
this.#totalWeight = options.serverConfigs.map((server) => server.weight).reduce((sum, term) => sum + term, 0);
|
|
27
28
|
this.#verifyKeyServers = options.verifyKeyServers ?? false;
|
|
28
29
|
this.#timeout = options.timeout ?? 1e4;
|
|
30
|
+
this.#fetch = options.fetch;
|
|
29
31
|
}
|
|
30
32
|
/**
|
|
31
33
|
* Return an encrypted message under the identity.
|
|
@@ -161,7 +163,7 @@ var SealClient = class {
|
|
|
161
163
|
if (this.#verifyKeyServers) await Promise.all(keyServers.map(async (server) => {
|
|
162
164
|
if (server.serverType === "Committee") return;
|
|
163
165
|
const config = this.#configs.get(server.objectId);
|
|
164
|
-
if (!await verifyKeyServer(server, this.#timeout, config?.apiKeyName, config?.apiKey)) throw new InvalidKeyServerError(`Key server ${server.objectId} is not valid`);
|
|
166
|
+
if (!await verifyKeyServer(server, this.#timeout, config?.apiKeyName, config?.apiKey, this.#fetch)) throw new InvalidKeyServerError(`Key server ${server.objectId} is not valid`);
|
|
165
167
|
}));
|
|
166
168
|
return new Map(keyServers.map((server) => [server.objectId, server]));
|
|
167
169
|
}
|
|
@@ -209,7 +211,8 @@ var SealClient = class {
|
|
|
209
211
|
timeout: this.#timeout,
|
|
210
212
|
apiKeyName: config?.apiKeyName,
|
|
211
213
|
apiKey: config?.apiKey,
|
|
212
|
-
signal: controller.signal
|
|
214
|
+
signal: controller.signal,
|
|
215
|
+
fetch: this.#fetch
|
|
213
216
|
});
|
|
214
217
|
for (const { fullId, key } of allKeys) {
|
|
215
218
|
const keyElement = G1Element.fromBytes(key);
|
package/dist/client.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.mjs","names":["#suiClient","#configs","#totalWeight","#verifyKeyServers","#timeout","#getWeightedKeyServers","#createEncryptionInput","#validateEncryptionServices","#cachedKeys","#weight","#keyServers","#loadKeyServers","#cachedPublicKeys"],"sources":["../src/client.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { EncryptedObject } from './bcs.js';\nimport { G1Element, G2Element } from './bls12381.js';\nimport { decrypt } from './decrypt.js';\nimport type { EncryptionInput } from './dem.js';\nimport { AesGcm256, Hmac256Ctr } from './dem.js';\nimport { DemType, encrypt, KemType } from './encrypt.js';\nimport {\n\tInconsistentKeyServersError,\n\tInvalidClientOptionsError,\n\tInvalidKeyServerError,\n\tInvalidPackageError,\n\tInvalidThresholdError,\n\ttoMajorityError,\n\tTooManyFailedFetchKeyRequestsError,\n} from './error.js';\nimport { BonehFranklinBLS12381Services } from './ibe.js';\nimport {\n\tBonehFranklinBLS12381DerivedKey,\n\tretrieveKeyServers,\n\tverifyKeyServer,\n\tfetchKeysForAllIds,\n} from './key-server.js';\nimport type { DerivedKey, KeyServer } from './key-server.js';\nimport type {\n\tDecryptOptions,\n\tEncryptOptions,\n\tFetchKeysOptions,\n\tGetDerivedKeysOptions,\n\tKeyCacheKey,\n\tKeyServerConfig,\n\tSealClientOptions,\n\tSealCompatibleClient,\n\tSealOptions,\n} from './types.js';\nimport { createFullId, count } from './utils.js';\n\nexport function seal<Name = 'seal'>({ name = 'seal' as Name, ...options }: SealOptions<Name>) {\n\treturn {\n\t\tname,\n\t\tregister: (client: SealCompatibleClient) => {\n\t\t\treturn new SealClient({\n\t\t\t\tsuiClient: client,\n\t\t\t\t...options,\n\t\t\t});\n\t\t},\n\t};\n}\n\nexport class SealClient {\n\t#suiClient: SealCompatibleClient;\n\t#configs: Map<string, KeyServerConfig>;\n\t#keyServers: Promise<Map<string, KeyServer>> | null = null;\n\t#verifyKeyServers: boolean;\n\t// A caching map for: fullId:object_id -> partial key.\n\t#cachedKeys = new Map<KeyCacheKey, G1Element>();\n\t#cachedPublicKeys = new Map<string, G2Element>();\n\t#timeout: number;\n\t#totalWeight: number;\n\n\tconstructor(options: SealClientOptions) {\n\t\tthis.#suiClient = options.suiClient;\n\n\t\tif (\n\t\t\tnew Set(options.serverConfigs.map((s) => s.objectId)).size !== options.serverConfigs.length\n\t\t) {\n\t\t\tthrow new InvalidClientOptionsError('Duplicate object IDs');\n\t\t}\n\n\t\tif (\n\t\t\toptions.serverConfigs.some((s) => (s.apiKeyName && !s.apiKey) || (!s.apiKeyName && s.apiKey))\n\t\t) {\n\t\t\tthrow new InvalidClientOptionsError(\n\t\t\t\t'Both apiKeyName and apiKey must be provided or not provided for all key servers',\n\t\t\t);\n\t\t}\n\n\t\tthis.#configs = new Map(options.serverConfigs.map((server) => [server.objectId, server]));\n\t\tthis.#totalWeight = options.serverConfigs\n\t\t\t.map((server) => server.weight)\n\t\t\t.reduce((sum, term) => sum + term, 0);\n\n\t\tthis.#verifyKeyServers = options.verifyKeyServers ?? false;\n\t\tthis.#timeout = options.timeout ?? 10_000;\n\t}\n\n\t/**\n\t * Return an encrypted message under the identity.\n\t *\n\t * @param kemType - The type of KEM to use.\n\t * @param demType - The type of DEM to use.\n\t * @param threshold - The threshold for the TSS encryption.\n\t * @param packageId - the packageId namespace.\n\t * @param id - the identity to use.\n\t * @param data - the data to encrypt.\n\t * @param aad - optional additional authenticated data.\n\t * @returns The bcs bytes of the encrypted object containing all metadata and the 256-bit symmetric key that was used to encrypt the object.\n\t * \tSince the symmetric key can be used to decrypt, it should not be shared but can be used e.g. for backup.\n\t */\n\tasync encrypt({\n\t\tkemType = KemType.BonehFranklinBLS12381DemCCA,\n\t\tdemType = DemType.AesGcm256,\n\t\tthreshold,\n\t\tpackageId,\n\t\tid,\n\t\tdata,\n\t\taad = new Uint8Array(),\n\t}: EncryptOptions) {\n\t\tconst packageObj = await this.#suiClient.core.getObject({ objectId: packageId });\n\t\tif (String(packageObj.object.version) !== '1') {\n\t\t\tthrow new InvalidPackageError(`Package ${packageId} is not the first version`);\n\t\t}\n\n\t\treturn encrypt({\n\t\t\tkeyServers: await this.#getWeightedKeyServers(),\n\t\t\tkemType,\n\t\t\tthreshold,\n\t\t\tpackageId,\n\t\t\tid,\n\t\t\tencryptionInput: this.#createEncryptionInput(\n\t\t\t\tdemType,\n\t\t\t\tdata as Uint8Array<ArrayBuffer>,\n\t\t\t\taad as Uint8Array<ArrayBuffer>,\n\t\t\t),\n\t\t});\n\t}\n\n\t#createEncryptionInput(\n\t\ttype: DemType,\n\t\tdata: Uint8Array<ArrayBuffer>,\n\t\taad: Uint8Array<ArrayBuffer>,\n\t): EncryptionInput {\n\t\tswitch (type) {\n\t\t\tcase DemType.AesGcm256:\n\t\t\t\treturn new AesGcm256(data, aad);\n\t\t\tcase DemType.Hmac256Ctr:\n\t\t\t\treturn new Hmac256Ctr(data, aad);\n\t\t}\n\t}\n\n\t/**\n\t * Decrypt the given encrypted bytes using cached keys.\n\t * Calls fetchKeys in case one or more of the required keys is not cached yet.\n\t * The function throws an error if the client's key servers are not a subset of\n\t * the encrypted object's key servers or if the threshold cannot be met.\n\t *\n\t * If checkShareConsistency is true, the decrypted shares are checked for consistency, meaning that\n\t * any combination of at least threshold shares should either succesfully combine to the plaintext or fail.\n\t * This is useful in case the encryptor is not trusted and the decryptor wants to ensure all decryptors\n\t * receive the same output (e.g., for onchain encrypted voting).\n\t *\n\t * @param data - The encrypted bytes to decrypt.\n\t * @param sessionKey - The session key to use.\n\t * @param txBytes - The transaction bytes to use (that calls seal_approve* functions).\n\t * @param checkShareConsistency - If true, the shares are checked for consistency.\n\t * @param checkLEEncoding - If true, the encryption is also checked using an LE encoded nonce.\n\t * @returns - The decrypted plaintext corresponding to ciphertext.\n\t */\n\tasync decrypt({\n\t\tdata,\n\t\tsessionKey,\n\t\ttxBytes,\n\t\tcheckShareConsistency,\n\t\tcheckLEEncoding,\n\t}: DecryptOptions) {\n\t\tconst encryptedObject = EncryptedObject.parse(data);\n\n\t\tthis.#validateEncryptionServices(\n\t\t\tencryptedObject.services.map((s) => s[0]),\n\t\t\tencryptedObject.threshold,\n\t\t);\n\n\t\tawait this.fetchKeys({\n\t\t\tids: [encryptedObject.id],\n\t\t\ttxBytes,\n\t\t\tsessionKey,\n\t\t\tthreshold: encryptedObject.threshold,\n\t\t});\n\n\t\tif (checkShareConsistency) {\n\t\t\tconst publicKeys = await this.getPublicKeys(\n\t\t\t\tencryptedObject.services.map(([objectId, _]) => objectId),\n\t\t\t);\n\t\t\treturn decrypt({\n\t\t\t\tencryptedObject,\n\t\t\t\tkeys: this.#cachedKeys,\n\t\t\t\tpublicKeys,\n\t\t\t\tcheckLEEncoding: false, // We intentionally do not support other encodings here\n\t\t\t});\n\t\t}\n\t\treturn decrypt({ encryptedObject, keys: this.#cachedKeys, checkLEEncoding });\n\t}\n\n\t#weight(objectId: string) {\n\t\treturn this.#configs.get(objectId)?.weight ?? 0;\n\t}\n\n\t#validateEncryptionServices(services: string[], threshold: number) {\n\t\t// Check that the client's key servers are a subset of the encrypted object's key servers.\n\t\tif (\n\t\t\tservices.some((objectId) => {\n\t\t\t\tconst countInClient = this.#weight(objectId);\n\t\t\t\treturn countInClient > 0 && countInClient !== count(services, objectId);\n\t\t\t})\n\t\t) {\n\t\t\tthrow new InconsistentKeyServersError(\n\t\t\t\t`Client's key servers must be a subset of the encrypted object's key servers`,\n\t\t\t);\n\t\t}\n\t\t// Check that the threshold can be met with the client's key servers.\n\t\tif (threshold > this.#totalWeight) {\n\t\t\tthrow new InvalidThresholdError(\n\t\t\t\t`Invalid threshold ${threshold} for ${this.#totalWeight} servers`,\n\t\t\t);\n\t\t}\n\t}\n\n\tasync getKeyServers(): Promise<Map<string, KeyServer>> {\n\t\tif (!this.#keyServers) {\n\t\t\tthis.#keyServers = this.#loadKeyServers().catch((error) => {\n\t\t\t\tthis.#keyServers = null;\n\t\t\t\tthrow error;\n\t\t\t});\n\t\t}\n\t\treturn this.#keyServers;\n\t}\n\n\t/**\n\t * Get the public keys for the given services.\n\t * If all public keys are not in the cache, they are retrieved.\n\t *\n\t * @param services - The services to get the public keys for.\n\t * @returns The public keys for the given services in the same order as the given services.\n\t */\n\tasync getPublicKeys(services: string[]): Promise<G2Element[]> {\n\t\tconst keyServers = await this.getKeyServers();\n\n\t\t// Collect the key servers not already in store or cache.\n\t\tconst missingKeyServers = services.filter(\n\t\t\t(objectId) => !keyServers.has(objectId) && !this.#cachedPublicKeys.has(objectId),\n\t\t);\n\n\t\t// If there are missing key servers, retrieve them and update the cache.\n\t\tif (missingKeyServers.length > 0) {\n\t\t\t(\n\t\t\t\tawait retrieveKeyServers({\n\t\t\t\t\tobjectIds: missingKeyServers,\n\t\t\t\t\tclient: this.#suiClient,\n\t\t\t\t\tconfigs: this.#configs,\n\t\t\t\t})\n\t\t\t).forEach((keyServer) =>\n\t\t\t\tthis.#cachedPublicKeys.set(keyServer.objectId, G2Element.fromBytes(keyServer.pk)),\n\t\t\t);\n\t\t}\n\n\t\treturn services.map((objectId) => {\n\t\t\tconst keyServer = keyServers.get(objectId);\n\t\t\tif (keyServer) {\n\t\t\t\treturn G2Element.fromBytes(keyServer.pk);\n\t\t\t}\n\t\t\treturn this.#cachedPublicKeys.get(objectId)!;\n\t\t});\n\t}\n\n\t/**\n\t * Returns a list of key servers with multiplicity according to their weights.\n\t * The list is used for encryption.\n\t */\n\tasync #getWeightedKeyServers() {\n\t\tconst keyServers = await this.getKeyServers();\n\t\tconst keyServersWithMultiplicity = [];\n\t\tfor (const [objectId, config] of this.#configs) {\n\t\t\tconst keyServer = keyServers.get(objectId)!;\n\t\t\tfor (let i = 0; i < config.weight; i++) {\n\t\t\t\tkeyServersWithMultiplicity.push(keyServer);\n\t\t\t}\n\t\t}\n\t\treturn keyServersWithMultiplicity;\n\t}\n\n\tasync #loadKeyServers(): Promise<Map<string, KeyServer>> {\n\t\tconst keyServers = await retrieveKeyServers({\n\t\t\tobjectIds: [...this.#configs.keys()],\n\t\t\tclient: this.#suiClient,\n\t\t\tconfigs: this.#configs,\n\t\t});\n\n\t\tif (keyServers.length === 0) {\n\t\t\tthrow new InvalidKeyServerError('No key servers found');\n\t\t}\n\n\t\tif (this.#verifyKeyServers) {\n\t\t\tawait Promise.all(\n\t\t\t\tkeyServers.map(async (server) => {\n\t\t\t\t\t// Skip /service verification for committee key server type since the request goes through an aggregator.\n\t\t\t\t\tif (server.serverType === 'Committee') {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst config = this.#configs.get(server.objectId);\n\t\t\t\t\tif (!(await verifyKeyServer(server, this.#timeout, config?.apiKeyName, config?.apiKey))) {\n\t\t\t\t\t\tthrow new InvalidKeyServerError(`Key server ${server.objectId} is not valid`);\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn new Map(keyServers.map((server) => [server.objectId, server]));\n\t}\n\n\t/**\n\t * Fetch keys from the key servers and update the cache.\n\t *\n\t * It is recommended to call this function once for all ids of all encrypted objects if\n\t * there are multiple, then call decrypt for each object. This avoids calling fetchKey\n\t * individually for each decrypt.\n\t *\n\t * @param ids - The ids of the encrypted objects.\n\t * @param txBytes - The transaction bytes to use (that calls seal_approve* functions).\n\t * @param sessionKey - The session key to use.\n\t * @param threshold - The threshold for the TSS encryptions. The function returns when a threshold of key servers had returned keys for all ids.\n\t */\n\tasync fetchKeys({ ids, txBytes, sessionKey, threshold }: FetchKeysOptions) {\n\t\tif (threshold > this.#totalWeight || threshold < 1) {\n\t\t\tthrow new InvalidThresholdError(\n\t\t\t\t`Invalid threshold ${threshold} servers with weights ${JSON.stringify(this.#configs)}`,\n\t\t\t);\n\t\t}\n\t\tconst keyServers = await this.getKeyServers();\n\t\tconst fullIds = ids.map((id) => createFullId(sessionKey.getPackageId(), id));\n\n\t\t// Count a server as completed if it has keys for all fullIds.\n\t\t// Duplicated key server ids will be counted towards the threshold.\n\t\tlet completedWeight = 0;\n\t\tconst remainingKeyServers = [];\n\t\tlet remainingKeyServersWeight = 0;\n\t\tfor (const objectId of keyServers.keys()) {\n\t\t\tif (fullIds.every((fullId) => this.#cachedKeys.has(`${fullId}:${objectId}`))) {\n\t\t\t\tcompletedWeight += this.#weight(objectId);\n\t\t\t} else {\n\t\t\t\tremainingKeyServers.push(objectId);\n\t\t\t\tremainingKeyServersWeight += this.#weight(objectId);\n\t\t\t}\n\t\t}\n\n\t\t// Return early if we have enough keys from cache.\n\t\tif (completedWeight >= threshold) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst certificate = await sessionKey.getCertificate();\n\t\tconst signedRequest = await sessionKey.createRequestParams(txBytes);\n\n\t\tconst controller = new AbortController();\n\t\tconst errors: Error[] = [];\n\n\t\tconst keyFetches = remainingKeyServers.map(async (objectId) => {\n\t\t\tconst server = keyServers.get(objectId)!;\n\t\t\ttry {\n\t\t\t\tconst config = this.#configs.get(objectId);\n\t\t\t\tconst allKeys = await fetchKeysForAllIds({\n\t\t\t\t\turl: server.url,\n\t\t\t\t\trequestSignature: signedRequest.requestSignature,\n\t\t\t\t\ttransactionBytes: txBytes,\n\t\t\t\t\tencKey: signedRequest.encKey,\n\t\t\t\t\tencKeyPk: signedRequest.encKeyPk,\n\t\t\t\t\tencVerificationKey: signedRequest.encVerificationKey,\n\t\t\t\t\tcertificate,\n\t\t\t\t\ttimeout: this.#timeout,\n\t\t\t\t\tapiKeyName: config?.apiKeyName,\n\t\t\t\t\tapiKey: config?.apiKey,\n\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t});\n\t\t\t\t// Check validity of the keys and add them to the cache.\n\t\t\t\tfor (const { fullId, key } of allKeys) {\n\t\t\t\t\tconst keyElement = G1Element.fromBytes(key);\n\t\t\t\t\tif (\n\t\t\t\t\t\t!BonehFranklinBLS12381Services.verifyUserSecretKey(\n\t\t\t\t\t\t\tkeyElement,\n\t\t\t\t\t\t\tfullId,\n\t\t\t\t\t\t\tG2Element.fromBytes(server.pk),\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tconsole.warn('Received invalid key from key server ' + server.objectId);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tthis.#cachedKeys.set(`${fullId}:${server.objectId}`, keyElement);\n\t\t\t\t}\n\n\t\t\t\t// Check if all the receivedIds are consistent with the requested fullIds.\n\t\t\t\t// If so, consider the key server got all keys and mark as completed.\n\t\t\t\tif (fullIds.every((fullId) => this.#cachedKeys.has(`${fullId}:${server.objectId}`))) {\n\t\t\t\t\tcompletedWeight += this.#weight(objectId);\n\n\t\t\t\t\t// Return early if the completed servers is more than the threshold.\n\t\t\t\t\tif (completedWeight >= threshold) {\n\t\t\t\t\t\tcontroller.abort();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\terrors.push(error as Error);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\t// If there are too many errors that the threshold is not attainable, return early with error.\n\t\t\t\tremainingKeyServersWeight -= this.#weight(objectId);\n\t\t\t\tif (remainingKeyServersWeight < threshold - completedWeight) {\n\t\t\t\t\tcontroller.abort(new TooManyFailedFetchKeyRequestsError());\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tawait Promise.allSettled(keyFetches);\n\n\t\tif (completedWeight < threshold) {\n\t\t\tthrow toMajorityError(errors);\n\t\t}\n\t}\n\n\t/**\n\t * Get derived keys from the given services.\n\t *\n\t * @param id - The id of the encrypted object.\n\t * @param txBytes - The transaction bytes to use (that calls seal_approve* functions).\n\t * @param sessionKey - The session key to use.\n\t * @param threshold - The threshold.\n\t * @returns - Derived keys for the given services that are in the cache as a \"service object ID\" -> derived key map. If the call is succesful, exactly threshold keys will be returned.\n\t */\n\tasync getDerivedKeys({\n\t\tkemType = KemType.BonehFranklinBLS12381DemCCA,\n\t\tid,\n\t\ttxBytes,\n\t\tsessionKey,\n\t\tthreshold,\n\t}: GetDerivedKeysOptions): Promise<Map<string, DerivedKey>> {\n\t\tswitch (kemType) {\n\t\t\tcase KemType.BonehFranklinBLS12381DemCCA:\n\t\t\t\tconst keyServers = await this.getKeyServers();\n\t\t\t\tif (threshold > this.#totalWeight) {\n\t\t\t\t\tthrow new InvalidThresholdError(\n\t\t\t\t\t\t`Invalid threshold ${threshold} for ${this.#totalWeight} servers`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tawait this.fetchKeys({\n\t\t\t\t\tids: [id],\n\t\t\t\t\ttxBytes,\n\t\t\t\t\tsessionKey,\n\t\t\t\t\tthreshold,\n\t\t\t\t});\n\n\t\t\t\t// After calling fetchKeys, we can be sure that there are at least `threshold` of the required keys in the cache.\n\t\t\t\t// It is also checked there that the KeyServerType is BonehFranklinBLS12381 for all services.\n\n\t\t\t\tconst fullId = createFullId(sessionKey.getPackageId(), id);\n\n\t\t\t\tconst derivedKeys = new Map();\n\t\t\t\tlet weight = 0;\n\t\t\t\tfor (const objectId of keyServers.keys()) {\n\t\t\t\t\t// The code below assumes that the KeyServerType is BonehFranklinBLS12381.\n\t\t\t\t\tconst cachedKey = this.#cachedKeys.get(`${fullId}:${objectId}`);\n\t\t\t\t\tif (cachedKey) {\n\t\t\t\t\t\tderivedKeys.set(objectId, new BonehFranklinBLS12381DerivedKey(cachedKey));\n\t\t\t\t\t\tweight += this.#weight(objectId);\n\t\t\t\t\t\tif (weight >= threshold) {\n\t\t\t\t\t\t\t// We have enough keys, so we can stop.\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn derivedKeys;\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.mjs","names":["#suiClient","#configs","#totalWeight","#verifyKeyServers","#timeout","#fetch","#getWeightedKeyServers","#createEncryptionInput","#validateEncryptionServices","#cachedKeys","#weight","#keyServers","#loadKeyServers","#cachedPublicKeys"],"sources":["../src/client.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { EncryptedObject } from './bcs.js';\nimport { G1Element, G2Element } from './bls12381.js';\nimport { decrypt } from './decrypt.js';\nimport type { EncryptionInput } from './dem.js';\nimport { AesGcm256, Hmac256Ctr } from './dem.js';\nimport { DemType, encrypt, KemType } from './encrypt.js';\nimport {\n\tInconsistentKeyServersError,\n\tInvalidClientOptionsError,\n\tInvalidKeyServerError,\n\tInvalidPackageError,\n\tInvalidThresholdError,\n\ttoMajorityError,\n\tTooManyFailedFetchKeyRequestsError,\n} from './error.js';\nimport { BonehFranklinBLS12381Services } from './ibe.js';\nimport {\n\tBonehFranklinBLS12381DerivedKey,\n\tretrieveKeyServers,\n\tverifyKeyServer,\n\tfetchKeysForAllIds,\n} from './key-server.js';\nimport type { DerivedKey, KeyServer } from './key-server.js';\nimport type {\n\tDecryptOptions,\n\tEncryptOptions,\n\tFetchKeysOptions,\n\tGetDerivedKeysOptions,\n\tKeyCacheKey,\n\tKeyServerConfig,\n\tSealClientOptions,\n\tSealCompatibleClient,\n\tSealOptions,\n} from './types.js';\nimport { createFullId, count } from './utils.js';\n\nexport function seal<Name = 'seal'>({ name = 'seal' as Name, ...options }: SealOptions<Name>) {\n\treturn {\n\t\tname,\n\t\tregister: (client: SealCompatibleClient) => {\n\t\t\treturn new SealClient({\n\t\t\t\tsuiClient: client,\n\t\t\t\t...options,\n\t\t\t});\n\t\t},\n\t};\n}\n\nexport class SealClient {\n\t#suiClient: SealCompatibleClient;\n\t#configs: Map<string, KeyServerConfig>;\n\t#keyServers: Promise<Map<string, KeyServer>> | null = null;\n\t#verifyKeyServers: boolean;\n\t// A caching map for: fullId:object_id -> partial key.\n\t#cachedKeys = new Map<KeyCacheKey, G1Element>();\n\t#cachedPublicKeys = new Map<string, G2Element>();\n\t#timeout: number;\n\t#totalWeight: number;\n\t#fetch?: typeof fetch;\n\n\tconstructor(options: SealClientOptions) {\n\t\tthis.#suiClient = options.suiClient;\n\n\t\tif (\n\t\t\tnew Set(options.serverConfigs.map((s) => s.objectId)).size !== options.serverConfigs.length\n\t\t) {\n\t\t\tthrow new InvalidClientOptionsError('Duplicate object IDs');\n\t\t}\n\n\t\tif (\n\t\t\toptions.serverConfigs.some((s) => (s.apiKeyName && !s.apiKey) || (!s.apiKeyName && s.apiKey))\n\t\t) {\n\t\t\tthrow new InvalidClientOptionsError(\n\t\t\t\t'Both apiKeyName and apiKey must be provided or not provided for all key servers',\n\t\t\t);\n\t\t}\n\n\t\tthis.#configs = new Map(options.serverConfigs.map((server) => [server.objectId, server]));\n\t\tthis.#totalWeight = options.serverConfigs\n\t\t\t.map((server) => server.weight)\n\t\t\t.reduce((sum, term) => sum + term, 0);\n\n\t\tthis.#verifyKeyServers = options.verifyKeyServers ?? false;\n\t\tthis.#timeout = options.timeout ?? 10_000;\n\t\tthis.#fetch = options.fetch;\n\t}\n\n\t/**\n\t * Return an encrypted message under the identity.\n\t *\n\t * @param kemType - The type of KEM to use.\n\t * @param demType - The type of DEM to use.\n\t * @param threshold - The threshold for the TSS encryption.\n\t * @param packageId - the packageId namespace.\n\t * @param id - the identity to use.\n\t * @param data - the data to encrypt.\n\t * @param aad - optional additional authenticated data.\n\t * @returns The bcs bytes of the encrypted object containing all metadata and the 256-bit symmetric key that was used to encrypt the object.\n\t * \tSince the symmetric key can be used to decrypt, it should not be shared but can be used e.g. for backup.\n\t */\n\tasync encrypt({\n\t\tkemType = KemType.BonehFranklinBLS12381DemCCA,\n\t\tdemType = DemType.AesGcm256,\n\t\tthreshold,\n\t\tpackageId,\n\t\tid,\n\t\tdata,\n\t\taad = new Uint8Array(),\n\t}: EncryptOptions) {\n\t\tconst packageObj = await this.#suiClient.core.getObject({ objectId: packageId });\n\t\tif (String(packageObj.object.version) !== '1') {\n\t\t\tthrow new InvalidPackageError(`Package ${packageId} is not the first version`);\n\t\t}\n\n\t\treturn encrypt({\n\t\t\tkeyServers: await this.#getWeightedKeyServers(),\n\t\t\tkemType,\n\t\t\tthreshold,\n\t\t\tpackageId,\n\t\t\tid,\n\t\t\tencryptionInput: this.#createEncryptionInput(\n\t\t\t\tdemType,\n\t\t\t\tdata as Uint8Array<ArrayBuffer>,\n\t\t\t\taad as Uint8Array<ArrayBuffer>,\n\t\t\t),\n\t\t});\n\t}\n\n\t#createEncryptionInput(\n\t\ttype: DemType,\n\t\tdata: Uint8Array<ArrayBuffer>,\n\t\taad: Uint8Array<ArrayBuffer>,\n\t): EncryptionInput {\n\t\tswitch (type) {\n\t\t\tcase DemType.AesGcm256:\n\t\t\t\treturn new AesGcm256(data, aad);\n\t\t\tcase DemType.Hmac256Ctr:\n\t\t\t\treturn new Hmac256Ctr(data, aad);\n\t\t}\n\t}\n\n\t/**\n\t * Decrypt the given encrypted bytes using cached keys.\n\t * Calls fetchKeys in case one or more of the required keys is not cached yet.\n\t * The function throws an error if the client's key servers are not a subset of\n\t * the encrypted object's key servers or if the threshold cannot be met.\n\t *\n\t * If checkShareConsistency is true, the decrypted shares are checked for consistency, meaning that\n\t * any combination of at least threshold shares should either succesfully combine to the plaintext or fail.\n\t * This is useful in case the encryptor is not trusted and the decryptor wants to ensure all decryptors\n\t * receive the same output (e.g., for onchain encrypted voting).\n\t *\n\t * @param data - The encrypted bytes to decrypt.\n\t * @param sessionKey - The session key to use.\n\t * @param txBytes - The transaction bytes to use (that calls seal_approve* functions).\n\t * @param checkShareConsistency - If true, the shares are checked for consistency.\n\t * @param checkLEEncoding - If true, the encryption is also checked using an LE encoded nonce.\n\t * @returns - The decrypted plaintext corresponding to ciphertext.\n\t */\n\tasync decrypt({\n\t\tdata,\n\t\tsessionKey,\n\t\ttxBytes,\n\t\tcheckShareConsistency,\n\t\tcheckLEEncoding,\n\t}: DecryptOptions) {\n\t\tconst encryptedObject = EncryptedObject.parse(data);\n\n\t\tthis.#validateEncryptionServices(\n\t\t\tencryptedObject.services.map((s) => s[0]),\n\t\t\tencryptedObject.threshold,\n\t\t);\n\n\t\tawait this.fetchKeys({\n\t\t\tids: [encryptedObject.id],\n\t\t\ttxBytes,\n\t\t\tsessionKey,\n\t\t\tthreshold: encryptedObject.threshold,\n\t\t});\n\n\t\tif (checkShareConsistency) {\n\t\t\tconst publicKeys = await this.getPublicKeys(\n\t\t\t\tencryptedObject.services.map(([objectId, _]) => objectId),\n\t\t\t);\n\t\t\treturn decrypt({\n\t\t\t\tencryptedObject,\n\t\t\t\tkeys: this.#cachedKeys,\n\t\t\t\tpublicKeys,\n\t\t\t\tcheckLEEncoding: false, // We intentionally do not support other encodings here\n\t\t\t});\n\t\t}\n\t\treturn decrypt({ encryptedObject, keys: this.#cachedKeys, checkLEEncoding });\n\t}\n\n\t#weight(objectId: string) {\n\t\treturn this.#configs.get(objectId)?.weight ?? 0;\n\t}\n\n\t#validateEncryptionServices(services: string[], threshold: number) {\n\t\t// Check that the client's key servers are a subset of the encrypted object's key servers.\n\t\tif (\n\t\t\tservices.some((objectId) => {\n\t\t\t\tconst countInClient = this.#weight(objectId);\n\t\t\t\treturn countInClient > 0 && countInClient !== count(services, objectId);\n\t\t\t})\n\t\t) {\n\t\t\tthrow new InconsistentKeyServersError(\n\t\t\t\t`Client's key servers must be a subset of the encrypted object's key servers`,\n\t\t\t);\n\t\t}\n\t\t// Check that the threshold can be met with the client's key servers.\n\t\tif (threshold > this.#totalWeight) {\n\t\t\tthrow new InvalidThresholdError(\n\t\t\t\t`Invalid threshold ${threshold} for ${this.#totalWeight} servers`,\n\t\t\t);\n\t\t}\n\t}\n\n\tasync getKeyServers(): Promise<Map<string, KeyServer>> {\n\t\tif (!this.#keyServers) {\n\t\t\tthis.#keyServers = this.#loadKeyServers().catch((error) => {\n\t\t\t\tthis.#keyServers = null;\n\t\t\t\tthrow error;\n\t\t\t});\n\t\t}\n\t\treturn this.#keyServers;\n\t}\n\n\t/**\n\t * Get the public keys for the given services.\n\t * If all public keys are not in the cache, they are retrieved.\n\t *\n\t * @param services - The services to get the public keys for.\n\t * @returns The public keys for the given services in the same order as the given services.\n\t */\n\tasync getPublicKeys(services: string[]): Promise<G2Element[]> {\n\t\tconst keyServers = await this.getKeyServers();\n\n\t\t// Collect the key servers not already in store or cache.\n\t\tconst missingKeyServers = services.filter(\n\t\t\t(objectId) => !keyServers.has(objectId) && !this.#cachedPublicKeys.has(objectId),\n\t\t);\n\n\t\t// If there are missing key servers, retrieve them and update the cache.\n\t\tif (missingKeyServers.length > 0) {\n\t\t\t(\n\t\t\t\tawait retrieveKeyServers({\n\t\t\t\t\tobjectIds: missingKeyServers,\n\t\t\t\t\tclient: this.#suiClient,\n\t\t\t\t\tconfigs: this.#configs,\n\t\t\t\t})\n\t\t\t).forEach((keyServer) =>\n\t\t\t\tthis.#cachedPublicKeys.set(keyServer.objectId, G2Element.fromBytes(keyServer.pk)),\n\t\t\t);\n\t\t}\n\n\t\treturn services.map((objectId) => {\n\t\t\tconst keyServer = keyServers.get(objectId);\n\t\t\tif (keyServer) {\n\t\t\t\treturn G2Element.fromBytes(keyServer.pk);\n\t\t\t}\n\t\t\treturn this.#cachedPublicKeys.get(objectId)!;\n\t\t});\n\t}\n\n\t/**\n\t * Returns a list of key servers with multiplicity according to their weights.\n\t * The list is used for encryption.\n\t */\n\tasync #getWeightedKeyServers() {\n\t\tconst keyServers = await this.getKeyServers();\n\t\tconst keyServersWithMultiplicity = [];\n\t\tfor (const [objectId, config] of this.#configs) {\n\t\t\tconst keyServer = keyServers.get(objectId)!;\n\t\t\tfor (let i = 0; i < config.weight; i++) {\n\t\t\t\tkeyServersWithMultiplicity.push(keyServer);\n\t\t\t}\n\t\t}\n\t\treturn keyServersWithMultiplicity;\n\t}\n\n\tasync #loadKeyServers(): Promise<Map<string, KeyServer>> {\n\t\tconst keyServers = await retrieveKeyServers({\n\t\t\tobjectIds: [...this.#configs.keys()],\n\t\t\tclient: this.#suiClient,\n\t\t\tconfigs: this.#configs,\n\t\t});\n\n\t\tif (keyServers.length === 0) {\n\t\t\tthrow new InvalidKeyServerError('No key servers found');\n\t\t}\n\n\t\tif (this.#verifyKeyServers) {\n\t\t\tawait Promise.all(\n\t\t\t\tkeyServers.map(async (server) => {\n\t\t\t\t\t// Skip /service verification for committee key server type since the request goes through an aggregator.\n\t\t\t\t\tif (server.serverType === 'Committee') {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst config = this.#configs.get(server.objectId);\n\t\t\t\t\tif (\n\t\t\t\t\t\t!(await verifyKeyServer(\n\t\t\t\t\t\t\tserver,\n\t\t\t\t\t\t\tthis.#timeout,\n\t\t\t\t\t\t\tconfig?.apiKeyName,\n\t\t\t\t\t\t\tconfig?.apiKey,\n\t\t\t\t\t\t\tthis.#fetch,\n\t\t\t\t\t\t))\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new InvalidKeyServerError(`Key server ${server.objectId} is not valid`);\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn new Map(keyServers.map((server) => [server.objectId, server]));\n\t}\n\n\t/**\n\t * Fetch keys from the key servers and update the cache.\n\t *\n\t * It is recommended to call this function once for all ids of all encrypted objects if\n\t * there are multiple, then call decrypt for each object. This avoids calling fetchKey\n\t * individually for each decrypt.\n\t *\n\t * @param ids - The ids of the encrypted objects.\n\t * @param txBytes - The transaction bytes to use (that calls seal_approve* functions).\n\t * @param sessionKey - The session key to use.\n\t * @param threshold - The threshold for the TSS encryptions. The function returns when a threshold of key servers had returned keys for all ids.\n\t */\n\tasync fetchKeys({ ids, txBytes, sessionKey, threshold }: FetchKeysOptions) {\n\t\tif (threshold > this.#totalWeight || threshold < 1) {\n\t\t\tthrow new InvalidThresholdError(\n\t\t\t\t`Invalid threshold ${threshold} servers with weights ${JSON.stringify(this.#configs)}`,\n\t\t\t);\n\t\t}\n\t\tconst keyServers = await this.getKeyServers();\n\t\tconst fullIds = ids.map((id) => createFullId(sessionKey.getPackageId(), id));\n\n\t\t// Count a server as completed if it has keys for all fullIds.\n\t\t// Duplicated key server ids will be counted towards the threshold.\n\t\tlet completedWeight = 0;\n\t\tconst remainingKeyServers = [];\n\t\tlet remainingKeyServersWeight = 0;\n\t\tfor (const objectId of keyServers.keys()) {\n\t\t\tif (fullIds.every((fullId) => this.#cachedKeys.has(`${fullId}:${objectId}`))) {\n\t\t\t\tcompletedWeight += this.#weight(objectId);\n\t\t\t} else {\n\t\t\t\tremainingKeyServers.push(objectId);\n\t\t\t\tremainingKeyServersWeight += this.#weight(objectId);\n\t\t\t}\n\t\t}\n\n\t\t// Return early if we have enough keys from cache.\n\t\tif (completedWeight >= threshold) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst certificate = await sessionKey.getCertificate();\n\t\tconst signedRequest = await sessionKey.createRequestParams(txBytes);\n\n\t\tconst controller = new AbortController();\n\t\tconst errors: Error[] = [];\n\n\t\tconst keyFetches = remainingKeyServers.map(async (objectId) => {\n\t\t\tconst server = keyServers.get(objectId)!;\n\t\t\ttry {\n\t\t\t\tconst config = this.#configs.get(objectId);\n\t\t\t\tconst allKeys = await fetchKeysForAllIds({\n\t\t\t\t\turl: server.url,\n\t\t\t\t\trequestSignature: signedRequest.requestSignature,\n\t\t\t\t\ttransactionBytes: txBytes,\n\t\t\t\t\tencKey: signedRequest.encKey,\n\t\t\t\t\tencKeyPk: signedRequest.encKeyPk,\n\t\t\t\t\tencVerificationKey: signedRequest.encVerificationKey,\n\t\t\t\t\tcertificate,\n\t\t\t\t\ttimeout: this.#timeout,\n\t\t\t\t\tapiKeyName: config?.apiKeyName,\n\t\t\t\t\tapiKey: config?.apiKey,\n\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\tfetch: this.#fetch,\n\t\t\t\t});\n\t\t\t\t// Check validity of the keys and add them to the cache.\n\t\t\t\tfor (const { fullId, key } of allKeys) {\n\t\t\t\t\tconst keyElement = G1Element.fromBytes(key);\n\t\t\t\t\tif (\n\t\t\t\t\t\t!BonehFranklinBLS12381Services.verifyUserSecretKey(\n\t\t\t\t\t\t\tkeyElement,\n\t\t\t\t\t\t\tfullId,\n\t\t\t\t\t\t\tG2Element.fromBytes(server.pk),\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tconsole.warn('Received invalid key from key server ' + server.objectId);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tthis.#cachedKeys.set(`${fullId}:${server.objectId}`, keyElement);\n\t\t\t\t}\n\n\t\t\t\t// Check if all the receivedIds are consistent with the requested fullIds.\n\t\t\t\t// If so, consider the key server got all keys and mark as completed.\n\t\t\t\tif (fullIds.every((fullId) => this.#cachedKeys.has(`${fullId}:${server.objectId}`))) {\n\t\t\t\t\tcompletedWeight += this.#weight(objectId);\n\n\t\t\t\t\t// Return early if the completed servers is more than the threshold.\n\t\t\t\t\tif (completedWeight >= threshold) {\n\t\t\t\t\t\tcontroller.abort();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tif (!controller.signal.aborted) {\n\t\t\t\t\terrors.push(error as Error);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\t// If there are too many errors that the threshold is not attainable, return early with error.\n\t\t\t\tremainingKeyServersWeight -= this.#weight(objectId);\n\t\t\t\tif (remainingKeyServersWeight < threshold - completedWeight) {\n\t\t\t\t\tcontroller.abort(new TooManyFailedFetchKeyRequestsError());\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tawait Promise.allSettled(keyFetches);\n\n\t\tif (completedWeight < threshold) {\n\t\t\tthrow toMajorityError(errors);\n\t\t}\n\t}\n\n\t/**\n\t * Get derived keys from the given services.\n\t *\n\t * @param id - The id of the encrypted object.\n\t * @param txBytes - The transaction bytes to use (that calls seal_approve* functions).\n\t * @param sessionKey - The session key to use.\n\t * @param threshold - The threshold.\n\t * @returns - Derived keys for the given services that are in the cache as a \"service object ID\" -> derived key map. If the call is succesful, exactly threshold keys will be returned.\n\t */\n\tasync getDerivedKeys({\n\t\tkemType = KemType.BonehFranklinBLS12381DemCCA,\n\t\tid,\n\t\ttxBytes,\n\t\tsessionKey,\n\t\tthreshold,\n\t}: GetDerivedKeysOptions): Promise<Map<string, DerivedKey>> {\n\t\tswitch (kemType) {\n\t\t\tcase KemType.BonehFranklinBLS12381DemCCA:\n\t\t\t\tconst keyServers = await this.getKeyServers();\n\t\t\t\tif (threshold > this.#totalWeight) {\n\t\t\t\t\tthrow new InvalidThresholdError(\n\t\t\t\t\t\t`Invalid threshold ${threshold} for ${this.#totalWeight} servers`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tawait this.fetchKeys({\n\t\t\t\t\tids: [id],\n\t\t\t\t\ttxBytes,\n\t\t\t\t\tsessionKey,\n\t\t\t\t\tthreshold,\n\t\t\t\t});\n\n\t\t\t\t// After calling fetchKeys, we can be sure that there are at least `threshold` of the required keys in the cache.\n\t\t\t\t// It is also checked there that the KeyServerType is BonehFranklinBLS12381 for all services.\n\n\t\t\t\tconst fullId = createFullId(sessionKey.getPackageId(), id);\n\n\t\t\t\tconst derivedKeys = new Map();\n\t\t\t\tlet weight = 0;\n\t\t\t\tfor (const objectId of keyServers.keys()) {\n\t\t\t\t\t// The code below assumes that the KeyServerType is BonehFranklinBLS12381.\n\t\t\t\t\tconst cachedKey = this.#cachedKeys.get(`${fullId}:${objectId}`);\n\t\t\t\t\tif (cachedKey) {\n\t\t\t\t\t\tderivedKeys.set(objectId, new BonehFranklinBLS12381DerivedKey(cachedKey));\n\t\t\t\t\t\tweight += this.#weight(objectId);\n\t\t\t\t\t\tif (weight >= threshold) {\n\t\t\t\t\t\t\t// We have enough keys, so we can stop.\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn derivedKeys;\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"key-server.d.mts","names":[],"sources":["../src/key-server.ts"],"mappings":";;;;KAsBY,UAAA;AAAA,KAEA,SAAA;EACX,QAAA;EACA,IAAA;EACA,GAAA;EACA,OAAA,EAAS,OAAA;EACT,EAAA,EAAI,UAAA,CAAW,WAAA;EACf,UAAA,EAAY,UAAA;AAAA;AAAA,aAGD,OAAA;EACX,qBAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"key-server.d.mts","names":[],"sources":["../src/key-server.ts"],"mappings":";;;;KAsBY,UAAA;AAAA,KAEA,SAAA;EACX,QAAA;EACA,IAAA;EACA,GAAA;EACA,OAAA,EAAS,OAAA;EACT,EAAA,EAAI,UAAA,CAAW,WAAA;EACf,UAAA,EAAY,UAAA;AAAA;AAAA,aAGD,OAAA;EACX,qBAAA;AAAA;AAAA,UAkMgB,UAAA;EAChB,QAAA;AAAA"}
|
package/dist/key-server.mjs
CHANGED
|
@@ -99,9 +99,9 @@ async function retrieveKeyServers({ objectIds, client, configs }) {
|
|
|
99
99
|
* @param server - The KeyServer to verify.
|
|
100
100
|
* @returns - True if the key server is valid, false otherwise.
|
|
101
101
|
*/
|
|
102
|
-
async function verifyKeyServer(server, timeout, apiKeyName, apiKey) {
|
|
102
|
+
async function verifyKeyServer(server, timeout, apiKeyName, apiKey, fetchFn = globalThis.fetch) {
|
|
103
103
|
const requestId = crypto.randomUUID();
|
|
104
|
-
const response = await
|
|
104
|
+
const response = await fetchFn(server.url + "/v1/service?service_id=" + server.objectId, {
|
|
105
105
|
method: "GET",
|
|
106
106
|
headers: {
|
|
107
107
|
"Content-Type": "application/json",
|
|
@@ -158,7 +158,7 @@ var BonehFranklinBLS12381DerivedKey = class {
|
|
|
158
158
|
* @param certificate - The certificate.
|
|
159
159
|
* @returns - A list of full ID and the decrypted key.
|
|
160
160
|
*/
|
|
161
|
-
async function fetchKeysForAllIds({ url, requestSignature, transactionBytes, encKey, encKeyPk, encVerificationKey, certificate, timeout, apiKeyName, apiKey, signal }) {
|
|
161
|
+
async function fetchKeysForAllIds({ url, requestSignature, transactionBytes, encKey, encKeyPk, encVerificationKey, certificate, timeout, apiKeyName, apiKey, signal, fetch: fetchFn = globalThis.fetch }) {
|
|
162
162
|
const body = {
|
|
163
163
|
ptb: toBase64(transactionBytes.slice(1)),
|
|
164
164
|
enc_key: toBase64(encKeyPk),
|
|
@@ -169,7 +169,7 @@ async function fetchKeysForAllIds({ url, requestSignature, transactionBytes, enc
|
|
|
169
169
|
const timeoutSignal = AbortSignal.timeout(timeout);
|
|
170
170
|
const combinedSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
|
|
171
171
|
const requestId = crypto.randomUUID();
|
|
172
|
-
const response = await
|
|
172
|
+
const response = await fetchFn(url + "/v1/fetch_key", {
|
|
173
173
|
method: "POST",
|
|
174
174
|
headers: {
|
|
175
175
|
"Content-Type": "application/json",
|
package/dist/key-server.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"key-server.mjs","names":[],"sources":["../src/key-server.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\nimport { bcs, fromBase64, fromHex, toBase64, toHex } from '@mysten/bcs';\nimport { bls12_381 } from '@noble/curves/bls12-381.js';\n\nimport { KeyServerMove, KeyServerMoveV1, KeyServerMoveV2 } from './bcs.js';\nimport {\n\tInvalidClientOptionsError,\n\tInvalidKeyServerError,\n\tInvalidKeyServerVersionError,\n\tSealAPIError,\n} from './error.js';\nimport { DST_POP } from './ibe.js';\nimport { PACKAGE_VERSION } from './version.js';\nimport type { KeyServerConfig, SealCompatibleClient } from './types.js';\nimport type { G1Element } from './bls12381.js';\nimport { flatten, Version } from './utils.js';\nimport { elgamalDecrypt } from './elgamal.js';\nimport type { Certificate } from './session-key.js';\n\nconst SUPPORTED_SERVER_VERSIONS = [2, 1]; // Must be configured in descending order.\n\nexport type ServerType = 'Independent' | 'Committee';\n\nexport type KeyServer = {\n\tobjectId: string;\n\tname: string;\n\turl: string;\n\tkeyType: KeyType;\n\tpk: Uint8Array<ArrayBuffer>;\n\tserverType: ServerType;\n};\n\nexport enum KeyType {\n\tBonehFranklinBLS12381 = 0,\n}\n\nexport const SERVER_VERSION_REQUIREMENT = new Version('0.4.1');\n\n/**\n * Given a list of key server object IDs, returns a list of SealKeyServer\n * from onchain state containing name, objectId, URL and pk.\n *\n * Supports both V1 (independent servers) and V2 (independent + committee servers).\n * For V2 committee servers, returns the aggregator URL from the config.\n *\n * @param objectIds - The key server object IDs.\n * @param client - The Sui client to use (SuiGrpcClient, SuiGraphQLClient, or SuiJsonRpcClient).\n * @param configs - The key server configurations containing aggregator URLs.\n * @returns - An array of SealKeyServer.\n */\nexport async function retrieveKeyServers({\n\tobjectIds,\n\tclient,\n\tconfigs,\n}: {\n\tobjectIds: string[];\n\tclient: SealCompatibleClient;\n\tconfigs: Map<string, KeyServerConfig>;\n}): Promise<KeyServer[]> {\n\treturn await Promise.all(\n\t\tobjectIds.map(async (objectId) => {\n\t\t\t// First get the KeyServer object and validate it.\n\t\t\tconst res = await client.core.getObject({\n\t\t\t\tobjectId,\n\t\t\t\tinclude: { content: true },\n\t\t\t});\n\t\t\tconst ks = KeyServerMove.parse(res.object.content);\n\n\t\t\t// Find the highest supported version.\n\t\t\tconst firstVersion = Number(ks.firstVersion);\n\t\t\tconst lastVersion = Number(ks.lastVersion);\n\t\t\tconst version = SUPPORTED_SERVER_VERSIONS.find((v) => v >= firstVersion && v <= lastVersion);\n\n\t\t\tif (version === undefined) {\n\t\t\t\tthrow new InvalidKeyServerVersionError(\n\t\t\t\t\t`Key server ${objectId} supports versions between ${ks.firstVersion} and ${ks.lastVersion} (inclusive), but SDK expects one of ${SUPPORTED_SERVER_VERSIONS.join(', ')}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Fetch the versioned object.\n\t\t\tconst versionedKeyServer = await client.core.getDynamicField({\n\t\t\t\tparentId: objectId,\n\t\t\t\tname: {\n\t\t\t\t\ttype: 'u64',\n\t\t\t\t\tbcs: bcs.u64().serialize(version).toBytes(),\n\t\t\t\t},\n\t\t\t});\n\n\t\t\t// Parse based on version.\n\t\t\tswitch (version) {\n\t\t\t\tcase 2: {\n\t\t\t\t\tconst ksV2 = KeyServerMoveV2.parse(versionedKeyServer.dynamicField.value.bcs);\n\t\t\t\t\tif (ksV2.keyType !== KeyType.BonehFranklinBLS12381) {\n\t\t\t\t\t\tthrow new InvalidKeyServerError(\n\t\t\t\t\t\t\t`Server ${objectId} has invalid key type: ${ksV2.keyType}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Return based on server type.\n\t\t\t\t\tswitch (ksV2.serverType.$kind) {\n\t\t\t\t\t\tcase 'Independent': {\n\t\t\t\t\t\t\tif (configs.get(objectId)?.aggregatorUrl) {\n\t\t\t\t\t\t\t\tthrow new InvalidClientOptionsError(\n\t\t\t\t\t\t\t\t\t`Independent server ${objectId} should not have aggregatorUrl in config`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tobjectId,\n\t\t\t\t\t\t\t\tname: ksV2.name,\n\t\t\t\t\t\t\t\turl: ksV2.serverType.Independent.url,\n\t\t\t\t\t\t\t\tkeyType: ksV2.keyType,\n\t\t\t\t\t\t\t\tpk: new Uint8Array(ksV2.pk),\n\t\t\t\t\t\t\t\tserverType: 'Independent',\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase 'Committee': {\n\t\t\t\t\t\t\t// For committee mode, get aggregator URL from config\n\t\t\t\t\t\t\tconst config = configs.get(objectId);\n\t\t\t\t\t\t\tif (!config?.aggregatorUrl) {\n\t\t\t\t\t\t\t\tthrow new InvalidClientOptionsError(\n\t\t\t\t\t\t\t\t\t`Committee server ${objectId} requires aggregatorUrl in config`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tobjectId,\n\t\t\t\t\t\t\t\tname: ksV2.name,\n\t\t\t\t\t\t\t\turl: config.aggregatorUrl,\n\t\t\t\t\t\t\t\tkeyType: ksV2.keyType,\n\t\t\t\t\t\t\t\tpk: new Uint8Array(ksV2.pk),\n\t\t\t\t\t\t\t\tserverType: 'Committee',\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow new InvalidKeyServerError(`Unknown server type for ${objectId}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcase 1: {\n\t\t\t\t\tconst ksV1 = KeyServerMoveV1.parse(versionedKeyServer.dynamicField.value.bcs);\n\t\t\t\t\tif (ksV1.keyType !== KeyType.BonehFranklinBLS12381) {\n\t\t\t\t\t\tthrow new InvalidKeyServerError(\n\t\t\t\t\t\t\t`Server ${objectId} has invalid key type: ${ksV1.keyType}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// V1 servers are always Independent and should not have aggregatorUrl\n\t\t\t\t\tif (configs.get(objectId)?.aggregatorUrl) {\n\t\t\t\t\t\tthrow new InvalidClientOptionsError(\n\t\t\t\t\t\t\t`V1 server ${objectId} is always Independent and should not have aggregatorUrl in config`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tobjectId,\n\t\t\t\t\t\tname: ksV1.name,\n\t\t\t\t\t\turl: ksV1.url,\n\t\t\t\t\t\tkeyType: ksV1.keyType,\n\t\t\t\t\t\tpk: new Uint8Array(ksV1.pk),\n\t\t\t\t\t\tserverType: 'Independent',\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new InvalidKeyServerVersionError(`Unsupported key server version: ${version}`);\n\t\t\t}\n\t\t}),\n\t);\n}\n\n/**\n * Given a KeyServer, fetch the proof of possession (PoP) from the URL and verify it\n * against the pubkey. This should be used only rarely when the dapp uses a dynamic\n * set of key servers.\n *\n * @param server - The KeyServer to verify.\n * @returns - True if the key server is valid, false otherwise.\n */\nexport async function verifyKeyServer(\n\tserver: KeyServer,\n\ttimeout: number,\n\tapiKeyName?: string,\n\tapiKey?: string,\n): Promise<boolean> {\n\tconst requestId = crypto.randomUUID();\n\tconst response = await fetch(server.url! + '/v1/service?service_id=' + server.objectId, {\n\t\tmethod: 'GET',\n\t\theaders: {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t'Request-Id': requestId,\n\t\t\t'Client-Sdk-Type': 'typescript',\n\t\t\t'Client-Sdk-Version': PACKAGE_VERSION,\n\t\t\t...(apiKeyName && apiKey ? { [apiKeyName]: apiKey } : {}),\n\t\t},\n\t\tsignal: AbortSignal.timeout(timeout),\n\t});\n\n\tawait SealAPIError.assertResponse(response, requestId);\n\tverifyKeyServerVersion(response);\n\tconst serviceResponse = await response.json();\n\n\tif (serviceResponse.service_id !== server.objectId) {\n\t\treturn false;\n\t}\n\tconst fullMsg = flatten([DST_POP, server.pk, fromHex(server.objectId)]);\n\treturn bls12_381.shortSignatures.verify(\n\t\tfromBase64(serviceResponse.pop),\n\t\tbls12_381.shortSignatures.hash(fullMsg),\n\t\tserver.pk,\n\t);\n}\n\n/**\n * Verify the key server version. Throws an `InvalidKeyServerError` if the version is not supported.\n *\n * @param response - The response from the key server.\n */\nexport function verifyKeyServerVersion(response: Response) {\n\tconst keyServerVersion = response.headers.get('X-KeyServer-Version');\n\tif (keyServerVersion == null) {\n\t\tthrow new InvalidKeyServerVersionError('Key server version not found');\n\t}\n\tif (new Version(keyServerVersion).older_than(SERVER_VERSION_REQUIREMENT)) {\n\t\tthrow new InvalidKeyServerVersionError(\n\t\t\t`Key server version ${keyServerVersion} is not supported`,\n\t\t);\n\t}\n}\n\nexport interface DerivedKey {\n\ttoString(): string;\n}\n\n/**\n * A user secret key for the Boneh-Franklin BLS12381 scheme.\n * This is a wrapper around the G1Element type.\n */\nexport class BonehFranklinBLS12381DerivedKey implements DerivedKey {\n\trepresentation: string;\n\n\tconstructor(public key: G1Element) {\n\t\tthis.representation = toHex(key.toBytes());\n\t}\n\n\ttoString(): string {\n\t\treturn this.representation;\n\t}\n}\n\n/**\n * Options for fetching keys from the key server.\n */\nexport interface FetchKeysOptions {\n\t/** The URL of the key server. */\n\turl: string;\n\t/** The Base64 string of request signature. */\n\trequestSignature: string;\n\t/** The transaction bytes. */\n\ttransactionBytes: Uint8Array;\n\t/** The ephemeral secret key. */\n\tencKey: Uint8Array<ArrayBuffer>;\n\t/** The ephemeral public key. */\n\tencKeyPk: Uint8Array<ArrayBuffer>;\n\t/** The ephemeral verification key. */\n\tencVerificationKey: Uint8Array;\n\t/** The certificate. */\n\tcertificate: Certificate;\n\t/** Request timeout in milliseconds. */\n\ttimeout: number;\n\t/** Optional API key name. */\n\tapiKeyName?: string;\n\t/** Optional API key. */\n\tapiKey?: string;\n\t/** Optional abort signal for cancellation. */\n\tsignal?: AbortSignal;\n}\n\n/**\n * Helper function to request all keys from URL with requestSig, txBytes, ephemeral pubkey.\n * Then decrypt the Seal key with ephemeral secret key. Returns a list decryption keys with\n * their full IDs.\n *\n * @param url - The URL of the key server.\n * @param requestSig - The Base64 string of request signature.\n * @param txBytes - The transaction bytes.\n * @param encKey - The ephemeral secret key.\n * @param certificate - The certificate.\n * @returns - A list of full ID and the decrypted key.\n */\nexport async function fetchKeysForAllIds({\n\turl,\n\trequestSignature,\n\ttransactionBytes,\n\tencKey,\n\tencKeyPk,\n\tencVerificationKey,\n\tcertificate,\n\ttimeout,\n\tapiKeyName,\n\tapiKey,\n\tsignal,\n}: FetchKeysOptions): Promise<{ fullId: string; key: Uint8Array<ArrayBuffer> }[]> {\n\tconst body = {\n\t\tptb: toBase64(transactionBytes.slice(1)), // removes the byte of the transaction type version\n\t\tenc_key: toBase64(encKeyPk),\n\t\tenc_verification_key: toBase64(encVerificationKey),\n\t\trequest_signature: requestSignature, // already b64\n\t\tcertificate,\n\t};\n\n\tconst timeoutSignal = AbortSignal.timeout(timeout);\n\tconst combinedSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;\n\n\tconst requestId = crypto.randomUUID();\n\tconst response = await fetch(url + '/v1/fetch_key', {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t'Request-Id': requestId,\n\t\t\t'Client-Sdk-Type': 'typescript',\n\t\t\t'Client-Sdk-Version': PACKAGE_VERSION,\n\t\t\t...(apiKeyName && apiKey ? { [apiKeyName]: apiKey } : {}),\n\t\t},\n\t\tbody: JSON.stringify(body),\n\t\tsignal: combinedSignal,\n\t});\n\tawait SealAPIError.assertResponse(response, requestId);\n\tconst resp = await response.json();\n\tverifyKeyServerVersion(response);\n\n\treturn resp.decryption_keys.map(\n\t\t(dk: { id: Uint8Array<ArrayBuffer>; encrypted_key: [string, string] }) => ({\n\t\t\tfullId: toHex(dk.id),\n\t\t\tkey: elgamalDecrypt(encKey, dk.encrypted_key.map(fromBase64) as [Uint8Array, Uint8Array]),\n\t\t}),\n\t);\n}\n"],"mappings":";;;;;;;;;;AAoBA,MAAM,4BAA4B,CAAC,GAAG,EAAE;AAaxC,IAAY,8CAAL;AACN;;;AAGD,MAAa,6BAA6B,IAAI,QAAQ,QAAQ;;;;;;;;;;;;;AAc9D,eAAsB,mBAAmB,EACxC,WACA,QACA,WAKwB;AACxB,QAAO,MAAM,QAAQ,IACpB,UAAU,IAAI,OAAO,aAAa;EAEjC,MAAM,MAAM,MAAM,OAAO,KAAK,UAAU;GACvC;GACA,SAAS,EAAE,SAAS,MAAM;GAC1B,CAAC;EACF,MAAM,KAAK,cAAc,MAAM,IAAI,OAAO,QAAQ;EAGlD,MAAM,eAAe,OAAO,GAAG,aAAa;EAC5C,MAAM,cAAc,OAAO,GAAG,YAAY;EAC1C,MAAM,UAAU,0BAA0B,MAAM,MAAM,KAAK,gBAAgB,KAAK,YAAY;AAE5F,MAAI,YAAY,OACf,OAAM,IAAI,6BACT,cAAc,SAAS,6BAA6B,GAAG,aAAa,OAAO,GAAG,YAAY,uCAAuC,0BAA0B,KAAK,KAAK,GACrK;EAIF,MAAM,qBAAqB,MAAM,OAAO,KAAK,gBAAgB;GAC5D,UAAU;GACV,MAAM;IACL,MAAM;IACN,KAAK,IAAI,KAAK,CAAC,UAAU,QAAQ,CAAC,SAAS;IAC3C;GACD,CAAC;AAGF,UAAQ,SAAR;GACC,KAAK,GAAG;IACP,MAAM,OAAO,gBAAgB,MAAM,mBAAmB,aAAa,MAAM,IAAI;AAC7E,QAAI,KAAK,YAAY,QAAQ,sBAC5B,OAAM,IAAI,sBACT,UAAU,SAAS,yBAAyB,KAAK,UACjD;AAIF,YAAQ,KAAK,WAAW,OAAxB;KACC,KAAK;AACJ,UAAI,QAAQ,IAAI,SAAS,EAAE,cAC1B,OAAM,IAAI,0BACT,sBAAsB,SAAS,0CAC/B;AAEF,aAAO;OACN;OACA,MAAM,KAAK;OACX,KAAK,KAAK,WAAW,YAAY;OACjC,SAAS,KAAK;OACd,IAAI,IAAI,WAAW,KAAK,GAAG;OAC3B,YAAY;OACZ;KAEF,KAAK,aAAa;MAEjB,MAAM,SAAS,QAAQ,IAAI,SAAS;AACpC,UAAI,CAAC,QAAQ,cACZ,OAAM,IAAI,0BACT,oBAAoB,SAAS,mCAC7B;AAEF,aAAO;OACN;OACA,MAAM,KAAK;OACX,KAAK,OAAO;OACZ,SAAS,KAAK;OACd,IAAI,IAAI,WAAW,KAAK,GAAG;OAC3B,YAAY;OACZ;;KAEF,QACC,OAAM,IAAI,sBAAsB,2BAA2B,WAAW;;;GAGzE,KAAK,GAAG;IACP,MAAM,OAAO,gBAAgB,MAAM,mBAAmB,aAAa,MAAM,IAAI;AAC7E,QAAI,KAAK,YAAY,QAAQ,sBAC5B,OAAM,IAAI,sBACT,UAAU,SAAS,yBAAyB,KAAK,UACjD;AAIF,QAAI,QAAQ,IAAI,SAAS,EAAE,cAC1B,OAAM,IAAI,0BACT,aAAa,SAAS,oEACtB;AAGF,WAAO;KACN;KACA,MAAM,KAAK;KACX,KAAK,KAAK;KACV,SAAS,KAAK;KACd,IAAI,IAAI,WAAW,KAAK,GAAG;KAC3B,YAAY;KACZ;;GAEF,QACC,OAAM,IAAI,6BAA6B,mCAAmC,UAAU;;GAErF,CACF;;;;;;;;;;AAWF,eAAsB,gBACrB,QACA,SACA,YACA,QACmB;CACnB,MAAM,YAAY,OAAO,YAAY;CACrC,MAAM,WAAW,MAAM,MAAM,OAAO,MAAO,4BAA4B,OAAO,UAAU;EACvF,QAAQ;EACR,SAAS;GACR,gBAAgB;GAChB,cAAc;GACd,mBAAmB;GACnB,sBAAsB;GACtB,GAAI,cAAc,SAAS,GAAG,aAAa,QAAQ,GAAG,EAAE;GACxD;EACD,QAAQ,YAAY,QAAQ,QAAQ;EACpC,CAAC;AAEF,OAAM,aAAa,eAAe,UAAU,UAAU;AACtD,wBAAuB,SAAS;CAChC,MAAM,kBAAkB,MAAM,SAAS,MAAM;AAE7C,KAAI,gBAAgB,eAAe,OAAO,SACzC,QAAO;CAER,MAAM,UAAU,QAAQ;EAAC;EAAS,OAAO;EAAI,QAAQ,OAAO,SAAS;EAAC,CAAC;AACvE,QAAO,UAAU,gBAAgB,OAChC,WAAW,gBAAgB,IAAI,EAC/B,UAAU,gBAAgB,KAAK,QAAQ,EACvC,OAAO,GACP;;;;;;;AAQF,SAAgB,uBAAuB,UAAoB;CAC1D,MAAM,mBAAmB,SAAS,QAAQ,IAAI,sBAAsB;AACpE,KAAI,oBAAoB,KACvB,OAAM,IAAI,6BAA6B,+BAA+B;AAEvE,KAAI,IAAI,QAAQ,iBAAiB,CAAC,WAAW,2BAA2B,CACvE,OAAM,IAAI,6BACT,sBAAsB,iBAAiB,mBACvC;;;;;;AAYH,IAAa,kCAAb,MAAmE;CAGlE,YAAY,AAAO,KAAgB;EAAhB;AAClB,OAAK,iBAAiB,MAAM,IAAI,SAAS,CAAC;;CAG3C,WAAmB;AAClB,SAAO,KAAK;;;;;;;;;;;;;;;AA4Cd,eAAsB,mBAAmB,EACxC,KACA,kBACA,kBACA,QACA,UACA,oBACA,aACA,SACA,YACA,QACA,UACiF;CACjF,MAAM,OAAO;EACZ,KAAK,SAAS,iBAAiB,MAAM,EAAE,CAAC;EACxC,SAAS,SAAS,SAAS;EAC3B,sBAAsB,SAAS,mBAAmB;EAClD,mBAAmB;EACnB;EACA;CAED,MAAM,gBAAgB,YAAY,QAAQ,QAAQ;CAClD,MAAM,iBAAiB,SAAS,YAAY,IAAI,CAAC,QAAQ,cAAc,CAAC,GAAG;CAE3E,MAAM,YAAY,OAAO,YAAY;CACrC,MAAM,WAAW,MAAM,MAAM,MAAM,iBAAiB;EACnD,QAAQ;EACR,SAAS;GACR,gBAAgB;GAChB,cAAc;GACd,mBAAmB;GACnB,sBAAsB;GACtB,GAAI,cAAc,SAAS,GAAG,aAAa,QAAQ,GAAG,EAAE;GACxD;EACD,MAAM,KAAK,UAAU,KAAK;EAC1B,QAAQ;EACR,CAAC;AACF,OAAM,aAAa,eAAe,UAAU,UAAU;CACtD,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,wBAAuB,SAAS;AAEhC,QAAO,KAAK,gBAAgB,KAC1B,QAA0E;EAC1E,QAAQ,MAAM,GAAG,GAAG;EACpB,KAAK,eAAe,QAAQ,GAAG,cAAc,IAAI,WAAW,CAA6B;EACzF,EACD"}
|
|
1
|
+
{"version":3,"file":"key-server.mjs","names":[],"sources":["../src/key-server.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\nimport { bcs, fromBase64, fromHex, toBase64, toHex } from '@mysten/bcs';\nimport { bls12_381 } from '@noble/curves/bls12-381.js';\n\nimport { KeyServerMove, KeyServerMoveV1, KeyServerMoveV2 } from './bcs.js';\nimport {\n\tInvalidClientOptionsError,\n\tInvalidKeyServerError,\n\tInvalidKeyServerVersionError,\n\tSealAPIError,\n} from './error.js';\nimport { DST_POP } from './ibe.js';\nimport { PACKAGE_VERSION } from './version.js';\nimport type { KeyServerConfig, SealCompatibleClient } from './types.js';\nimport type { G1Element } from './bls12381.js';\nimport { flatten, Version } from './utils.js';\nimport { elgamalDecrypt } from './elgamal.js';\nimport type { Certificate } from './session-key.js';\n\nconst SUPPORTED_SERVER_VERSIONS = [2, 1]; // Must be configured in descending order.\n\nexport type ServerType = 'Independent' | 'Committee';\n\nexport type KeyServer = {\n\tobjectId: string;\n\tname: string;\n\turl: string;\n\tkeyType: KeyType;\n\tpk: Uint8Array<ArrayBuffer>;\n\tserverType: ServerType;\n};\n\nexport enum KeyType {\n\tBonehFranklinBLS12381 = 0,\n}\n\nexport const SERVER_VERSION_REQUIREMENT = new Version('0.4.1');\n\n/**\n * Given a list of key server object IDs, returns a list of SealKeyServer\n * from onchain state containing name, objectId, URL and pk.\n *\n * Supports both V1 (independent servers) and V2 (independent + committee servers).\n * For V2 committee servers, returns the aggregator URL from the config.\n *\n * @param objectIds - The key server object IDs.\n * @param client - The Sui client to use (SuiGrpcClient, SuiGraphQLClient, or SuiJsonRpcClient).\n * @param configs - The key server configurations containing aggregator URLs.\n * @returns - An array of SealKeyServer.\n */\nexport async function retrieveKeyServers({\n\tobjectIds,\n\tclient,\n\tconfigs,\n}: {\n\tobjectIds: string[];\n\tclient: SealCompatibleClient;\n\tconfigs: Map<string, KeyServerConfig>;\n}): Promise<KeyServer[]> {\n\treturn await Promise.all(\n\t\tobjectIds.map(async (objectId) => {\n\t\t\t// First get the KeyServer object and validate it.\n\t\t\tconst res = await client.core.getObject({\n\t\t\t\tobjectId,\n\t\t\t\tinclude: { content: true },\n\t\t\t});\n\t\t\tconst ks = KeyServerMove.parse(res.object.content);\n\n\t\t\t// Find the highest supported version.\n\t\t\tconst firstVersion = Number(ks.firstVersion);\n\t\t\tconst lastVersion = Number(ks.lastVersion);\n\t\t\tconst version = SUPPORTED_SERVER_VERSIONS.find((v) => v >= firstVersion && v <= lastVersion);\n\n\t\t\tif (version === undefined) {\n\t\t\t\tthrow new InvalidKeyServerVersionError(\n\t\t\t\t\t`Key server ${objectId} supports versions between ${ks.firstVersion} and ${ks.lastVersion} (inclusive), but SDK expects one of ${SUPPORTED_SERVER_VERSIONS.join(', ')}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Fetch the versioned object.\n\t\t\tconst versionedKeyServer = await client.core.getDynamicField({\n\t\t\t\tparentId: objectId,\n\t\t\t\tname: {\n\t\t\t\t\ttype: 'u64',\n\t\t\t\t\tbcs: bcs.u64().serialize(version).toBytes(),\n\t\t\t\t},\n\t\t\t});\n\n\t\t\t// Parse based on version.\n\t\t\tswitch (version) {\n\t\t\t\tcase 2: {\n\t\t\t\t\tconst ksV2 = KeyServerMoveV2.parse(versionedKeyServer.dynamicField.value.bcs);\n\t\t\t\t\tif (ksV2.keyType !== KeyType.BonehFranklinBLS12381) {\n\t\t\t\t\t\tthrow new InvalidKeyServerError(\n\t\t\t\t\t\t\t`Server ${objectId} has invalid key type: ${ksV2.keyType}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Return based on server type.\n\t\t\t\t\tswitch (ksV2.serverType.$kind) {\n\t\t\t\t\t\tcase 'Independent': {\n\t\t\t\t\t\t\tif (configs.get(objectId)?.aggregatorUrl) {\n\t\t\t\t\t\t\t\tthrow new InvalidClientOptionsError(\n\t\t\t\t\t\t\t\t\t`Independent server ${objectId} should not have aggregatorUrl in config`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tobjectId,\n\t\t\t\t\t\t\t\tname: ksV2.name,\n\t\t\t\t\t\t\t\turl: ksV2.serverType.Independent.url,\n\t\t\t\t\t\t\t\tkeyType: ksV2.keyType,\n\t\t\t\t\t\t\t\tpk: new Uint8Array(ksV2.pk),\n\t\t\t\t\t\t\t\tserverType: 'Independent',\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase 'Committee': {\n\t\t\t\t\t\t\t// For committee mode, get aggregator URL from config\n\t\t\t\t\t\t\tconst config = configs.get(objectId);\n\t\t\t\t\t\t\tif (!config?.aggregatorUrl) {\n\t\t\t\t\t\t\t\tthrow new InvalidClientOptionsError(\n\t\t\t\t\t\t\t\t\t`Committee server ${objectId} requires aggregatorUrl in config`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tobjectId,\n\t\t\t\t\t\t\t\tname: ksV2.name,\n\t\t\t\t\t\t\t\turl: config.aggregatorUrl,\n\t\t\t\t\t\t\t\tkeyType: ksV2.keyType,\n\t\t\t\t\t\t\t\tpk: new Uint8Array(ksV2.pk),\n\t\t\t\t\t\t\t\tserverType: 'Committee',\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow new InvalidKeyServerError(`Unknown server type for ${objectId}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcase 1: {\n\t\t\t\t\tconst ksV1 = KeyServerMoveV1.parse(versionedKeyServer.dynamicField.value.bcs);\n\t\t\t\t\tif (ksV1.keyType !== KeyType.BonehFranklinBLS12381) {\n\t\t\t\t\t\tthrow new InvalidKeyServerError(\n\t\t\t\t\t\t\t`Server ${objectId} has invalid key type: ${ksV1.keyType}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// V1 servers are always Independent and should not have aggregatorUrl\n\t\t\t\t\tif (configs.get(objectId)?.aggregatorUrl) {\n\t\t\t\t\t\tthrow new InvalidClientOptionsError(\n\t\t\t\t\t\t\t`V1 server ${objectId} is always Independent and should not have aggregatorUrl in config`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tobjectId,\n\t\t\t\t\t\tname: ksV1.name,\n\t\t\t\t\t\turl: ksV1.url,\n\t\t\t\t\t\tkeyType: ksV1.keyType,\n\t\t\t\t\t\tpk: new Uint8Array(ksV1.pk),\n\t\t\t\t\t\tserverType: 'Independent',\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new InvalidKeyServerVersionError(`Unsupported key server version: ${version}`);\n\t\t\t}\n\t\t}),\n\t);\n}\n\n/**\n * Given a KeyServer, fetch the proof of possession (PoP) from the URL and verify it\n * against the pubkey. This should be used only rarely when the dapp uses a dynamic\n * set of key servers.\n *\n * @param server - The KeyServer to verify.\n * @returns - True if the key server is valid, false otherwise.\n */\nexport async function verifyKeyServer(\n\tserver: KeyServer,\n\ttimeout: number,\n\tapiKeyName?: string,\n\tapiKey?: string,\n\tfetchFn: typeof fetch = globalThis.fetch,\n): Promise<boolean> {\n\tconst requestId = crypto.randomUUID();\n\tconst response = await fetchFn(server.url! + '/v1/service?service_id=' + server.objectId, {\n\t\tmethod: 'GET',\n\t\theaders: {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t'Request-Id': requestId,\n\t\t\t'Client-Sdk-Type': 'typescript',\n\t\t\t'Client-Sdk-Version': PACKAGE_VERSION,\n\t\t\t...(apiKeyName && apiKey ? { [apiKeyName]: apiKey } : {}),\n\t\t},\n\t\tsignal: AbortSignal.timeout(timeout),\n\t});\n\n\tawait SealAPIError.assertResponse(response, requestId);\n\tverifyKeyServerVersion(response);\n\tconst serviceResponse = await response.json();\n\n\tif (serviceResponse.service_id !== server.objectId) {\n\t\treturn false;\n\t}\n\tconst fullMsg = flatten([DST_POP, server.pk, fromHex(server.objectId)]);\n\treturn bls12_381.shortSignatures.verify(\n\t\tfromBase64(serviceResponse.pop),\n\t\tbls12_381.shortSignatures.hash(fullMsg),\n\t\tserver.pk,\n\t);\n}\n\n/**\n * Verify the key server version. Throws an `InvalidKeyServerError` if the version is not supported.\n *\n * @param response - The response from the key server.\n */\nexport function verifyKeyServerVersion(response: Response) {\n\tconst keyServerVersion = response.headers.get('X-KeyServer-Version');\n\tif (keyServerVersion == null) {\n\t\tthrow new InvalidKeyServerVersionError('Key server version not found');\n\t}\n\tif (new Version(keyServerVersion).older_than(SERVER_VERSION_REQUIREMENT)) {\n\t\tthrow new InvalidKeyServerVersionError(\n\t\t\t`Key server version ${keyServerVersion} is not supported`,\n\t\t);\n\t}\n}\n\nexport interface DerivedKey {\n\ttoString(): string;\n}\n\n/**\n * A user secret key for the Boneh-Franklin BLS12381 scheme.\n * This is a wrapper around the G1Element type.\n */\nexport class BonehFranklinBLS12381DerivedKey implements DerivedKey {\n\trepresentation: string;\n\n\tconstructor(public key: G1Element) {\n\t\tthis.representation = toHex(key.toBytes());\n\t}\n\n\ttoString(): string {\n\t\treturn this.representation;\n\t}\n}\n\n/**\n * Options for fetching keys from the key server.\n */\nexport interface FetchKeysOptions {\n\t/** The URL of the key server. */\n\turl: string;\n\t/** The Base64 string of request signature. */\n\trequestSignature: string;\n\t/** The transaction bytes. */\n\ttransactionBytes: Uint8Array;\n\t/** The ephemeral secret key. */\n\tencKey: Uint8Array<ArrayBuffer>;\n\t/** The ephemeral public key. */\n\tencKeyPk: Uint8Array<ArrayBuffer>;\n\t/** The ephemeral verification key. */\n\tencVerificationKey: Uint8Array;\n\t/** The certificate. */\n\tcertificate: Certificate;\n\t/** Request timeout in milliseconds. */\n\ttimeout: number;\n\t/** Optional API key name. */\n\tapiKeyName?: string;\n\t/** Optional API key. */\n\tapiKey?: string;\n\t/** Optional abort signal for cancellation. */\n\tsignal?: AbortSignal;\n\t/** Optional custom fetch implementation. Defaults to the global `fetch`. */\n\tfetch?: typeof fetch;\n}\n\n/**\n * Helper function to request all keys from URL with requestSig, txBytes, ephemeral pubkey.\n * Then decrypt the Seal key with ephemeral secret key. Returns a list decryption keys with\n * their full IDs.\n *\n * @param url - The URL of the key server.\n * @param requestSig - The Base64 string of request signature.\n * @param txBytes - The transaction bytes.\n * @param encKey - The ephemeral secret key.\n * @param certificate - The certificate.\n * @returns - A list of full ID and the decrypted key.\n */\nexport async function fetchKeysForAllIds({\n\turl,\n\trequestSignature,\n\ttransactionBytes,\n\tencKey,\n\tencKeyPk,\n\tencVerificationKey,\n\tcertificate,\n\ttimeout,\n\tapiKeyName,\n\tapiKey,\n\tsignal,\n\tfetch: fetchFn = globalThis.fetch,\n}: FetchKeysOptions): Promise<{ fullId: string; key: Uint8Array<ArrayBuffer> }[]> {\n\tconst body = {\n\t\tptb: toBase64(transactionBytes.slice(1)), // removes the byte of the transaction type version\n\t\tenc_key: toBase64(encKeyPk),\n\t\tenc_verification_key: toBase64(encVerificationKey),\n\t\trequest_signature: requestSignature, // already b64\n\t\tcertificate,\n\t};\n\n\tconst timeoutSignal = AbortSignal.timeout(timeout);\n\tconst combinedSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;\n\n\tconst requestId = crypto.randomUUID();\n\tconst response = await fetchFn(url + '/v1/fetch_key', {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t'Request-Id': requestId,\n\t\t\t'Client-Sdk-Type': 'typescript',\n\t\t\t'Client-Sdk-Version': PACKAGE_VERSION,\n\t\t\t...(apiKeyName && apiKey ? { [apiKeyName]: apiKey } : {}),\n\t\t},\n\t\tbody: JSON.stringify(body),\n\t\tsignal: combinedSignal,\n\t});\n\tawait SealAPIError.assertResponse(response, requestId);\n\tconst resp = await response.json();\n\tverifyKeyServerVersion(response);\n\n\treturn resp.decryption_keys.map(\n\t\t(dk: { id: Uint8Array<ArrayBuffer>; encrypted_key: [string, string] }) => ({\n\t\t\tfullId: toHex(dk.id),\n\t\t\tkey: elgamalDecrypt(encKey, dk.encrypted_key.map(fromBase64) as [Uint8Array, Uint8Array]),\n\t\t}),\n\t);\n}\n"],"mappings":"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"}
|
package/dist/types.d.mts
CHANGED
|
@@ -28,6 +28,12 @@ interface SealClientOptions {
|
|
|
28
28
|
verifyKeyServers?: boolean;
|
|
29
29
|
/** Timeout in milliseconds for network requests. */
|
|
30
30
|
timeout?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Custom fetch implementation used for all key server requests, for example to send
|
|
33
|
+
* cookies (`credentials: 'include'`) or attach your own headers.
|
|
34
|
+
* Defaults to the global `fetch`.
|
|
35
|
+
*/
|
|
36
|
+
fetch?: typeof fetch;
|
|
31
37
|
}
|
|
32
38
|
interface EncryptOptions {
|
|
33
39
|
/** The type of KEM to use. */
|
package/dist/types.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;KAQY,oBAAA,GAAuB,oBAAA;EAClC,IAAA,EAAM,UAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;KAQY,oBAAA,GAAuB,oBAAA;EAClC,IAAA,EAAM,UAAA;AAAA;AAAA,UAwBU,eAAA;EAChB,QAAA;EACA,MAAA;EACA,UAAA;EACA,MAAA;EAwBoB;;EArBpB,aAAA;AAAA;;UAIgB,iBAAA;EAChB,SAAA,EAAW,oBAAA;EAUX;EARA,aAAA,EAAe,eAAA;EAcA;;;AAGhB;;EAXC,gBAAA;EAaU;EAXV,OAAA;EAqBM;;;;;EAfN,KAAA,UAAe,KAAA;AAAA;AAAA,UAGC,cAAA;EAMhB;EAJA,OAAA,GAAU,OAAA;EAQV;EANA,OAAA,GAAU,OAAA;EAQJ;EANN,SAAA;EAQM;EANN,SAAA;EAMgB;EAJhB,EAAA;EAO8B;EAL9B,IAAA,EAAM,UAAA;EAOA;EALN,GAAA,GAAM,UAAA;AAAA;AAAA,UAGU,cAAA;EAMG;EAJnB,IAAA,EAAM,UAAA;EAAA;EAEN,UAAA,EAAY,UAAA;EAAA;EAEZ,OAAA,EAAS,UAAA;EAAA;EAET,qBAAA;EAEA;EAAA,eAAA;AAAA;AAAA,UAGgB,gBAAA;EAAgB;EAEhC,GAAA;EAIsB;EAFtB,OAAA,EAAS,UAAA;EAAT;EAEA,UAAA,EAAY,UAAA;EAAZ;EAEA,SAAA;AAAA;AAAA,UAGgB,qBAAA;EAChB,OAAA,GAAU,OAAA;EADM;EAGhB,EAAA;;EAEA,OAAA,EAAS,UAAA;EAAA;EAET,UAAA,EAAY,UAAA;EAAU;EAEtB,SAAA;AAAA"}
|
package/dist/version.mjs
CHANGED
package/dist/version.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.mjs","names":[],"sources":["../src/version.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\n// This file is generated by genversion.mjs. Do not edit it directly.\n\nexport const PACKAGE_VERSION = '1.
|
|
1
|
+
{"version":3,"file":"version.mjs","names":[],"sources":["../src/version.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\n// This file is generated by genversion.mjs. Do not edit it directly.\n\nexport const PACKAGE_VERSION = '1.4.0';\n"],"mappings":";AAKA,MAAa,kBAAkB"}
|
package/docs/index.md
CHANGED
|
@@ -46,6 +46,9 @@ The `seal()` function accepts the following options:
|
|
|
46
46
|
authentication
|
|
47
47
|
- **`verifyKeyServers`** (optional) - Whether to verify key server authenticity (default: `true`)
|
|
48
48
|
- **`timeout`** (optional) - Timeout in milliseconds for network requests (default: `10000`)
|
|
49
|
+
- **`fetch`** (optional) - Custom fetch implementation used for all key server requests (default:
|
|
50
|
+
the global `fetch`), for example to send cookies with `credentials: 'include'` or attach your own
|
|
51
|
+
headers
|
|
49
52
|
|
|
50
53
|
## Choosing key servers
|
|
51
54
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mysten/seal",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Seal SDK",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Mysten Labs <build@mystenlabs.com>",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@mysten/bcs": "^2.1.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@mysten/sui": "^2.
|
|
43
|
+
"@mysten/sui": "^2.24.0"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"clean": "rm -rf tsconfig.tsbuildinfo ./dist",
|