diff --git a/src/taco.ts b/src/taco.ts new file mode 100644 index 000000000..69d90525f --- /dev/null +++ b/src/taco.ts @@ -0,0 +1,52 @@ +import { Ciphertext } from '@nucypher/nucypher-core'; +import { ethers } from 'ethers'; + +import { makeCohort } from '../test/utils'; + +import { ThresholdDecrypter } from './characters/cbd-recipient'; +import { ConditionExpression } from './conditions'; +import { CbdStrategy } from './sdk/strategy/cbd-strategy'; + +export interface TacoMessageKit { + ciphertext: Ciphertext; + aad: Uint8Array; + decrypter: ThresholdDecrypter; + conditions: ConditionExpression; +} + +export const encrypt = async ( + message: string, + conditions: ConditionExpression, + ritualId: number, + web3Provider: ethers.providers.Web3Provider, +): Promise => { + const cohort = await makeCohort([]); + const strategy = CbdStrategy.create(cohort); + const deployedStrategy = await strategy.deploy(web3Provider, ritualId); + const { ciphertext, aad } = deployedStrategy + .makeEncrypter(conditions) + .encryptMessageCbd(message); + + return { + ciphertext, + aad, + decrypter: deployedStrategy.decrypter, + conditions, + }; +}; + +export const decrypt = async ( + messageKit: TacoMessageKit, + web3Provider: ethers.providers.Web3Provider, +): Promise => { + return await messageKit.decrypter.retrieveAndDecrypt( + web3Provider, + messageKit.conditions, + messageKit.ciphertext, + ); +}; + +export const taco = { + encrypt, + decrypt, +}; diff --git a/test/unit/taco.test.ts b/test/unit/taco.test.ts new file mode 100644 index 000000000..caa9f7524 --- /dev/null +++ b/test/unit/taco.test.ts @@ -0,0 +1,93 @@ +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, + fakeTDecFlow, + fakeUrsulas, + fakeWeb3Provider, + mockCbdDecrypt, + mockGetExistingRitual, + mockGetParticipants, + mockGetRitualState, + mockGetUrsulas, + 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 ursulas = fakeUrsulas(); +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 getUrsulasSpy = mockGetUrsulas(ursulas); + const getExistingRitualSpy = mockGetExistingRitual(mockedDkgRitual); + + const tacoMk = await taco.encrypt( + message, + conditionExpr, + mockedDkg.ritualId, + web3Provider + ); + + expect(getUrsulasSpy).toHaveBeenCalled(); + 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 mockGetRitualStateSpy = mockGetRitualState(); + const getParticipantsSpy = mockGetParticipants(participants); + const getUrsulasSpy2 = mockGetUrsulas(ursulas); + const sessionKeySpy = mockRandomSessionStaticSecret(requesterSessionKey); + + const decryptedMessage = await taco.decrypt(tacoMk, web3Provider); + expect(mockGetRitualStateSpy).toHaveBeenCalled(); + expect(getUrsulasSpy2).toHaveBeenCalled(); + expect(getParticipantsSpy).toHaveBeenCalled(); + expect(sessionKeySpy).toHaveBeenCalled(); + expect(decryptSpy).toHaveBeenCalled(); + expect(decryptedMessage).toEqual(toBytes(message)); + }); +});