UNPKG

@nucypher/taco

Version:

### [`nucypher/taco-web`](../../README.md)

61 lines 4.42 kB
import { AccessControlPolicy, combineDecryptionSharesSimple, DecryptionShareSimple, encryptForDkg, FerveoVariant, SessionStaticSecret, ThresholdDecryptionRequest, ThresholdMessageKit, } from '@nucypher/nucypher-core'; import { DkgCoordinatorAgent, toBytes, } from '@nucypher/shared'; import { arrayify, keccak256 } from 'ethers/lib/utils'; import { ConditionContext } from './conditions/context'; import { DkgClient } from './dkg'; const ERR_DECRYPTION_FAILED = (errors) => `Threshold of responses not met; TACo decryption failed with errors: ${JSON.stringify(errors)}`; const ERR_RITUAL_ID_MISMATCH = (expectedRitualId, ritualIds) => `Ritual id mismatch. Expected ${expectedRitualId}, got ${ritualIds}`; export const encryptMessage = async (plaintext, encryptingKey, conditions, authSigner) => { const [ciphertext, authenticatedData] = encryptForDkg(plaintext instanceof Uint8Array ? plaintext : toBytes(plaintext), encryptingKey, conditions.toCoreCondition()); const headerHash = keccak256(ciphertext.header.toBytes()); const authorization = await authSigner.signMessage(arrayify(headerHash)); const acp = new AccessControlPolicy(authenticatedData, toBytes(authorization)); return new ThresholdMessageKit(ciphertext, acp); }; // Retrieve and decrypt ciphertext using provider and condition expression export const retrieveAndDecrypt = async (provider, domain, porter, thresholdMessageKit, ritualId, context) => { const decryptionShares = await retrieve(provider, domain, porter, thresholdMessageKit, ritualId, context); const sharedSecret = combineDecryptionSharesSimple(decryptionShares); return thresholdMessageKit.decryptWithSharedSecret(sharedSecret); }; // Retrieve decryption shares const retrieve = async (provider, domain, porter, thresholdMessageKit, ritualId, context) => { const ritual = await DkgClient.getActiveRitual(provider, domain, ritualId); const dkgParticipants = await DkgCoordinatorAgent.getParticipants(provider, domain, ritualId, ritual.sharesNum); const conditionContext = context ? context : ConditionContext.fromMessageKit(thresholdMessageKit); const { sharedSecrets, encryptedRequests } = await makeDecryptionRequests(ritualId, conditionContext, dkgParticipants, thresholdMessageKit); const { encryptedResponses, errors } = await porter.tacoDecrypt(encryptedRequests, ritual.threshold); if (Object.keys(encryptedResponses).length < ritual.threshold) { throw new Error(ERR_DECRYPTION_FAILED(errors)); } return makeDecryptionShares(encryptedResponses, sharedSecrets, ritualId); }; const makeDecryptionShares = (encryptedResponses, sessionSharedSecret, expectedRitualId) => { const decryptedResponses = Object.entries(encryptedResponses).map(([ursula, response]) => response.decrypt(sessionSharedSecret[ursula])); const ritualIds = decryptedResponses.map(({ ritualId }) => ritualId); if (ritualIds.some((ritualId) => ritualId !== expectedRitualId)) { throw new Error(ERR_RITUAL_ID_MISMATCH(expectedRitualId, ritualIds)); } return decryptedResponses.map(({ decryptionShare }) => DecryptionShareSimple.fromBytes(decryptionShare)); }; const makeDecryptionRequests = async (ritualId, conditionContext, dkgParticipants, thresholdMessageKit) => { const coreContext = await conditionContext.toCoreContext(); const decryptionRequest = new ThresholdDecryptionRequest(ritualId, FerveoVariant.simple, thresholdMessageKit.ciphertextHeader, thresholdMessageKit.acp, coreContext); const ephemeralSessionKey = makeSessionKey(); // Compute shared secrets for each participant const sharedSecrets = Object.fromEntries(dkgParticipants.map(({ provider, decryptionRequestStaticKey }) => { const sharedSecret = ephemeralSessionKey.deriveSharedSecret(decryptionRequestStaticKey); return [provider, sharedSecret]; })); // Create encrypted requests for each participant const encryptedRequests = Object.fromEntries(Object.entries(sharedSecrets).map(([provider, sessionSharedSecret]) => { const encryptedRequest = decryptionRequest.encrypt(sessionSharedSecret, ephemeralSessionKey.publicKey()); return [provider, encryptedRequest]; })); return { sharedSecrets, encryptedRequests }; }; // Moving to a separate function to make it easier to mock const makeSessionKey = () => SessionStaticSecret.random(); //# sourceMappingURL=tdec.js.map