swift-crypto icon indicating copy to clipboard operation
swift-crypto copied to clipboard

Add ML-DSA post-quantum signatures to `_CryptoExtras`

Open fpseverino opened this issue 1 year ago • 1 comments

Add support for ML-DSA post-quantum digital signatures inside _CryptoExtras.

Checklist

  • [x] I've run tests to see all new and existing tests pass
  • [x] I've followed the code style of the rest of the project
  • [x] I've read the Contribution Guidelines
  • [x] I've updated the documentation if necessary

If you've made changes to gyb files

  • [ ] I've run .script/generate_boilerplate_files_with_gyb and included updated generated files in a commit of this pull request

Motivation:

With the advent of quantum computing, the mathematical foundations on which the cryptographic protocols in use today are based have been questioned, as they can easily be circumvented and violated by quantum computers.

While waiting for the creation of quantum computers that work at full capacity, and to protect network communications from "Harvest Now, Decrypt Later" attacks, the cryptographic community is working on post-quantum cryptography algorithms, which work on the traditional computers we use today, but are resistant to future attacks by quantum computers.

One of these algorithms is ML-DSA (AKA Dilithium), a module lattice-based signature scheme standardized by NIST in FIPS 204, that is available inside BoringSSL.

By including ML-DSA inside Swift Crypto, we can get closer to normalizing quantum secure algorithms and start implementing them into our apps and libraries to make them quantum-proof.

Modifications:

Added a MLDSA enum inside the _CryptoExtras module with corresponding PrivateKey, PublicKey and Signature structs that use BoringSSL methods to produce and verify ML-DSA-65 digital signatures, with the code style of other signature schemes in the library.

Added tests that cover use cases of the ML-DSA scheme, including test vectors taken from the BoringSSL repo (extracted from a .txt file and encoded in JSON).

Result:

ML-DSA-65 digital signatures can be created and verified with Swift Crypto.

fpseverino avatar Oct 02 '24 15:10 fpseverino

Hi @Lukasa, thank you very much for the quick feedback and directions.

I think I fixed most of your requested changes, but I have some problems with the DER and PEM representations. Unlike RSA, where there are clear BoringSSL methods for generating and parsing them, I can't find any for ML-DSA. Maybe there are some generic ones? Or a pure Swift implementation (perhaps with swift-asn1) is possible/required?

Please let me know if the other changes I made are valid and how I could fix the PEM/DER issue. Thanks again for the help!

fpseverino avatar Oct 03 '24 17:10 fpseverino

Just a few CI jobs to fix up. Missing license headers, and a need to run the cmake script in the scripts directory.

Lukasa avatar Nov 08 '24 16:11 Lukasa

The license headers are there, but I think the CI wants a CONTRIBUTORS.txt, whereas in this repo there is a CONTRIBUTORS.md

fpseverino avatar Nov 08 '24 17:11 fpseverino

Regarding the CMake script, if I run sh scripts/update_cmakelists.sh it removes all the libraries string from the CMakeLists.txt files. I suppose that's not the intended outcome.

Here's the output:

Finding source files (*.c *.swift) under /Users/francescopaoloseverino/Documents/GitHub/swift-crypto/Sources/CCryptoBoringSSL
scripts/update_cmakelists.sh: line 58: gfind: command not found

Updated /Users/francescopaoloseverino/Documents/GitHub/swift-crypto/Sources/CCryptoBoringSSL/CMakeLists.txt
Finding source files (*.c *.swift) under /Users/francescopaoloseverino/Documents/GitHub/swift-crypto/Sources/CCryptoBoringSSLShims
scripts/update_cmakelists.sh: line 58: gfind: command not found

Updated /Users/francescopaoloseverino/Documents/GitHub/swift-crypto/Sources/CCryptoBoringSSLShims/CMakeLists.txt
Finding source files (*.c *.swift) under /Users/francescopaoloseverino/Documents/GitHub/swift-crypto/Sources/CryptoBoringWrapper
scripts/update_cmakelists.sh: line 58: gfind: command not found

Updated /Users/francescopaoloseverino/Documents/GitHub/swift-crypto/Sources/CryptoBoringWrapper/CMakeLists.txt
Finding source files (*.c *.swift) under /Users/francescopaoloseverino/Documents/GitHub/swift-crypto/Sources/Crypto
scripts/update_cmakelists.sh: line 58: gfind: command not found

Updated /Users/francescopaoloseverino/Documents/GitHub/swift-crypto/Sources/Crypto/CMakeLists.txt
Finding source files (*.c *.swift) under /Users/francescopaoloseverino/Documents/GitHub/swift-crypto/Sources/_CryptoExtras
Excluding source paths (*/AES/*.swift) under /Users/francescopaoloseverino/Documents/GitHub/swift-crypto/Sources/_CryptoExtras
scripts/update_cmakelists.sh: line 58: gfind: command not found

Updated /Users/francescopaoloseverino/Documents/GitHub/swift-crypto/Sources/_CryptoExtras/CMakeLists.txt
Finding assembly files (.S) under /Users/francescopaoloseverino/Documents/GitHub/swift-crypto/Sources/CCryptoBoringSSL
scripts/update_cmakelists.sh: line 72: gfind: command not found
scripts/update_cmakelists.sh: line 73: gfind: command not found
scripts/update_cmakelists.sh: line 74: gfind: command not found
scripts/update_cmakelists.sh: line 75: gfind: command not found




Updated /Users/francescopaoloseverino/Documents/GitHub/swift-crypto/Sources/CCryptoBoringSSL/CMakeLists.txt

P.S. I do have the find command installed on my computer

fpseverino avatar Nov 08 '24 17:11 fpseverino

We expect GNU find. You can get it by running brew install findutils

Lukasa avatar Nov 20 '24 12:11 Lukasa

@Lukasa all done, now the jobs should pass

fpseverino avatar Nov 20 '24 18:11 fpseverino

@Lukasa I saw that the BoringSSL team added another parameter set to ML-KEM. Considering that they might do this for ML-DSA too, to avoid breaking the API, should we put the current implementation inside a namespace that identifies the parameter set? If so, I'm open to suggestions for names, as the following (which are the most obvious) are not valid.

enum MLDSA {
    enum 65 {
        // Implementation proposed in this PR
    }
    
    // Possible future ones
    enum 44 {}
    enum 87 {}
}

P.S. Each parameter set uses completely different C++ functions and structures

EDIT: As suggested by Cory I went with MLDSA65.PrivateKey etc.

fpseverino avatar Nov 27 '24 19:11 fpseverino

There's an annoying thing in the signature and isValidSignature methods that I don't know how to solve:

I wanted to give a separate generic type to the context argument, like Curve25519 (and now also MLDSA65) do for the data and signature arguments, but since it is nil by the default the compiler can't infer it. The solution in place right now is to use the same generic type as data.

fpseverino avatar Jan 03 '25 14:01 fpseverino

Thank you @Lukasa for all the help and guidance you have given me!

fpseverino avatar Apr 30 '25 11:04 fpseverino