-
Notifications
You must be signed in to change notification settings - Fork 2
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
New on-chain registration flow #955
Conversation
This way we can introduce it without breaking everything just yet
This lets us use the count as the derivation path for now.
This lets us change the mapping so that instead of being indexed by verifying key we're not indexing by the signature request account.
The notion of the signature_request_account is meant to be ephemeral, so we don't really need to have registration know anything about this beyond the initial extrinsic.
The CI is failing because Synedrion isn't able to compile to the |
All contributors have signed the CLA ✍️ ✅ |
pallets/registry/src/lib.rs
Outdated
return Err(Error::<T>::JumpStartNotCompleted.into()); | ||
}; | ||
|
||
// TODO (Nando): For a `CountedStorageMap` there is the possibility that the counter |
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.
I'll swap this out with an issue after we go through the review process a bit in case there are discussions around this that pop up
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.
ya also are we not moving from a counter to using the account or is there a possibility we would keep the counter?
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.
There is the possibility we keep the counter, but it would probably be in the context of something like hash(account ID) ++ counter
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.
Opened #984.
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.
💯 looks great.
Only concern i have about using a counter as input is that anybody can know what the next entropy account public key is going to be before it is made. As soon as the network jump starts everyone can know the complete set of all the entropy account public keys there will ever be.
I can't think of a reason why this is bad - but my hunch is that concatenating something from the user (eg: signature request account id and/or program modification account id) to the counter in the derivation path feels safer.
let network_verifying_key = | ||
if let Some(key) = <JumpStartProgress<T>>::get().verifying_key { | ||
SynedrionVerifyingKey::try_from(key.as_slice()) | ||
.expect("The network verifying key must be valid.") |
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.
Did you mean to leave this expect
in? I guess it should be impossible to get into a state where it is invalid
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.
ya def remove it for proper error handling
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 this is intentional. If this expect
is hit it means there's a bug somewhere in the code (we're storing an invalid verifying key), and I would like users to log a report about it.
// down the line. | ||
let count = RegisteredOnChain::<T>::count(); | ||
let path = | ||
bip32::DerivationPath::from_str(&scale_info::prelude::format!("m/0/{}", count)) |
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.
im guessing the m/0
bit is like a version number that we can bump if the derivation process changes?
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.
No, the m/.../...
bit is the actual derivation path.
If you take a look at the graphic here you can see that it's sort of like a namespace. So accounts under m/0/*
are all associated with each other, while those under m/1/*
are distinct from m/0/*
(but associated with each other).
let signature_request_account = ensure_signed(origin)?; | ||
|
||
ensure!( | ||
signature_request_account.encode() != NETWORK_PARENT_KEY.encode(), |
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.
I dont think we need this check anymore, as it was to stop the network parent keyshare getting clobbered by a user keyshare in the kvdb. But here the user has no keyshare to be stored.
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.
yaaaa but this may be one of those I don't know what this could lead to but I have a bad feeling about it not being in here
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 jumpstart PR where this was introduced I mentioned that allowing registration from the parent key could be cool.
While a bit weird, it would allow the network to have a registered account for use on other networks. Maybe it could allow for governance actions on Bitcoin or Ethereum for example. I'd be down to remove this check as long as its cool with both of you
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.
I think leave it in make an issue and this is actually a good retreat topic
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.
Opened #983.
let child_verifying_key = BoundedVec::try_from( | ||
child_verifying_key.to_encoded_point(true).as_bytes().to_vec(), | ||
) | ||
.expect("Synedrion must have returned a valid verifying key."); |
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.
agree that this could never happen but i still kinda don't like having expect
s
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.
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.
Same thing here, this would be a bug on the Synedrion side and I would like a bug report about it instead of "handling" it.
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.
looks good in flow, won't approve till you do negative tests
let signature_request_account = ensure_signed(origin)?; | ||
|
||
ensure!( | ||
signature_request_account.encode() != NETWORK_PARENT_KEY.encode(), |
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.
yaaaa but this may be one of those I don't know what this could lead to but I have a bad feeling about it not being in here
let network_verifying_key = | ||
if let Some(key) = <JumpStartProgress<T>>::get().verifying_key { | ||
SynedrionVerifyingKey::try_from(key.as_slice()) | ||
.expect("The network verifying key must be valid.") |
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.
ya def remove it for proper error handling
pallets/registry/src/lib.rs
Outdated
return Err(Error::<T>::JumpStartNotCompleted.into()); | ||
}; | ||
|
||
// TODO (Nando): For a `CountedStorageMap` there is the possibility that the counter |
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.
ya also are we not moving from a counter to using the account or is there a possibility we would keep the counter?
// down the line. | ||
let count = RegisteredOnChain::<T>::count(); | ||
let path = | ||
bip32::DerivationPath::from_str(&scale_info::prelude::format!("m/0/{}", count)) |
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.
This looks good but what path is the parent key at and we def need to block it, if the parent key is at 0 we need to start the count from 1
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 we use m/0/0
it still ends up with a different private key. From this bip32 website:
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.
true Im fine, should be a really easy test, just one assert statment in the test, probably worth it?
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.
I don't think this is possible as long as some sort of derivation step exists in the extrinsic.
What do you think a test for this should look like though? Would we just check the m/0/0
path, or enumerate all the paths and check those?
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.
just in the positive register test you can take the key you put as the parent network key derived off and assert there is not program data for that, one line no?
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.
That would only check for that specific derivation path used in the test though, e.g m/0/0
. Right now I don't think it's really practical to test for this, but I'll consider it further when making more changes to the actual derivation scheme
let child_verifying_key = BoundedVec::try_from( | ||
child_verifying_key.to_encoded_point(true).as_bytes().to_vec(), | ||
) | ||
.expect("Synedrion must have returned a valid verifying key."); |
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.
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.
add negative tests
@HCastano @JesseAbram - one thing that just occurred to me about this: When we come to do the signing flow, i assume the signature request is going to specify the verifying key, and that to sign a message the threshold server will need to know the derivation path. So we would need a way of looking up what count number a given verifying key has. Maybe |
good point, def the second, the second is magnitudes more simple |
Yeah knowing the public key of an account isn't inherently dangerous. Maybe there are some scenarios where this could be used in some way, but I don't think it's any different from having access to a vanity generator (e.g if you want an account like
You're right here, and it's something I was going to deal with in the signing flow PRs. |
This PR adds a new extrinsic,
Registry::register_on_chain()
, which uses the new childkey derivation feature in Synedrion in order to simplify the registration process.
Since we can derive a child verification key from a parent verification key, all we need
to do for user registration is derive a user's key from the network key and store it
on-chain (alongside some program info). We don't need to reach out to the TSS to do any
cryptographic operations for us.
This PR is the first of a few that will be required to fully integrate the new
registration flow. In follow up PRs I plan to:
coverage
Closes #961.