-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Alter PRE-adapted tDec API design for CBD-DKG #166
Comments
ferveo
into the CBD designferveo
into the CBD design
Ritual InitiationWe already have Cohorts and Strategies so this will stay unchanged! import { Cohort, Strategy } from '@nucypher/nucypher-ts';
const config = {
threshold: 3,
shares: 5,
porterUri: 'https://porter-tapir.nucypher.community',
};
const newCohort = await Cohort.create(config);
const newStrategy = Strategy.create(newCohort);
import detectEthereumProvider from '@metamask/detect-provider';
import { providers } from 'ethers';
const MMprovider = await detectEthereumProvider();
const mumbai = providers.getNetwork(80001);
const web3Provider = new providers.Web3Provider(MMprovider, mumbai);
const newDeployed = await newStrategy.deploy('test', web3Provider); The background work will be very different though. This also means that enum RitualState {
NON_INITIATED,
AWAITING_TRANSCRIPTS,
AWAITING_AGGREGATIONS,
TIMEOUT,
INVALID,
FINALIZED
}
|
Another option for Ritual Initiation... We don't handle it within the strategy because this could become restrictive. Instead we just give detailed examples of how to achieve the functionality with standard tools (ethersjs, hardhat, truffle, etc): import { Cohort, CoordinatorABI, CoordinatorAddress } from '@nucypher/nucypher-ts';
const config = {
threshold: 3,
shares: 5,
porterUri: 'https://porter-tapir.nucypher.community',
};
const newCohort = await Cohort.create(config);
const nodes = newCohort.ursulaAddresses;
import { ethers } from "ethers";
const provider = new ethers.providers.Web3Provider(window.ethereum);
const coordinatorContract = new ethers.Contract(CoordinatorAddress, CoordinatorABI, provider);
// currently only connected via provider which is read-only, we need to connect using the signer
const signer = provider.getSigner();
const CoordinatorWithSigner = coordinatorContract.connect(signer);
// initiate ritual
tx = await CoordinatorWithSigner.initiateRitual(nodes); There are similar questions regarding PSS and how that status is handled. |
Another question... Thus |
Currently, |
ferveo
into the CBD designferveo
into CBD
ferveo
into CBD
|
Marking this issue as a blocker for #197 Need further clarity on the design of CBD API in
|
This issue is updated by changes in #210
|
This issue can now be understood as two separate efforts:
|
Notes from #227
|
Some of my notes from observations made while working with
|
Addressed some comments
There are some outstanding talking points related to this issue. Form discussion on Discord:
|
Some more thought after chats with @arjunhassard @derekpierre @cygnusv @manumonti How do we feel about removing some of the objects and taking a more functional approach? Those objects were required before because we carried around state, but that's no longer the case. We're thinking something crazy simple along the lines of: import taco
public_key = # read from Coordinator contract
conditions = # build some conditions
ciphertext = taco.encrypt("plaintext", public_key, conditions, porter_uri) evidence = # generate signature, zk proof, whatever
plaintext = taco.decrypt(ciphertext, ritual_id, evidence, porter_uri) I'm aware that this looks like python not ts, but the idea is the same |
Sounds good to me. Are we still interested in making some of the protocol objects compatible with PRE? Additional thoughts: Do we want to rely on configuration objects, like
|
Do you need to know the cohort here? or can you just encrypt with the But yeah, there's definitely still some state around... |
From my ETHBCN notes (sorry I didn't share this earlier, I thought I did 🙈 ): EncryptEither the creator is blockchainy (which gives them access to the public key from the ritualID by querying the Coordinator): import { taco } from "@thresold-network/taco";
messageKit = taco.encrypt(message, ritualId, web3Provider, conditions) or not (i.e., the creator must know the public key): import { taco } from "@thresold-network/taco";
messageKit = taco.encrypt(message, publicKey, conditions) Decrypt import { taco } from "@thresold-network/taco";
taco.decrypt(messageKit, porterURI, web3Provider) ## Notes
|
Potential iteration based on comments from discussion with @ghardin1314 @derekpierre @jMyles. Mayor changes in debate here:
Encrypt3 possible approaches:
import { taco } from "@thresold-network/taco";
messageKit = taco.encrypt(message, conditions, ritualId, web3Provider, [signer])
import { taco } from "@thresold-network/taco";
messageKit = taco.encrypt(message, conditions, ritualId, porterURI, [signer])
import { taco } from "@thresold-network/taco";
messageKit = taco.encrypt(message, conditions, publicKey, [signer]) Decrypt import { taco } from "@thresold-network/taco";
message = taco.decrypt(messageKit, porterURI, [signer])
Thoughts? |
Thanks for posting this @cygnusv 🎸 !
The approaches do not have to be exclusive, and providing more than one encrypt function is not a bad thing. 1) and 3) are pretty natural based on our API thus far.
Just of note: at this current moment, Porter only connects to the Ethereum network and does not connect to the Polygon network at all, since it never had to previously. Of course, we control the code, and that can be changed if desired. |
I guess, if we are providing 3) which is the lowest common function (and provides the most flexibility), then we would need to provide an API for getting the public key from a ritual Id...? If we are, is that functional or Object-oriented, and does that remove the need for 1)? 1) would just be a convenience method at that point. If functional, something like: publicKey = taco.getPublicKey(ritualId, web3Provider) Or, if object-oriented then something like: coordinator = new Coordinator(web3Provider)
publicKey = coordinator.getPublicKey(ritualId)
... There may be other methods on the object, like Thinking out loud here. |
Not sure exactly the full logic of the signature validation on the Ursula side (do they make an RPC call to verify the block number/hash used?) but does the signature really need to be chain specific? Can all |
Here's the verification function on the Ursula side - https://github.com/nucypher/nucypher/blob/development/nucypher/policy/conditions/context.py#L30. It's basically an For signing the chain id is included in the domain section as part of the EIP712 spec (as it pertains to replay attack). See |
True, but the chainId is mostly used when verifying the signature onchain to avoid cross chain replays. Since this is purely offchain signature verification, it does not really matter what the chainId is (or if there even is one) |
Yep it doesn't really matter, but it does prevent reuse of the signature for other chains - forcing a new signing; unless that's the thing you are looking to avoid... |
Are you actually checking that anywhere though? Like if the Also how does this work with cross/multi chain conditions (which is think are supported or planned to be?) Does Ursula need to verify a signature against each chain with a corresponding Condition? |
I haven't dug into the |
From the link you sent, it looks like the Ursula only checks to see if the signature itself is valid and has no validation about the other parameters passed in. In reality, this is no better than just using a random salt to sign and verify against. Although I'm not sure the extra step of validating the block number/hash is really work the RPC call in this case. Either way, it doesnt seem to me that the signature validation really needs to match the chain in which the conditions refer to |
We can expose a simplified API using existing primitives: 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<TacoMessageKit> => {
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<Uint8Array> => {
return await messageKit.decrypter.retrieveAndDecrypt(
web3Provider,
messageKit.conditions,
FerveoVariant.simple,
messageKit.ciphertext,
false,
);
};
export const taco = {
encrypt,
decrypt,
}; Then, we can selectively expose them if needed: import { Strategy } from "@thresold-network/core"; // common? shared? Alternatively, we can eliminate those primitives either during refactoring to a more straightforward |
That looks pretty good to me generally. Its been a week or so since I looked at this, do you need to deploy a new strategy every time you encrypt something? What exactly are you deploying here? And how would you encrypt using an existing strategy? |
We don't have to deploy a new strategy every time we encrypt something, we can re-use our ritual.
What we're deploying is a new DKG ritual. In case when we're re-using the existing ritual, we still want to run some checks in balances to validate its correctness. Perhaps the notion of "deploying" is not the best description. Or we could use another verb in case of re-using a ritual.
To encrypt using an existing strategy, re-use The code example I shared is just for illustratory purposes, i.e. to show how we could implement that today without changes to the structure of the existing API. I want to iterate on it before we settle on the final design. |
Ah gotcha, I do think |
Closed by #263 |
The text was updated successfully, but these errors were encountered: