An MD5 implementation was originally included in #8097, but, since there are a couple different implementations of that digest algorithm (@alco mentioned his implementation on the mailing list just before I opened that PR), it was suggested that I remove it from that PR and open up a new PR to discuss the different implementations and the best way forward. If anyone wants to discuss a different implementation, feel free to present it here and discuss and compare it to this one. I'll just discuss my implementation and I'll leave it to others to present details of theirs.
This implementation relies on the FixedBuffer struct from cryptoutil.rs for managing the input buffer, just like the Sha1 and Sha2 digest implementations do. I tried manually unrolling the loops in the compression function, but I got slightly worse performance when I did that.
Outside of the #[test]s, I also tested the implementation by generating 1,000 inputs of up to 10MB in size and checking the MD5 digest calculated by this code against the MD5 digest calculated by Java's implementation.
On my computer, I'm getting the following performance:
```
test md5::bench::md5_10 ... bench: 52 ns/iter (+/- 1) = 192 MB/s
test md5::bench::md5_1k ... bench: 2819 ns/iter (+/- 44) = 363 MB/s
test md5::bench::md5_64k ... bench: 178566 ns/iter (+/- 4927) = 367 MB/s
```
Addresses part of #7104
This module adds the ability to generate UUIDs (on all Rust-supported platforms).
I reviewed the existing UUID support in libraries for a range of languages; Go, D, C#, Java and Boost++. The features were all very similar, and this patch essentially covers the union. The implmentation is quite straightforward, and uses the underlying rng support which is assumed to be sufficiently strong for this purpose.
This patch is not complete, however I have put this up for review to gather feedback before finalising. It has tests for most features and documentation for most functions.
Outstanding issues:
* Only generates V4 (Random) UUIDs. Do we want to support the SHA-1 hash based flavour as well?
* Is it worth having the field-based struct public as well as the byte array?
* Formatting the string with '-' between groups not done yet.
* Parsing full string not done as there appears to be no regexp support yet. I can write a simple manual parser for now?
* D has a generator as well. This would be easy to add. However, given the simple interface for creating a new one, and the presence of the macro, is this useful?
* Is it worth having a separate UUID trait and specific implementation? Or should it just have a struct+impl with the same name? Currently it feels weird to have the trait (which can't be named UUID so as to conflict) a separate thing.
* Should the macro be visible at the top level scope?
As this is a first attempt, some code may not be idiomatic. Please comment below...
Thanks for all feedback!
...er
I believe the calls to waitpid are interacting badly with the message passing that goes
on between schedulers and causing us to have very little parallelism in
the test suite. I don't fully understand the sequence of events that causes
the problem here but clearly blocking on waitpid is something that a
well-behaved task should not be doing.
Unfortunately this adds quite a bit of overhead to each test: one thread, two
tasks, three stacks, so there's a tradeoff. The time to execute run-pass on
my 4-core machine goes from ~750s to ~300s.
This should have a pretty good impact on cycle times.
cc @toddaaro
The shift_add_check_overflow and shift_add_check_overflow_tuple functions are
re-written to be more efficient and to make use of the CheckedAdd instrinsic
instead of manually checking for integer overflow.
* The invokation leading_zeros() is removed and replaced with simple integer
comparison. The leading_zeros() method results in a ctpop LLVM instruction
and it may not be efficient on all architectures; integer comparisons,
however, are efficient on just about any architecture.
* The methods lose the ability for the caller to specify a particular shift
value - that functionality wasn't being used and removing it allows for the
code to be simplified.
* Finally, the methods are renamed to add_bytes_to_bits and
add_bytes_to_bits_tuple to reflect their very specific purposes.
When using a `do` block to call an internal iterator, if you forgot to
return a value from the body, it would tell you
error: Do-block body must return bool, but returns () here. Perhaps
you meant to write a `for`-loop?
This advice no longer applies as `for` loops are now for external
iterators. Delete this message outright and let it use the default error
message
error: mismatched types: expected `bool` but found `()`
This allows the internal implementation details of the TLS keys to be
changed without requiring the update of all the users. (Or, applying
changes that *have* to be applied for the keys to work correctly, e.g.
forcing LLVM to not merge these constants.)
- generate random UUIDs
- convert to and from strings and bytes
- parse common string formats
- implements Zero, Clone, FromStr, ToStr, Eq, TotalEq and Rand
- unit tests and documentation
- parsing error codes and strings
- incorporate feedback from PR review