-
Notifications
You must be signed in to change notification settings - Fork 579
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
eXtendable Output Functions as first-class citizen #3671
Conversation
e0adc08
to
291c56f
Compare
b28bd76
to
afa8bae
Compare
afa8bae
to
7f1b216
Compare
7f1b216
to
0a0291d
Compare
Rebased onto @falko-strenzke's Keccak refactoring as a sanity checks. Findings are in #3673. |
0a0291d
to
75ec144
Compare
75ec144
to
b3daafb
Compare
0276fac
to
ba45416
Compare
Re: XOFs based on stream ciphers Maybe we should step back and rethink the XOF interface somewhat. Looking at NIST SP.800-185 they define things like KMAC-XOF that is KMAC with a variable output length. I.e. just like the AES/CTR-XOF used in CRYSTALS Kyber/Dilithium, it takes a key (and potentially other customization parameters). Another aspect is cSHAKE (also NIST SP.800-185), which is basically SHAKE, but with additional domain separation parameters I think it would be great to incorporate such XOFs off the bat, when introducing a new API. |
To my mind an abstract XOF should have two phases:
The "output phase" is simple and inherently generic. The user just calls The "parameterization phase" is algorithm-specific, unfortunately. Here are some relevant examples:
Reflecting this parameter space in a common In fact, looking at the existing use cases in Kyber and Dilithium, this is exactly what we need there. Depending on the algorithm mode ("90s" or "modern"), the AES/CTR or SHAKE XOF is parameterized inside a polymorphic method and then handed out as an abstract (pre-parameterized) reference. The common code, that is independent of the specific mode, then just "reads" from the abstract XOF object via |
Given the above-described constraints, it seems reasonable to abandon the ubiquitous @randombit Does that sound like a reasonable abstraction to you? |
Benchmarking the SHAKE-128/256 XOF showed comparable results for
|
I very much dislike this. A lot of effort was spent in 2->3 in removing all of the concrete subclasses from the public API; this minimizes API and ABI surface. This would also complicate the FFI interface. I don't think CTR mode "XOF" is worth optimizing for. It is a weird corner case that should not be exposed to applications. And it seems Kyber is dropping "90s mode" entirely (#3543) so it is probably going to be removed soonish anyway. Then we're left with
CTR, which doesn't support inputs, is handled by the funny case that |
KMAC needs to set |
@randombit Thanks for your opinion. Your points make sense and I agree in general. I'll be AFK until the beginning of September and will come back to this after. |
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.
First pass review
virtual Key_Length_Specification key_spec() const = 0; | ||
|
||
/** | ||
* @return the intrinsic processing block size of this XOF |
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 probably also mention it returns 0 if there is no such value.
What is this used for?
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.
If std::optional
wasn't so awkward to use I'd suggest returning an optional
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.
I changed this to be a pure-virtual, forcing downstream implementations to make up their minds.
src/lib/xof/shake_xof/shake_xof.cpp
Outdated
} | ||
|
||
void SHAKE_XOF::start(std::span<const uint8_t> salt, std::span<const uint8_t> key) { | ||
BOTAN_UNUSED(key); |
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.
If the caller provides a non-empty key here it is just ignored, which is going to be confusing and a possible security issue if someone misuses the API. We should instead throw Invalid_Key_Length
if this occurs.
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.
Agreed. Now implemented as the base-implementation of XOF::start()
. Also the base methods XOF::key_spec()
and XOF::valid_salt_length()
now have default implementations that basically disable support for keys and salts by default.
src/lib/xof/shake_xof/shake_xof.cpp
Outdated
// We deliberately do not check the salt length here. There's no technical | ||
// reason to reject a salt buffer passed in by an application that exceeds | ||
// the (arbitrarily set) valid_salt_length() restriction. | ||
keccak_absorb_padded_strings_encoding(*this, block_size(), m_function_name, salt); |
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.
Not restricting the cSHAKE salts seems fine, but we also here will accept a salt with plain SHAKE XOF where this is not defined at all.
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.
Yikes, indeed! The condition above was previously meant to exclude non-cSHAKE instances of this base class. But I must have broken it in some restructuring. Anyway, that's certainly not optimal.
I'll look into giving the cSHAKE variants their own base class and leave the salt logic out of the vanilla SHAKE implementation.
72afe40
to
32f5dc4
Compare
Thanks for the review! I rebased to latest master (after merging the Most notably, I split the Also, I |
Co-Authored-By: René Meusel <[email protected]>
32f5dc4
to
afb70af
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.
Looks good now. Should we have some tests for cSHAKE as well?
There are four test vectors from NIST, all of which have an empty value for N. I just implemented cSHAKE for another libgcrpyt and created two test vectors with non empty N using https://asecuritysite.com/golang/cs. I checked their results for empty N and that was at least fine. In any case, the KMAC test vectors will also verify non-empty N.
|
Thanks for checking this @falko-strenzke. @reneme can we get these included here so we have some baseline check on cSHAKE? I guess it is a little complicated by cSHAKE not being exposed to applications so you can't immediately use the normal XOF test. |
f52a8aa
to
14b4183
Compare
@falko-strenzke Nice! Thanks for the test vectors. I did look for something "official" for cSHAKE but wasn't successful. @randombit I hacked the XOF allocation in |
@reneme looks good thanks. I couldn't find the tests themselves though - are you missing a |
14b4183
to
73f7c2d
Compare
73f7c2d
to
e499bbf
Compare
🤦♂️ |
I was fighting some linker visibility issues. Had to move the Now everything should turn green. |
🥳 |
Motivation
Most PQC schemes use XOFs as a building block in one or the other way. This is a proposal to establish
XOF
as a new public API base class. The only implementation currently provided isSHAKE-128
andSHAKE-256
.Pull Request Dependencies
Refactoring SHA3: based on new permutation keccak-fips #3673Find included
class XOF
as abstract base classstart()
allows priming certain XOFs with asalt
andkey
(otherwise its a NOOP)update()
allows streamed input of an arbitrarily long messageoutput()
allows streamed access to the XOF's infinitely long output streamupdate()
s after the first call tooutput()
SHAKE_128_XOF
andSHAKE_256_XOF
as sub-classes ofXOF
cSHAKE_128_XOF
andcSHAKE_256_XOF
as sub-classes ofXOF
(for internal use only)(those functions can be reused to implement KMAC -- see KMAC, 2nd: added keccak-fips as standalone; added KMAC-256 #3570)
Things to be considered
XOFs based on stream ciphers
Kyber and Dilithium build their "90s-crypto" variants on XOF constructions based on AES-256/CTR. We could look into providing support for such stream-cipher XOFs independent of the CRYSTALS algorithms. (See #3672)
Retrofitting PQC algorithms
That's future work and will be done in a follow-up. (See #3672)