From 050bd60628a3e7c2e9bd5890e3b0965490022fe0 Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Mon, 14 Aug 2023 11:16:22 +0200
Subject: [PATCH 1/9] draft taco api
---
src/characters/cbd-recipient.ts | 11 ++-
src/dkg.ts | 13 +++
src/sdk/strategy/cbd-strategy.ts | 6 +-
src/taco.ts | 61 ++++++++++++++
test/unit/cbd-strategy.test.ts | 2 +-
test/unit/conditions/condition-expr.test.ts | 44 +++++++++++
test/unit/taco.test.ts | 88 +++++++++++++++++++++
test/utils.ts | 5 +-
8 files changed, 218 insertions(+), 12 deletions(-)
create mode 100644 src/taco.ts
create mode 100644 test/unit/taco.test.ts
diff --git a/src/characters/cbd-recipient.ts b/src/characters/cbd-recipient.ts
index ad973616a..585ad7faa 100644
--- a/src/characters/cbd-recipient.ts
+++ b/src/characters/cbd-recipient.ts
@@ -14,7 +14,6 @@ import { ethers } from 'ethers';
import { DkgCoordinatorAgent, DkgParticipant } from '../agents/coordinator';
import { ConditionContext } from '../conditions';
-import { DkgRitual } from '../dkg';
import { PorterClient } from '../porter';
import { fromJSON, objectEquals, toJSON } from '../utils';
@@ -31,22 +30,22 @@ export class ThresholdDecrypter {
private readonly threshold: number
) {}
- public static create(porterUri: string, dkgRitual: DkgRitual) {
+ public static create(porterUri: string, ritualId: number, threshold: number) {
return new ThresholdDecrypter(
new PorterClient(porterUri),
- dkgRitual.id,
- dkgRitual.dkgParams.threshold
+ ritualId,
+ threshold
);
}
// Retrieve and decrypt ciphertext using provider and condition expression
public async retrieveAndDecrypt(
- provider: ethers.providers.Provider,
+ web3Provider: ethers.providers.Provider,
thresholdMessageKit: ThresholdMessageKit,
signer?: ethers.Signer
): Promise {
const decryptionShares = await this.retrieve(
- provider,
+ web3Provider,
thresholdMessageKit,
signer
);
diff --git a/src/dkg.ts b/src/dkg.ts
index c1ab06499..8fa9dd6ec 100644
--- a/src/dkg.ts
+++ b/src/dkg.ts
@@ -135,6 +135,19 @@ export class DkgClient {
);
}
+ public static async getFinalizedRitual(
+ web3Provider: ethers.providers.Web3Provider,
+ ritualId: number
+ ): Promise {
+ const ritual = await DkgClient.getExistingRitual(web3Provider, ritualId);
+ if (ritual.state !== DkgRitualState.FINALIZED) {
+ throw new Error(
+ `Ritual ${ritualId} is not finalized. State: ${ritual.state}`
+ );
+ }
+ return ritual;
+ }
+
// TODO: Without Validator public key in Coordinator, we cannot verify the
// transcript. We need to add it to the Coordinator (nucypher-contracts #77).
// public async verifyRitual(ritualId: number): Promise {
diff --git a/src/sdk/strategy/cbd-strategy.ts b/src/sdk/strategy/cbd-strategy.ts
index 56a91c6c3..ed0a37d8f 100644
--- a/src/sdk/strategy/cbd-strategy.ts
+++ b/src/sdk/strategy/cbd-strategy.ts
@@ -78,7 +78,11 @@ export class DeployedCbdStrategy {
) {}
public static create(dkgRitual: DkgRitual, porterUri: string) {
- const decrypter = ThresholdDecrypter.create(porterUri, dkgRitual);
+ const decrypter = ThresholdDecrypter.create(
+ porterUri,
+ dkgRitual.id,
+ dkgRitual.dkgParams.threshold
+ );
return new DeployedCbdStrategy(decrypter, dkgRitual.dkgPublicKey);
}
diff --git a/src/taco.ts b/src/taco.ts
new file mode 100644
index 000000000..3d4228c24
--- /dev/null
+++ b/src/taco.ts
@@ -0,0 +1,61 @@
+import { Ciphertext, ferveoEncrypt } from '@nucypher/nucypher-core';
+import { ethers } from 'ethers';
+
+import { ThresholdDecrypter } from './characters/cbd-recipient';
+import { ConditionExpression } from './conditions';
+import { DkgClient } from './dkg';
+import { toBytes } from './utils';
+
+export interface TacoMessageKit {
+ ciphertext: Ciphertext;
+ aad: Uint8Array;
+ ritualId: number;
+ threshold: number;
+}
+
+export const encrypt = async (
+ web3Provider: ethers.providers.Web3Provider,
+ message: string,
+ conditions: ConditionExpression,
+ ritualId: number
+): Promise => {
+ const dkgRitual = await DkgClient.getFinalizedRitual(web3Provider, ritualId);
+ const aad = conditions.asAad();
+ const ciphertext = ferveoEncrypt(
+ toBytes(message),
+ aad,
+ dkgRitual.dkgPublicKey
+ );
+ return {
+ ciphertext,
+ aad,
+ ritualId,
+ threshold: dkgRitual.dkgParams.threshold,
+ };
+};
+
+export const decrypt = async (
+ web3Provider: ethers.providers.Web3Provider,
+ messageKit: TacoMessageKit,
+ porterUri: string
+): Promise => {
+ const decrypter = ThresholdDecrypter.create(
+ porterUri,
+ messageKit.ritualId,
+ messageKit.threshold
+ );
+ const condExpr = ConditionExpression.fromAad(messageKit.aad);
+ // TODO: Need web3Provider to fetch participants from Coordinator to make decryption requests.
+ // Should we put them into the message kit instead?
+ // Consider case where participants are changing over time. Is that an issue we should consider now?
+ return decrypter.retrieveAndDecrypt(
+ web3Provider,
+ condExpr,
+ messageKit.ciphertext
+ );
+};
+
+export const taco = {
+ encrypt,
+ decrypt,
+};
diff --git a/test/unit/cbd-strategy.test.ts b/test/unit/cbd-strategy.test.ts
index 7251262b1..2dfc76fca 100644
--- a/test/unit/cbd-strategy.test.ts
+++ b/test/unit/cbd-strategy.test.ts
@@ -51,11 +51,11 @@ const makeCbdStrategy = async () => {
async function makeDeployedCbdStrategy() {
const strategy = await makeCbdStrategy();
-
const mockedDkg = fakeDkgFlow(variant, 0, 4, 4);
const mockedDkgRitual = fakeDkgRitual(mockedDkg);
const getUrsulasSpy = mockGetUrsulas(ursulas);
const getExistingRitualSpy = mockGetExistingRitual(mockedDkgRitual);
+
const deployedStrategy = await strategy.deploy(aliceProvider, ritualId);
expect(getUrsulasSpy).toHaveBeenCalled();
diff --git a/test/unit/conditions/condition-expr.test.ts b/test/unit/conditions/condition-expr.test.ts
index 1ef17774a..abdf09f5f 100644
--- a/test/unit/conditions/condition-expr.test.ts
+++ b/test/unit/conditions/condition-expr.test.ts
@@ -221,6 +221,50 @@ describe('condition set', () => {
}
);
+ it.each([
+ // no "operator" nor "method" value
+ {
+ version: ConditionExpression.VERSION,
+ condition: {
+ randoKey: 'randoValue',
+ otherKey: 'otherValue',
+ },
+ },
+ // invalid "method" and no "contractAddress"
+ {
+ version: ConditionExpression.VERSION,
+ condition: {
+ method: 'doWhatIWant',
+ returnValueTest: {
+ index: 0,
+ comparator: '>',
+ value: '100',
+ },
+ chain: 5,
+ },
+ },
+ // condition with wrong method "method" and no contract address
+ {
+ version: ConditionExpression.VERSION,
+ condition: {
+ ...testTimeConditionObj,
+ method: 'doWhatIWant',
+ },
+ },
+ // rpc condition (no contract address) with disallowed method
+ {
+ version: ConditionExpression.VERSION,
+ condition: {
+ ...testRpcConditionObj,
+ method: 'isPolicyActive',
+ },
+ },
+ ])("can't determine condition type", (invalidCondition) => {
+ expect(() => {
+ ConditionExpression.fromObj(invalidCondition);
+ }).toThrow('unrecognized condition data');
+ });
+
it.each(['_invalid_condition_type_', undefined as unknown as string])(
'rejects an invalid condition type',
(invalidConditionType) => {
diff --git a/test/unit/taco.test.ts b/test/unit/taco.test.ts
new file mode 100644
index 000000000..fe74043dd
--- /dev/null
+++ b/test/unit/taco.test.ts
@@ -0,0 +1,88 @@
+import {
+ FerveoVariant,
+ SecretKey,
+ SessionStaticSecret,
+} from '@nucypher/nucypher-core';
+
+import { conditions } from '../../src';
+import { taco } from '../../src/taco';
+import { toBytes } from '../../src/utils';
+import {
+ fakeDkgFlow,
+ fakeDkgParticipants,
+ fakeDkgRitual,
+ fakePorterUri,
+ fakeTDecFlow,
+ fakeWeb3Provider,
+ mockCbdDecrypt,
+ mockGetExistingRitual,
+ mockGetParticipants,
+ mockRandomSessionStaticSecret,
+} from '../utils';
+
+import { aliceSecretKeyBytes } from './testVariables';
+
+const {
+ predefined: { ERC721Ownership },
+ ConditionExpression,
+} = conditions;
+
+// Shared test variables
+const aliceSecretKey = SecretKey.fromBEBytes(aliceSecretKeyBytes);
+const ownsNFT = new ERC721Ownership({
+ contractAddress: '0x1e988ba4692e52Bc50b375bcC8585b95c48AaD77',
+ parameters: [3591],
+ chain: 5,
+});
+const conditionExpr = new ConditionExpression(ownsNFT);
+const variant = FerveoVariant.precomputed;
+// const ritualId = 0;
+const message = 'this is a secret';
+
+describe('taco', () => {
+ it('encrypts and decrypts', async () => {
+ const mockedDkg = fakeDkgFlow(variant, 0, 4, 4);
+ const mockedDkgRitual = fakeDkgRitual(mockedDkg);
+ const web3Provider = fakeWeb3Provider(aliceSecretKey.toBEBytes());
+ const getExistingRitualSpy = mockGetExistingRitual(mockedDkgRitual);
+
+ const tacoMk = await taco.encrypt(
+ web3Provider,
+ message,
+ conditionExpr,
+ mockedDkg.ritualId
+ );
+
+ expect(getExistingRitualSpy).toHaveBeenCalled();
+
+ const { decryptionShares } = fakeTDecFlow({
+ ...mockedDkg,
+ message: toBytes(message),
+ aad: tacoMk.aad,
+ ciphertext: tacoMk.ciphertext,
+ });
+ const { participantSecrets, participants } = fakeDkgParticipants(
+ mockedDkg.ritualId,
+ variant
+ );
+ const requesterSessionKey = SessionStaticSecret.random();
+ const decryptSpy = mockCbdDecrypt(
+ mockedDkg.ritualId,
+ decryptionShares,
+ participantSecrets,
+ requesterSessionKey.publicKey()
+ );
+ const getParticipantsSpy = mockGetParticipants(participants);
+ const sessionKeySpy = mockRandomSessionStaticSecret(requesterSessionKey);
+
+ const decryptedMessage = await taco.decrypt(
+ web3Provider,
+ tacoMk,
+ fakePorterUri
+ );
+ expect(getParticipantsSpy).toHaveBeenCalled();
+ expect(sessionKeySpy).toHaveBeenCalled();
+ expect(decryptSpy).toHaveBeenCalled();
+ expect(decryptedMessage).toEqual(toBytes(message));
+ });
+});
diff --git a/test/utils.ts b/test/utils.ts
index 11f8b6714..e41b00144 100644
--- a/test/utils.ts
+++ b/test/utils.ts
@@ -324,10 +324,7 @@ export const fakeTDecFlow = async ({
thresholdMessageKit,
}: FakeDkgRitualFlow) => {
// Having aggregated the transcripts, the validators can now create decryption shares
- const decryptionShares: (
- | DecryptionSharePrecomputed
- | DecryptionShareSimple
- )[] = [];
+ const decryptionShares: DecryptionShareSimple[] = [];
zip(validators, validatorKeypairs).forEach(([validator, keypair]) => {
const dkg = new Dkg(ritualId, sharesNum, threshold, validators, validator);
const aggregate = dkg.aggregateTranscript(receivedMessages);
From 3c6f0de3cb027b8dc56acb9594d796aa0f4602db Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Mon, 14 Aug 2023 13:16:02 +0200
Subject: [PATCH 2/9] draft light encryption method
---
src/taco.ts | 42 ++++++++++++++++++++++++++++++++----------
test/unit/taco.test.ts | 1 -
2 files changed, 32 insertions(+), 11 deletions(-)
diff --git a/src/taco.ts b/src/taco.ts
index 3d4228c24..816d24943 100644
--- a/src/taco.ts
+++ b/src/taco.ts
@@ -1,4 +1,8 @@
-import { Ciphertext, ferveoEncrypt } from '@nucypher/nucypher-core';
+import {
+ Ciphertext,
+ DkgPublicKey,
+ ferveoEncrypt,
+} from '@nucypher/nucypher-core';
import { ethers } from 'ethers';
import { ThresholdDecrypter } from './characters/cbd-recipient';
@@ -9,7 +13,10 @@ import { toBytes } from './utils';
export interface TacoMessageKit {
ciphertext: Ciphertext;
aad: Uint8Array;
+ // TODO: How do we get rid of these two fields? We need them for decrypting
+ // We ritualId in order to fetch the DKG participants and create DecryptionRequests for them
ritualId: number;
+ // We need to know the threshold in order to create DecryptionRequests
threshold: number;
}
@@ -20,17 +27,30 @@ export const encrypt = async (
ritualId: number
): Promise => {
const dkgRitual = await DkgClient.getFinalizedRitual(web3Provider, ritualId);
- const aad = conditions.asAad();
- const ciphertext = ferveoEncrypt(
- toBytes(message),
- aad,
- dkgRitual.dkgPublicKey
+ return await encryptLight(
+ message,
+ conditions,
+ dkgRitual.dkgPublicKey,
+ dkgRitual.dkgParams.threshold,
+ ritualId
);
+};
+
+export const encryptLight = async (
+ message: string,
+ conditions: ConditionExpression,
+ dkgPublicKey: DkgPublicKey,
+ // TODO: Remove these parameters after fixing TacoMessageKit
+ threshold: number,
+ ritualId: number
+): Promise => {
+ const aad = conditions.asAad();
+ const ciphertext = ferveoEncrypt(toBytes(message), aad, dkgPublicKey);
return {
ciphertext,
aad,
+ threshold,
ritualId,
- threshold: dkgRitual.dkgParams.threshold,
};
};
@@ -45,9 +65,10 @@ export const decrypt = async (
messageKit.threshold
);
const condExpr = ConditionExpression.fromAad(messageKit.aad);
- // TODO: Need web3Provider to fetch participants from Coordinator to make decryption requests.
- // Should we put them into the message kit instead?
- // Consider case where participants are changing over time. Is that an issue we should consider now?
+ // TODO: We need web3Provider to fetch participants from Coordinator to make decryption requests.
+ // Removing this dependency is tied to release of ThresholdMessageKit
+ // Blocked by changes to nucypher-core and nucypher:
+ // https://github.com/nucypher/nucypher/pull/3194
return decrypter.retrieveAndDecrypt(
web3Provider,
condExpr,
@@ -57,5 +78,6 @@ export const decrypt = async (
export const taco = {
encrypt,
+ encryptLight,
decrypt,
};
diff --git a/test/unit/taco.test.ts b/test/unit/taco.test.ts
index fe74043dd..907b58f86 100644
--- a/test/unit/taco.test.ts
+++ b/test/unit/taco.test.ts
@@ -36,7 +36,6 @@ const ownsNFT = new ERC721Ownership({
});
const conditionExpr = new ConditionExpression(ownsNFT);
const variant = FerveoVariant.precomputed;
-// const ritualId = 0;
const message = 'this is a secret';
describe('taco', () => {
From 6ad6130012c05cf294ec18963ad531a9d8a72e06 Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Thu, 24 Aug 2023 13:08:49 +0200
Subject: [PATCH 3/9] hide condition expression from the taco api
---
src/taco.ts | 10 +++++-----
test/unit/taco.test.ts | 4 +---
2 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/src/taco.ts b/src/taco.ts
index 816d24943..f378477a3 100644
--- a/src/taco.ts
+++ b/src/taco.ts
@@ -6,7 +6,7 @@ import {
import { ethers } from 'ethers';
import { ThresholdDecrypter } from './characters/cbd-recipient';
-import { ConditionExpression } from './conditions';
+import { Condition, ConditionExpression } from './conditions';
import { DkgClient } from './dkg';
import { toBytes } from './utils';
@@ -23,13 +23,13 @@ export interface TacoMessageKit {
export const encrypt = async (
web3Provider: ethers.providers.Web3Provider,
message: string,
- conditions: ConditionExpression,
+ condition: Condition,
ritualId: number
): Promise => {
const dkgRitual = await DkgClient.getFinalizedRitual(web3Provider, ritualId);
return await encryptLight(
message,
- conditions,
+ condition,
dkgRitual.dkgPublicKey,
dkgRitual.dkgParams.threshold,
ritualId
@@ -38,13 +38,13 @@ export const encrypt = async (
export const encryptLight = async (
message: string,
- conditions: ConditionExpression,
+ condition: Condition,
dkgPublicKey: DkgPublicKey,
// TODO: Remove these parameters after fixing TacoMessageKit
threshold: number,
ritualId: number
): Promise => {
- const aad = conditions.asAad();
+ const aad = new ConditionExpression(condition).asAad();
const ciphertext = ferveoEncrypt(toBytes(message), aad, dkgPublicKey);
return {
ciphertext,
diff --git a/test/unit/taco.test.ts b/test/unit/taco.test.ts
index 907b58f86..619620202 100644
--- a/test/unit/taco.test.ts
+++ b/test/unit/taco.test.ts
@@ -24,7 +24,6 @@ import { aliceSecretKeyBytes } from './testVariables';
const {
predefined: { ERC721Ownership },
- ConditionExpression,
} = conditions;
// Shared test variables
@@ -34,7 +33,6 @@ const ownsNFT = new ERC721Ownership({
parameters: [3591],
chain: 5,
});
-const conditionExpr = new ConditionExpression(ownsNFT);
const variant = FerveoVariant.precomputed;
const message = 'this is a secret';
@@ -48,7 +46,7 @@ describe('taco', () => {
const tacoMk = await taco.encrypt(
web3Provider,
message,
- conditionExpr,
+ ownsNFT,
mockedDkg.ritualId
);
From 0319e0fb2b1b9a9d5f47a38e3596fd9e45c7b621 Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Thu, 24 Aug 2023 13:30:31 +0200
Subject: [PATCH 4/9] set a default porter uri
---
src/taco.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/taco.ts b/src/taco.ts
index f378477a3..434a587e7 100644
--- a/src/taco.ts
+++ b/src/taco.ts
@@ -8,6 +8,7 @@ import { ethers } from 'ethers';
import { ThresholdDecrypter } from './characters/cbd-recipient';
import { Condition, ConditionExpression } from './conditions';
import { DkgClient } from './dkg';
+import { getPorterUri } from './porter';
import { toBytes } from './utils';
export interface TacoMessageKit {
@@ -57,7 +58,7 @@ export const encryptLight = async (
export const decrypt = async (
web3Provider: ethers.providers.Web3Provider,
messageKit: TacoMessageKit,
- porterUri: string
+ porterUri = getPorterUri('tapir')
): Promise => {
const decrypter = ThresholdDecrypter.create(
porterUri,
From 9f974c0f719b1f991144dc7c69c82d03c329aace Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Mon, 4 Sep 2023 09:45:04 +0200
Subject: [PATCH 5/9] update after rebase
---
src/conditions/context/context.ts | 2 +-
src/dkg.ts | 4 +-
src/taco.ts | 41 +++++++++----------
test/unit/cbd-strategy.test.ts | 16 ++++----
test/unit/conditions/condition-expr.test.ts | 44 ---------------------
test/unit/conditions/context.test.ts | 2 +-
test/unit/taco.test.ts | 18 +++++----
test/utils.ts | 14 +++----
8 files changed, 48 insertions(+), 93 deletions(-)
diff --git a/src/conditions/context/context.ts b/src/conditions/context/context.ts
index c1d8426df..0b64cad90 100644
--- a/src/conditions/context/context.ts
+++ b/src/conditions/context/context.ts
@@ -51,7 +51,7 @@ export class ConditionContext {
);
if (conditionRequiresSigner && !this.signer) {
throw new Error(
- `Condition contains ${USER_ADDRESS_PARAM} context variable and requires a signer to populate`
+ `Cannot use ${USER_ADDRESS_PARAM} as a parameter without a signer`
);
}
diff --git a/src/dkg.ts b/src/dkg.ts
index 8fa9dd6ec..c5056c8f7 100644
--- a/src/dkg.ts
+++ b/src/dkg.ts
@@ -136,10 +136,10 @@ export class DkgClient {
}
public static async getFinalizedRitual(
- web3Provider: ethers.providers.Web3Provider,
+ provider: ethers.providers.Provider,
ritualId: number
): Promise {
- const ritual = await DkgClient.getExistingRitual(web3Provider, ritualId);
+ const ritual = await DkgClient.getExistingRitual(provider, ritualId);
if (ritual.state !== DkgRitualState.FINALIZED) {
throw new Error(
`Ritual ${ritualId} is not finalized. State: ${ritual.state}`
diff --git a/src/taco.ts b/src/taco.ts
index 434a587e7..6ea3c997d 100644
--- a/src/taco.ts
+++ b/src/taco.ts
@@ -1,19 +1,16 @@
-import {
- Ciphertext,
- DkgPublicKey,
- ferveoEncrypt,
-} from '@nucypher/nucypher-core';
+import { DkgPublicKey, ThresholdMessageKit } from '@nucypher/nucypher-core';
import { ethers } from 'ethers';
import { ThresholdDecrypter } from './characters/cbd-recipient';
+import { Enrico } from './characters/enrico';
import { Condition, ConditionExpression } from './conditions';
import { DkgClient } from './dkg';
import { getPorterUri } from './porter';
import { toBytes } from './utils';
export interface TacoMessageKit {
- ciphertext: Ciphertext;
- aad: Uint8Array;
+ thresholdMessageKit: ThresholdMessageKit;
+ conditionExpr: ConditionExpression;
// TODO: How do we get rid of these two fields? We need them for decrypting
// We ritualId in order to fetch the DKG participants and create DecryptionRequests for them
ritualId: number;
@@ -22,12 +19,12 @@ export interface TacoMessageKit {
}
export const encrypt = async (
- web3Provider: ethers.providers.Web3Provider,
+ provider: ethers.providers.Provider,
message: string,
condition: Condition,
ritualId: number
): Promise => {
- const dkgRitual = await DkgClient.getFinalizedRitual(web3Provider, ritualId);
+ const dkgRitual = await DkgClient.getFinalizedRitual(provider, ritualId);
return await encryptLight(
message,
condition,
@@ -45,19 +42,24 @@ export const encryptLight = async (
threshold: number,
ritualId: number
): Promise => {
- const aad = new ConditionExpression(condition).asAad();
- const ciphertext = ferveoEncrypt(toBytes(message), aad, dkgPublicKey);
+ const encrypter = new Enrico(dkgPublicKey);
+ const conditionExpr = new ConditionExpression(condition);
+ const thresholdMessageKit = await encrypter.encryptMessageCbd(
+ toBytes(message),
+ conditionExpr
+ );
return {
- ciphertext,
- aad,
+ thresholdMessageKit,
threshold,
ritualId,
+ conditionExpr,
};
};
export const decrypt = async (
- web3Provider: ethers.providers.Web3Provider,
+ provider: ethers.providers.Provider,
messageKit: TacoMessageKit,
+ signer?: ethers.Signer,
porterUri = getPorterUri('tapir')
): Promise => {
const decrypter = ThresholdDecrypter.create(
@@ -65,15 +67,10 @@ export const decrypt = async (
messageKit.ritualId,
messageKit.threshold
);
- const condExpr = ConditionExpression.fromAad(messageKit.aad);
- // TODO: We need web3Provider to fetch participants from Coordinator to make decryption requests.
- // Removing this dependency is tied to release of ThresholdMessageKit
- // Blocked by changes to nucypher-core and nucypher:
- // https://github.com/nucypher/nucypher/pull/3194
return decrypter.retrieveAndDecrypt(
- web3Provider,
- condExpr,
- messageKit.ciphertext
+ provider,
+ messageKit.thresholdMessageKit,
+ signer
);
};
diff --git a/test/unit/cbd-strategy.test.ts b/test/unit/cbd-strategy.test.ts
index 2dfc76fca..440fbd1b6 100644
--- a/test/unit/cbd-strategy.test.ts
+++ b/test/unit/cbd-strategy.test.ts
@@ -29,9 +29,9 @@ const {
} = conditions;
// Shared test variables
-const aliceSecretKey = SecretKey.fromBEBytes(aliceSecretKeyBytes);
-const aliceProvider = fakeProvider(aliceSecretKey.toBEBytes());
-const aliceSigner = fakeSigner(aliceSecretKey.toBEBytes());
+const secretKey = SecretKey.fromBEBytes(aliceSecretKeyBytes);
+const provider = fakeProvider(secretKey.toBEBytes());
+const signer = fakeSigner(secretKey.toBEBytes());
const ownsNFT = new ERC721Ownership({
contractAddress: '0x1e988ba4692e52Bc50b375bcC8585b95c48AaD77',
parameters: [3591],
@@ -56,7 +56,7 @@ async function makeDeployedCbdStrategy() {
const getUrsulasSpy = mockGetUrsulas(ursulas);
const getExistingRitualSpy = mockGetExistingRitual(mockedDkgRitual);
- const deployedStrategy = await strategy.deploy(aliceProvider, ritualId);
+ const deployedStrategy = await strategy.deploy(provider, ritualId);
expect(getUrsulasSpy).toHaveBeenCalled();
expect(getExistingRitualSpy).toHaveBeenCalled();
@@ -108,13 +108,13 @@ describe('CbdDeployedStrategy', () => {
.encryptMessageCbd(message);
// Setup mocks for `retrieveAndDecrypt`
- const { decryptionShares } = await fakeTDecFlow({
+ const { decryptionShares } = fakeTDecFlow({
...mockedDkg,
message: toBytes(message),
dkgPublicKey: mockedDkg.dkg.publicKey(),
thresholdMessageKit,
});
- const { participantSecrets, participants } = await fakeDkgParticipants(
+ const { participantSecrets, participants } = fakeDkgParticipants(
mockedDkg.ritualId
);
const requesterSessionKey = SessionStaticSecret.random();
@@ -130,9 +130,9 @@ describe('CbdDeployedStrategy', () => {
const decryptedMessage =
await deployedStrategy.decrypter.retrieveAndDecrypt(
- aliceProvider,
+ provider,
thresholdMessageKit,
- aliceSigner
+ signer
);
expect(getUrsulasSpy).toHaveBeenCalled();
expect(getParticipantsSpy).toHaveBeenCalled();
diff --git a/test/unit/conditions/condition-expr.test.ts b/test/unit/conditions/condition-expr.test.ts
index abdf09f5f..1ef17774a 100644
--- a/test/unit/conditions/condition-expr.test.ts
+++ b/test/unit/conditions/condition-expr.test.ts
@@ -221,50 +221,6 @@ describe('condition set', () => {
}
);
- it.each([
- // no "operator" nor "method" value
- {
- version: ConditionExpression.VERSION,
- condition: {
- randoKey: 'randoValue',
- otherKey: 'otherValue',
- },
- },
- // invalid "method" and no "contractAddress"
- {
- version: ConditionExpression.VERSION,
- condition: {
- method: 'doWhatIWant',
- returnValueTest: {
- index: 0,
- comparator: '>',
- value: '100',
- },
- chain: 5,
- },
- },
- // condition with wrong method "method" and no contract address
- {
- version: ConditionExpression.VERSION,
- condition: {
- ...testTimeConditionObj,
- method: 'doWhatIWant',
- },
- },
- // rpc condition (no contract address) with disallowed method
- {
- version: ConditionExpression.VERSION,
- condition: {
- ...testRpcConditionObj,
- method: 'isPolicyActive',
- },
- },
- ])("can't determine condition type", (invalidCondition) => {
- expect(() => {
- ConditionExpression.fromObj(invalidCondition);
- }).toThrow('unrecognized condition data');
- });
-
it.each(['_invalid_condition_type_', undefined as unknown as string])(
'rejects an invalid condition type',
(invalidConditionType) => {
diff --git a/test/unit/conditions/context.test.ts b/test/unit/conditions/context.test.ts
index 4a0815912..d87c6291a 100644
--- a/test/unit/conditions/context.test.ts
+++ b/test/unit/conditions/context.test.ts
@@ -114,7 +114,7 @@ describe('context parameters', () => {
const conditionExpr = new ConditionExpression(condition);
expect(conditionExpr.contextRequiresSigner()).toBe(true);
expect(() => conditionExpr.buildContext(provider, {}, undefined)).toThrow(
- `Condition contains ${USER_ADDRESS_PARAM} context variable and requires a signer to populate`
+ `Cannot use ${USER_ADDRESS_PARAM} as a parameter without a signer`
);
});
diff --git a/test/unit/taco.test.ts b/test/unit/taco.test.ts
index 619620202..2158337ef 100644
--- a/test/unit/taco.test.ts
+++ b/test/unit/taco.test.ts
@@ -12,8 +12,9 @@ import {
fakeDkgParticipants,
fakeDkgRitual,
fakePorterUri,
+ fakeProvider,
+ fakeSigner,
fakeTDecFlow,
- fakeWeb3Provider,
mockCbdDecrypt,
mockGetExistingRitual,
mockGetParticipants,
@@ -40,11 +41,12 @@ describe('taco', () => {
it('encrypts and decrypts', async () => {
const mockedDkg = fakeDkgFlow(variant, 0, 4, 4);
const mockedDkgRitual = fakeDkgRitual(mockedDkg);
- const web3Provider = fakeWeb3Provider(aliceSecretKey.toBEBytes());
+ const provider = fakeProvider(aliceSecretKey.toBEBytes());
+ const signer = fakeSigner(aliceSecretKey.toBEBytes());
const getExistingRitualSpy = mockGetExistingRitual(mockedDkgRitual);
const tacoMk = await taco.encrypt(
- web3Provider,
+ provider,
message,
ownsNFT,
mockedDkg.ritualId
@@ -55,12 +57,11 @@ describe('taco', () => {
const { decryptionShares } = fakeTDecFlow({
...mockedDkg,
message: toBytes(message),
- aad: tacoMk.aad,
- ciphertext: tacoMk.ciphertext,
+ dkgPublicKey: mockedDkg.dkg.publicKey(),
+ thresholdMessageKit: tacoMk.thresholdMessageKit,
});
const { participantSecrets, participants } = fakeDkgParticipants(
- mockedDkg.ritualId,
- variant
+ mockedDkg.ritualId
);
const requesterSessionKey = SessionStaticSecret.random();
const decryptSpy = mockCbdDecrypt(
@@ -73,8 +74,9 @@ describe('taco', () => {
const sessionKeySpy = mockRandomSessionStaticSecret(requesterSessionKey);
const decryptedMessage = await taco.decrypt(
- web3Provider,
+ provider,
tacoMk,
+ signer,
fakePorterUri
);
expect(getParticipantsSpy).toHaveBeenCalled();
diff --git a/test/utils.ts b/test/utils.ts
index e41b00144..1ce7ae461 100644
--- a/test/utils.ts
+++ b/test/utils.ts
@@ -313,7 +313,7 @@ interface FakeDkgRitualFlow {
thresholdMessageKit: ThresholdMessageKit;
}
-export const fakeTDecFlow = async ({
+export const fakeTDecFlow = ({
validators,
validatorKeypairs,
ritualId,
@@ -364,7 +364,7 @@ const fakeConditionExpr = () => {
return new ConditionExpression(erc721Balance);
};
-export const fakeDkgTDecFlowE2E = async (
+export const fakeDkgTDecFlowE2E = (
ritualId = 0,
variant: FerveoVariant = FerveoVariant.precomputed,
conditionExpr: ConditionExpression = fakeConditionExpr(),
@@ -379,7 +379,7 @@ export const fakeDkgTDecFlowE2E = async (
conditionExpr
);
- const { decryptionShares } = await fakeTDecFlow({
+ const { decryptionShares } = fakeTDecFlow({
...ritual,
message,
dkgPublicKey,
@@ -429,13 +429,13 @@ export const fakeCoordinatorRitual = async (
};
};
-export const fakeDkgParticipants = async (
+export const fakeDkgParticipants = (
ritualId: number
-): Promise<{
+): {
participants: DkgParticipant[];
participantSecrets: Record;
-}> => {
- const ritual = await fakeDkgTDecFlowE2E(ritualId);
+} => {
+ const ritual = fakeDkgTDecFlowE2E(ritualId);
const label = toBytes(`${ritualId}`);
const participantSecrets: Record =
From 26a54e6dc6c24112e1edaf230e3fcf6f1faa73fc Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Tue, 5 Sep 2023 15:18:48 +0200
Subject: [PATCH 6/9] update coordinator contract
---
abi/Coordinator.json | 905 ++++++++++++++++++--
src/agents/coordinator.ts | 45 +-
src/dkg.ts | 21 +-
src/sdk/strategy/cbd-strategy.ts | 4 +-
src/taco.ts | 60 +-
test/unit/cbd-strategy.test.ts | 4 +-
test/unit/conditions/condition-expr.test.ts | 8 +-
test/unit/taco.test.ts | 17 +-
test/utils.ts | 12 +-
9 files changed, 950 insertions(+), 126 deletions(-)
diff --git a/abi/Coordinator.json b/abi/Coordinator.json
index c572ea259..a9f0143da 100644
--- a/abi/Coordinator.json
+++ b/abi/Coordinator.json
@@ -3,7 +3,7 @@
"inputs": [
{
"internalType": "contract IAccessControlApplication",
- "name": "app",
+ "name": "_stakes",
"type": "address"
},
{
@@ -12,9 +12,24 @@
"type": "uint32"
},
{
- "internalType": "uint32",
+ "internalType": "uint16",
"name": "_maxDkgSize",
- "type": "uint32"
+ "type": "uint16"
+ },
+ {
+ "internalType": "address",
+ "name": "_admin",
+ "type": "address"
+ },
+ {
+ "internalType": "contract IERC20",
+ "name": "_currency",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_feeRatePerSecond",
+ "type": "uint256"
}
],
"stateMutability": "nonpayable",
@@ -45,21 +60,65 @@
"name": "AggregationPosted",
"type": "event"
},
+ {
+ "anonymous": false,
+ "inputs": [],
+ "name": "DefaultAdminDelayChangeCanceled",
+ "type": "event"
+ },
{
"anonymous": false,
"inputs": [
{
- "indexed": true,
- "internalType": "uint32",
- "name": "ritualId",
- "type": "uint32"
+ "indexed": false,
+ "internalType": "uint48",
+ "name": "newDelay",
+ "type": "uint48"
},
+ {
+ "indexed": false,
+ "internalType": "uint48",
+ "name": "effectSchedule",
+ "type": "uint48"
+ }
+ ],
+ "name": "DefaultAdminDelayChangeScheduled",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [],
+ "name": "DefaultAdminTransferCanceled",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
{
"indexed": true,
"internalType": "address",
- "name": "initiator",
+ "name": "newAdmin",
"type": "address"
},
+ {
+ "indexed": false,
+ "internalType": "uint48",
+ "name": "acceptSchedule",
+ "type": "uint48"
+ }
+ ],
+ "name": "DefaultAdminTransferScheduled",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "uint32",
+ "name": "ritualId",
+ "type": "uint32"
+ },
{
"indexed": false,
"internalType": "bool",
@@ -75,15 +134,15 @@
"inputs": [
{
"indexed": false,
- "internalType": "uint32",
+ "internalType": "uint16",
"name": "oldSize",
- "type": "uint32"
+ "type": "uint16"
},
{
"indexed": false,
- "internalType": "uint32",
+ "internalType": "uint16",
"name": "newSize",
- "type": "uint32"
+ "type": "uint16"
}
],
"name": "MaxDkgSizeChanged",
@@ -92,20 +151,118 @@
{
"anonymous": false,
"inputs": [
+ {
+ "indexed": true,
+ "internalType": "uint32",
+ "name": "ritualId",
+ "type": "uint32"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "participant",
+ "type": "address"
+ },
+ {
+ "components": [
+ {
+ "internalType": "bytes32",
+ "name": "word0",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "bytes32",
+ "name": "word1",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "bytes32",
+ "name": "word2",
+ "type": "bytes32"
+ }
+ ],
+ "indexed": false,
+ "internalType": "struct BLS12381.G2Point",
+ "name": "publicKey",
+ "type": "tuple"
+ }
+ ],
+ "name": "ParticipantPublicKeySet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ },
+ {
+ "indexed": true,
+ "internalType": "bytes32",
+ "name": "previousAdminRole",
+ "type": "bytes32"
+ },
+ {
+ "indexed": true,
+ "internalType": "bytes32",
+ "name": "newAdminRole",
+ "type": "bytes32"
+ }
+ ],
+ "name": "RoleAdminChanged",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "sender",
+ "type": "address"
+ }
+ ],
+ "name": "RoleGranted",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ },
{
"indexed": true,
"internalType": "address",
- "name": "previousOwner",
+ "name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
- "name": "newOwner",
+ "name": "sender",
"type": "address"
}
],
- "name": "OwnershipTransferred",
+ "name": "RoleRevoked",
"type": "event"
},
{
@@ -133,7 +290,7 @@
{
"indexed": true,
"internalType": "address",
- "name": "initiator",
+ "name": "authority",
"type": "address"
},
{
@@ -190,6 +347,52 @@
"name": "TranscriptPosted",
"type": "event"
},
+ {
+ "inputs": [],
+ "name": "DEFAULT_ADMIN_ROLE",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "INITIATOR_ROLE",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "TREASURY_ROLE",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "acceptDefaultAdminTransfer",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [],
"name": "application",
@@ -203,6 +406,39 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newAdmin",
+ "type": "address"
+ }
+ ],
+ "name": "beginDefaultAdminTransfer",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "cancelDefaultAdminTransfer",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint48",
+ "name": "newDelay",
+ "type": "uint48"
+ }
+ ],
+ "name": "changeDefaultAdminDelay",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -223,11 +459,95 @@
"type": "function"
},
{
- "inputs": [
+ "inputs": [],
+ "name": "currency",
+ "outputs": [
+ {
+ "internalType": "contract IERC20",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "defaultAdmin",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "defaultAdminDelay",
+ "outputs": [
+ {
+ "internalType": "uint48",
+ "name": "",
+ "type": "uint48"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "defaultAdminDelayIncreaseWait",
+ "outputs": [
+ {
+ "internalType": "uint48",
+ "name": "",
+ "type": "uint48"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "feeRatePerSecond",
+ "outputs": [
{
"internalType": "uint256",
- "name": "ritualID",
+ "name": "",
"type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint32",
+ "name": "ritualId",
+ "type": "uint32"
+ }
+ ],
+ "name": "getAuthority",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint32",
+ "name": "ritualId",
+ "type": "uint32"
},
{
"internalType": "address",
@@ -312,17 +632,271 @@
{
"inputs": [
{
- "internalType": "uint256",
- "name": "ritualId",
- "type": "uint256"
+ "internalType": "address",
+ "name": "_provider",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_ritualId",
+ "type": "uint256"
+ }
+ ],
+ "name": "getProviderPublicKey",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "bytes32",
+ "name": "word0",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "bytes32",
+ "name": "word1",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "bytes32",
+ "name": "word2",
+ "type": "bytes32"
+ }
+ ],
+ "internalType": "struct BLS12381.G2Point",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint32",
+ "name": "ritualId",
+ "type": "uint32"
+ }
+ ],
+ "name": "getPublicKeyFromRitualId",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "bytes32",
+ "name": "word0",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "bytes16",
+ "name": "word1",
+ "type": "bytes16"
+ }
+ ],
+ "internalType": "struct BLS12381.G1Point",
+ "name": "dkgPublicKey",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "bytes32",
+ "name": "word0",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "bytes16",
+ "name": "word1",
+ "type": "bytes16"
+ }
+ ],
+ "internalType": "struct BLS12381.G1Point",
+ "name": "dkgPublicKey",
+ "type": "tuple"
+ }
+ ],
+ "name": "getRitualIdFromPublicKey",
+ "outputs": [
+ {
+ "internalType": "uint32",
+ "name": "ritualId",
+ "type": "uint32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address[]",
+ "name": "providers",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint32",
+ "name": "duration",
+ "type": "uint32"
+ }
+ ],
+ "name": "getRitualInitiationCost",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint32",
+ "name": "ritualId",
+ "type": "uint32"
+ }
+ ],
+ "name": "getRitualState",
+ "outputs": [
+ {
+ "internalType": "enum Coordinator.RitualState",
+ "name": "",
+ "type": "uint8"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ }
+ ],
+ "name": "getRoleAdmin",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint16",
+ "name": "size",
+ "type": "uint16"
+ }
+ ],
+ "name": "getThresholdForRitualSize",
+ "outputs": [
+ {
+ "internalType": "uint16",
+ "name": "",
+ "type": "uint16"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "grantRole",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "hasRole",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address[]",
+ "name": "providers",
+ "type": "address[]"
+ },
+ {
+ "internalType": "address",
+ "name": "authority",
+ "type": "address"
+ },
+ {
+ "internalType": "uint32",
+ "name": "duration",
+ "type": "uint32"
+ },
+ {
+ "internalType": "contract IEncryptionAuthorizer",
+ "name": "accessController",
+ "type": "address"
}
],
- "name": "getRitualState",
+ "name": "initiateRitual",
"outputs": [
{
- "internalType": "enum Coordinator.RitualState",
+ "internalType": "uint32",
"name": "",
- "type": "uint8"
+ "type": "uint32"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "isInitiationPublic",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
}
],
"stateMutability": "view",
@@ -331,19 +905,26 @@
{
"inputs": [
{
- "internalType": "address[]",
- "name": "providers",
- "type": "address[]"
+ "internalType": "uint32",
+ "name": "ritualId",
+ "type": "uint32"
}
],
- "name": "initiateRitual",
+ "name": "isRitualFinalized",
"outputs": [
{
- "internalType": "uint32",
+ "internalType": "bool",
"name": "",
- "type": "uint32"
+ "type": "bool"
}
],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "makeInitiationPublic",
+ "outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
@@ -352,9 +933,9 @@
"name": "maxDkgSize",
"outputs": [
{
- "internalType": "uint32",
+ "internalType": "uint16",
"name": "",
- "type": "uint32"
+ "type": "uint16"
}
],
"stateMutability": "view",
@@ -386,6 +967,61 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "pendingDefaultAdmin",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "newAdmin",
+ "type": "address"
+ },
+ {
+ "internalType": "uint48",
+ "name": "schedule",
+ "type": "uint48"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "pendingDefaultAdminDelay",
+ "outputs": [
+ {
+ "internalType": "uint48",
+ "name": "newDelay",
+ "type": "uint48"
+ },
+ {
+ "internalType": "uint48",
+ "name": "schedule",
+ "type": "uint48"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "pendingFees",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -412,7 +1048,7 @@
}
],
"internalType": "struct BLS12381.G1Point",
- "name": "publicKey",
+ "name": "dkgPublicKey",
"type": "tuple"
},
{
@@ -445,8 +1081,50 @@
"type": "function"
},
{
- "inputs": [],
- "name": "renounceOwnership",
+ "inputs": [
+ {
+ "internalType": "uint32",
+ "name": "ritualId",
+ "type": "uint32"
+ }
+ ],
+ "name": "processPendingFee",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "renounceRole",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "revokeRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -468,23 +1146,48 @@
},
{
"internalType": "uint32",
- "name": "dkgSize",
+ "name": "initTimestamp",
"type": "uint32"
},
{
"internalType": "uint32",
- "name": "initTimestamp",
+ "name": "endTimestamp",
"type": "uint32"
},
{
- "internalType": "uint32",
+ "internalType": "uint16",
"name": "totalTranscripts",
- "type": "uint32"
+ "type": "uint16"
},
{
- "internalType": "uint32",
+ "internalType": "uint16",
"name": "totalAggregations",
- "type": "uint32"
+ "type": "uint16"
+ },
+ {
+ "internalType": "address",
+ "name": "authority",
+ "type": "address"
+ },
+ {
+ "internalType": "uint16",
+ "name": "dkgSize",
+ "type": "uint16"
+ },
+ {
+ "internalType": "uint16",
+ "name": "threshold",
+ "type": "uint16"
+ },
+ {
+ "internalType": "bool",
+ "name": "aggregationMismatch",
+ "type": "bool"
+ },
+ {
+ "internalType": "contract IEncryptionAuthorizer",
+ "name": "accessController",
+ "type": "address"
},
{
"components": [
@@ -503,11 +1206,6 @@
"name": "publicKey",
"type": "tuple"
},
- {
- "internalType": "bool",
- "name": "aggregationMismatch",
- "type": "bool"
- },
{
"internalType": "bytes",
"name": "aggregatedTranscript",
@@ -517,12 +1215,19 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "rollbackDefaultAdminDelay",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
- "internalType": "uint32",
+ "internalType": "uint16",
"name": "newSize",
- "type": "uint32"
+ "type": "uint16"
}
],
"name": "setMaxDkgSize",
@@ -530,6 +1235,67 @@
"stateMutability": "nonpayable",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "bytes32",
+ "name": "word0",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "bytes32",
+ "name": "word1",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "bytes32",
+ "name": "word2",
+ "type": "bytes32"
+ }
+ ],
+ "internalType": "struct BLS12381.G2Point",
+ "name": "_publicKey",
+ "type": "tuple"
+ }
+ ],
+ "name": "setProviderPublicKey",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "contract IReimbursementPool",
+ "name": "pool",
+ "type": "address"
+ }
+ ],
+ "name": "setReimbursementPool",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint32",
+ "name": "ritualId",
+ "type": "uint32"
+ },
+ {
+ "internalType": "address",
+ "name": "authority",
+ "type": "address"
+ }
+ ],
+ "name": "setRitualAuthority",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -543,6 +1309,25 @@
"stateMutability": "nonpayable",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "bytes4",
+ "name": "interfaceId",
+ "type": "bytes4"
+ }
+ ],
+ "name": "supportsInterface",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [],
"name": "timeout",
@@ -556,15 +1341,33 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "totalPendingFees",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
{
- "internalType": "address",
- "name": "newOwner",
+ "internalType": "contract IERC20",
+ "name": "token",
"type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
}
],
- "name": "transferOwnership",
+ "name": "withdrawTokens",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
diff --git a/src/agents/coordinator.ts b/src/agents/coordinator.ts
index db8378d8d..28ed866cc 100644
--- a/src/agents/coordinator.ts
+++ b/src/agents/coordinator.ts
@@ -1,5 +1,5 @@
-import { SessionStaticKey } from '@nucypher/nucypher-core';
-import { ethers } from 'ethers';
+import { DkgPublicKey, SessionStaticKey } from '@nucypher/nucypher-core';
+import { BigNumberish, ethers } from 'ethers';
import {
Coordinator,
@@ -13,12 +13,16 @@ import { DEFAULT_WAIT_N_CONFIRMATIONS, getContract } from './contracts';
export interface CoordinatorRitual {
initiator: string;
- dkgSize: number;
initTimestamp: number;
+ endTimestamp: number;
totalTranscripts: number;
totalAggregations: number;
- publicKey: BLS12381.G1PointStructOutput;
+ authority: string;
+ dkgSize: number;
+ threshold: number;
aggregationMismatch: boolean;
+ accessController: string;
+ publicKey: BLS12381.G1PointStructOutput;
aggregatedTranscript: string;
}
@@ -59,10 +63,18 @@ export class DkgCoordinatorAgent {
public static async initializeRitual(
provider: ethers.providers.Provider,
signer: ethers.Signer,
- providers: ChecksumAddress[]
+ providers: ChecksumAddress[],
+ authority: string,
+ duration: BigNumberish,
+ accessController: string
): Promise {
const Coordinator = await this.connectReadWrite(provider, signer);
- const tx = await Coordinator.initiateRitual(providers);
+ const tx = await Coordinator.initiateRitual(
+ providers,
+ authority,
+ duration,
+ accessController
+ );
const txReceipt = await tx.wait(DEFAULT_WAIT_N_CONFIRMATIONS);
const [ritualStartEvent] = txReceipt.events ?? [];
if (!ritualStartEvent) {
@@ -95,16 +107,25 @@ export class DkgCoordinatorAgent {
const Coordinator = await this.connectReadOnly(provider);
// We leave `initiator` undefined because we don't care who the initiator is
// We leave `successful` undefined because we don't care if the ritual was successful
- const eventFilter = Coordinator.filters.EndRitual(
- ritualId,
- undefined,
- undefined
- );
- Coordinator.once(eventFilter, (_ritualId, _initiator, successful) => {
+ const eventFilter = Coordinator.filters.EndRitual(ritualId, undefined);
+ Coordinator.once(eventFilter, (_ritualId, successful) => {
callback(successful);
});
}
+ public static async getRitualIdFromPublicKey(
+ provider: ethers.providers.Provider,
+ dkgPublicKey: DkgPublicKey
+ ): Promise {
+ const Coordinator = await this.connectReadOnly(provider);
+ const dkgPublicKeyBytes = dkgPublicKey.toBytes();
+ const pointStruct: BLS12381.G1PointStruct = {
+ word0: dkgPublicKeyBytes.slice(0, 16),
+ word1: dkgPublicKeyBytes.slice(16, 32),
+ };
+ return await Coordinator.getRitualIdFromPublicKey(pointStruct);
+ }
+
private static async connectReadOnly(provider: ethers.providers.Provider) {
return await this.connect(provider);
}
diff --git a/src/dkg.ts b/src/dkg.ts
index c5056c8f7..b907158ad 100644
--- a/src/dkg.ts
+++ b/src/dkg.ts
@@ -1,5 +1,5 @@
import { DkgPublicKey } from '@nucypher/nucypher-core';
-import { ethers } from 'ethers';
+import { BigNumberish, ethers } from 'ethers';
import { DkgCoordinatorAgent, DkgRitualState } from './agents/coordinator';
import { ChecksumAddress } from './types';
@@ -58,22 +58,23 @@ export class DkgRitual {
}
}
-// TODO: Currently, we're assuming that the threshold is always `floor(sharesNum / 2) + 1`.
-// https://github.com/nucypher/nucypher/issues/3095
-const assumedThreshold = (sharesNum: number): number =>
- Math.floor(sharesNum / 2) + 1;
-
export class DkgClient {
public static async initializeRitual(
provider: ethers.providers.Provider,
signer: ethers.Signer,
ursulas: ChecksumAddress[],
+ authority: string,
+ duration: BigNumberish,
+ accessController: string,
waitUntilEnd = false
): Promise {
const ritualId = await DkgCoordinatorAgent.initializeRitual(
provider,
signer,
- ursulas.sort()
+ ursulas.sort(),
+ authority,
+ duration,
+ accessController
);
if (waitUntilEnd) {
@@ -111,7 +112,7 @@ export class DkgClient {
});
};
- public static async getExistingRitual(
+ public static async getRitual(
provider: ethers.providers.Provider,
ritualId: number
): Promise {
@@ -129,7 +130,7 @@ export class DkgClient {
DkgPublicKey.fromBytes(dkgPkBytes),
{
sharesNum: ritual.dkgSize,
- threshold: assumedThreshold(ritual.dkgSize),
+ threshold: ritual.threshold,
},
ritualState
);
@@ -139,7 +140,7 @@ export class DkgClient {
provider: ethers.providers.Provider,
ritualId: number
): Promise {
- const ritual = await DkgClient.getExistingRitual(provider, ritualId);
+ const ritual = await DkgClient.getRitual(provider, ritualId);
if (ritual.state !== DkgRitualState.FINALIZED) {
throw new Error(
`Ritual ${ritualId} is not finalized. State: ${ritual.state}`
diff --git a/src/sdk/strategy/cbd-strategy.ts b/src/sdk/strategy/cbd-strategy.ts
index ed0a37d8f..ed27e24f7 100644
--- a/src/sdk/strategy/cbd-strategy.ts
+++ b/src/sdk/strategy/cbd-strategy.ts
@@ -44,7 +44,7 @@ export class CbdStrategy {
// // Given that we just initialized the ritual, this should never happen
// throw new Error('Ritual ID is undefined');
// }
- const dkgRitual = await DkgClient.getExistingRitual(provider, ritualId);
+ const dkgRitual = await DkgClient.getRitual(provider, ritualId);
return DeployedCbdStrategy.create(dkgRitual, this.cohort.porterUri);
}
@@ -92,7 +92,7 @@ export class DeployedCbdStrategy {
porterUri: string,
ritualId: number
): Promise {
- const dkgRitual = await DkgClient.getExistingRitual(provider, ritualId);
+ const dkgRitual = await DkgClient.getRitual(provider, ritualId);
return DeployedCbdStrategy.create(dkgRitual, porterUri);
}
diff --git a/src/taco.ts b/src/taco.ts
index 6ea3c997d..6ded5a372 100644
--- a/src/taco.ts
+++ b/src/taco.ts
@@ -1,6 +1,7 @@
import { DkgPublicKey, ThresholdMessageKit } from '@nucypher/nucypher-core';
import { ethers } from 'ethers';
+import { DkgCoordinatorAgent } from './agents/coordinator';
import { ThresholdDecrypter } from './characters/cbd-recipient';
import { Enrico } from './characters/enrico';
import { Condition, ConditionExpression } from './conditions';
@@ -8,70 +9,47 @@ import { DkgClient } from './dkg';
import { getPorterUri } from './porter';
import { toBytes } from './utils';
-export interface TacoMessageKit {
- thresholdMessageKit: ThresholdMessageKit;
- conditionExpr: ConditionExpression;
- // TODO: How do we get rid of these two fields? We need them for decrypting
- // We ritualId in order to fetch the DKG participants and create DecryptionRequests for them
- ritualId: number;
- // We need to know the threshold in order to create DecryptionRequests
- threshold: number;
-}
-
export const encrypt = async (
provider: ethers.providers.Provider,
message: string,
condition: Condition,
ritualId: number
-): Promise => {
+): Promise => {
const dkgRitual = await DkgClient.getFinalizedRitual(provider, ritualId);
- return await encryptLight(
- message,
- condition,
- dkgRitual.dkgPublicKey,
- dkgRitual.dkgParams.threshold,
- ritualId
- );
+ return await encryptLight(message, condition, dkgRitual.dkgPublicKey);
};
export const encryptLight = async (
message: string,
condition: Condition,
- dkgPublicKey: DkgPublicKey,
- // TODO: Remove these parameters after fixing TacoMessageKit
- threshold: number,
- ritualId: number
-): Promise => {
+ dkgPublicKey: DkgPublicKey
+): Promise => {
const encrypter = new Enrico(dkgPublicKey);
const conditionExpr = new ConditionExpression(condition);
- const thresholdMessageKit = await encrypter.encryptMessageCbd(
- toBytes(message),
- conditionExpr
- );
- return {
- thresholdMessageKit,
- threshold,
- ritualId,
- conditionExpr,
- };
+ return encrypter.encryptMessageCbd(toBytes(message), conditionExpr);
};
export const decrypt = async (
provider: ethers.providers.Provider,
- messageKit: TacoMessageKit,
+ messageKit: ThresholdMessageKit,
signer?: ethers.Signer,
porterUri = getPorterUri('tapir')
): Promise => {
+ const ritualId = await DkgCoordinatorAgent.getRitualIdFromPublicKey(
+ provider,
+ messageKit.acp.publicKey
+ );
+ const ritual = await DkgClient.getFinalizedRitual(provider, ritualId);
const decrypter = ThresholdDecrypter.create(
porterUri,
- messageKit.ritualId,
- messageKit.threshold
- );
- return decrypter.retrieveAndDecrypt(
- provider,
- messageKit.thresholdMessageKit,
- signer
+ ritualId,
+ ritual.dkgParams.threshold
);
+ // TODO: What do we do if there are no conditions?
+ if (!messageKit.acp.conditions) {
+ throw new Error('ThresholdMessageKit does not contain conditions');
+ }
+ return decrypter.retrieveAndDecrypt(provider, messageKit, signer);
};
export const taco = {
diff --git a/test/unit/cbd-strategy.test.ts b/test/unit/cbd-strategy.test.ts
index 440fbd1b6..51810e531 100644
--- a/test/unit/cbd-strategy.test.ts
+++ b/test/unit/cbd-strategy.test.ts
@@ -15,8 +15,8 @@ import {
fakeUrsulas,
makeCohort,
mockCbdDecrypt,
- mockGetExistingRitual,
mockGetParticipants,
+ mockGetRitual,
mockGetUrsulas,
mockRandomSessionStaticSecret,
} from '../utils';
@@ -54,7 +54,7 @@ async function makeDeployedCbdStrategy() {
const mockedDkg = fakeDkgFlow(variant, 0, 4, 4);
const mockedDkgRitual = fakeDkgRitual(mockedDkg);
const getUrsulasSpy = mockGetUrsulas(ursulas);
- const getExistingRitualSpy = mockGetExistingRitual(mockedDkgRitual);
+ const getExistingRitualSpy = mockGetRitual(mockedDkgRitual);
const deployedStrategy = await strategy.deploy(provider, ritualId);
diff --git a/test/unit/conditions/condition-expr.test.ts b/test/unit/conditions/condition-expr.test.ts
index 1ef17774a..6941f834d 100644
--- a/test/unit/conditions/condition-expr.test.ts
+++ b/test/unit/conditions/condition-expr.test.ts
@@ -9,7 +9,7 @@ import {
TimeCondition,
TimeConditionProps,
} from '../../../src/conditions/base';
-import { RpcConditionType } from '../../../src/conditions/base/rpc';
+import { RpcConditionType } from '../../../src/conditions/base';
import { USER_ADDRESS_PARAM } from '../../../src/conditions/const';
import { ERC721Balance } from '../../../src/conditions/predefined';
import { objectEquals, toJSON } from '../../../src/utils';
@@ -187,6 +187,12 @@ describe('condition set', () => {
ConditionExpression.fromJSON(conditionExprJson);
expect(conditionExprFromJson).toBeDefined();
expect(conditionExprFromJson.equals(conditionExprFromJson)).toBeTruthy();
+
+ const asWasmConditions = conditionExprFromJson.toWASMConditions();
+ const fromWasmConditions =
+ ConditionExpression.fromWASMConditions(asWasmConditions);
+ expect(fromWasmConditions).toBeDefined();
+ expect(fromWasmConditions.equals(conditionExprFromJson)).toBeTruthy();
});
it('serializes to and from WASM conditions', () => {
diff --git a/test/unit/taco.test.ts b/test/unit/taco.test.ts
index 2158337ef..2648abff9 100644
--- a/test/unit/taco.test.ts
+++ b/test/unit/taco.test.ts
@@ -16,8 +16,9 @@ import {
fakeSigner,
fakeTDecFlow,
mockCbdDecrypt,
- mockGetExistingRitual,
mockGetParticipants,
+ mockGetRitual,
+ mockGetRitualIdFromPublicKey,
mockRandomSessionStaticSecret,
} from '../utils';
@@ -43,9 +44,9 @@ describe('taco', () => {
const mockedDkgRitual = fakeDkgRitual(mockedDkg);
const provider = fakeProvider(aliceSecretKey.toBEBytes());
const signer = fakeSigner(aliceSecretKey.toBEBytes());
- const getExistingRitualSpy = mockGetExistingRitual(mockedDkgRitual);
+ const getExistingRitualSpy = mockGetRitual(mockedDkgRitual);
- const tacoMk = await taco.encrypt(
+ const messageKit = await taco.encrypt(
provider,
message,
ownsNFT,
@@ -58,7 +59,7 @@ describe('taco', () => {
...mockedDkg,
message: toBytes(message),
dkgPublicKey: mockedDkg.dkg.publicKey(),
- thresholdMessageKit: tacoMk.thresholdMessageKit,
+ thresholdMessageKit: messageKit,
});
const { participantSecrets, participants } = fakeDkgParticipants(
mockedDkg.ritualId
@@ -72,15 +73,21 @@ describe('taco', () => {
);
const getParticipantsSpy = mockGetParticipants(participants);
const sessionKeySpy = mockRandomSessionStaticSecret(requesterSessionKey);
+ const getRitualIdFromPublicKey = mockGetRitualIdFromPublicKey(
+ mockedDkg.ritualId
+ );
+ const getRitualSpy = mockGetRitual(mockedDkgRitual);
const decryptedMessage = await taco.decrypt(
provider,
- tacoMk,
+ messageKit,
signer,
fakePorterUri
);
expect(getParticipantsSpy).toHaveBeenCalled();
expect(sessionKeySpy).toHaveBeenCalled();
+ expect(getRitualIdFromPublicKey).toHaveBeenCalled();
+ expect(getRitualSpy).toHaveBeenCalled();
expect(decryptSpy).toHaveBeenCalled();
expect(decryptedMessage).toEqual(toBytes(message));
});
diff --git a/test/utils.ts b/test/utils.ts
index 1ce7ae461..066ee5d61 100644
--- a/test/utils.ts
+++ b/test/utils.ts
@@ -524,12 +524,20 @@ export const fakeDkgRitual = (ritual: {
);
};
-export const mockGetExistingRitual = (dkgRitual: DkgRitual) => {
- return jest.spyOn(DkgClient, 'getExistingRitual').mockImplementation(() => {
+export const mockGetRitual = (dkgRitual: DkgRitual) => {
+ return jest.spyOn(DkgClient, 'getRitual').mockImplementation(() => {
return Promise.resolve(dkgRitual);
});
};
+export const mockGetRitualIdFromPublicKey = (ritualId: number) => {
+ return jest
+ .spyOn(DkgCoordinatorAgent, 'getRitualIdFromPublicKey')
+ .mockImplementation(() => {
+ return Promise.resolve(ritualId);
+ });
+};
+
export const makeCohort = async (ursulas: Ursula[]) => {
const getUrsulasSpy = mockGetUrsulas(ursulas);
const porterUri = 'https://_this.should.crash';
From 19a73b7124ca0d87cff3d6858576ff4e5d50cb08 Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Wed, 6 Sep 2023 11:08:57 +0200
Subject: [PATCH 7/9] update after rebase
---
src/taco.ts | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/taco.ts b/src/taco.ts
index 6ded5a372..7b5e15876 100644
--- a/src/taco.ts
+++ b/src/taco.ts
@@ -45,10 +45,6 @@ export const decrypt = async (
ritualId,
ritual.dkgParams.threshold
);
- // TODO: What do we do if there are no conditions?
- if (!messageKit.acp.conditions) {
- throw new Error('ThresholdMessageKit does not contain conditions');
- }
return decrypter.retrieveAndDecrypt(provider, messageKit, signer);
};
From 1dba09f9ea713e2eca43a5bbe30558d1e889c08b Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Fri, 8 Sep 2023 19:18:55 +0200
Subject: [PATCH 8/9] apply pr suggestions
---
src/agents/coordinator.ts | 4 ++--
src/conditions/context/context.ts | 2 +-
test/unit/conditions/context.test.ts | 8 +++++++-
3 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/src/agents/coordinator.ts b/src/agents/coordinator.ts
index 28ed866cc..3f480e698 100644
--- a/src/agents/coordinator.ts
+++ b/src/agents/coordinator.ts
@@ -120,8 +120,8 @@ export class DkgCoordinatorAgent {
const Coordinator = await this.connectReadOnly(provider);
const dkgPublicKeyBytes = dkgPublicKey.toBytes();
const pointStruct: BLS12381.G1PointStruct = {
- word0: dkgPublicKeyBytes.slice(0, 16),
- word1: dkgPublicKeyBytes.slice(16, 32),
+ word0: dkgPublicKeyBytes.slice(0, 32),
+ word1: dkgPublicKeyBytes.slice(32, 48),
};
return await Coordinator.getRitualIdFromPublicKey(pointStruct);
}
diff --git a/src/conditions/context/context.ts b/src/conditions/context/context.ts
index 0b64cad90..feeeb257c 100644
--- a/src/conditions/context/context.ts
+++ b/src/conditions/context/context.ts
@@ -51,7 +51,7 @@ export class ConditionContext {
);
if (conditionRequiresSigner && !this.signer) {
throw new Error(
- `Cannot use ${USER_ADDRESS_PARAM} as a parameter without a signer`
+ `Signer required to satisfy ${USER_ADDRESS_PARAM} context variable in condition`
);
}
diff --git a/test/unit/conditions/context.test.ts b/test/unit/conditions/context.test.ts
index d87c6291a..dc629c7a5 100644
--- a/test/unit/conditions/context.test.ts
+++ b/test/unit/conditions/context.test.ts
@@ -91,6 +91,10 @@ describe('context parameters', () => {
const condition = new ContractCondition(conditionObj);
const conditionExpr = new ConditionExpression(condition);
expect(conditionExpr.contextRequiresSigner()).toBe(true);
+ expect(conditionExpr.buildContext(provider, {}, signer)).toBeDefined();
+ expect(() => conditionExpr.buildContext(provider, {})).toThrow(
+ `Signer required to satisfy ${USER_ADDRESS_PARAM} context variable in condition`
+ );
});
it('detects if a signer is not required', () => {
@@ -100,6 +104,8 @@ describe('context parameters', () => {
false
);
expect(conditionExpr.contextRequiresSigner()).toBe(false);
+ expect(conditionExpr.buildContext(provider, {}, signer)).toBeDefined();
+ expect(conditionExpr.buildContext(provider, {})).toBeDefined();
});
it('rejects on a missing signer', () => {
@@ -114,7 +120,7 @@ describe('context parameters', () => {
const conditionExpr = new ConditionExpression(condition);
expect(conditionExpr.contextRequiresSigner()).toBe(true);
expect(() => conditionExpr.buildContext(provider, {}, undefined)).toThrow(
- `Cannot use ${USER_ADDRESS_PARAM} as a parameter without a signer`
+ `Signer required to satisfy ${USER_ADDRESS_PARAM} context variable in condition`
);
});
From e1a0cd1508a67765b5e0e9544180c20c08e0aa84 Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Tue, 12 Sep 2023 15:53:00 +0200
Subject: [PATCH 9/9] remove redundant DkgRitualParameters struct
---
src/dkg.ts | 31 +++++++++++++++----------------
src/sdk/strategy/cbd-strategy.ts | 2 +-
src/taco.ts | 2 +-
test/utils.ts | 6 ++----
4 files changed, 19 insertions(+), 22 deletions(-)
diff --git a/src/dkg.ts b/src/dkg.ts
index b907158ad..479213f3e 100644
--- a/src/dkg.ts
+++ b/src/dkg.ts
@@ -3,17 +3,13 @@ import { BigNumberish, ethers } from 'ethers';
import { DkgCoordinatorAgent, DkgRitualState } from './agents/coordinator';
import { ChecksumAddress } from './types';
-import { fromHexString, objectEquals } from './utils';
-
-export type DkgRitualParameters = {
- sharesNum: number;
- threshold: number;
-};
+import { fromHexString } from './utils';
export interface DkgRitualJSON {
id: number;
dkgPublicKey: Uint8Array;
- dkgParams: DkgRitualParameters;
+ sharesNum: number;
+ threshold: number;
state: DkgRitualState;
}
@@ -21,7 +17,8 @@ export class DkgRitual {
constructor(
public readonly id: number,
public readonly dkgPublicKey: DkgPublicKey,
- public readonly dkgParams: DkgRitualParameters,
+ public readonly sharesNum: number,
+ public readonly threshold: number,
public readonly state: DkgRitualState
) {}
@@ -29,7 +26,8 @@ export class DkgRitual {
return {
id: this.id,
dkgPublicKey: this.dkgPublicKey.toBytes(),
- dkgParams: this.dkgParams,
+ sharesNum: this.sharesNum,
+ threshold: this.threshold,
state: this.state,
};
}
@@ -37,13 +35,15 @@ export class DkgRitual {
public static fromObj({
id,
dkgPublicKey,
- dkgParams,
+ sharesNum,
+ threshold,
state,
}: DkgRitualJSON): DkgRitual {
return new DkgRitual(
id,
DkgPublicKey.fromBytes(dkgPublicKey),
- dkgParams,
+ sharesNum,
+ threshold,
state
);
}
@@ -52,7 +52,8 @@ export class DkgRitual {
return [
this.id === other.id,
this.dkgPublicKey.equals(other.dkgPublicKey),
- objectEquals(this.dkgParams, other.dkgParams),
+ this.sharesNum === other.sharesNum,
+ this.threshold === other.threshold,
this.state === other.state,
].every(Boolean);
}
@@ -128,10 +129,8 @@ export class DkgClient {
return new DkgRitual(
ritualId,
DkgPublicKey.fromBytes(dkgPkBytes),
- {
- sharesNum: ritual.dkgSize,
- threshold: ritual.threshold,
- },
+ ritual.dkgSize,
+ ritual.threshold,
ritualState
);
}
diff --git a/src/sdk/strategy/cbd-strategy.ts b/src/sdk/strategy/cbd-strategy.ts
index ed27e24f7..acca9c3f7 100644
--- a/src/sdk/strategy/cbd-strategy.ts
+++ b/src/sdk/strategy/cbd-strategy.ts
@@ -81,7 +81,7 @@ export class DeployedCbdStrategy {
const decrypter = ThresholdDecrypter.create(
porterUri,
dkgRitual.id,
- dkgRitual.dkgParams.threshold
+ dkgRitual.threshold
);
return new DeployedCbdStrategy(decrypter, dkgRitual.dkgPublicKey);
}
diff --git a/src/taco.ts b/src/taco.ts
index 7b5e15876..13034bef7 100644
--- a/src/taco.ts
+++ b/src/taco.ts
@@ -43,7 +43,7 @@ export const decrypt = async (
const decrypter = ThresholdDecrypter.create(
porterUri,
ritualId,
- ritual.dkgParams.threshold
+ ritual.threshold
);
return decrypter.retrieveAndDecrypt(provider, messageKit, signer);
};
diff --git a/test/utils.ts b/test/utils.ts
index 066ee5d61..ec8b1aeee 100644
--- a/test/utils.ts
+++ b/test/utils.ts
@@ -516,10 +516,8 @@ export const fakeDkgRitual = (ritual: {
return new DkgRitual(
fakeRitualId,
ritual.dkg.publicKey(),
- {
- sharesNum: ritual.sharesNum,
- threshold: ritual.threshold,
- },
+ ritual.sharesNum,
+ ritual.threshold,
DkgRitualState.FINALIZED
);
};