diff --git a/docs/generated/changelog.html b/docs/generated/changelog.html
index e7b6bd536..cd367daa8 100644
--- a/docs/generated/changelog.html
+++ b/docs/generated/changelog.html
@@ -10,6 +10,10 @@
Agent-JS Changelog
+ Version 0.13.3
+
+ - adds ability to polyfill bls verification in Certificate
+
Version 0.13.2
- auth-client avoids localstorage global and can be used in a web worker or nodejs
diff --git a/e2e/node/basic/canisterStatus.test.ts b/e2e/node/basic/canisterStatus.test.ts
index 5b7e31cf9..dff687889 100644
--- a/e2e/node/basic/canisterStatus.test.ts
+++ b/e2e/node/basic/canisterStatus.test.ts
@@ -3,6 +3,9 @@ import { Principal } from '@dfinity/principal';
import counter from '../canisters/counter';
jest.setTimeout(30_000);
+afterEach(async () => {
+ await Promise.resolve();
+});
describe.only('canister status', () => {
it('should fetch successfully', async () => {
const counterObj = await (await counter)();
diff --git a/packages/agent/src/actor.ts b/packages/agent/src/actor.ts
index 270455679..5e6dfc5ec 100644
--- a/packages/agent/src/actor.ts
+++ b/packages/agent/src/actor.ts
@@ -14,6 +14,7 @@ import { pollForResponse, PollStrategyFactory, strategy } from './polling';
import { Principal } from '@dfinity/principal';
import { RequestId } from './request_id';
import { toHex } from './utils/buffer';
+import { CreateCertificateOptions } from './certificate';
export class ActorCallError extends AgentError {
constructor(
@@ -115,6 +116,11 @@ export interface ActorConfig extends CallConfig {
args: unknown[],
callConfig: CallConfig,
): Partial | void;
+
+ /**
+ * Polyfill for BLS Certificate verification in case wasm is not supported
+ */
+ blsVerify?: CreateCertificateOptions['blsVerify'];
}
// TODO: move this to proper typing when Candid support TypeScript.
@@ -254,7 +260,7 @@ export class Actor {
});
for (const [methodName, func] of service._fields) {
- this[methodName] = _createActorMethod(this, methodName, func);
+ this[methodName] = _createActorMethod(this, methodName, func, config.blsVerify);
}
}
}
@@ -299,7 +305,12 @@ const DEFAULT_ACTOR_CONFIG = {
export type ActorConstructor = new (config: ActorConfig) => ActorSubclass;
-function _createActorMethod(actor: Actor, methodName: string, func: IDL.FuncClass): ActorMethod {
+function _createActorMethod(
+ actor: Actor,
+ methodName: string,
+ func: IDL.FuncClass,
+ blsVerify?: CreateCertificateOptions['blsVerify'],
+): ActorMethod {
let caller: (options: CallConfig, ...args: unknown[]) => Promise;
if (func.annotations.includes('query')) {
caller = async (options, ...args) => {
@@ -357,7 +368,7 @@ function _createActorMethod(actor: Actor, methodName: string, func: IDL.FuncClas
}
const pollStrategy = pollingStrategyFactory();
- const responseBytes = await pollForResponse(agent, ecid, requestId, pollStrategy);
+ const responseBytes = await pollForResponse(agent, ecid, requestId, pollStrategy, blsVerify);
if (responseBytes !== undefined) {
return decodeReturnValue(func.retTypes, responseBytes);
diff --git a/packages/agent/src/canisterStatus/index.ts b/packages/agent/src/canisterStatus/index.ts
index d4c151cce..3c31ae80b 100644
--- a/packages/agent/src/canisterStatus/index.ts
+++ b/packages/agent/src/canisterStatus/index.ts
@@ -4,6 +4,7 @@ import { lebDecode, PipeArrayBuffer } from '@dfinity/candid';
import { Principal } from '@dfinity/principal';
import { AgentError } from '../errors';
import { HttpAgent, Cbor, Certificate, toHex } from '..';
+import type { CreateCertificateOptions } from '..';
/**
* Types of an entry on the canisterStatus map.
@@ -50,6 +51,7 @@ export type CanisterStatusOptions = {
canisterId: Principal;
agent: HttpAgent;
paths?: Path[] | Set;
+ blsVerify?: CreateCertificateOptions['blsVerify'];
};
/**
diff --git a/packages/agent/src/certificate.ts b/packages/agent/src/certificate.ts
index a92824cd1..16262e37e 100644
--- a/packages/agent/src/certificate.ts
+++ b/packages/agent/src/certificate.ts
@@ -1,9 +1,9 @@
import * as cbor from './cbor';
import { AgentError } from './errors';
import { hash } from './request_id';
-import { blsVerify } from './utils/bls';
import { concat, fromHex, toHex } from './utils/buffer';
import { Principal } from '@dfinity/principal';
+import * as bls from './utils/bls';
/**
* A certificate may fail verification with respect to the provided public key
@@ -98,6 +98,8 @@ function isBufferEqual(a: ArrayBuffer, b: ArrayBuffer): boolean {
return true;
}
+type VerifyFunc = (pk: Uint8Array, sig: Uint8Array, msg: Uint8Array) => Promise;
+
export interface CreateCertificateOptions {
/**
* The bytes encoding the certificate to be verified
@@ -113,6 +115,10 @@ export interface CreateCertificateOptions {
* the signing canister ID when verifying a certified variable.
*/
canisterId: Principal;
+ /**
+ * BLS Verification strategy. Default strategy uses wasm for performance, but that may not be available in all contexts.
+ */
+ blsVerify?: VerifyFunc;
}
export class Certificate {
@@ -130,7 +136,16 @@ export class Certificate {
* @throws {CertificateVerificationError}
*/
public static async create(options: CreateCertificateOptions): Promise {
- const cert = new Certificate(options.certificate, options.rootKey, options.canisterId);
+ let blsVerify = options.blsVerify;
+ if (!blsVerify) {
+ blsVerify = bls.blsVerify;
+ }
+ const cert = new Certificate(
+ options.certificate,
+ options.rootKey,
+ options.canisterId,
+ blsVerify,
+ );
await cert.verify();
return cert;
}
@@ -139,6 +154,7 @@ export class Certificate {
certificate: ArrayBuffer,
private _rootKey: ArrayBuffer,
private _canisterId: Principal,
+ private _blsVerify: VerifyFunc,
) {
this.cert = cbor.decode(new Uint8Array(certificate));
}
@@ -155,7 +171,7 @@ export class Certificate {
const msg = concat(domain_sep('ic-state-root'), rootHash);
let sigVer = false;
try {
- sigVer = await blsVerify(new Uint8Array(key), new Uint8Array(sig), new Uint8Array(msg));
+ sigVer = await this._blsVerify(new Uint8Array(key), new Uint8Array(sig), new Uint8Array(msg));
} catch (err) {
sigVer = false;
}
diff --git a/packages/agent/src/polling/index.ts b/packages/agent/src/polling/index.ts
index 788550583..09c1e445d 100644
--- a/packages/agent/src/polling/index.ts
+++ b/packages/agent/src/polling/index.ts
@@ -1,6 +1,6 @@
import { Principal } from '@dfinity/principal';
import { Agent, RequestStatusResponseStatus } from '../agent';
-import { Certificate } from '../certificate';
+import { Certificate, CreateCertificateOptions } from '../certificate';
import { RequestId } from '../request_id';
import { toHex } from '../utils/buffer';
@@ -29,6 +29,7 @@ export async function pollForResponse(
strategy: PollStrategy,
// eslint-disable-next-line
request?: any,
+ blsVerify?: CreateCertificateOptions['blsVerify'],
): Promise {
const path = [new TextEncoder().encode('request_status'), requestId];
const currentRequest = request ?? (await agent.createReadStateRequest?.({ paths: [path] }));
@@ -38,6 +39,7 @@ export async function pollForResponse(
certificate: state.certificate,
rootKey: agent.rootKey,
canisterId: canisterId,
+ blsVerify,
});
const maybeBuf = cert.lookup([...path, new TextEncoder().encode('status')]);
let status;