-
Couldn't load subscription status.
- Fork 305
Use fixed width serde impls for keys #406
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
Conversation
64754a5 to
50ab92c
Compare
6e3e256 to
d8a0399
Compare
cd44138 to
4e8e095
Compare
4e8e095 to
a58dc21
Compare
a58dc21 to
ba9e23d
Compare
|
I think we can just use a fixed-size array of size 74 rather than a |
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.
Interesting idea! I'd have to see some analysis on real impact of this change on existing formats to believe we should do this. I worry many formats will store type along with each item.
no_std_test/src/main.rs
Outdated
| let _ = SharedSecret::new(&public_key, &secret_key); | ||
| let _ = ecdh::shared_secret_point(&public_key, &secret_key); | ||
|
|
||
| #[cfg(feature = "use-serde")] { |
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 style is inconsistent with the rest of the code and quite confusing.
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.
Do you mean inconsistent with the scratch through because removal of rust-secp256k1 crate? This is a separate crate and the features are only used, as far as I can tell, to run this crate and selectively run parts of the test (start function).Vec removes the need for this feature anyways.
FTR I'm not sure why this is a separate crate, I'm not super deep in the no-std stuff, @elichai do you remember off the top of your head why we had to put it in a separate crate and not in the tests directory (i.e., standard integration tests directory)?
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 goal was to simulate macro usage from rust-bitcoin, which has less visibility of symbols than anything within the crate (including, I think (?) stuff in the tests/ directory).
I believe this also predates the tests directory.
src/key.rs
Outdated
| )) | ||
| } else { | ||
| d.deserialize_bytes(super::serde_util::BytesVisitor::new( | ||
| d.deserialize_seq(super::serde_util::SeqVisitor::new( |
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 should be deserialize_tuple
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.
Oh so implement de::Visitor for each fixed size type we have and use deserialize_tuple, interesting. I'll give it a shot.
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, if you want to keep it generic I suspect you'll have to use PhantomData<fn() -> T>
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.
With a macro for the serde impls, and serializing with tuple this PR is way cleaner now!
Cargo.toml
Outdated
| secp256k1-sys = { version = "0.4.2", default-features = false, path = "./secp256k1-sys" } | ||
| bitcoin_hashes = { version = "0.10", optional = true } | ||
| rand = { version = "0.6", default-features = false, optional = true } | ||
| # Our custom serde code requires an allocator, enable secp256k1 feature `std` or `alloc`. |
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.
Where does it allocate? I don't see any such instance.
Besides, TODO after MSRV bump: use crate renaming trick instead.
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.
Allocates due to use of the Vec in visit_seq method.
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.
Ah, I see. Looks like using array is feasible?
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.
Besides, TODO after MSRV bump: use crate renaming trick instead.
Not sure what you mean here mate, is this comment still relevant with the removal of alloc/vec stuff?
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 not.
If we follow @Kixunil's suggestion above the |
ba9e23d to
4169e1f
Compare
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.
Generics would be more elegant than macro but without const generics it'd be a bit more boilerplate, so I think it's OK.
Do we know for sure binary codecs don't store type with each element?
src/serde_util.rs
Outdated
| v[i] = value; | ||
| } else { | ||
| let msg = format!("tuple too short, index: {}, expected length: {}", i, $len); | ||
| return Err(de::Error::custom(msg)); |
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.
invalid_length() would be better. Also I think de::Error is a bit confusing because it refers to the trait not type. Err:: would look better but Err is also special - even used here - how come it even works? I suggest either calling it Error or just E.
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.
Will do, thanks.
src/serde_util.rs
Outdated
| return Err(de::Error::custom(msg)); | ||
| } | ||
| } | ||
| (self.parse_fn)(&v).map_err(de::Error::custom) |
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 error could be specialized too. Maybe parse_fn should return appropriate serde error already?
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.
Will re-think, thanks.
src/serde_util.rs
Outdated
| macro_rules! impl_tuple_visitor { | ||
| ($thing:ident, $len:expr) => { | ||
| /// Visitor type for de/ser a 32 byte sequence. | ||
| #[cfg(any(feature = "std", feature = "alloc"))] |
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 this is no longer needed and the reason why test fails. FTR, if it was needed it'd be a demonstration of the compatibility issues I mentioned a few times.
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.
Oh, sloppy work by me. This is not needed.
Don't the unit tests check that? They test the token is exactly the expected type? Or do you mean that we should pick a binary codec and add a unit test that serializes and checks the number of bytes is as expected? |
|
Thanks for the review @Kixunil, I'll re-spin tomorrow. |
|
I mean this could be regression in data size for some formats. We don't have tests for specific data. |
4169e1f to
330a18e
Compare
f498e1b to
7ebb6a5
Compare
|
Changes in foce-push:
|
7ebb6a5 to
f11c1d6
Compare
|
Changes in force-push: Updated serde unit test for |
f7eba2b to
db656a5
Compare
|
And added the hex docs suggestion from above. |
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.
ACK db656a5
Thank you for checking the actual behavior! And for adding integration tests that will detect if we break things in the future.
I am a little bit wary of this PR beacuse it will result in serialization breakage. It will definitely need to go in a major release at least.
Do you want me to look into adding some sort of compatibility code for migrating from the current serialization to the one in this PR? |
|
@tcharding sure -- but I'm not optimistic because there is no versioning or anything in our encoding. One strategy might be to continue to allow decoding the old format, while only encoding the new format ... but that has the potential to just make the breakage harder-to-find for downstream users. |
|
Ok, without a clear positive way forward I'll leave it as is and hide behind 'not version 1.0 yet' :) |
db656a5 to
76d7cf3
Compare
|
Changes in force push: rebase, the only merge conflict was a path (add |
Currently we serialize keys using the `BytesVisitor`, this causes the serialized data to contain additional metadata encoding the length (an extra 8 bytes) when serialized with the `bincode` crate. This extra data is unnecessary since we know in advance the length of these types. It would be useful for users of the lib to be able to get a fixed width binary serialization, this can be done but it depends on the crate used to do the serialization. We elect to optimise for `bincode` and add docs noting that other binary serialization crates may differ (rustdocs added in separate patches). Implement a tuple based visitor that encodes the keys as fixed width data. Do fixed width serde implementations for: - `SecretKey` - `PublicKey` - `KeyPair` - `XOnlyPublicKey`
Currently the rustdocs for `KeyPair` are stale in regards to serde, we _do_ implement `Serialize` and `Deserialize` for `KeyPair`. Improve the rustdocs for `KeyPair` by removing stale docs and adding docs on fixed width binary serialization.
We recently added fixed width serialization for some types however serialization is only fixed width when data is serialized with the `bincode` crate. Add rustdocs describing fixed width serde to `SecretKey`, `PublicKey`, and `XOnlyPublicKey` (`KeyPair` is already done).
Add a `tests` directory. Add `serde` tests for the recently added fixed width binary serialization code. Please note, serialization is only fixed width when serialized with the `bincode` crate.
76d7cf3 to
3ca7f49
Compare
|
FTR I do not intend to push for this PR to be merged, I am unclear whether it is worth having or not. I will keep rebasing it to give others a chance to comment. |
|
I think up to 25% space saving is worth breaking already unstable library. :) |
|
I have mixed feelings, but concept ACK from me because @Kixunil is so persuasive. Also, selfishly, I think that my personal applications will be unaffected because I always store keys in the ASCII serialization.. Will re-review and merge this shortly. |
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.
ACK 3ca7f49
…r keys 3ca7f499e0dab28c8dedc94e580a5c55005d60e2 Add fixed-width-serde integration tests (Tobin Harding) bf9f5562259244850b826982dd29f7cd9fa14624 Add rustdocs describing fixed width serde (Tobin Harding) c28808c5a414929f88ec16ac07ff7e67467c9f28 Improve rustdocs for KeyPair (Tobin Harding) 6842383161aaa3024339b300dea15d6620221228 Use fixed width serde impls for keys (Tobin Harding) Pull request description: Currently we serialize keys using the `BytesVisitor`, this causes the serialized data to contain additional metadata encoding the length (an extra 8 bytes) when serialized with [bincode.](https://docs.rs/bincode/latest/bincode/index.html). This extra data is unnecessary since we know in advance the length of these two types. We do not control the data output by serialization of our types because it depends on which crate is used to do the serialization. This PR improves the situation for serialization using the `bincode` crate, and this PR introduces mentions of `bincode` in the rustdocs, is this acceptable? See below for a table that describes binary serialization by other crates. Implement a sequence based visitor that encodes the keys as fixed width data for: - `SecretKey` - `PublicKey` - `KeyPair` - `XOnlyPublicKey` Fixes: #295 **Question**: PR only does keys, do we want to do signatures as well? ACKs for top commit: apoelstra: ACK 3ca7f499e0dab28c8dedc94e580a5c55005d60e2 Tree-SHA512: 77babce74fa9f0981bb3b869c4e77a68a4d1ec28d22d2c3be4305e27ef01d4828dac210e20b968cbbe5de8a0563cd985d7969bccf75cfe627a34a116fed1a5df
…r keys 3ca7f499e0dab28c8dedc94e580a5c55005d60e2 Add fixed-width-serde integration tests (Tobin Harding) bf9f5562259244850b826982dd29f7cd9fa14624 Add rustdocs describing fixed width serde (Tobin Harding) c28808c5a414929f88ec16ac07ff7e67467c9f28 Improve rustdocs for KeyPair (Tobin Harding) 6842383161aaa3024339b300dea15d6620221228 Use fixed width serde impls for keys (Tobin Harding) Pull request description: Currently we serialize keys using the `BytesVisitor`, this causes the serialized data to contain additional metadata encoding the length (an extra 8 bytes) when serialized with [bincode.](https://docs.rs/bincode/latest/bincode/index.html). This extra data is unnecessary since we know in advance the length of these two types. We do not control the data output by serialization of our types because it depends on which crate is used to do the serialization. This PR improves the situation for serialization using the `bincode` crate, and this PR introduces mentions of `bincode` in the rustdocs, is this acceptable? See below for a table that describes binary serialization by other crates. Implement a sequence based visitor that encodes the keys as fixed width data for: - `SecretKey` - `PublicKey` - `KeyPair` - `XOnlyPublicKey` Fixes: #295 **Question**: PR only does keys, do we want to do signatures as well? ACKs for top commit: apoelstra: ACK 3ca7f499e0dab28c8dedc94e580a5c55005d60e2 Tree-SHA512: 77babce74fa9f0981bb3b869c4e77a68a4d1ec28d22d2c3be4305e27ef01d4828dac210e20b968cbbe5de8a0563cd985d7969bccf75cfe627a34a116fed1a5df
Currently we serialize keys using the
BytesVisitor, this causes the serialized data to contain additional metadata encoding the length (an extra 8 bytes) when serialized with bincode.. This extra data is unnecessary since we know in advance the length of these two types.We do not control the data output by serialization of our types because it depends on which crate is used to do the serialization. This PR improves the situation for serialization using the
bincodecrate, and this PR introduces mentions ofbincodein the rustdocs, is this acceptable? See below for a table that describes binary serialization by other crates.Implement a sequence based visitor that encodes the keys as fixed width data for:
SecretKeyPublicKeyKeyPairXOnlyPublicKeyFixes: #295
Question: PR only does keys, do we want to do signatures as well?