diff --git a/src/dkg.ts b/src/dkg.ts index 749dae96f..7481f65ce 100644 --- a/src/dkg.ts +++ b/src/dkg.ts @@ -102,21 +102,6 @@ export class DkgRitual { const assumedThreshold = (sharesNum: number): number => Math.floor(sharesNum / 2) + 1; -// TODO: Without Validator public key in Coordinator, we cannot verify the -// transcript. We need to add it to the Coordinator (nucypher-contracts #77). -const participantPublicKeys: Record = { - '0x210eeAC07542F815ebB6FD6689637D8cA2689392': FerveoPublicKey.fromBytes( - fromHexString( - 'ace9d7567b26dafc512b2303cfdaa872850c62b100078ddeaabf8408c7308b3a43dfeb88375c21ef63230fb4008ce7e908764463c6765e556f9b03009eb1757d179eaa26bf875332807cc070d62a385ed2e66e09f4f4766451da12779a09036e' - ) - ), - '0xb15d5A4e2be34f4bE154A1b08a94Ab920FfD8A41': FerveoPublicKey.fromBytes( - fromHexString( - '8b373fdb6b43e9dca028bd603c2bf90f0e008ec83ff217a8d7bc006b585570e6ab1ce761bad0e21c1aed1363286145f61134ed0ab53f4ebaa05036396c57f6e587f33d49667c1003cd03b71ad651b09dd4791bc631eaef93f1b313bbee7bd63a' - ) - ), -}; - export class DkgClient { public static async initializeRitual( web3Provider: ethers.providers.Web3Provider, @@ -209,7 +194,7 @@ export class DkgClient { const validatorAddress = EthereumAddress.fromString(p.provider); // TODO: Replace with real keys // const publicKey = FerveoPublicKey.fromBytes(fromHexString(p.???)); - const publicKey = participantPublicKeys[p.provider]; + const publicKey = DkgClient.getParticipantPublicKey(p.provider); const validator = new Validator(validatorAddress, publicKey); return new ValidatorMessage(validator, p.transcript); }); @@ -217,4 +202,27 @@ export class DkgClient { return aggregate.verify(ritual.dkgSize, validatorMessages); } + + public static getParticipantPublicKey = (address: string) => { + // TODO: Without Validator public key in Coordinator, we cannot verify the + // transcript. We need to add it to the Coordinator (nucypher-contracts #77). + const participantPublicKeys: Record = { + '0x210eeAC07542F815ebB6FD6689637D8cA2689392': FerveoPublicKey.fromBytes( + fromHexString( + 'ace9d7567b26dafc512b2303cfdaa872850c62b100078ddeaabf8408c7308b3a43dfeb88375c21ef63230fb4008ce7e908764463c6765e556f9b03009eb1757d179eaa26bf875332807cc070d62a385ed2e66e09f4f4766451da12779a09036e' + ) + ), + '0xb15d5A4e2be34f4bE154A1b08a94Ab920FfD8A41': FerveoPublicKey.fromBytes( + fromHexString( + '8b373fdb6b43e9dca028bd603c2bf90f0e008ec83ff217a8d7bc006b585570e6ab1ce761bad0e21c1aed1363286145f61134ed0ab53f4ebaa05036396c57f6e587f33d49667c1003cd03b71ad651b09dd4791bc631eaef93f1b313bbee7bd63a' + ) + ), + }; + + const publicKey = participantPublicKeys[address]; + if (!publicKey) { + throw new Error(`No public key for participant: ${address}`); + } + return publicKey; + }; } diff --git a/test/integration/dkg-client.test.ts b/test/integration/dkg-client.test.ts index acb8337b6..ff2150465 100644 --- a/test/integration/dkg-client.test.ts +++ b/test/integration/dkg-client.test.ts @@ -1,18 +1,22 @@ import { SecretKey } from '@nucypher/nucypher-core'; import { DkgCoordinatorAgent } from '../../src/agents/coordinator'; +import { DkgClient } from '../../src/dkg'; import { fakeCoordinatorRitual, fakeDkgParticipants, fakeRitualId, fakeWeb3Provider, + mockGetParticipantPublicKey, mockGetParticipants, + mockVerifyRitual, } from '../utils'; jest.mock('../../src/agents/coordinator', () => ({ DkgCoordinatorAgent: { getRitual: () => Promise.resolve(fakeCoordinatorRitual(fakeRitualId)), - getParticipants: () => Promise.resolve(fakeDkgParticipants(fakeRitualId)), + getParticipants: () => + Promise.resolve(fakeDkgParticipants(fakeRitualId).participants), }, })); @@ -42,13 +46,39 @@ describe('DkgCoordinatorAgent', () => { }); }); -// TODO: Fix this test after the DkgClient.verifyRitual() method is implemented -// describe('DkgClient', () => { -// it('verifies the dkg ritual', async () => { -// const provider = fakeWeb3Provider(SecretKey.random().toBEBytes()); -// -// const dkgClient = new DkgClient(provider); -// const isValid = await dkgClient.verifyRitual(fakeRitualId); -// expect(isValid).toBeTruthy(); -// }); -// }); +describe('DkgClient', () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('verifies the dkg ritual', async () => { + const provider = fakeWeb3Provider(SecretKey.random().toBEBytes()); + const verifyRitualSpy = mockVerifyRitual(); + + const isValid = await DkgClient.verifyRitual(provider, fakeRitualId); + expect(isValid).toBeTruthy(); + expect(verifyRitualSpy).toHaveBeenCalled(); + }); + + it('rejects on missing participant pk', async () => { + const provider = fakeWeb3Provider(SecretKey.random().toBEBytes()); + + await expect(async () => + DkgClient.verifyRitual(provider, fakeRitualId) + ).rejects.toThrow( + 'No public key for participant: 0x0000000000000000000000000000000000000000' + ); + }); + + it('rejects on bad participant pk', async () => { + const provider = fakeWeb3Provider(SecretKey.random().toBEBytes()); + const getParticipantPublicKeysSpy = mockGetParticipantPublicKey(); + + await expect(async () => + DkgClient.verifyRitual(provider, fakeRitualId) + ).rejects.toThrow( + "Transcript aggregate doesn't match the received PVSS instances" + ); + expect(getParticipantPublicKeysSpy).toHaveBeenCalled(); + }); +}); diff --git a/test/utils.ts b/test/utils.ts index f33791cec..76749cf58 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -18,6 +18,7 @@ import { EncryptedTreasureMap, EthereumAddress, ferveoEncrypt, + FerveoPublicKey, FerveoVariant, Keypair, PublicKey, @@ -552,3 +553,13 @@ export const mockVerifyRitual = (isValid = true) => { .spyOn(DkgClient, 'verifyRitual') .mockImplementation((_provider, _ritualId) => Promise.resolve(isValid)); }; + +export const mockGetParticipantPublicKey = (pk = fakeFerveoPublicKey()) => { + return jest + .spyOn(DkgClient, 'getParticipantPublicKey') + .mockImplementation((_address) => pk); +}; + +export const fakeFerveoPublicKey = (): FerveoPublicKey => { + return Keypair.random().publicKey; +};