-
Notifications
You must be signed in to change notification settings - Fork 2.7k
ristretto crypto module #1706
ristretto crypto module #1706
Conversation
This comment has been minimized.
This comment has been minimized.
1 similar comment
|
It looks like @kianenigma hasn't signed our Contributor License Agreement, yet.
You can read and sign our full Contributor License Agreement at the following URL: https://cla.parity.io Once you've signed, please reply to this thread with Many thanks, Parity Technologies CLA Bot |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
1 similar comment
|
It looks like @kianenigma signed our Contributor License Agreement. 👍 Many thanks, Parity Technologies CLA Bot |
|
@kianenigma I would recommend making a PR to |
core/primitives/src/sr25519.rs
Outdated
| use serde::{de, Deserialize, Deserializer, Serializer}; | ||
|
|
||
| // signing context | ||
| const SIGNING_CTX: &'static [u8] = b"polkadot transaction"; |
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 doesn't seem right, since we're in the substrate code.
Also, the way that schnorrkel is meant to be used is that signatures for each purpose will have their own signing-context (to create domain separation, prevent length-extension attacks).
Using it with a single global context lowers the security of the library.
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.
We should eventually be able to write roughly this whenever const fn gets stabilized and becomes popular enough for merlin to use:
const POLKADOT_PAYMENT_CTX: SigningContext = signing_context(b"PolkadotPayment");
but right now this would require a lazy_static I think.
It's entirely possible that I overthought this interface though. ;) In fact, one could add convenience methods like
fn sign_bytes(&self, context: &'static [u8], bytes: &[u8]) {
self.sign(signing_context(contect).bytes(bytes))
}
but there are places in polkadot where you want the hash256 builder method instead of the bytes builder method because Sha2 or Shake128 sound faster than merlin's Keccek variant. And these builder help keep the interface simple in this case.
Also, there are cases where you sign very small things, like certificates and the VRF in block production, where you could build the merlin transcript manually, maybe using an extension trait like merlin recommends.
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.
b"substrate transaction" or even b"transaction" is fine. This is the fundamental "context" and here is not the place to be trying to shovel data concerning e.g. the genesis block or chain ID into. The signature payload already depends on this stuff which is added at the sensible place further down the stack where this information is more readily available.
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.
Anyways @rphmeier is correct that using the same context for everything breaks the domain separation that signing_context helps provide.
We could do domain separation in other ways like by substrate and polkadot having their own versions of the signing_context function that do "substrate" or "polkadot" before whatever context the users provides, so
pub fn polkadot_context(context : &'static [u8]) -> SigningContext {
let mut t = SigningContext::new("polkadot")
t.commit_bytes(b"",context);
SigningContext(t)
}
We should however do some domain separation though because the alternatives are either adding more key types, which wastes space on chain, or everyone reinventing domain separation locally, probably by doing more careful serialization.
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.
Based on what I am reading so far, adding a set of sign() / verify() methods that accept the context seems to be a good way to go. API-wise it also looks clean. we will end up with two groups of exposed functions:
- default context:
pub fn verify_strong(sig, message, pubkey) -> bool/pub fn sign(message) - custom context:
pub fn verify_strong_ctx(sig, message, pubkey) -> bool/pub fn sign_ctx(message)
as already suggested by @burdges
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.
Happy to make it more general to e.g. "Substrate family" or some such so it nominally covers more than transaction signing. But Polkadot and Substrate domain separation are managed at a place further down in the stack where it makes more sense for that data to be integrated into the signing data.
If there's any use at all to this context parameter it's to distinguish between using the key for Substrate-family signing and the key being used in other non-Substrate family contexts (which are probably nil, but then I'm unconvinced of the utility of exposing context at this low-level).
cb21d4f to
a9bc9f1
Compare
Indeed possible and since I am already quite entangled with this crypto library it's a good way to go. Though, I should take some time and inform myself properly of the context and probably ask around a lot to get an exact view of what each component (e.g parity-codec) is and how they will fit. Important to do so given the fact that I am new to all of this. |
|
Yeah I think adding parity-codec seems fine. I haven't used parity-codec yet myself, but I homogenized the serde code quite a bit in https://github.com/w3f/schnorrkel/blob/master/src/serdey.rs#L16 so maybe parity codec would be similar. And parity-codec can be feature gated like serde for outside users. |
| fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) { | ||
| self.0.hash(state); | ||
| } | ||
| } |
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'd think derive works 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.
true. Fixed
|
Unless |
gavofyork
left 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.
All good apart from maybe switching "polkadot transaction" to "substrate transaction".
|
@gavofyork I think you misunderstand the signing context a little bit. While it could be used for Chain ID replay protection and things like that, it's also the case that we might use this library for signatures which are not on transactions. Maybe we should have a |
|
Just. curious: Is it possible for polkadot to pass these |
I think the way to circumvent this is to have sth like Instead of the current I also don't like it from the perspective of being uniform. schnorrkel provides types for KeyPair, Public and Private key as well but we have wrapper structs for them (here, here). Why not have one for Signature as well? at the end of the day, all of them should be treated the same way. Either all type aliases or all wrapped instructs of our own so we can implement all needed traits on them. [not 100% sure and have not tested this approach out so it might not work/ have other consequences. Just an idea] Or go with the PR to the original repo with a built-in implementation of parity-codec types so they can be derived here. |
|
Another thing not to be forgotten: a new |
Makes sense to me. |
|
This PR will most likely be closed/ignored in favor of #1730. |
a step toward solving #1685. remarks:
A general dilemma in implementing this so far has been choosing the degree to which this module is going to be similar to
ed25519.ed25519.rs.Signature(which is now aliased via:pub type Signature = schnorrkel::Signature;) is still implementingpub trait Verifiablebut this slightly counter-intuitive now since schnorrkel does NOT provide a verify object via itsSignaturebut instead via itsKeyPair/PublicKey. This still works but comparing the current implementation ofVerifiableto the one for ed25519, it seems slightly hacky.untrustedcrate again.LocalizedSignaturein ed25519 derives two additional traits (Encode, Decode) which are not possible atm since both the trait and the struct for which the trait should exist (Signature) are external to the crate. I guess this might be an issue?