Skip to content
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

Secp256k1 in parity crypto and alternative wasm32 implementation #80

Closed
wants to merge 46 commits into from

Conversation

cheme
Copy link
Collaborator

@cheme cheme commented Nov 15, 2018

Removal of rust-crypto

This PR superseed #14 , also probably nice to have for openethereum/parity-ethereum#7915

RustCrypto hashing crate are already used Parity-ethereum (deps from new hyper version).

AES, on the other hand is new, possible change:

  • adopt a conservative approach and restore old unmaintained AES rust-crypto implementation and put RustCrypto in an alt implementation crate.

Also note that we can enable aes-ni while building for a nice bench boost (requires RUSTFLAGS="-C target-feature=+aes,+sse2,+ssse3" cargo bench) :

aes_ctr/10000           time:   [3.5767 us 3.5778 us 3.5789 us]                           
                        change: [-98.174% -98.174% -98.173%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 3 outliers among 100 measurements (3.00%)
  3 (3.00%) high mild
aes_ctr/100000          time:   [36.707 us 36.740 us 36.778 us]                            
                        change: [-98.091% -98.089% -98.087%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 14 outliers among 100 measurements (14.00%)

Alternate implementation

This PR exposes alternate implementation (mainly for wasm32 usecase), the choice of crates is less secure but it is an alternate implementation (wasm32 does not give the same garantie as native code).

Possible change:

  • add feature switch to make them default implementation (for custom build for instance)

secp256k1

basic integration

A quick and dirty basic integration was running correctly at this point (really conservative) : https://github.com/cheme/parity-common/blob/wasm-test/parity-crypto/src/secp256k1.rs and https://github.com/cheme/parity-common/blob/wasm-test/parity-crypto/src/secp256k1_alt.rs .

This can still be an alternative but is not really fit for a common crate.

trait

Using the previous basic integration reveals some small discrepancy between both crates.
At the end it seems obvious that using a trait to reduce exposed functionality makes senses to ensure compatibility in the long term.

A trait was define for secp in module traits.

Some alternative:

  • At a some point I made PublicKey and SecretKey implements AsRef<u8>, but I revert back (if we want to maintain a cache of serialize value it should be at parity-ethereum/ethkey instead).
  • If reverting back to being AsRef<u8> use fixed-hash for inner cache, using H512 to get efficient equality, and derive ordering, probably not it should be done at ethkey level.
  • define Signature as a trait, I see signature as a 'use once' operation so I keept things light with bytes here.
  • Public key size for secp to 65 (currently 64 without uncompressed tag) could be more correct.
  • Add default value to PublicKey : this was done at some point but feels wrong.
  • error changes the way debug trait behave, originally the native error where displayed in debug mode from json rpc therefore parity ethereum rpc changes a bit. I only identified one message, so I do not think a compatibility layer is needed, but that is an open question.

Secret Store

On my parity branch (https://github.com/cheme/parity-ethereum/tree/crypto-only), secret store switch to the secp trait did not work well due to a few design point:

  • default public key use in test (and asymption on its first position in btree), the value is an invalid publickey that cannot be spawn.

Currently on branch there is a mix of NodeId aka H512 and actual full PublicKey, with a lot of conversion between each. Moreover there is
a artificial unsafe Default implementation in secp256k1.rs.

Possibility:

  • do not switch secret-store : keep dependancy on secp crate for secret-store only
  • revert to a more conservative approach : use NodeId (H512) everywhere and Public only for spawning and maths
  • Integrate Public everywhere (except Serialize objects) by very involved refactoring
  • keep as is on the branch, even if tests are passing I am not to confident with that, and there is already a lot of byte copy involved.

bench

I initiated some bench, but there is not much.
bench --feature alt to get both secp implementation benched (alt tests are run without this feature it is related to an issue with bench not running with deps embedding test code).

clear on drop

crate clear_on_drop is used and exposed, MemZero from parity-ethereum has been copied to parity common and can both use clean_on_drop or previous implementation.

Possibility:

  • I realize while creating this pr that I use internally ClearOnDrop instead of MemZero, it could make sense to use MemZero

Next steps

I did fail at keeping the PR small (especially when considering https://github.com/cheme/parity-ethereum/tree/crypto-only).
Next step is integration into parity-ethereum (after pushing crate version of course), then others PR to use trait for other crypto things. Doing things in a iterative way.

Another important thing is to make the crate no_std compatible (at least the traits and some implementations).

Also a TODO in secp alt impl for clearing memory (we need an unsafe method to access inner field of secret key).

Some alternative:

  • wait for better math design (to replace ethstore and ethkey secret store impls)
  • wait for other traits impl.

cheme added 30 commits August 6, 2018 14:34
Note that we use RustCrypto aes root crates : so if we build with RUSTFLAGS='-C target-feature=+aes,+ssse3,+sse2' on x86, AES native instruction will be used.

Also added two Aes encryptor struct in preparation of switching (only
two use case remaining at the time in 'network-devp2p' crate.
Remove unused scrypt features.
something in a trait to factor tests) secp256k1, derived from parity
ethereum usage.
Add an alternate implementation that compiles to wasm32 (from sorpass
secp crate).
needed (some details of call from parity-ethereum are not understandable
otherwhise).
First compat is OsRng, which would probably soon be useless (0.6 of
rand?).

Make it works half 0.4/0.5 , it would be a great idea to move all crates
to 0.5.
condition with single thread threadpool (see ethkey command)).
- hook print to redirect globally to console.
- memap to fix compilation errors : do not use
- time
- fs : very incomplete (would need path support, still metadata could be
quick and simple to add).
Impl alt secp as asym trait.
Add missing files from previous commits.
@sorpaas
Copy link
Member

sorpaas commented Nov 20, 2018

Published libsecp256k1 0.2 so that we can test this without affecting existing users (if any!).

mem/Cargo.toml Outdated
[package]
name = "mem"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need description, license and repository info here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The crate was copied from https://github.com/paritytech/parity-ethereum/tree/master/util/mem so staying with gpl 3 license.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Just make sure you add the required fields to the [package] section here (or else it can't be published).

mem/Cargo.toml Outdated Show resolved Hide resolved
mem/src/lib.rs Outdated Show resolved Hide resolved
mem/Cargo.toml Outdated
clear_on_drop = "0.2.3"

[features]
# when activated mem is removed through volatile primitive instead of clear_on_drop crate
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably go into the README/module docs

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure about 'README/module', just added a README file to mem.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine, I just meant "make sure this info is in either the README or in the module-level docs (or both)".

parity-crypto/Cargo.toml Outdated Show resolved Hide resolved
parity-crypto/src/hmac_alt.rs Outdated Show resolved Hide resolved
parity-crypto/src/secp256k1.rs Outdated Show resolved Hide resolved
parity-crypto/src/secp256k1_alt.rs Outdated Show resolved Hide resolved
parity-crypto/src/secp256k1_alt.rs Outdated Show resolved Hide resolved
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

//! asymetric trait
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need more docs here.

@dvdplm dvdplm requested a review from twittner November 22, 2018 14:04
Copy link
Contributor

@twittner twittner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I probably lack some context but it is my understanding that this PR attempts to achieve three objectives:

  1. Remove rust-crypto.
  2. Enable cross-compilation to wasm32 target.
  3. Add support for secp256k1.

Item 3 in particular seems complicated given that it depends on eth-secp256k1 and libsecp256k1. As for item 2, the APIs of the "alt" implementations differ enough (at least in some types) to make seamless cross-compilation not quite possible yet.

Instead of having this single PR, would it be possible to move from 1 to 3 one PR at a time?

mem/src/lib.rs Outdated
}
}

#[cfg(not(feature = "volatile-erase"))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When should volatile-erase not be used and why offering clear_on_drop and write_volatile?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did use 'clear_on_drop' in my implementation (it is a bit more flexible api-wise) in other contexts and feel like using a single erasure mechanism was simpler.
The crate in itself got its own advantages (cesarb/clear_on_drop#2), yet for me it was just a matter of giving the choice (under current configuration it is imported with 'volatile' feature activated in parity-crypto).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in this case "less is more". I think we should have a single way of doing memory zeroing.

signer1.update(&input[..]);
for i in 0 .. big_input.len() / 33 {
signer2.update(&big_input[i*33..(i+1)*33]);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind explaining what this is about?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just running the update on slices that are not 64 byte multiple, a best test would use different sizes.

impl AesEcb256 {

/// New encoder/decoder, no iv for ecb
#[inline]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is LLVM not smart enough to figure out when to inline and when not to? Could bin crates not turn on LTO to achieve the same effect as having #[inline] everywhere?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it is a bad habit I have to add those, I will rem them in next commit.

let salt = include_bytes!("../test/salt1");
let content = include_bytes!("../test/content");
let ctr_enc = include_bytes!("../test/result_128_ctr");
let cbc_enc = include_bytes!("../test/result_128_cbc");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that all those files contain only small amounts of data, why not inlining those test values?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do.

@cheme
Copy link
Collaborator Author

cheme commented Nov 23, 2018

@twittner

Instead of having this single PR, would it be possible to move from 1 to 3 one PR at a time?

Could do, it will be probably in 1-3-2 order. Only thing will be that my current parity-ethereum branch testing this pr will be hard to align, but it do not really have to if I maintain a sync of those three branch with this branch.

@dvdplm
Copy link
Contributor

dvdplm commented May 17, 2019

@cheme what is the status of this work? Should we close this in favour of the three split PRs you mention above?

@cheme
Copy link
Collaborator Author

cheme commented May 17, 2019

I do not really know, the main point of this pr is to be able to compile parity-ethereum to webassembly.
It also go in a different way than recent wasm compatibility pr: it uses feature a lot when recent pr focused on removing non compatible eth implementation. eg aes-gcm
Here we use multiple implementation behind a trait, that is a totally different direction for the crate (this pr see this crate as a unified place for parity related crypto implementation with trait to allow easy inter-operabillity, cross implementation testing, auditability and such but it seems it was not really a goal).
I will still rebase, because whereas switching from ring to dalek seems good, switching to other secp for wasm may be another question.
The PR could probably be close afterward, close pr still have the visibility so if we need to get secp to wasm this could be revive easily.

cheme added 2 commits May 17, 2019 09:58
Warn: mem drop is totally deprecated (should stop using clear on drop :
I think it can break wasm).
@cheme
Copy link
Collaborator Author

cheme commented May 17, 2019

also merging this requires a pr on ethereum size that is pretty impacting and maybe not worth it if we do not want to compile to wasm; therefore I am closing the PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants