From 57ad721b75893886344a91908d6516efc7d4340f Mon Sep 17 00:00:00 2001 From: Sean McGrail Date: Thu, 29 Aug 2024 23:36:36 +0000 Subject: [PATCH] Add ED25519 ACVP Testing --- crypto/fipsmodule/curve25519/curve25519.c | 7 + .../fipsmodule/curve25519/curve25519_nohw.c | 8 + .../curve25519/curve25519_s2n_bignum_asm.c | 8 + crypto/fipsmodule/curve25519/internal.h | 5 + .../acvp/acvptool/subprocess/eddsa.go | 308 ++++++++++++++++++ .../acvp/acvptool/subprocess/subprocess.go | 1 + .../acvp/acvptool/test/expected/EDDSA.bz2 | Bin 0 -> 281 bytes util/fipstools/acvp/acvptool/test/tests.json | 5 +- .../acvptool/test/vectors/EDDSA-KeyGen.bz2 | Bin 0 -> 287 bytes .../acvptool/test/vectors/EDDSA-SigGen.bz2 | Bin 0 -> 513 bytes .../acvp/acvptool/test/vectors/EDDSA.bz2 | Bin 0 -> 687 bytes .../acvp/modulewrapper/modulewrapper.cc | 95 +++++- 12 files changed, 433 insertions(+), 4 deletions(-) create mode 100644 util/fipstools/acvp/acvptool/subprocess/eddsa.go create mode 100644 util/fipstools/acvp/acvptool/test/expected/EDDSA.bz2 create mode 100644 util/fipstools/acvp/acvptool/test/vectors/EDDSA-KeyGen.bz2 create mode 100644 util/fipstools/acvp/acvptool/test/vectors/EDDSA-SigGen.bz2 create mode 100644 util/fipstools/acvp/acvptool/test/vectors/EDDSA.bz2 diff --git a/crypto/fipsmodule/curve25519/curve25519.c b/crypto/fipsmodule/curve25519/curve25519.c index 5717984a61..50aa6cdeb3 100644 --- a/crypto/fipsmodule/curve25519/curve25519.c +++ b/crypto/fipsmodule/curve25519/curve25519.c @@ -224,6 +224,13 @@ int ED25519_verify(const uint8_t *message, size_t message_len, return res; } +int ED25519_check_public_key(const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]) { +#if defined(CURVE25519_S2N_BIGNUM_CAPABLE) + return ed25519_check_public_key_s2n_bignum(public_key); +#else + return ed25519_check_public_key_nohw(public_key); +#endif +} void X25519_public_from_private( uint8_t out_public_value[X25519_PUBLIC_VALUE_LEN], diff --git a/crypto/fipsmodule/curve25519/curve25519_nohw.c b/crypto/fipsmodule/curve25519/curve25519_nohw.c index 32d946f5c4..d51c94c261 100644 --- a/crypto/fipsmodule/curve25519/curve25519_nohw.c +++ b/crypto/fipsmodule/curve25519/curve25519_nohw.c @@ -2043,3 +2043,11 @@ int ed25519_verify_nohw(uint8_t R_computed_encoded[32], return 1; } + +int ed25519_check_public_key_nohw(const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]) { + ge_p3 A; + if (!x25519_ge_frombytes_vartime(&A, public_key)) { + return 0; + } + return 1; +} diff --git a/crypto/fipsmodule/curve25519/curve25519_s2n_bignum_asm.c b/crypto/fipsmodule/curve25519/curve25519_s2n_bignum_asm.c index 59be5df878..50e52f02c1 100644 --- a/crypto/fipsmodule/curve25519/curve25519_s2n_bignum_asm.c +++ b/crypto/fipsmodule/curve25519/curve25519_s2n_bignum_asm.c @@ -120,4 +120,12 @@ int ed25519_verify_s2n_bignum(uint8_t R_computed_encoded[32], return 1; } +int ed25519_check_public_key_s2n_bignum(const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]) { + uint64_t A[8] = {0}; + if (edwards25519_decode_selector(A, public_key) != 0) { + return 0; + } + return 1; +} + #endif diff --git a/crypto/fipsmodule/curve25519/internal.h b/crypto/fipsmodule/curve25519/internal.h index 0f1010d7b4..ebedea9c81 100644 --- a/crypto/fipsmodule/curve25519/internal.h +++ b/crypto/fipsmodule/curve25519/internal.h @@ -185,6 +185,11 @@ void ed25519_sha512(uint8_t out[SHA512_DIGEST_LENGTH], const void *input1, size_t len1, const void *input2, size_t len2, const void *input3, size_t len3); + +int ed25519_check_public_key_s2n_bignum(const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]); +int ed25519_check_public_key_nohw(const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]); +OPENSSL_EXPORT int ED25519_check_public_key(const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]); + #if defined(__cplusplus) } // extern C #endif diff --git a/util/fipstools/acvp/acvptool/subprocess/eddsa.go b/util/fipstools/acvp/acvptool/subprocess/eddsa.go new file mode 100644 index 0000000000..2f8698b73f --- /dev/null +++ b/util/fipstools/acvp/acvptool/subprocess/eddsa.go @@ -0,0 +1,308 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +package subprocess + +import ( + "encoding/json" + "fmt" + "strings" +) + +// NIST ACVP EDDSA Schema: https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html +type eddsa struct{} + +func (e *eddsa) Process(vectorSet []byte, m Transactable) (interface{}, error) { + var vs struct { + Mode string `json:"mode"` + TestGroups json.RawMessage `json:"testGroups"` + } + + if err := json.Unmarshal(vectorSet, &vs); err != nil { + return nil, err + } + + var processTestGroups func(json.RawMessage, Transactable) (interface{}, error) + + switch { + case strings.EqualFold(vs.Mode, "keyGen"): + processTestGroups = processEddsaKeyGenTestGroup + case strings.EqualFold(vs.Mode, "keyVer"): + processTestGroups = processEddsaKeyVerTestGroup + case strings.EqualFold(vs.Mode, "sigGen"): + processTestGroups = processEddsaSigGenTestGroup + case strings.EqualFold(vs.Mode, "sigVer"): + processTestGroups = processEddsaSigVerTestGroup + default: + return nil, fmt.Errorf("unsupported EDDSA mode %q", vs.Mode) + } + + return processTestGroups(vs.TestGroups, m) +} + +func processEddsaKeyGenTestGroup(testGroups json.RawMessage, m Transactable) (interface{}, error) { + var groups []eddsaKeyGenTestGroup + if err := json.Unmarshal(testGroups, &groups); err != nil { + return nil, err + } + + var ret []eddsaKeyGenTestGroupResponse + + for _, group := range groups { + response := eddsaKeyGenTestGroupResponse{ + ID: group.ID, + } + + if group.Type != "AFT" { + return nil, fmt.Errorf("unsupported test type %q", group.Type) + } + + for _, test := range group.Tests { + result, err := m.Transact("EDDSA/"+string(group.Curve)+"/keyGen", 2) + if err != nil { + return nil, err + } + + response.Tests = append(response.Tests, eddsaKeyGenTestCaseResponse{ + ID: test.ID, + D: result[0], + Q: result[1], + }) + } + + ret = append(ret, response) + } + + return ret, nil +} + +func processEddsaKeyVerTestGroup(testGroups json.RawMessage, m Transactable) (interface{}, error) { + var groups []eddsaKeyVerTestGroup + if err := json.Unmarshal(testGroups, &groups); err != nil { + return nil, err + } + + var ret []eddsaKeyVerTestGroupResponse + + for _, group := range groups { + if group.Type != "AFT" { + return nil, fmt.Errorf("unsupported test type %q", group.Type) + } + + response := eddsaKeyVerTestGroupResponse{ + ID: group.ID, + } + + for _, test := range group.Tests { + results, err := m.Transact("EDDSA/"+string(group.Curve)+"/keyVer", 1, test.Q) + if err != nil { + return nil, err + } + + var passed *bool + if len(results[0]) == 1 { + val := results[0][0] == 1 + passed = &val + } + + response.Tests = append(response.Tests, eddsaKeyVerTestCaseResponse{ + ID: test.ID, + Passed: passed, + }) + } + + ret = append(ret, response) + } + + return ret, nil +} + +func processEddsaSigGenTestGroup(testGroups json.RawMessage, m Transactable) (interface{}, error) { + var groups []eddsaSigGenTestGroup + if err := json.Unmarshal(testGroups, &groups); err != nil { + return nil, err + } + + var ret []eddsaSigGenTestGroupResponse + + for _, group := range groups { + if group.Type != "AFT" && group.Type != "BFT" { + return nil, fmt.Errorf("unsupported test type %q", group.Type) + } + + results, err := m.Transact("EDDSA/"+string(group.Curve)+"/keyGen", 2) + if err != nil { + return nil, err + } + + seed := results[0] + + response := eddsaSigGenTestGroupResponse{ + ID: group.ID, + Q: results[1], + } + + for _, test := range group.Tests { + results, err := m.Transact("EDDSA/"+string(group.Curve)+"/sigGen", 1, seed, test.Message) + if err != nil { + return nil, err + } + + response.Tests = append(response.Tests, eddsaSigGenTestCaseResponse{ + ID: test.ID, + Signature: results[0], + }) + } + + ret = append(ret, response) + } + + return ret, nil +} + +func processEddsaSigVerTestGroup(testGroups json.RawMessage, m Transactable) (interface{}, error) { + var groups []eddsaSigVerTestGroup + if err := json.Unmarshal(testGroups, &groups); err != nil { + return nil, err + } + + var ret []eddsaSigVerTestGroupResponse + + for _, group := range groups { + if group.Type != "AFT" { + return nil, fmt.Errorf("unsupported test type %q", group.Type) + } + + response := eddsaSigVerTestGroupResponse{ + ID: group.ID, + } + + for _, test := range group.Tests { + results, err := m.Transact("EDDSA/"+string(group.Curve)+"/sigVer", 1, test.Message, test.Q, test.Signature) + if err != nil { + return nil, err + } + + var passed *bool + if len(results[0]) == 1 { + val := results[0][0] == 1 + passed = &val + } + + response.Tests = append(response.Tests, eddsaSigVerTestCaseResponse{ + ID: test.ID, + Passed: passed, + }) + } + + ret = append(ret, response) + } + + return ret, nil +} + +const Ed25519 EDDSACurve = "ED-25519" + +type EDDSACurve string + +func (e *EDDSACurve) UnmarshalJSON(v []byte) error { + var str string + + if err := json.Unmarshal(v, &str); err != nil { + return err + } + + switch { + case strings.EqualFold(str, "ED-25519"): + *e = Ed25519 + default: + return fmt.Errorf("unsupported EDDSA curve: %q", str) + } + + return nil +} + +type eddsaKeyGenTestGroup struct { + ID uint64 `json:"tgId"` + Curve EDDSACurve `json:"curve"` + Type string `json:"testType"` + Tests []struct { + ID uint64 `json:"tcId"` + } +} + +type eddsaKeyVerTestGroup struct { + ID uint64 `json:"tgId"` + Curve EDDSACurve `json:"curve"` + Type string `json:"testType"` + Tests []struct { + ID uint64 `json:"tcId"` + Q hexEncodedByteString `json:"q"` + } +} + +type eddsaSigGenTestGroup struct { + ID uint64 `json:"tgId"` + Curve EDDSACurve `json:"curve"` + Prehash bool `json:"prehash"` + Type string `json:"testType"` + Tests []struct { + ID uint64 `json:"tcId"` + Message hexEncodedByteString `json:"message"` + } +} + +type eddsaSigVerTestGroup struct { + ID uint64 `json:"tgId"` + Curve EDDSACurve `json:"curve"` + Prehash bool `json:"prehash"` + Type string `json:"testType"` + Tests []struct { + ID uint64 `json:"tcId"` + Message hexEncodedByteString `json:"message"` + Q hexEncodedByteString `json:"q"` + Signature hexEncodedByteString `json:"signature"` + } +} + +type eddsaKeyGenTestGroupResponse struct { + ID uint64 `json:"tgId"` + Tests []eddsaKeyGenTestCaseResponse `json:"tests"` +} + +type eddsaKeyGenTestCaseResponse struct { + ID uint64 `json:"tcId"` + D hexEncodedByteString `json:"d"` + Q hexEncodedByteString `json:"q"` +} + +type eddsaKeyVerTestGroupResponse struct { + ID uint64 `json:"tgId"` + Tests []eddsaKeyVerTestCaseResponse `json:"tests"` +} + +type eddsaKeyVerTestCaseResponse struct { + ID uint64 `json:"tcId"` + Passed *bool `json:"testPassed"` +} + +type eddsaSigGenTestGroupResponse struct { + ID uint64 `json:"tgId"` + Q hexEncodedByteString `json:"q"` + Tests []eddsaSigGenTestCaseResponse `json:"tests"` +} + +type eddsaSigGenTestCaseResponse struct { + ID uint64 `json:"tcId"` + Signature hexEncodedByteString `json:"signature"` +} + +type eddsaSigVerTestGroupResponse struct { + ID uint64 `json:"tgId"` + Tests []eddsaSigVerTestCaseResponse `json:"tests"` +} + +type eddsaSigVerTestCaseResponse struct { + ID uint64 `json:"tcId"` + Passed *bool `json:"testPassed"` +} diff --git a/util/fipstools/acvp/acvptool/subprocess/subprocess.go b/util/fipstools/acvp/acvptool/subprocess/subprocess.go index 2f21c70723..dc60c3050a 100644 --- a/util/fipstools/acvp/acvptool/subprocess/subprocess.go +++ b/util/fipstools/acvp/acvptool/subprocess/subprocess.go @@ -154,6 +154,7 @@ func NewWithIO(cmd *exec.Cmd, in io.WriteCloser, out io.ReadCloser) *Subprocess "KAS-FFC-SSC": &kasDH{}, "PBKDF": &pbkdf{}, "ML-KEM": &mlKem{}, + "EDDSA": &eddsa{}, } m.primitives["ECDSA"] = &ecdsa{"ECDSA", map[string]bool{"P-224": true, "P-256": true, "P-384": true, "P-521": true}, m.primitives} diff --git a/util/fipstools/acvp/acvptool/test/expected/EDDSA.bz2 b/util/fipstools/acvp/acvptool/test/expected/EDDSA.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..954e023b5139856fe589b005522004f54e943beb GIT binary patch literal 281 zcmV+!0p|WfT4*^jL0KkKSxl;b)c^p@|A0hPKmbq%{_rNCP8u)g-wH4R8Bh`_Q`t<7 zPgB&%wHjuoMol!(Z71nN05s8{(+~gv41fxxnrSkb4^u-Sh|>tu5E(2H$#POI=JlMK zl_;%S*)?h}$8dyngT@5>n)6`2ZZ0l6k^2cL9n7gD$W;u6GxIiIsD|3nB1;9Jq`Lje z(-jd_%gR2j(^f^YJ&!R_C6Qep)ClGI4du_T8%mGUYKRV4+8u+9nzJB8wy fT0cb+CvilRWK<5M@G%(8%luu*6yZWaGO7Pm(!zVr literal 0 HcmV?d00001 diff --git a/util/fipstools/acvp/acvptool/test/tests.json b/util/fipstools/acvp/acvptool/test/tests.json index ee530fffa9..1ac72c0bef 100644 --- a/util/fipstools/acvp/acvptool/test/tests.json +++ b/util/fipstools/acvp/acvptool/test/tests.json @@ -33,5 +33,8 @@ {"Wrapper": "modulewrapper", "In": "vectors/PBKDF.bz2", "Out": "expected/PBKDF.bz2"}, {"Wrapper": "modulewrapper", "In": "vectors/KDA-HKDF.bz2", "Out": "expected/KDA-HKDF.bz2"}, {"Wrapper": "modulewrapper", "In": "vectors/KDA-OneStep.bz2", "Out": "expected/KDA-OneStep.bz2"}, -{"Wrapper": "modulewrapper", "In": "vectors/ML-KEM.bz2", "Out": "expected/ML-KEM.bz2"} +{"Wrapper": "modulewrapper", "In": "vectors/ML-KEM.bz2", "Out": "expected/ML-KEM.bz2"}, +{"Wrapper": "modulewrapper", "In": "vectors/EDDSA.bz2", "Out": "expected/EDDSA.bz2"}, +{"Wrapper": "modulewrapper", "In": "vectors/EDDSA-KeyGen.bz2"}, +{"Wrapper": "modulewrapper", "In": "vectors/EDDSA-SigGen.bz2"} ] diff --git a/util/fipstools/acvp/acvptool/test/vectors/EDDSA-KeyGen.bz2 b/util/fipstools/acvp/acvptool/test/vectors/EDDSA-KeyGen.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..66c8536078ad093b0004823096498997e52bf9e3 GIT binary patch literal 287 zcmV+)0pR{ZT4*^jL0KkKS)~D<-2ecgUw~CmPzV0-C!h`*F7MweFaY_pVWMgcLF#Gg z8X5rg0qO(P9#CqVB-7N5GBhy^OqeEvCYk{xlTAjN4Kx}68UQo^fRXkS9GO&n?O zo$rc@NJtD8krMsf0&{pge^A#%{rB zwQdRQK%)K*==mV{z`_PBl2T(SRJs&*s#Ik>)wG*Bl+7fjcu!oFo%;2NuFVnPmf1Nn lObuk9WcJc#gdx_(AX$@Z23^o)`AQ-DUC9*TLPC@Vdvv2(ef|Id literal 0 HcmV?d00001 diff --git a/util/fipstools/acvp/acvptool/test/vectors/EDDSA-SigGen.bz2 b/util/fipstools/acvp/acvptool/test/vectors/EDDSA-SigGen.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..98199ace179320f98ac34ad7e4d585fce6762d5c GIT binary patch literal 513 zcmV+c0{;C%T4*^jL0KkKSwWe$cmM%&-+)z6PzV3;Kj01;FX!JXKmpwD=q_;7)jXP> zrJXs+MCfq zrcD4e1}CTusSrWFK+L6&i1egK0t5;|1Ql0F4PEpoW|$<*92sOXRHfOAIR5 zkHElt66er2K#C(UtT_V|ND@e+2rz?an3nxlK}pNYrfGF9xHpGv2suwqopj<>4F5ol zBoq*IlUaos;jr~ORdzF+LAdX&S5t)W2eLIxxDzuZQX*sbG}P$c=u&Paf-)ACAmBl8 zpx;0cR~LhV+yyQT69XiS?2k3Ih{9Mo8bzrJm1|ThF26Z%uJ+wqD zZgmw1TP(5#kEG#zJV$Ytq~|4DK6kcpV4+E)OVW5+vmd D(b(BD literal 0 HcmV?d00001 diff --git a/util/fipstools/acvp/acvptool/test/vectors/EDDSA.bz2 b/util/fipstools/acvp/acvptool/test/vectors/EDDSA.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..4d32631402857ba14e368e898d299dcf438fd61a GIT binary patch literal 687 zcmV;g0#N-zT4*^jL0KkKS?aS1rvL&t-+)z6PzV3;Kj041UI&uPJY9uhTj5{Y7Gn%%UEh>emsrdO|se_h#dlyJ#@RlvgoKK^d^NU2ES-#^#F> z$n8~uG=wsFs__-6MlEuzSer(>sAdNEw-_DONXbb#9iwFE*Q$WTg}EH(oAeQb9qUAg z44Ra*CM1D^;1mpDJn`DuLv%R{<4}}Eq|4ibF)Nu&Ib9M7cj37aO2i`&Q(g3CLyhi;As1Fuy&SV;xF9Up zswfiL)0$bbRduZ9s@6U?!^<>;(~U+qk`#%kggq{@dR7M9m@MH9M{Uy-EcxFh1limK zLiWN>c&sZ*FT-V%n%zOpSHPl-;g7=qqnzACV$||U5pqBI+^B2Rs&$!fFtNV#=Uj@W z1A1-~^!2ZSmuc#I7ZyrO^rFRy11T3~iFIvBf+Gybu%w`N!cIGV6iGm^v6d1@z@koH zS_z6Q7|35xsw4a9VJw=uNRd?`GED%^m{A*A$V^OLw5+Om%j!fNyhT8N Vg8JZGFvG9$cO+AV2@b0;nsDexG8q5> literal 0 HcmV?d00001 diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc index 61dcf0843f..31dfa2ac1f 100644 --- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc +++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ #include "../../../../crypto/fipsmodule/ec/internal.h" #include "../../../../crypto/fipsmodule/hmac/internal.h" #include "../../../../crypto/fipsmodule/rand/internal.h" +#include "../../../../crypto/fipsmodule/curve25519/internal.h" #include "modulewrapper.h" @@ -1330,8 +1332,32 @@ static bool GetConfig(const Span args[], "revision": "FIPS203", "parameterSets": ["ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"], "functions": ["encapsulation", "decapsulation"] - } - ])"; + },)" + R"({ + "algorithm": "EDDSA", + "mode": "keyGen", + "revision": "1.0", + "curve": ["ED-25519"] + },{ + "algorithm": "EDDSA", + "mode": "keyVer", + "revision": "1.0", + "curve": ["ED-25519"] + },{ + "algorithm": "EDDSA", + "mode": "sigGen", + "revision": "1.0", + "curve": ["ED-25519"], + "pure": true, + "preHash": false + },{ + "algorithm": "EDDSA", + "mode": "sigVer", + "revision": "1.0", + "curve": ["ED-25519"], + "pure": true, + "preHash": false + }])"; return write_reply({Span( reinterpret_cast(kConfig), sizeof(kConfig) - 1)}); } @@ -2967,6 +2993,66 @@ static bool ML_KEM_DECAP(const Span args[], {Span(shared_secret.data(), shared_secret_len)}); } +static bool ED25519KeyGen(const Span args[], + ReplyCallback write_reply) { + std::vector private_key(ED25519_PRIVATE_KEY_LEN); + std::vector public_key(ED25519_PUBLIC_KEY_LEN); + ::ED25519_keypair(public_key.data(), private_key.data()); + const Span seed(private_key.data(), ED25519_PRIVATE_KEY_SEED_LEN); + return write_reply({seed, Span(public_key)}); +} + +static bool ED25519KeyVer(const Span args[], + ReplyCallback write_reply) { + const Span public_key = args[0]; + + uint8_t reply[1] = {0}; + if (::ED25519_check_public_key(public_key.data())) { + reply[0] = 1; + } else { + ERR_clear_error(); + } + + return write_reply({Span(reply)}); +} + +static bool ED25519SigGen(const Span args[], + ReplyCallback write_reply) { + const Span seed = args[0]; + const Span message = args[1]; + + std::vector private_key(ED25519_PRIVATE_KEY_LEN); + std::vector public_key(ED25519_PUBLIC_KEY_LEN); + std::vector signature(ED25519_SIGNATURE_LEN); + + ::ED25519_keypair_from_seed(public_key.data(), private_key.data(), + seed.data()); + + if (!::ED25519_sign(signature.data(), message.data(), message.size(), + private_key.data())) { + return false; + } + + return write_reply({Span(signature)}); +} + +static bool ED25519SigVer(const Span args[], + ReplyCallback write_reply) { + const Span message = args[0]; + const Span public_key = args[1]; + const Span signature = args[2]; + + uint8_t reply[1] = {0}; + if (::ED25519_verify(message.data(), message.size(), signature.data(), + public_key.data())) { + reply[0] = 1; + } else { + ERR_clear_error(); + } + + return write_reply({Span(reply)}); +} + static struct { char name[kMaxNameLength + 1]; uint8_t num_expected_args; @@ -3210,7 +3296,10 @@ static struct { {"ML-KEM/ML-KEM-512/decap", 2, ML_KEM_DECAP}, {"ML-KEM/ML-KEM-768/decap", 2, ML_KEM_DECAP}, {"ML-KEM/ML-KEM-1024/decap", 2, ML_KEM_DECAP}, -}; + {"EDDSA/ED-25519/keyGen", 0, ED25519KeyGen}, + {"EDDSA/ED-25519/keyVer", 1, ED25519KeyVer}, + {"EDDSA/ED-25519/sigGen", 2, ED25519SigGen}, + {"EDDSA/ED-25519/sigVer", 3, ED25519SigVer}}; Handler FindHandler(Span> args) { const bssl::Span algorithm = args[0];