Secure Message Delivery initial changes #1714
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.
Looks good a couple of comments.
Mostly can we test the new code?
src/chain/bls_emu.rs
Outdated
|
||
impl fmt::Debug for PublicKey { | ||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | ||
write!(formatter, "[BLS PublicKey]") |
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.
Maybe use the SectionInfo debug value 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.
Right. This was pre-SectionInfo, but it makes sense now 👍
src/chain/shared_state.rs
Outdated
|
||
#[derive(Clone, PartialEq, Eq)] | ||
pub struct SectionProofBlock { | ||
key: PublicKey, |
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.
Would it make sense as BlsPublicKey and BlsSignature?
I'm thinking having 2 different crypto keys/signature will cause confusion if we are not explicit.
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 was kind of aiming for a drop-in replacement of BLS. With these names, we can just replace use bls_emu::...
with use threshold_crypto::...
and it should (mostly) just work. I can use bls_emu::PublicKey as BlsPublicKey
etc., though.
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, could also do that at the crate level in lib.rs so you only do it once and then use crate::{BlsPublicKey, ...}
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 to me.
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
pub struct PublicKeyShare(PublicId); | ||
|
||
#[derive(Clone, PartialEq, Eq)] | ||
pub struct Signature { |
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.
shall the name of the struct to be Signatures
?
Also, as it only contains one field, shall it be Signatures(BTreeMap<PublicId, SignatureShare>)
?
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 struct is supposed to emulate the BLS Signature
type, hence it's singular - with BLS, this would be indeed just a single signature, here we just emulate the functionality using a set of signatures.
I could make it a tuple struct, though.
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.
Quite happy with the struct with a name as it is personally.
} | ||
|
||
#[derive(Clone, PartialEq, Eq)] | ||
pub struct PublicKey(PublicKeySet); |
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 got little bit confused with the first glance of this PublicKey(PublicKeySet)
.
Also, the name of the file is bls_emu.rs
.
However the comment at #1714 (comment) mentioned BlsPublicKey
as well for the shared state.
I am not sure, however shall we use Bls...
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.
Like with Signature
- this is an emulated implementation of threshold_crypto::PublicKey
. I want to keep the names the same as they are in threshold_crypto
, so that when we merge BLS, we can just replace this module with threshold_crypto
crate and keep the rest of the code mostly intact.
In this case, we would replace this in lib.rs
:
pub use crate::chain::bls_emu::PublicKey as BlsPublicKey;
with this:
pub use threshold_crypto::PublicKey as BlsPublicKey;
when BLS is merged.
|
||
pub fn from_section_info(threshold: usize, sec_info: SectionInfo) -> Self { | ||
Self { | ||
threshold, |
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 wondering, can the threshold be deduced from the section info?
and in which case the threshold can be un-related to the section info?
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 our use cases, it probably can - but I wanted to keep the code as generic as possible. This part probably won't make it to the code after BLS is merged, so maybe coupling the threshold with the section info here is not such a bad idea. What do you think @jeanphilippeD ?
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 guess you can make that function non public as well.
Since it is code that is going to go away, I'd go for whatever is simpler.
It seem it may be simplifying code & test if you use your delivery_group function inside it instead of taking the threshold param? would 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.
(as in you are using in in PublicKey, so why not moving it into PublicKeySet?)
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.
Yeah, I originally wanted to calculate the threshold completely outside this module to make the functionality boundaries more clear (BLS won't be aware of our threshold requirements, we'll have to pass it the threshold we want explicitly), but then I did this thing in PublicKey
. I'm not sure which is better - make the method in PublicKey
also take the threshold from outside, or just move this into PublicKeySet
. Might be that it's the latter, as this code won't work with real BLS, anyway (we won't be able to derive keys from SectionInfo
s, we'll have to get them from DKG).
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.
Correct me if I'm wrong, but we will not pass the threshold to either signature or public key, only the DKG.
The way we'll know we reach the threshold is if the combined signature is valid against the public key.
If anything, we would use the threshold directly in the signature validation. But where it is fine too (i.e pre-computed once and cached). and I don't want us spend too much time on something that is going to be disappearing soon-ish :-)
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.
(also I still assume we'll have to fix stuff when moving to real BLS).
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, I think you're right - the threshold is passed to the DKG, then it is actually stored in the resulting PublicKeySet
IIRC (it has to know what the degree of the polynomial needs to be when combining the signatures).
.map(|(pk, ss)| (pk.0, *ss)) | ||
.collect(); | ||
if sigs.len() <= self.threshold { | ||
None |
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 name of the function is combine
, however here seems a threshold screening
?
if it's really required, would it be better to at least have a comment to explain?
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 emulates threshold_crypto::PublicKeySet::combine_signatures
, which can only succeed if there are more than threshold
valid signatures. Again, the reason here is the emulation of BLS functionality. I can add a comment 👍
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.
yeah, pls add a comment then. thx
src/chain/bls_emu.rs
Outdated
impl PublicKey { | ||
pub fn from_section_info(sec_info: &SectionInfo) -> Self { | ||
let threshold = delivery_group_size(sec_info.members().len()) - 1; | ||
PublicKey(PublicKeySet::from_section_info(threshold, sec_info.clone())) |
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.
as mentioned above, I'd prefer the threshold to be calculated inside the PublicKeySet::from_section_info
function.
self.blocks.push(block); | ||
} | ||
|
||
#[allow(unused)] |
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 this function is only to be used during test, shall we use cfg(test)
guard instead of the allow(unused)
?
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.
It's only used in tests now, but it is intended to be used in production code as well in the future - it will probably be useful during verification of chains attached to messages.
let mut current_pk = &self.genesis_pk; | ||
for block in &self.blocks { | ||
if !block.verify_with_pk(current_pk) { | ||
return false; |
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.
maybe log some info about which block fails the verification?
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 kind of message would you have in mind, though? The blocks don't really contain any meaningful data that would make it easier to identify the offender - it's a public key and a signature, neither is very readable.
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.
maybe the public key (which is a public id)?
In case of failure, we need to find out who is failing anyway, right?
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 public key here is more of a set of public IDs, not a single one - and it actually contains a full section info... But it makes sense 👍
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.
right, then maybe that shall be inside the PublicKey::verify
, we shall log which one is failing or whether it's not reaching the threshold.
Maybe no need to log whehter reaching the threshold.
However failing a signature is some behaviour shall be noticed.
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.
Would not spend too much time on that, when we debug the first issue we will find out what log we need and we can add it then (it might be neither of the options, as I think we will probably want the id of the current node).
So I'd say, add something minimal if that make sense otherwise happy to leave it as is.
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 I'd leave it as is for now, then - adding some logging to the verification with a single public ID would make the code there quite a bit uglier, which we can probably do temporarily when debugging, but I'm not sure if it's worth it to have such code by default.
This PR makes some initial changes related to SMD:
our_history
andtheir_keys
to the shared stateour_history
together withour_infos
Closes #1672
Closes #1673
Closes #1674
Closes #1675