diff --git a/src/characters/cbd-recipient.ts b/src/characters/cbd-recipient.ts index 97354ff49..9f9b11bd7 100644 --- a/src/characters/cbd-recipient.ts +++ b/src/characters/cbd-recipient.ts @@ -13,7 +13,7 @@ import { import { ethers } from 'ethers'; import { DkgCoordinatorAgent, DkgParticipant } from '../agents/coordinator'; -import { ConditionExpression } from '../conditions'; +import { ConditionContext } from '../conditions'; import { DkgRitual } from '../dkg'; import { PorterClient } from '../porter'; import { fromJSON, objectEquals, toJSON } from '../utils'; @@ -42,13 +42,11 @@ export class ThresholdDecrypter { // Retrieve and decrypt ciphertext using provider and condition expression public async retrieveAndDecrypt( provider: ethers.providers.Provider, - conditionExpr: ConditionExpression, thresholdMessageKit: ThresholdMessageKit, signer?: ethers.Signer ): Promise { const decryptionShares = await this.retrieve( provider, - conditionExpr, thresholdMessageKit, signer ); @@ -59,7 +57,6 @@ export class ThresholdDecrypter { // Retrieve decryption shares public async retrieve( provider: ethers.providers.Provider, - conditionExpr: ConditionExpression, thresholdMessageKit: ThresholdMessageKit, signer?: ethers.Signer ): Promise { @@ -67,15 +64,18 @@ export class ThresholdDecrypter { provider, this.ritualId ); - const contextStr = await conditionExpr - .buildContext(provider, {}, signer) - .toJson(); - const { sharedSecrets, encryptedRequests } = this.makeDecryptionRequests( - this.ritualId, - new Context(contextStr), - dkgParticipants, - thresholdMessageKit - ); + const wasmContext = await ConditionContext.fromAccessControlPolicy( + provider, + thresholdMessageKit.acp, + signer + ).toWASMContext(); + const { sharedSecrets, encryptedRequests } = + await this.makeDecryptionRequests( + this.ritualId, + wasmContext, + dkgParticipants, + thresholdMessageKit + ); const { encryptedResponses, errors } = await this.porter.cbdDecrypt( encryptedRequests, @@ -117,21 +117,21 @@ export class ThresholdDecrypter { ); } - private makeDecryptionRequests( + private async makeDecryptionRequests( ritualId: number, - conditionContext: Context, + wasmContext: Context, dkgParticipants: Array, thresholdMessageKit: ThresholdMessageKit - ): { + ): Promise<{ sharedSecrets: Record; encryptedRequests: Record; - } { + }> { const decryptionRequest = new ThresholdDecryptionRequest( ritualId, FerveoVariant.simple, thresholdMessageKit.ciphertextHeader, thresholdMessageKit.acp, - conditionContext + wasmContext ); const ephemeralSessionKey = this.makeSessionKey(); diff --git a/src/conditions/condition-expr.ts b/src/conditions/condition-expr.ts index 697687088..ee12d7ccb 100644 --- a/src/conditions/condition-expr.ts +++ b/src/conditions/condition-expr.ts @@ -2,7 +2,7 @@ import { Conditions as WASMConditions } from '@nucypher/nucypher-core'; import { ethers } from 'ethers'; import { SemVer } from 'semver'; -import { toBytes, toJSON } from '../utils'; +import { toJSON } from '../utils'; import { Condition } from './condition'; import { ConditionContext, CustomContextParam } from './context'; @@ -13,7 +13,7 @@ export type ConditionExpressionJSON = { }; export class ConditionExpression { - static VERSION = '1.0.0'; + public static VERSION = '1.0.0'; constructor( public readonly condition: Condition, @@ -61,6 +61,10 @@ export class ConditionExpression { return new WASMConditions(toJSON(this.toObj())); } + public static fromWASMConditions(conditions: WASMConditions) { + return ConditionExpression.fromJSON(conditions.toString()); + } + public buildContext( provider: ethers.providers.Provider, customParameters: Record = {}, @@ -78,10 +82,6 @@ export class ConditionExpression { return this.condition.requiresSigner(); } - public asAad(): Uint8Array { - return toBytes(this.toJson()); - } - public equals(other: ConditionExpression): boolean { return [ this.version === other.version, diff --git a/src/conditions/condition.ts b/src/conditions/condition.ts index b16444ef1..26f08618d 100644 --- a/src/conditions/condition.ts +++ b/src/conditions/condition.ts @@ -75,6 +75,6 @@ export class Condition { } public equals(other: Condition) { - return objectEquals(this, other); + return objectEquals(this.toObj(), other.toObj()); } } diff --git a/src/conditions/context/context.ts b/src/conditions/context/context.ts index b32e5a4e1..a71e90d91 100644 --- a/src/conditions/context/context.ts +++ b/src/conditions/context/context.ts @@ -1,8 +1,13 @@ -import { Conditions as WASMConditions } from '@nucypher/nucypher-core'; +import { + AccessControlPolicy, + Context, + Conditions as WASMConditions, +} from '@nucypher/nucypher-core'; import { ethers } from 'ethers'; import { fromJSON, toJSON } from '../../utils'; import { Condition } from '../condition'; +import { ConditionExpression } from '../condition-expr'; import { USER_ADDRESS_PARAM } from '../const'; import { TypedSignature, WalletAuthenticationProvider } from './providers'; @@ -31,7 +36,7 @@ export class ConditionContext { this.validate(); } - public requiresSigner(): boolean { + private requiresSigner(): boolean { return this.conditions.some((cond) => cond.requiresSigner()); } @@ -120,19 +125,35 @@ export class ConditionContext { return parameters; }; - public toJson = async (): Promise => { + public async toJson(): Promise { const parameters = await this.toObj(); return toJSON(parameters); - }; + } - public withCustomParams = ( + public withCustomParams( params: Record - ): ConditionContext => { + ): ConditionContext { return new ConditionContext( this.provider, this.conditions, params, this.signer ); - }; + } + + public async toWASMContext(): Promise { + const asJson = await this.toJson(); + return new Context(asJson); + } + + public static fromAccessControlPolicy( + provider: ethers.providers.Provider, + acp: AccessControlPolicy, + signer?: ethers.Signer + ): ConditionContext { + const conditions = acp.conditions + ? [ConditionExpression.fromWASMConditions(acp.conditions).condition] + : []; + return new ConditionContext(provider, conditions, {}, signer); + } } diff --git a/test/unit/cbd-strategy.test.ts b/test/unit/cbd-strategy.test.ts index 56fc7ddca..bbba1606f 100644 --- a/test/unit/cbd-strategy.test.ts +++ b/test/unit/cbd-strategy.test.ts @@ -132,7 +132,6 @@ describe('CbdDeployedStrategy', () => { const decryptedMessage = await deployedStrategy.decrypter.retrieveAndDecrypt( aliceProvider, - conditionExpr, thresholdMessageKit, aliceSigner ); diff --git a/test/unit/conditions/condition-expr.test.ts b/test/unit/conditions/condition-expr.test.ts index ff53730e1..f7d11fe2c 100644 --- a/test/unit/conditions/condition-expr.test.ts +++ b/test/unit/conditions/condition-expr.test.ts @@ -188,6 +188,13 @@ describe('condition set', () => { expect(conditionExprFromJson.equals(conditionExprFromJson)).toBeTruthy(); }); + it('serializes to and from WASM conditions', () => { + const conditionExpr = new ConditionExpression(erc721BalanceCondition); + const wasmConditions = conditionExpr.toWASMConditions(); + const fromWasm = ConditionExpression.fromWASMConditions(wasmConditions); + expect(conditionExpr.equals(fromWasm)).toBeTruthy(); + }); + it('incompatible version', () => { const currentVersion = new SemVer(ConditionExpression.VERSION); const invalidVersion = currentVersion.inc('major'); diff --git a/test/unit/conditions/context.test.ts b/test/unit/conditions/context.test.ts index 3f0f9e501..124fd3e07 100644 --- a/test/unit/conditions/context.test.ts +++ b/test/unit/conditions/context.test.ts @@ -90,20 +90,16 @@ describe('context parameters', () => { }; const condition = new ContractCondition(conditionObj); const conditionExpr = new ConditionExpression(condition); - const conditionContext = conditionExpr.buildContext(provider, {}, signer); expect(conditionExpr.contextRequiresSigner()).toBe(true); - expect(conditionContext.requiresSigner()).toBe(true); }); it('detects if a signer is not required', () => { const condition = new RpcCondition(testRpcConditionObj); const conditionExpr = new ConditionExpression(condition); - const conditionContext = conditionExpr.buildContext(provider, {}, signer); expect(JSON.stringify(condition.toObj()).includes(USER_ADDRESS_PARAM)).toBe( false ); expect(conditionExpr.contextRequiresSigner()).toBe(false); - expect(conditionContext.requiresSigner()).toBe(false); }); describe('custom method parameters', () => { diff --git a/test/utils.ts b/test/utils.ts index 7a815fc1b..b40e63ae9 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -14,7 +14,6 @@ import { DkgPublicKey, EncryptedThresholdDecryptionResponse, EncryptedTreasureMap, - encryptForDkg, EthereumAddress, FerveoVariant, Keypair, @@ -323,16 +322,8 @@ export const fakeTDecFlow = async ({ threshold, receivedMessages, message, - conditionExpr, - dkgPublicKey, thresholdMessageKit, }: FakeDkgRitualFlow) => { - const [_ciphertext, authenticatedData] = encryptForDkg( - message, - dkgPublicKey, - conditionExpr.toWASMConditions() - ); - // Having aggregated the transcripts, the validators can now create decryption shares const decryptionShares: ( | DecryptionSharePrecomputed @@ -349,7 +340,7 @@ export const fakeTDecFlow = async ({ const decryptionShare = aggregate.createDecryptionShareSimple( dkg, thresholdMessageKit.ciphertextHeader, - authenticatedData.aad(), + thresholdMessageKit.acp.aad(), keypair ); decryptionShares.push(decryptionShare); @@ -362,7 +353,6 @@ export const fakeTDecFlow = async ({ throw new Error('Decryption failed'); } return { - authenticatedData, decryptionShares, plaintext, sharedSecret, @@ -393,7 +383,7 @@ export const fakeDkgTDecFlowE2E = async ( conditionExpr ); - const { decryptionShares, authenticatedData } = await fakeTDecFlow({ + const { decryptionShares } = await fakeTDecFlow({ ...ritual, message, conditionExpr, @@ -405,7 +395,6 @@ export const fakeDkgTDecFlowE2E = async ( ...ritual, message, decryptionShares, - authenticatedData, thresholdMessageKit, }; };