Can a SHA3 engine be used to construct a Keccak implementation?

I am working on a cSHAKE-128 & cSHAKE-256 implementation that takes advantage of a number of hardware accelerators I have at my disposal, specifically for SHA-3 256/384/512 and SHAKE 128/256.

cSHAKE 128 is defined as follows:

1. If N = "" and S = "":
return SHAKE128(X, L);
2. Else:
return KECCAK[256](bytepad(encode_string(N) || encode_string(S), 168) || X || 00, L).


If condition 1 is met, the solution is trivial, since I do have a SHAKE128 engine available.

However, in the case of condition 2, I don't have a Keccak engine readily available. I'm wondering if SHA3 can be used as primitive to construct Keccak 256.

I have read that SHA3 is directly derived from Keccak (was a result of a contest which Keccak won), but I've also read they're not exactly the same. This very useful on-line hasher does not produce the same hash values for SHA3 256 and Keccak 256.

• See page 28 nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf and see that none of the SHA3-x is using the KECCAK[256], extract the sponge construction and base keccak from the SHA3 then you get the base to construct all! – kelalaka Dec 2 '20 at 10:50
• Thanks for your reply. I'm reading through the document and am trying to understand, but I'm afraid I'm not very familiar with cryptography. I can see this correspondence: SHA3-256(M) = KECCAK[512](M || 01, 256). Let's say I want to hash string 'N' using Keccak-512. Is it possible to achieve this: my_keccak_func(sha3-256_func(), N) = KECCAK-256(N)? Keep in mind one of the restrictions is I cannot modify in any way the SHA3 function, which is given to me as a black box function. – ismarlowe Dec 2 '20 at 11:22
• Only if $M$ ends in the bits $01$ you can strip these bits from the end of $M$ and send the remaining part to SHA3. For other messages, I'm afraid, there won't be a solution. – cisnjxqu Dec 2 '20 at 11:34
• At this point, my question would be: why does this NIST document (nvlpubs.nist.gov/nistpubs/SpecialPublications/…) refer to cSHAKE128/256 as SHA-3 derived functions, if SHA-3 cannot be used as building block for cSHAKE? – ismarlowe Dec 2 '20 at 11:39
• I think there is some misunderstanding about "derived" here. Derivation doesn't preclude alteration and it certainly doesn't necessarily mean that the function needs to be a primitive within the derived function. In other words, I don't think that "derived" as used by NIST is the same "derived" as used for mathematical constructions. – Maarten Bodewes Dec 2 '20 at 12:21

Let first look at $$\operatorname{KECCAK}[c] (N || suffix, d) \label{1}\tag{1}$$ It calls

$$\operatorname{KECCAK}[c] (N, d) = \operatorname{SPONGE}[\operatorname{KECCAK-p}[1600, 24], pad10*1, 1600 – c] (N, d).$$

• $$c$$ is the capacity
• $$d$$ is the output size
• 1600 is the base $$b$$
• $$pad10*1$$ is the multi rate padding.
• 24 is the number of rounds $$n_r$$
• The sponge in short is the framework for specifying functions on binary data with arbitrary output length.

Let assume that we have a black box SHA3 implementation of any mode

• $$\operatorname{SHA3-224}(M) = \operatorname{KECCAK}[448] (M || 01, 224)$$
• $$\operatorname{SHA3-256}(M) = \operatorname{KECCAK}[512] (M || 01, 256)$$
• $$\operatorname{SHA3-384}(M) = \operatorname{KECCAK}[768] (M || 01, 384)$$
• $$\operatorname{SHA3-512}(M) = \operatorname{KECCAK}[1024] (M || 01, 512)$$

and black box SHAKEx implementations

• $$\operatorname{SHAKE128}(M, d) = \operatorname{RawSHAKE128}(M || 11, d)$$

• $$\operatorname{SHAKE256}(M, d) = \operatorname{RawSHAKE256}(M || 11, d)$$

where

• $$\operatorname{RawSHAKE128}(J, d) = \operatorname{KECCAK}[256] (J || 11, d)$$
• $$\operatorname{RawSHAKE256}(J, d) = \operatorname{KECCAK}[512] (J || 11, d)$$

Now you want to use the above as black box implementation for cSHAKE

 cSHAKE128(X, L, N, S):
1. If N = "" and S = "":
return SHAKE128(X, L);
2. Else:
return KECCAK[256](bytepad(encode_string(N) || encode_string(S), 168) || X || 00, L).

• The if part is not a problem, since it directly uses the SHAKE128.
• The else part is the problematic part. One can externally implement bytepad(encode_string(N) || encode_string(S), 168) and concatenate it with X. The domain separation padding 00 is the real issue. If the block box doesn't allow this as input, then there is no way to this.

If the library somehow extendible one may use the \ref{1} to generate all of the above, otherwise no.

The cSHAKE is the base for KMAC, TupleHash, and ParallelHash. If you are going to need those, you may need to implement yourself.