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

SHA3 and SHAKE - New API Design #2098

Open
wants to merge 73 commits into
base: main
Choose a base branch
from

Conversation

manastasova
Copy link
Contributor

@manastasova manastasova commented Jan 7, 2025

Issues:

Resolves #CryptoAlg-2810

Description of changes:

AWS-LC supports SHA3 and SHAKE algorithms though low level SHA3_Init, SHA3_Update, SHA3_Final and SHAKE_init, SHAKE_Final APIs. Currently, there are two issues with the implementation and usage of SHA3 and SHAKE:

  • There is no support for SHAKE_Update function. SHAKE is implemented by calling SHAKE_Init, SHA3_Update and SHAKE_Final.
  • SHAKE_Final allows multiple consecutive calls to enable incremental XOF output generation.

This PR addresses both of them as follows:

  • Introduce new API layers - FIPS202, SHA3 and SHAKE.

    • Keccak1600 layer (Keccak1600_Squeeze/Absorb Layer (rename) #2097) implements KeccakF1600 Absorb and Squeeze functions; Keccak1600 layer does not manage internal input/output buffers.
    • FIPS202 layer implements Reset, Init, Update, and Finalize functionalities; FIPS202 layer manages the internal input/output buffers, allowing incremental requests (not necessarily multiple of block size) to Update (Absorb) and Squeeze for input/output processing. (Other functionalities, such as zero-ing of bitstate, block size checks, etc. are also handled by FIPS202 API layer).
      • FIPS202 layer implements all common behavior between SHA3 and SHAKE algorithms.
      • FIPS202 layer checks/updates the |ctx->state| flag when handling a common behavior between SHA3 and SHAKE algorithms. |ctx->state| is updated in the higher level SHA3_ SHAKE_ API layer when the behavior of both algorithms diverges (SHAKE can allow incremental squeezes).
    • SHA3 layer implements Init, Update, and Final functionalities; SHA3 layer only implements SHA3 algorithm, thus, offers a single-call SHA3_Final function. SHA3_Final will update internal |ctx->state| flag to prevent any sequential calls.
    • SHAKE layer implements XOF SHAKE algorithm, therefore, offers Init, Absorb, Squeeze, and Final functionalities;
      • SHAKE layer implements Init, and Absorb, Squeeze with incremental call support for absorb (byte-wise) and squeeze (block-wise).
      • SHAKE layer implements a single-call SHAKE_Final function that generates an arbitrary length output and finalizes SHAKE. Incremental XOF output generation is handled by |SHAKE_Squeeze|. |SHAKE_Squeeze| can be called multiple times. SHAKE_Final should be called only once.
  • KECCAK600_CTX struct updates:

    • Remove |padded| field
    • Introduce |state| field
      • |state| can be |KECCAK1600_STATE_ABSORB|, |KECCAK1600_STATE_SQUEEZE|, |KECCAK1600_STATE_FINAL|
      • |KECCAK1600_STATE_ABSORB| - allows incremental absorbs until the state is changed
      • |KECCAK1600_STATE_SQUEEZE| - allows incremental squeezes for |SHAKE_Squeeze|
      • |KECCAK1600_STATE_Final| - prevents from incremental squeezes via |SHAKE_Final| and prevents from consecutive calls to |SHA3_Final| (Final functions are single-shot functions).

SHA3 vs SHAKE algorithms (APIs usage):

  • SHA3 digest generation: SHA3_Init; SHA3_Update; SHA3_Final;
  • SHAKE (single-shot-output) output generation: SHAKE_Init; SHAKE_Absorb; SHAKE_Final;
  • SHAKE (incremental) output generation: SHAKE_Init; SHAKE_Absorb; SHAKE_Squeeze+;

Call-outs:

Service indicator is updated:

  • Inside SHA3 and SHAKE single shot APIs (as previously in AWS-LC);
  • Inside SHA3_Final (as previously in AWS-LC);
  • Inside SHAKE_Final (Single-Shot XOF Final output generation as previously in AWS-LC);
  • Inside SHAKE_Squeeze (Streaming XOF Squeezes output generation updates the service indicator after each extendable output update);

All other algorithms that use SHA3/SHAKE APIs are updated:

  • ML-KEM (SHA3/SHAKE calls will be inlined later)
  • ML-DSA (SHAKE_Squeeze (incremental XOF output functionality) inside ML-DSA is never invoked with the KAT test vectors and gtests)

Testing:

./crypto/crypto_test --gtest_filter="KeccakInternalTest.*"
./crypto/crypto_test --gtest_filter="SHA3Test.*"
./crypto/crypto_test --gtest_filter="SHAKETest.*"

./crypto/crypto_test --gtest_filter="All/PerKEMTest.*"
./crypto/crypto_test --gtest_filter="All/PQDSAParameterTest.*"

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license.

manastasova and others added 26 commits December 30, 2024 16:57
Define Keccak1600, FIPS202, and SHA3/SHAKE API layers

Keccak1600 implements absorb and squeeze functionalities. It defines the lowest lever APIs for SHA3/SHAKE; Keccak1600 functions only process complete blocks; internal input/output buffers are handles by higher layer (FIPS202) APIs.

FIPS202 APIs handle the internal input/output buffers to allow incremental function calls. FIPS202 layer is used by both SHA3 and SHAKE high level APIs. FIPS202 defines Reset, Init, Update, Finalize APIs.

SHA3/SHAKE layer implements the SHA3 and SHAKE algorithms. SHA3 supports Init, Update and Final APIs since it produces a given length digest and should be Finalized in a single Final function call. SHAKE supports Init, Update, Finalize and Squeeze APIs since it can generate arbitrary length output in incremental way. SHAKE_Finalize processes padding and absorb of last input block and generates the first output value; Incremental XOF output generation is defined by SHAKE_Squeeze function which implements the squeeze phase (it does not finalize the absorb, SHAKE_Squeeze can be only called after SHAKE_Finalize
Note: symmetric-shake.c will be inlined, therefore, additional checks for |ctx->padded| flag will be omitted (SHAKE_Finalize should be called once to finalize absorb and initialize squeeze phase; SHAKE_Squeeze should be called to generate additional incremental XOF output).
…on may not be completed (incremental XOF output request); however, the SHAKE_Finalize function completes the first requested output, thus, SHAKE has processed the first valid output value
Rename SHAKE_Update to SHAKE_Absorb; Define SHAKE_Final as a single-shot API; Defined SHAKE_Squeeze as an incremental (independent) API. It can can be called immediately after SHAKE_Absorb; SHAKE_Squeeze will finalize absorb phase and initiate squeeze phase; When called a signle time SHAKE_Squeeze has the same behavior as SHAKE_Final, SHAKE_Final cannot be called consecutive times; SHAKE_Squeeze can be called multiple times; SHAKE_Squeeze can be called after SHAKE_Final (to squeeze more bytes).
Allow KECCAK1600_STATE_ABSORB, KECCAK1600_STATE_SQUEEZE, KECCAK1600_STATE_FINAL state flag values to prevent incremental usage of SHAKE_Final or SHAKE_Squeeze after SHAKE_Final

The cahnge is introduced for consistency reasons

KECCAK1600_STATE_ABSORB corresponds to |ctx->padded| = 0 (NOT_PADDED), KECCAK1600_STATE_SQUEEZE corresponds to |ctx->padded| = 1 (PADDED), and KECCAK1600_STATE_FINAL blocks incremental Squeeze calls.
Make FIPS202 functions static; Do not export SHA3 and SHAKE internal functions
Clean redefinition of SHAKE blocksize/rate macros; Update their use inside MLKEM and MLDSA.
Fix alignment

Co-authored-by: Jake Massimo <[email protected]>
Upon Init, the |ctx->state| is set to |KECCAK1600_STATE_ABSORB| allowing absorb calls from both SHA3 and SHAKE; Upon Finalize (padding and last absorb) SHA3 and SHAKE (Final or incremental Squeeze) behave in a different way; thus, the |ctx->state| is set to |KECCAK1600_STATE_FINAL| when no incremental calls are allowed (|SHA3_Final| and |SHAKE_Final| and to |KECCAK1600_STATE_SQUEEZE| when incremental squeezes are allowed (SHAKE_Squeeze).
@manastasova manastasova requested a review from a team as a code owner January 7, 2025 21:11
@codecov-commenter
Copy link

codecov-commenter commented Jan 7, 2025

Codecov Report

Attention: Patch coverage is 81.60920% with 16 lines in your changes missing coverage. Please review.

Project coverage is 78.97%. Comparing base (39a4383) to head (1fdb30e).

Files with missing lines Patch % Lines
crypto/fipsmodule/sha/sha3.c 78.68% 13 Missing ⚠️
crypto/ml_dsa/ml_dsa_ref/poly.c 76.92% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2098      +/-   ##
==========================================
+ Coverage   78.95%   78.97%   +0.01%     
==========================================
  Files         611      611              
  Lines      105522   105555      +33     
  Branches    14946    14951       +5     
==========================================
+ Hits        83317    83362      +45     
+ Misses      21553    21542      -11     
+ Partials      652      651       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

jakemas and others added 27 commits January 30, 2025 17:33
### Issues:
Aligned with
https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/06/
on ML-DSA ASN.1 encoding and decoding.

### Description of changes: 
Will and I checked through the ASN.1 encoding and decoding functions to
check compatibility with the draft RFC. We have confirmed that we are in
alignment with the standard, so can remove this TODO.

### Call-outs:
For reference, the padding bit `0` used in `!CBB_add_u8(&key_bitstring,
0 /* padding */) ||` is present because DER-encoded bit strings use the
first "value" byte to give the number of (least significant) 0-padding
bits at the end of byte sequence. As the padding is 0 for ML-DSA keys,
we encode this value at the start of the bitstring.

For private keys, OCTET STRING encoding is used.

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
OpenSSL's historically printed `BN_bn2hex` with upper case letters, as
opposed to our original upstream predecessors. We haven't had a concrete
ask to change this until recently:
ruby/openssl#833.
As most of the open source community and our integration targets still
depend on OpenSSL as their main libcrypto dependency, we should consider
making the minor adjustment to minimize churn for us and our consumers.

### Testing:
Tweaks to existing tests.

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
We've historically settled on treating asserts as not in scope for our
constant-time goals. Production binaries are expected to be optimized
builds, with debug assertions turned off. (We have a handful of
assertions in perf-sensitive code that you definitely do not want to run
with.) Secret data has invariants too, so it is useful to be able to
write debug assertions on them.

However, combined with our default CMake build being a debug build, this
seems to cause some confusion with researchers sometimes. Also, if we
ever get language-level constant-time support, we would need to resolve
this mismatch anyway. (I assume any language support would put enough
into the type system to force us to declassify any intentional branches
on secret-by-data-flow bools, notably those we assert on.) So I'm
inclined to just make our asserts constant-time.

There are two issues around asserts, at least with our valgrind-based
validation:

The first is that a couple of asserts over secret data compute their
condition leakily. We can just fix these. The only such ones I found
were in bn_reduce_once and bn_gcd_consttime.

The second is that almost every assert over secret data will be flagged
as an invalid branch by valgrind. However, presuming the condition
itself was computed in constant time, this branch is actually safe. If
we were willing to abort the process when false, the assert is clearly
publicly true. We just need to declassify the boolean to assert on it.

assert(constant_time_declassify_int(expr)) is really long, so I made an
internal wrapper macro declassify_assert(expr). Not sure if that's the
best name. constant_time_declassify_assert(expr) is kinda long.
constant_time_assert(expr) fits with the rest of that namespace, but
reads as if we're somehow running an assert without branching, when the
whole point is that we *are* branching and need to explicitly say it's
okay to.

Fixed: 339
Change-Id: Ie33b99bf9a269b11d2c48d246cc4934be7e239ff
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/65467
Reviewed-by: Bob Beck <[email protected]>
Commit-Queue: David Benjamin <[email protected]>
(cherry picked from commit 9b8b483276da2b3d36ea21e97743e310314a8de0)
gen_group wasn't copied over.

Change-Id: If5341dce69fe0297b6bd9a5fb7ed34d546201604
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/67167
Reviewed-by: Bob Beck <[email protected]>
Commit-Queue: David Benjamin <[email protected]>
(cherry picked from commit 8248baaf3e14895cc85255c009aace5fb92d0c95)
AWS-LC:
- X509_TRUST is in include/openssl/x509.h;
  the check_trust function pointer was changed there.
Change-Id: Ie16e9ab0897305089672720efa4530d43074f692
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/67387
Auto-Submit: Theo Buehler <[email protected]>
Reviewed-by: Bob Beck <[email protected]>
Reviewed-by: David Benjamin <[email protected]>
Commit-Queue: Bob Beck <[email protected]>
(cherry picked from commit 4ac76f07a401b9b11d6ff305049721cfe3f6a777)
Lots of code relies on this, so we ought to document it. A null
STACK_OF(T) is treated as an immutable empty list.

AWS-LC:
- sk_TEST_INT_find takes 2 arguments only due to
  aws@9860446
- Based on changes to stack.h L-513-515 in the same commit, in compatibility
  with OpenSSL, -1 is returned in the last check in NullIsEmpty test.

Change-Id: I10d0ba8f7b33c7f3febaf92c2cd3da25a0eb0f80
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/67407
Reviewed-by: Theo Buehler <[email protected]>
Auto-Submit: David Benjamin <[email protected]>
Commit-Queue: Bob Beck <[email protected]>
Reviewed-by: Bob Beck <[email protected]>
(cherry picked from commit 821fe3380cce646fa3557b882d91fba318981b9b)
See https://developer.apple.com/documentation/bundleresources/privacy_manifest_files

Change-Id: I12e485ce294ead6a6cc16018e7e2adbb1efeddec
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/67487
Auto-Submit: Adam Langley <[email protected]>
Reviewed-by: David Benjamin <[email protected]>
Commit-Queue: Adam Langley <[email protected]>
(cherry picked from commit a2ef200d79158613f5a312eb5a13ddceae518bfb)
We're using it in parts of EVP already and this is much more readable.

Change-Id: I42f30b83331cafdabd4f5d995b61176458e906bc
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/67567
Auto-Submit: David Benjamin <[email protected]>
Commit-Queue: David Benjamin <[email protected]>
Reviewed-by: Adam Langley <[email protected]>
Commit-Queue: Adam Langley <[email protected]>

(cherry picked from commit b171749734c438994526096c2150e9baf9d87313)
Noncharacters are weird. They're code points and generally expected to
pass through string APIs and such, but they're also not meant to be used
for "open interchange". We reject them, while most Unicode APIs accept
them. They're public API nowadays, so document this.

Change-Id: I56aa436ae954b591d9a00b6560617e1ad5c26d95
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/67568
Auto-Submit: David Benjamin <[email protected]>
Reviewed-by: Adam Langley <[email protected]>
Commit-Queue: Adam Langley <[email protected]>
Commit-Queue: David Benjamin <[email protected]>

(cherry picked from commit 27e09a3277d17718902afca16cce7e2fb9a82ec2)
The docs still describe the old implementation, but our PRNG has changed
drastically since then.

Change-Id: I51c34833a364a1d6bd70cf5d3b6cfb87b4aa06e7
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/67569
Commit-Queue: Adam Langley <[email protected]>
Reviewed-by: Adam Langley <[email protected]>
Auto-Submit: David Benjamin <[email protected]>
Commit-Queue: David Benjamin <[email protected]>

(cherry picked from commit ec6cb3e3a016a8e7ffee42d589d423e6057f21bf)
…IMPL.`

Change-Id: I8340cf9259de72792a01049ecc36997233887006
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/67607
Commit-Queue: David Benjamin <[email protected]>
Reviewed-by: David Benjamin <[email protected]>
(cherry picked from commit 68c6fd8943ffba4e5054ff3a9befa8882b6b226a)
Bug: chromium:40925630
Change-Id: Ide72960600747f5ce9a9213a9103510fee3e3806
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/67527
Reviewed-by: David Benjamin <[email protected]>
Commit-Queue: David Benjamin <[email protected]>

(cherry picked from commit f94f3ed3965ea033001fb9ae006084eee408b861)
This makes me sad, but strdup may be more trouble than is worth it?
Being not in C (until C23) and only a (by POSIX standards) recent
addition to POSIX means a lot of folks seem to make it unnecessarily
hard to use:

- MSVC adds a deprecation warning that we have to suppress

- glibc gates it on feature macros; we just don't notice because we
  already have to work around their bad behavior for pthread_rwlock

- musl gates it on feature macros, which was one of the things that
  tripped cl/583161936

Given we only want to use strdup in one file (err.c, which wants to
avoid OPENSSL_malloc), a small reimplementation is probably not the end
of the world.

While I'm here, we can actually make OPENSSL_strdup's implementation a
little simpler.

Change-Id: I4e6c743b3104a67357d7d527c178c615de6bc844
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/64047
Reviewed-by: Bob Beck <[email protected]>
Commit-Queue: David Benjamin <[email protected]>
(cherry picked from commit 89f097740e6376521926eb56a61b25f639c473ac)
### Description of changes: 
The [GitHub Mac runners occasionally
fail](https://github.com/aws/aws-lc/actions/runs/12839452846/job/35806842991?pr=2127)
the Channel ID tests with an error like:
```
bad error (wanted ':CHANNEL_ID_SIGNATURE_INVALID:' / ''): local error 'channel ID unexpectedly negotiated', child error 'exit status 1', stdout:
```
This change logs more things to get more info to help debugging
these failures.

### Call-outs:
I wasn't able to test this code path locally because I can't get these
failures to reproduce locally.

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
### Issues:
Resolves: P189934541

### Description of changes: 
* The size of `generated-src/crypto_test_data.cc` is approaching 100MB.
This change generates the file into a compressed form.

### Call-outs:
Updating scripts related to this files creation and validation.

### Testing:
These changes are thoroughly covered by our CI.

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
### Description of changes: 
Prepare AWS-LC v1.43.0

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
Ruby's made a couple larger refactors to require versions later than
OpenSSL 1.1.1.

These changes require us to make a few tweaks to the patch in
aws#2071 and have exposed a couple minor
symbols that we don't support. Adding support for the ones that aren't
complicated in this commit.

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
### Issues:
Resolves #CryptoAlg-2819

### Description of changes: 
Implements:
- https://pages.nist.gov/ACVP/draft-celi-acvp-ml-dsa.html
-
https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/ML-DSA-keyGen-FIPS204
-
https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/ML-DSA-sigGen-FIPS204
-
https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/ML-DSA-sigVer-FIPS204

### Additional Details
Added testing for ML-DSA configured with`deterministic = true`
`externalmu = true, false` `signatureInterface = internal` for
`parameterSet = ML-DSA-44, ML-DSA-65, ML-DSA-87`.

We add the [ML-DSA sigGen Test Case JSON
Schema](https://pages.nist.gov/ACVP/draft-celi-acvp-ml-dsa.html#name-ml-dsa-siggen-test-case-jso):

```
type mlDsaSigGenTestGroup struct {
	ID                 uint64 `json:"tgId"`
	Type               string `json:"testType"`
	ParameterSet       string `json:"parameterSet"`
	Deterministic      bool   `json:"deterministic"`
	SignatureInterface string `json:"signatureInterface"`
	ExternalMu         bool   `json:"externalMu`
	Tests         []struct {
		ID      uint64               `json:"tcId"`
		Message hexEncodedByteString `json:"message"`
		MU      hexEncodedByteString `json:"mu"`
		SK      hexEncodedByteString `json:"sk"`
		RND     hexEncodedByteString `json:"rnd"`
		Context hexEncodedByteString `json:"context"`
		HashAlg string               `json:"hashAlg"`
	}
}
```
and [ML-DSA sigVer Test Case JSON
Schema](https://pages.nist.gov/ACVP/draft-celi-acvp-ml-dsa.html#name-ml-dsa-sigver-test-case-jso):
```
type mlDsaSigVerTestGroup struct {
	ID                 uint64 `json:"tgId"`
	Type               string `json:"testType"`
	ParameterSet       string `json:"parameterSet"`
	Deterministic      bool   `json:"deterministic"`
	SignatureInterface string `json:"signatureInterface"`
	ExternalMu         bool   `json:"externalMu`
	Tests        []struct {
		ID        uint64               `json:"tcId"`
		PK        hexEncodedByteString `json:"pk"`
		Message   hexEncodedByteString `json:"message"`
		MU        hexEncodedByteString `json:"mu"`
		Signature hexEncodedByteString `json:"signature"`
		Context   hexEncodedByteString `json:"context"`
                HashAlg   string               `json:"hashAlg"`
	}
}
```




### Testing:
```
Running ACVP tests
2025/01/17 14:09:39 40 ACVP tests matched expectations
2025/01/17 14:09:40 1 ACVP tests matched expectations
2025/01/17 14:09:41 1 ACVP tests matched expectations
2025/01/17 14:09:42 1 ACVP tests matched expectations
2025/01/17 14:09:44 1 ACVP tests matched expectations
2025/01/17 14:09:46 1 ACVP tests matched expectations
2025/01/17 14:09:48 1 ACVP tests matched expectations
2025/01/17 14:09:50 1 ACVP tests matched expectations
2025/01/17 14:09:52 1 ACVP tests matched expectations
2025/01/17 14:10:09 1 ACVP tests matched expectations
2025/01/17 14:10:10 1 ACVP tests matched expectations
2025/01/17 14:10:11 1 ACVP tests matched expectations
2025/01/17 14:10:12 1 ACVP tests matched expectations
2025/01/17 14:10:12 1 ACVP tests matched expectations
```

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
…s#2136)

These operating systems are unused, untested, and not a priority for us. Remove remnants of them
A bimodal performance occurred in the XTS encrypt AVX512 implementation. We have observed more than 80% drop in performance. This is caused by mixing SSE and AVX instructions in the AVX512 implementation. For a subset of input lengths, the code path contained a single move movdqa, an SSE instruction. Use vmovdqa instead.
### Issues:
Resolves #CryptoAlg-2868

### Description of changes: 

It is often useful when serializing asymmetric key pairs to populate
both the public and private elements, given only the private element.
For this to be possible, an algorithm utility function is often provided
to derive key material. ML-DSA does not support this in the reference
implementation.

#### Background ML-DSA keypairs 

An ML-DSA private key is constructed of the following elements: (ref
https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf)
```
sk = (
      rho, // public random seed (32-bytes)
      tr,  // public key hash (64-bytes)
      key, // private random seed (32-bytes) (utilized during sign)
      t0,  // polynomial vector: encodes the least significant bits of public-key polynomial t, facilitating certain computational efficiencies.
      s1,  // secret polynomial vectors. These vectors contain polynomials with coefficients in a specified range, 
      s2.  // serving as the secret components in the lattice-based structure of ML-DSA.
)
```

An ML-DSA public key is constructed of the following elements:
```
pk = (
      rho, // public random seed (32-bytes)
      t1.  // compressed representation of the public key polynomial 
)
```

- The vector t is decomposed into two parts:
- `t1`: Represents the higher-order bits of `t`.
- `t0`: Represents the lower-order bits of `t`.

One can see that to reconstruct the public key from the private key, one
must:
1. Extract all elements from `sk`, using the existing function in
`/ml_dsa_ref/packing.c`: `ml_dsa_unpack_sk`
    1. This will provide `sk = (rho, tr, key, t0, s1, s2)`.
2. Reconstruct `A` using `rho` with the existing function in
`/ml_dsa_ref/polyvec.c`: `ml_dsa_polyvec_matrix_expand`
3. Reconstruct `t` from `t = A*s1 + s2`
4. Drop `d` lower bits from `t` to get `t1`
5. Pack `rho`, `t1` into public key.
6. Verify `pk` matches expected value, by comparing SHAKE256(pk) + `tr`
(unpacked from secret key).

This has been implemented in `ml_dsa_pack_pk_from_sk` -- not tied to the
name, just using what I've seen so far in common nomenclature.

As the values of `d` differ for each parameter set of ML-DSA, we must
create packing functions for each parameter size. As such,
`ml_dsa_44_pack_pk_from_sk``, `ml_dsa_65_pack_pk_from_sk``, and
`ml_dsa_87_pack_pk_from_sk`` have been added to `ml_dsa.h` to serve as
utility functions in higher level EVP APIs.

### Call-outs:

The scope of this PR is only the algorithm level, using these functions
for useful tasks such as populating the public key automatically on
private key import -- will be added in subsequent PRs.

### Testing:
A new test has been added to `PQDSAParameterTest`, namely,
`KeyConsistencyTest` that will assert that packing the key is
successful, and that the key produced matches the original public key.

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
### Description of changes: 
* Add support for Ed25519ph and Ed25519ph where the digest is
pre-computed and provided externally.
* Add support for Ed25519ctx from RFC 8032.

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
### Issues:
Addresses: 
* aws/aws-lc-rs#522

### Description of changes: 
Setup macros for big-endian MIPS in "target.h"

### Callout
A contributor informs us that the build for `mips-unknown-linux-musl`
succeeds with this change:
aws/aws-lc-rs#522 (comment)

### Testing:
No CI testing for it. 

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
As suggested in https://github.com/animetosho/md5-optimisation?tab=readme-ov-file#dependency-shortcut-in-g-function, we can delay the dependency on 'x' by recognizing that ((x & z) | (y & ~z)) is equivalent to ((x & z) + (y + ~z)) in this scenario, and we can perform those additions independently, leaving our dependency on x to the final addition. This speeds it up around 5% on both platforms.
### Issues:
Resolves #CryptoAlg-2868

### Description of changes: 
Following from the first part of this PR to add low level support for
ML-DSA public key generation from private keys. This PR uses the new
`pqdsa` method `pqdsa->pqdsa_pack_pk_from_sk`. We supply
`ml_dsa_44_pack_pk_from_sk`, `ml_dsa_65_pack_pk_from_sk`, and
`ml_dsa_87_pack_pk_from_sk` from `ml_dsa.h` to provide this
functionality for ML-DSA.

As we use `EVP_parse_private_key` to import `PQDSA` keys into AWS-LC, we
need to modify the `PQDSA` asn.1 private key decoding function to
additionally populate the corresponding public key.

The `pqdsa_priv_decode` function in `p_pqdsa_asn1.c` has been modified
to attempt to generate a public key from the provided secret key, should
the method be defined for that `pqdsa` structure. As ML-DSA is the only
current `PQDSA`, the library currently does implement methods for all
`PQDSA` PKEY types.

### Call-outs:
> what happens if a new `PQDSA` algorithm is introduced to aws-lc, and
doesn't support `pk` calculation from `sk`?

We populate the methods as `NULL` and will modify the G.test that
expects the public key to be generated. We can make this change simply
if/when we add to the `PQDSA` capabilites with an algorithm that doesn't
support `pk` from `sk`.

### Testing:
To test functionality, I have adapted the `PQDSAParameterTest` G.test
`MarshalParse` to now verify that the public key is populated after
calling `EVP_parse_private_key`. We then verify that the public key
calculated is equal to the original public key.

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
@manastasova manastasova marked this pull request as ready for review January 30, 2025 17:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.