-
Notifications
You must be signed in to change notification settings - Fork 272
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
DKG Authorization Models #3050
Comments
This seems like a subset of a bigger issue: #3080 I also think we can assume condition freeloading is a much more niche issue than DKG initialization ritual freeloading (i.e. with your own unique conditions but some other adopter's cohort). |
Some thoughts on this... DKGPermissionlessAnyone can initialize a ritual and network nodes must comply. This may lead to #3102 PermissionedWe can build a simple payment-checking mechanism on Ursula by using the ritual ID/initiator address to check for payment or other authorization logic. A simple example: the initiator pays nodes directly or has paid for services via contract. Threshold DecryptionPermissionlessIt does not matter who uses the service to encrypt or decrypt as long as nodes are paid for the ritual by someone somehow. PermissionedThink "API Keys". Only authorized Enricos can encrypt. It is possible to authorize only particular enricos to encrypt by taking advantage of ferveo's AAD as a signed token and publishing authorized keys onchain for node evaluation.
attack surface
drawbacks
|
Approach 1. Signed tokens
An alternative design doesn't designate an Enrico PK when producing the signed token, which on the one hand makes Enrico's life easier (doesn't need a keypair, doesn't need to sign the ciphertext), but on the other hand, makes possible for Bob to reuse the signed token. Approach 2. Smart contractI describe here a generic approach that generalizes @KPrasch's message above, but that could be used in different ways:
function isEnricoAuthorized(uint256 ritualID, bytes evidence, bytes ciphertextHash) public view returns(bool);
|
After re-reading @jMyles's original post, and considering also #3080, I think this problem has two independent dimensions, which in the end boil down to two questions:
Wrt to my previous comment, just want to point out that both proposed approaches assume that Alice indeed cares about someone else using her cohort, and both approaches could be applied to either "Alice decides" or "Enrico decides". If Alice doesn't care about free-riding, then there's no point in restricting Enricos. |
On free-riding: A purist microeconomics viewpoint would rule out launching a non-excludable service, i.e. where there's no mechanism to prevent open and unpaid usage. An interesting example from the past; Prysm were concerned that Ursulas who received re-encryption requests after the threshold had already been met (i.e. via sequential node discovery), wouldn't bother to answer at all. We rejected that particular 'audit finding' because the effort and risk associated with client code modification outweighed any nano-benefit gainable by circumventing a cheap local operation. Is that similar to this problem? Will the world simply use paid-for Strategies to the detriment of 'honest' adopters? I'm not sure. At the very least, it could be premature optimization for v7.0.0. The first few CBD versions will restrict the number of public keys that one can encrypt to. This means a whitelist of adopting projects will unilaterally control the parameters associated with a given cohort of nodes. Eventually, we hope they will cede some of that control to their users/DAO/SCs. Regardless, free-riding – i.e. encrypting real data to one of those available public keys, outside of the context of the app/DAO that controls it, carries highly unpredictable long-term risk: On closer inspection, it is irrational for any project/application/system/adopter that handles 'real' user data to take on these risks. Certain use cases cannot accommodate, for logistical or trust reasons, underlying data being decrypted and encrypted again to a new public key. Any application which intends to grow their user base beyond testers, and understands the massive potential downside of (i-iii) above, is unlikely to free-ride. This is particularly true because the savings – i.e. the upsides of free-riding – are near-negligible. For those just hacking on CBD – where there is no objective of heavy end-usage – free-riding may indeed occur. We could even encourage it along with some strongly-worded caveats re: risks (i-iii). But low throughput free-riding is non-rivalrous, inasmuch as the extra operations lumped on Ursulas aren't going to affect their computational overhead, and therefore will have no detrimental effect on the network, nor the 'honest' adopters who paid. Free-riding protections may therefore be superfluous until we modify the coordinator contract to allow permissionless cohort generation – i.e. when operator replacement is economically sustainable for stakers. Although, even then, risks (i-iii) still apply! |
I think this is an argument for introducing Enrico-level authorization, as it can serve as a place to introduce a payment gate. It would be good then to, at least, future-proof this option (e.g., introducing free Enrico authorization from start).
This is true if we assume that cohort "owners" are willing to pull the plug at some point, but I don't think that's a good assumption because, ideally, adopters will be locked-in to their cohorts since their own service is tied to the set of public keys associated to these cohorts (as you mention in point (i) above). In other words, if CBD doesn't include a solution to dinamically and selectively (de)authorize Enricos from start, free-riders "only" need to choose cohorts that seem long-term, from likely-stable adopters, and if/when these adopters change their mind wrt to the free-riding problem, they wouldn't have any recourse going forward. Again, I see this more as a future-proofing thing, than anything else. |
By the way, from a future-proofing perspective, I think Approach #2 here is superior, and would be relatively easy to implement. |
Here's a take on a specification from @theref @cygnusv and I: changes
User Stories
|
Good stuff 🎸 : Apologies if some of these questions were already previously addressed:
|
I guess I have some economic questions in there - not sure if there is a separate issue for that. The last point on Enrico is a question based on your earlier specification comment. |
Q1 - good question, and is up for debate |
I propose, always used. Not additionally, but primarily.
Good question. At least the way I understand it, adopters are paying for the ability to authorize Enricos as they please. Perhaps they have their own business logic around authorizing their users but ultimately, yes. If the adopter wants to authorize one of their users "for free" (in their own domain) and have already paid for CBD usage - they can just add a new address to the ritual's allow list.
Yes, but only once. but I'd reframe this as "adopters pay for the ability to authorize/deauth enricos as they please". Of course, there will still be a transaction gas fee for adding new keys to a rituals allow list.
@theref and I discussed using different cryptosystems for authorization artifacts - I assert that using an ethereum wallet is the lightest, most interoperable, and friendly UX. An enrico that runs in the browser can simply use metamask or another browser wallet. Otherwise we'd need some key management mechanisms for an alternate cryptosystem. Plus, we can use an ethereum signing standard, and there is native strong typing for addresses in solidity. |
(1) The gas cost of a adding every single new end-user device/wallet to the Enrico allowlist may be an economic friction for certain use cases, to the point that some adopters may not bother to use the allowlist – especially given the previously discussed risks of free-riding for apps of any significance. Hence to @derekpierre’s point, it may be better as an opt-in facility (or at least comes with an easy opt-out). Of course it depends on (i) the GWEI cost per Enrico and (ii) how volatile MATICUSD is going forward. But eventually there will be an adopter for which this is a non-starter – like a Telegram clone with very large group chats or IOT network with thousands of new sensors frequently added and removed. It would be a different matter if we controlled this price point completely (i.e. beyond contract optimization), because we could tune it to adopters’ budgets. For example, the total number of decryption requests covered by a sponsor would in most cases increase with an expanding user base, but there’s no unpredictable third-party cost. (2)
This is a good way of phrasing it, but it may be premature to configure a payment gate here during the invite-only era, since by controlling ritual initialization we are de facto controlling who can use the AccessController contract – and the duration-based fee easily covers nodes’ out-of-pocket expenses – see calculations in discord (Fees thread). Is this ultimately a question of trusting genesis adopters not to abuse the AccessController contract? (3)
With an explicit mapping of a ritual ID to the Enrico address allowlist, is there a way to decouple ritual authority from sponsorship and associated powers? We don’t know ex ante the order of power devolution by adopters. Initially, the developers integrating TACo will be trusted by their users with:
|
(1) For use cases with large numbers of enricos being added/removed, there are better storage solutions. Both Arweave and IPFS would both be cost efficient for this case. Obviously there is development work that would need to be done to allow that functionality, but this is perfectly feasable (3) Sometimes I'm getting lost in terminology, we came up with some preliminary entities whilst brainstorming. I'll throw them here.
Authoriser and Initiator/Owner could be decoupled if we wanted. The Initiator sets the authoriser during the ritual initialisation process, but after that, only the Authoriser has the power to change the Authoriser (ie, send the power to another entity)
|
@theref Thanks for the quick and useful answer. On (1) – if I haven't misunderstood, this would be adopters bundling new Enricos, storing a list of their IDs on some persistent storage, and creating + posting an on-chain reference to that list (hash), that Ursulas go and check when pinged with ciphertexts – thereby reducing the gas cost per Enrico by some multiple. In some cases this would be very helpful, but not when new devices need to be able to encrypt immediately, so they can't be queued up until some threshold of Enricos is reached. Even for a few minutes would be unacceptable UX in many apps. Also new Enricos joining is unpredictable – although I suppose there could be a maximum queue time regardless of list length. (3) Very clear and logical hierarchy. The only adjustment I would suggest is; although the Initiator is indeed NuCypher in v7, we need all three roles/powers (Initatior, Owner & Authorizer) to be transferred to the adopter right after each initialization, or we undermine our claim that v7 is decentralized from genesis. It needs to be 'day one decentralized' inasmuch as the first byte of data encrypted is being managed multilaterally, but maybe not 'minute one decentralized' inasmuch as the initialization is a trusted setup, with immediate power devolvement (i.e. before the first encryption event!)*. Re: open payments, that's fine as long as random payments don't (unintentionally) confer Authorizer power to random payers. *Acknowledging that this transfer moves power from NuCypher to another central authority, but (1) the core, user-facing component of the service – access – is fully decentralized and (2) symbolically and practically its carries a lower trust burden compared to NuCypher retaining any of these three powers, because we have more power over the DAO and the contracts than an adopter, so this transfer is a genuine spreading out of censoring power. |
(1) Nah you can do it way faster than that. Especially with arweave which allows tagging. So you store a tag onchain, then look for all transactions on arweave that a) contain the tag, b) were sent by the authoriser. Adding a new enrico is then super quick and cheap (potentially free because it's such a small amount of data, i think tx under 100kb are free on arweave). But we can definitely look into this further when adopters need it. Also, as long as decryption isn't also happening immediately, there's nothing stopping Enrico just cracking on with encryption and the authorisation coming a little later (unless we plan to implement some timestamping at encryption time). (3) Yes, totally agree that all power needs to be transferred immediately in v7. Ideally Initiation should be done with the adopter present I think :) |
From Barcelona in-person discussions:
|
Excellent example of a custom allow logic contract from @jdbertron (comment in fee + rollout RFC)
|
Personally I like this approach the best. For each ritual creation, the initiator would pass an For a higher throughput of Enricos where it is infeasible to store every address on chain (or Enricos dont have a key pair), potentially you could support something like this: https://eips.ethereum.org/EIPS/eip-3668 Where the |
Continuing the iteration on Approach#2, currently being implemented nucypher/nucypher-contracts#89: function isAuthorized(
uint32 ritualID,
bytes memory evidence, // signature
bytes memory digest // signed message hash
) external view returns(bool); Let's see how 3 different authorization mechanisms could be implemented pursuant to this interface (I'm being very loose with the code here, so please bear with me). These 3 examples assume the creator has an ECDSA keypair, and in all of them they sign a digest of the Ferveo Ciphertext (specifically, of the "thin" format, see nucypher/ferveo#147 (comment)). In pseudo-code: digest = keccak(thin_ferveo_ciphertext)
signature = sign(creator_private_key, digest) On-chain allowlistLet's assume that function isAuthorized(
uint32 ritualID,
bytes memory evidence,
bytes memory digest
) external view returns(bool){
v, r, s = vrs_decode(evidence);
address creator = ecrecover(digest, v, r, s);
return allowlist[ritualID][creator];
} Merkle Tree allowlistInstead of adding individual creators to the contract, the authorizer creates a Merkle Tree (thanks @ghardin1314 for the idea). Let's assume that the Merkle tree is implemented with OpenZeppelin, where each leaf is an authorized address and the authorizer sets a global root, and that function isAuthorized(
uint32 ritualID,
bytes memory evidence,
bytes memory digest
) external view returns(bool){
signature, proof = parse_evidence(evidence)
v, r, s = vrs_decode(signature);
address leaf = ecrecover(digest, v, r, s);
return MerkleProof.verify(proof, root, bytes32(leaf));
} NFT AuthorizationLet's assume that function isAuthorized(
uint32 ritualID,
bytes memory evidence,
bytes memory digest
) external view returns(bool){
v, r, s = vrs_decode(evidence);
address creator = ecrecover(digest, v, r, s);
return ERC721.balanceOf(creator) > 0;
} It seems all of them can be accommodated to the interface. A question that you may have is why the creator always signs a hash of the thin ciphertext: there may be other approaches, but signing the ciphertext ensures that it's not possible to perform signature stripping, since we have to assume that MessageKits are public (at the very least, the consumer and the nodes will see it). We need to sign something unique to the request, and the ciphertext is the best representative of the request. |
Closed via #3226. |
As we determine whether Alice pays on a usage model, a subscription model, or both - ie:
#3057
...we also need to define how Enrico has standing to adhere conditions to a ciphertext of his making.
We don't want: a single Alice to make an "open" Strategy (meaning, without defined parameters for condition adherence), and for any Enrico to then be able to make ciphertexts with conditions of his choosing - because then, the whole world will simply use that Strategy-Cohort.
So, two types of relationship emerge:
Alice authors condition parameters and makes them broadly available. For example, Alice can author seven different conditions, hash them individually, and place them on-chain (perhaps using proto-danksharding or something).
Alice specifically authorizes, via an access token, label-derivation scheme, allowlist, or some other mechanism, particular Enrico configurations which have standing to author and adhere conditions under the auspices of her funding.
The text was updated successfully, but these errors were encountered: