-
Notifications
You must be signed in to change notification settings - Fork 9
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
Introduces incremental hash. #188
Conversation
Fixes typelevel#181. Each API is subtly different, but in general we have a new/update/finalize/reset. The WebCrypto API for browsers doesn't support incremental hashes yet; we could either shim it (i.e. build up the `ByteVector` in memory) or just throw. I feel that it is better to throw so that the user does not have an expectation of memory usage, but it might be a PITA for anyone cross-compling.
3a9501e
to
502c96d
Compare
/** | ||
* Used for incremental hashing. | ||
*/ | ||
sealed trait Digest[F[_]] { |
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'm not against this, but I do want to point out some trade-offs ...
An incremental hashing API in terms of update
/get
/reset
is "lower-level" vs an API expressed as a Stream
.
This is relevant because there is a proposal for browsers to support incremental hashing, but this will likely be in the form of streams. I think it might still be possible to implement the API you've declared here with a stream, but we should be thoughtful about that.
https://github.com/wintercg/proposal-webcrypto-streams
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 agree; I wasn't sure which way we wanted the dependency graph (as in bobcats <- fs2
or fs2 -> bobcats
where ->
is dependent on). If the former then more flexibility is always nicer.
EDIT. I'll take a look at the webcrypto-streams proposal and see if I can stub an implementation with this API.
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.
bobcats <- fs2
Definitely not this. There is a high bar for FS2 taking on new dependencies and although it currently has crypto code I believe moving it out to a library like this makes much more 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.
👍 Then I'll switch over to a Stream
based API - we can always split into multiple modules if we don't want consumers to pull in fs2
.
implicit def forAsync[F[_]](implicit F: Async[F]): Hash[F] = | ||
implicit def forAsync[F[_]](implicit F: Async[F]): Hash[F] = forSync |
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.
Btw: I now believe offering implicits in exchange for Sync
/Async
is an anti-pattern. See:
implicit F: Applicative[F]) | ||
extends UnsealedHash1[F] { | ||
|
||
override def digest(data: ByteVector): F[ByteVector] = F.pure { |
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.
So I think by convention this shouldn't throw if the MessageDigest
is well behaved but we can err on the side of caution and just catchNonFatal
.
extends UnsealedHash1[F] { | ||
|
||
override def digest(data: ByteVector): F[ByteVector] = F.pure { | ||
val h = hash.clone().asInstanceOf[MessageDigest] |
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.
Doesn't look like cloning is always supported.
Implementations are free to implement the Cloneable interface. Client applications can test cloneability by attempting cloning and catching the CloneNotSupportedException:
https://docs.oracle.com/javase/8/docs/api/java/security/MessageDigest.html
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.
Argh! This is very annoying.
I think I'll double check bouncy castle (since that's probably going to be the biggest implementation) and if they support cloning then I'll do a .clone
when creating the Hash1
and switch out to a different implementation if it can't.
* Use this class if you have a specific `HashAlgorithm` known in advance or you're using a | ||
* customized algorithm not covered by the `HashAlgorithm` class. | ||
*/ | ||
sealed trait Hash1[F[_]] { |
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 idea is that this should wrap the MessageDigest
/EVP_MD
/Hash
equivalent on each platform so folks can construct them when the HashAlgorithm
isn't complete.
It's also means that you can fail-fast if you have an application which is dependent on certain algorithm's, which imo is better than waiting until later.
If I feel like this mechanism is good, we can reuse the same pattern for most of the other algorithm selection. Hash
is the simplest so doing it here first is good.
Another high-level idea: have you seen this issue? You could set up some sort of keypool of |
Yes I have; I think that apart from the performance gains, it doesn't help in this case (apologies if I've misinterpreted your comment). I think the underlying issue that Consider you set up a pool and there aren't any more Maybe this is overthinking it though, since 99% of users won't be doing |
Ahh, I'm sorry, I just understood what you are trying to do with that. Hmm. Ok, how about this: if you have a known list of Then to construct the https://docs.oracle.com/javase/8/docs/api/java/security/Security.html#getProviders-- Edit: hmmmmmmm, maybe not 😭 even Edit 2: perhaps if you clone the providers beforehand? |
dc23f27
to
0c38396
Compare
A lot of code for very little functionality; but it opens up it up for #189. I'm generally happy with the pattern as well, exposing a variant of the capabilities for #58. I think the names are a little meh; the reason I'm not using Some love needs to be put into ignoring the test cases and fixtures (maybe a switch to weaver would be good). |
Fixes #181. Each API is subtly different, but in general we have a new/update/finalize/reset.
The WebCrypto API for browsers doesn't support incremental hashes yet; we could either shim it (i.e. build up the
ByteVector
in memory) or just throw. I feel that it is better to throw so that the user does not have an expectation of memory usage, but it might be a PITA for anyone cross-compling.