-
Notifications
You must be signed in to change notification settings - Fork 11
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
TACo Encryption Allow Logic Interfaces #89
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good! Some preliminar comments.
bytes memory evidence, | ||
bytes memory ciphertextHash | ||
) public view override returns(bool) { | ||
address enricoAddress = address(uint160(bytes20(evidence))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An address can't be the evidence, otherwise anyone can put any address there. The evidence was defined as a signature, so what we want here is to do something like:
address enricoAddress = ecrecover(ciphertextHash, v, r, s)
where v, r, s
are somehow extracted from the signature evidence
, and ciphertextHash
should be somehow casted to bytes32 (what ecrecover
expects). See https://docs.soliditylang.org/en/latest/cheatsheet.html#mathematical-and-cryptographic-functions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@theref and I considered recovering the address on-chain via ECDSA, however in the case of the AllowList
for example, the only way an address can be "authorized" is by Ritual.authority
setting it in a permissioned way. In other words, only the ritual's authority can add new enricos. Are we missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's say the authority authorizes 0x1234
. I don't own that address, but I just write 0x1234
as evidence when creating the conditions and access control policy. Ursulas would accept this evidence and that's not what we want. We need to provide evidence
that I own that address.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If enricos are submitting a signature of the ciphertext and policy, doesn't that mitigate the issue you indicate (as enrico cannot simply "write 0x1234
as evidence")?
Ursula can recover the address from the signature provided in AccessControlPolicy.authorization
and check that it's in the allow list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If enricos are submitting a signature of the ciphertext and policy, doesn't that mitigate the issue you indicate (as enrico cannot simply "write
0x1234
as evidence")?
Yes, that's what I suggested initially.
Ursula can recover the address from the signature provided in
AccessControlPolicy.authorization
and check that it's in the allow list.
Right, what I'm saying is that what you called AccessControlPolicy.authorization
is what must be submitted as evidence
by Ursula. That's what I originally meant by the evidence is attached to the ciphertext.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, not sure I'm following - why "must" that be the case?
Is there a problem with trusting ursula to perform a valid signature recovery from AccessControlPolicy.authorization
?
Is that different than trusting ursula to perform a valid condition evaluation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another way of framing it: What is the advantage of doing an authorization signature recovery onchian vs. in Ursula's runtime?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main advantage I see is that this allows for modular and pluggable evidence evaluation mechanisms (via smart contracts), without having to change Ursula's code
import "./Coordinator.sol"; | ||
|
||
|
||
contract AllowList is AccessControlDefaultAdminRules, IAccessController { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you don't plan to use role management functions, AccessControl
may be enough.
0be3cf3
to
e5e8a05
Compare
@KPrasch I think you've overwritten some work here, I'll push to another branch so that we can compare |
"Only ritual authority is permitted"); | ||
require(coordinator.isRitualFinalized(ritualID), | ||
"Only active rituals can add authorizations"); | ||
for (uint i=0; i<addresses.length; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (uint i=0; i<addresses.length; i++) { | |
for (uint256 i=0; i < addresses.length; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✔️
"Only ritual authority is permitted"); | ||
require(coordinator.isRitualFinalized(ritualID), | ||
"Only active rituals can add authorizations"); | ||
for (uint i=0; i<addresses.length; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (uint i=0; i<addresses.length; i++) { | |
for (uint256 i=0; i < addresses.length; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✔️
@@ -184,11 +198,15 @@ contract Coordinator is AccessControlDefaultAdminRules { | |||
return ritual.participant; | |||
} | |||
|
|||
function initiateRitual( | |||
function _initiateRitual( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we walk back this change i.e. change _initiateRitual
-> initiatRitual
and remove the function on L254, since the params are now the same?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✔️
@@ -359,13 +391,13 @@ contract Coordinator is AccessControlDefaultAdminRules { | |||
} | |||
|
|||
function getParticipantFromProvider( | |||
uint256 ritualID, | |||
uint32 ritualID, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be consistent with our camel-case (other spots as well - L400 and L412)?
uint32 ritualID, | |
uint32 ritualId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✔️
require(coordinator.getAuthority(ritualID) == msg.sender, | ||
"Only ritual authority is permitted"); | ||
require(coordinator.isRitualFinalized(ritualID), | ||
"Only active rituals can add authorizations"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to turn these requires into one of those solidity modifiers like onlyOwner
etc., in this case onlyAuthorityForActiveRitual
or something like that...
It can be used for authorizing and deauthorizing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✔️
@@ -93,49 +93,93 @@ def coordinator(project, deployer, stake_info, flat_rate_fee_model, initiator): | |||
return contract | |||
|
|||
|
|||
@pytest.fixture() | |||
def global_allow_list(project, deployer, coordinator): | |||
contract = project.GlobalAllowList.deploy( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add tests (maybe not in this file) for the actual GlobalAllowList
contract?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, certainly. I intend to push new tests before merging, but still want to get a review in the meantime 👍🏻
@@ -0,0 +1,9 @@ | |||
pragma solidity ^0.8.0; | |||
|
|||
interface IRitualAuthorizer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Nice!
coordinator = _coordinator; | ||
} | ||
|
||
function isAuthorized( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the DKG client supposed to call this method at some point? Fore example, when picking nodes for the DKG cohort?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not when picking nodes for the cohort but rather when decryption is requested from the nodes. Each node that receives a decryption request will check to make sure that this encryptor is allowed to use the corresponding ritual/encrypting key and therefore worthy to be decrypted. This is showcased in WIP PR 3194 - see https://github.com/nucypher/nucypher/pull/3194/files#diff-8df83dacf71b2ff2ca3636cd470cba70eb6b141e3c8843fadfab72514aafa3f6R199 and https://github.com/nucypher/nucypher/pull/3194/files#diff-911a370c18d0d0e3ea62099fc5ff6daa16915da19cf5399f24e404b7d8d6d168R790
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! My main comment is regarding how hash within the authorization check is performed and the lack of tests for that.
@@ -9,6 +9,8 @@ import "./IFeeModel.sol"; | |||
import "./IReimbursementPool.sol"; | |||
import "../lib/BLS12381.sol"; | |||
import "../../threshold/IAccessControlApplication.sol"; | |||
import "../../../../nucypher/tests/acceptance/contracts/.cache/openzeppelin/v4.8.1/access/IAccessControl.sol"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How many headaches you gave us in Barcelona...
// TODO: restrict to ritualID < rituals.length? | ||
return getRitualState(rituals[ritualId]); | ||
} | ||
|
||
function isRitualFinalized(uint32 ritualId) external view returns (bool){ | ||
return getRitualState(rituals[ritualId]) == RitualState.FINALIZED; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a comment for this PR, but something to consider I just realized: we may need to discern if a covenant is currently active or not, depending whether it's within its arranged duration or not. The fact that the ritual is FINALIZED
is a prerequisite for that to happen, of course. I can address that in #107
import "./IRitualAuthorizer.sol"; | ||
import "./Coordinator.sol"; | ||
|
||
contract GlobalAllowList is AccessControlDefaultAdminRules, IRitualAuthorizer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After re-reading this PR, I think a more descriptive name for the interface is IEncryptionAuthorizer
, and subsequently the contract could be GlobalEncryptionAllowList
(although not as necessary if the interface is renamed).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✔️
|
||
function setCoordinator(Coordinator _coordinator) public { | ||
require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Only admin can set coordinator"); | ||
coordinator = _coordinator; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the use case for setting the Coordinator after deployment, if it was already set on construction time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the event the coordinator is redeployed to support a security patch or new feature.
bytes memory evidence, | ||
bytes memory digest | ||
) public view override returns(bool) { | ||
address recovered_address = keccak256(digest) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If digest
is already a digest, there should be no need to call keccak256
. Related to this is the lack of tests for this method. Maybe we can just put a pin on this for the moment and revisit in a separate PR, but something needs to be done here.
…tuals use a default authorization contract deployemnt (AllowList). Co-authored-by: James Campbell <james.campbell@tanti.org.uk> Co-authored-by: Kieran Prasch <kieranprasch@gmail.com>
…ual initialization
Thanks for all of the reviews and suggestions on this PR. I introduced some new tests and covered every RFC. Let me know if there's anything else before merging. If you've already reviewed, perhaps just skim the new commits. 🤠 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎸
Implements the contracts from the specification.
Co Authored By @theref @cygnusv @jMyles @derekpierre
Based over #86