diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 806e5d0..e24bae6 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -34,8 +34,8 @@ jobs: args: --release --sdist -i python${{ matrix.python-version }} -o dist - name: Install wheel run: | - pip install hpke_spec --no-index --find-links dist --force-reinstall - python -c "import hpke_spec" + pip install hybrid_pke --no-index --find-links dist --force-reinstall + python -c "import hybrid_pke" - name: Test wheel run: | pip install pytest absl-py @@ -73,8 +73,8 @@ jobs: args: --release -i ${{ steps.py3.outputs.python-path }} -o dist - name: Install wheel run: | - pip install hpke_spec --no-index --find-links dist --force-reinstall - python -c "import hpke_spec" + pip install hybrid_pke --no-index --find-links dist --force-reinstall + python -c "import hybrid_pke" - name: Test wheel run: | pip install pytest absl-py @@ -112,8 +112,8 @@ jobs: args: --release -i ${{ steps.py3.outputs.python-path }} --out dist --sdist - name: Install wheel - x86_64 run: | - pip install hpke_spec --no-index --find-links dist --force-reinstall - python -c "import hpke_spec" + pip install hybrid_pke --no-index --find-links dist --force-reinstall + python -c "import hybrid_pke" - name: Test wheel run: | pip install pytest absl-py @@ -125,8 +125,8 @@ jobs: args: --release --universal2 -o dist - name: Install wheel - universal2 run: | - pip install hpke_spec --no-index --find-links dist --force-reinstall - python -c "import hpke_spec" + pip install hybrid_pke --no-index --find-links dist --force-reinstall + python -c "import hybrid_pke" - name: Upload wheels uses: actions/upload-artifact@v2 with: diff --git a/Cargo.lock b/Cargo.lock index f03fcb6..7e5ad49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,28 +3,39 @@ version = 3 [[package]] -name = "abstract_integers" -version = "0.1.5" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" dependencies = [ - "num", - "num-bigint", + "generic-array", ] [[package]] -name = "addr2line" -version = "0.17.0" +name = "aes" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ - "gimli", + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", ] [[package]] -name = "adler" -version = "1.0.2" +name = "aes-gcm" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] [[package]] name = "autocfg" @@ -33,19 +44,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] -name = "backtrace" -version = "0.3.66" +name = "base16ct" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base64ct" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bdca834647821e0b13d9539a8634eb62d3501b6b6c2cec1722786ee6671b851" [[package]] name = "bitflags" @@ -54,10 +62,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "cc" -version = "1.0.73" +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" + +[[package]] +name = "byteorder" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cfg-if" @@ -66,364 +98,382 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "getrandom" -version = "0.2.7" +name = "chacha20" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" dependencies = [ "cfg-if", - "libc", - "wasi", + "cipher", + "cpufeatures", + "zeroize", ] [[package]] -name = "gimli" -version = "0.26.1" +name = "chacha20poly1305" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" - -[[package]] -name = "hacspec-aes" -version = "0.1.0" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" dependencies = [ - "hacspec-lib", + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", ] [[package]] -name = "hacspec-aes128-gcm" -version = "0.1.0" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" dependencies = [ - "hacspec-aes", - "hacspec-gf128", - "hacspec-lib", + "generic-array", ] [[package]] -name = "hacspec-chacha20" -version = "0.1.0" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" -dependencies = [ - "hacspec-lib", -] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" [[package]] -name = "hacspec-chacha20poly1305" -version = "0.1.0" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" dependencies = [ - "hacspec-chacha20", - "hacspec-lib", - "hacspec-poly1305", + "libc", ] [[package]] -name = "hacspec-curve25519" -version = "0.1.0" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" dependencies = [ - "hacspec-lib", + "generic-array", + "rand_core", + "subtle", + "zeroize", ] [[package]] -name = "hacspec-derive" -version = "0.1.0" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "hacspec-lib", - "proc-macro2", - "quote", - "syn", + "generic-array", + "typenum", ] [[package]] -name = "hacspec-ecdsa-p256-sha256" -version = "0.1.0" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" dependencies = [ - "hacspec-lib", - "hacspec-p256", - "hacspec-sha256", + "generic-array", + "subtle", ] [[package]] -name = "hacspec-gf128" -version = "0.1.0" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +name = "ctr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" dependencies = [ - "hacspec-lib", + "cipher", ] [[package]] -name = "hacspec-hkdf" -version = "0.1.0" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +name = "curve25519-dalek-ng" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" dependencies = [ - "hacspec-hmac", - "hacspec-lib", - "hacspec-sha256", + "byteorder", + "digest 0.9.0", + "rand_core", + "subtle-ng", + "zeroize", ] [[package]] -name = "hacspec-hmac" -version = "0.1.0" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" dependencies = [ - "hacspec-lib", - "hacspec-sha256", + "const-oid", ] [[package]] -name = "hacspec-lib" -version = "0.1.0-beta.1" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "abstract_integers", - "num", - "secret_integers", + "generic-array", ] [[package]] -name = "hacspec-p256" -version = "0.1.0" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" dependencies = [ - "backtrace", - "hacspec-lib", + "block-buffer 0.10.2", + "crypto-common", + "subtle", ] [[package]] -name = "hacspec-poly1305" -version = "0.1.0" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" dependencies = [ - "hacspec-lib", + "der", + "elliptic-curve", + "rfc6979", + "signature", ] [[package]] -name = "hacspec-sha256" -version = "0.1.0" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" dependencies = [ - "abstract_integers", - "hacspec-derive", - "hacspec-lib", - "secret_integers", + "base16ct", + "crypto-bigint", + "der", + "ff", + "generic-array", + "group", + "rand_core", + "sec1", + "subtle", + "zeroize", ] [[package]] -name = "hacspec_cryptolib" -version = "0.1.0" -source = "git+https://github.com/cryspen/hpke-spec#65bc3a6356c3d94c15cd5048ac41faa41b3c92ea" +name = "ff" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" dependencies = [ - "hacspec-aes", - "hacspec-aes128-gcm", - "hacspec-chacha20", - "hacspec-chacha20poly1305", - "hacspec-curve25519", - "hacspec-ecdsa-p256-sha256", - "hacspec-gf128", - "hacspec-hkdf", - "hacspec-hmac", - "hacspec-lib", - "hacspec-p256", - "hacspec-poly1305", - "hacspec-sha256", + "rand_core", + "subtle", ] [[package]] -name = "hpke" -version = "0.1.0" -source = "git+https://github.com/cryspen/hpke-spec#65bc3a6356c3d94c15cd5048ac41faa41b3c92ea" +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ - "hacspec-lib", - "hpke_aead", - "hpke_errors", - "hpke_kdf", - "hpke_kem", + "typenum", + "version_check", ] [[package]] -name = "hpke_aead" -version = "0.1.0" -source = "git+https://github.com/cryspen/hpke-spec#65bc3a6356c3d94c15cd5048ac41faa41b3c92ea" +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ - "hacspec-lib", - "hacspec_cryptolib", - "hpke_errors", + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", ] [[package]] -name = "hpke_errors" -version = "0.1.0" -source = "git+https://github.com/cryspen/hpke-spec#65bc3a6356c3d94c15cd5048ac41faa41b3c92ea" +name = "ghash" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" dependencies = [ - "hacspec-lib", + "opaque-debug", + "polyval", ] [[package]] -name = "hpke_kdf" -version = "0.1.0" -source = "git+https://github.com/cryspen/hpke-spec#65bc3a6356c3d94c15cd5048ac41faa41b3c92ea" +name = "group" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" dependencies = [ - "hacspec-lib", - "hacspec_cryptolib", - "hpke_errors", + "ff", + "rand_core", + "subtle", ] [[package]] -name = "hpke_kem" -version = "0.1.0" -source = "git+https://github.com/cryspen/hpke-spec#65bc3a6356c3d94c15cd5048ac41faa41b3c92ea" +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" dependencies = [ - "hacspec-lib", - "hacspec_cryptolib", - "hpke_errors", - "hpke_kdf", + "hmac 0.12.1", ] [[package]] -name = "hpke_spec" -version = "0.2.1-dev0" +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ - "hacspec-lib", - "hpke", - "hpke_aead", - "hpke_errors", - "hpke_kdf", - "hpke_kem", - "pyo3", - "rand", + "crypto-mac", + "digest 0.9.0", ] [[package]] -name = "indoc" -version = "1.0.6" +name = "hmac" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05a0bd019339e5d968b37855180087b7b9d512c5046fbd244cf8c95687927d6e" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.3", +] [[package]] -name = "libc" -version = "0.2.126" +name = "hpke-rs" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "c9c8449efb0694b5dd0ee0d7a5582eccce1eb3aeb6c25dc569143ceadc536ca5" +dependencies = [ + "hpke-rs-crypto", + "log", + "zeroize", +] [[package]] -name = "lock_api" -version = "0.4.7" +name = "hpke-rs-crypto" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "6fdcfe5eed821c92bedc9d05a1e8b4d42a858e5326031086bb5256b778ce9455" dependencies = [ - "autocfg", - "scopeguard", + "getrandom", + "rand", + "serde", + "serde_json", + "tls_codec", ] [[package]] -name = "memchr" -version = "2.5.0" +name = "hpke-rs-rust-crypto" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "8603fbb7674b627cb9f3de6ae5ba8b7e621ef5fdea6489363cb4bef26e5fce52" +dependencies = [ + "aes-gcm", + "chacha20poly1305", + "getrandom", + "hkdf", + "hpke-rs-crypto", + "p256", + "p384", + "rand", + "rand_chacha", + "sha2 0.10.2", + "x25519-dalek-ng", +] [[package]] -name = "miniz_oxide" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +name = "hybrid_pke" +version = "0.2.1-dev0" dependencies = [ - "adler", + "hpke-rs", + "hpke-rs-crypto", + "hpke-rs-rust-crypto", + "pyo3", + "rand", ] [[package]] -name = "num" -version = "0.4.0" +name = "indoc" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adab1eaa3408fb7f0c777a73e7465fd5656136fc93b670eb6df3c88c2c1344e3" + +[[package]] +name = "itoa" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" [[package]] -name = "num-bigint" -version = "0.4.3" +name = "js-sys" +version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" dependencies = [ - "autocfg", - "num-integer", - "num-traits", + "wasm-bindgen", ] [[package]] -name = "num-complex" -version = "0.4.2" +name = "libc" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" -dependencies = [ - "num-traits", -] +checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b" [[package]] -name = "num-integer" -version = "0.1.45" +name = "lock_api" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" dependencies = [ "autocfg", - "num-traits", + "scopeguard", ] [[package]] -name = "num-iter" -version = "0.1.43" +name = "log" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "autocfg", - "num-integer", - "num-traits", + "cfg-if", ] [[package]] -name = "num-rational" -version = "0.4.1" +name = "once_cell" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-bigint", - "num-integer", - "num-traits", -] +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" [[package]] -name = "num-traits" -version = "0.2.15" +name = "opaque-debug" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] -name = "object" -version = "0.29.0" +name = "p256" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +checksum = "19736d80675fbe9fe33426268150b951a3fb8f5cfca2a23a17c85ef3adb24e3b" dependencies = [ - "memchr", + "ecdsa", + "elliptic-curve", + "sec1", + "sha2 0.9.9", ] [[package]] -name = "once_cell" -version = "1.13.0" +name = "p384" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +checksum = "755d8266e41f57bd8562ed9b6e93cdcf73ead050e1e8c3a27ea3871b6643a20c" +dependencies = [ + "elliptic-curve", + "sec1", +] [[package]] name = "parking_lot" @@ -448,6 +498,40 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "pkcs8" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +dependencies = [ + "der", + "spki", + "zeroize", +] + +[[package]] +name = "poly1305" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "ppv-lite86" version = "0.2.16" @@ -456,9 +540,9 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ "unicode-ident", ] @@ -524,9 +608,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] @@ -563,18 +647,29 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] [[package]] -name = "rustc-demangle" -version = "0.1.21" +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac 0.11.0", + "zeroize", +] + +[[package]] +name = "ryu" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "scopeguard" @@ -583,9 +678,82 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] -name = "secret_integers" -version = "0.1.7" -source = "git+https://github.com/hacspec/hacspec#709a1c89df4a47a3607ea055df53c243c72a5a5a" +name = "sec1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +dependencies = [ + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.142" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e590c437916fb6b221e1d00df6e3294f3fccd70ca7e92541c475d6ed6ef5fee2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.142" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b5b8d809babe02f538c2cfec6f2c1ed10804c0e5a6a041a049a4f5588ccc2e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.3", +] + +[[package]] +name = "signature" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +dependencies = [ + "digest 0.9.0", + "rand_core", +] [[package]] name = "smallvec" @@ -593,34 +761,117 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" +[[package]] +name = "spki" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "subtle-ng" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" + [[package]] name = "syn" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + [[package]] name = "target-lexicon" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1" +[[package]] +name = "tls_codec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "172a9c24d46b5fe280b77f37161ed9a919229cb104085384e8bf30637c2e4bca" +dependencies = [ + "tls_codec_derive", + "zeroize", +] + +[[package]] +name = "tls_codec_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a787719c86efec1535b071bde678f5fd649380e8005cd1ebd0afeb4bcc4d2a85" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" + +[[package]] +name = "unicode-xid" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "unindent" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52fee519a3e570f7df377a06a1a7775cdbfb7aa460be7e08de2b1f0e69973a44" +checksum = "58ee9362deb4a96cef4d437d1ad49cffc9b9e92d202b6995674e928ce684f112" + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" @@ -628,6 +879,60 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" + [[package]] name = "windows-sys" version = "0.36.1" @@ -670,3 +975,36 @@ name = "windows_x86_64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "x25519-dalek-ng" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7074de8999662970c3c4c8f7f30925028dd8f4ca31ad4c055efa9cdf2ec326" +dependencies = [ + "curve25519-dalek-ng", + "rand", + "rand_core", + "zeroize", +] + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/Cargo.toml b/Cargo.toml index 5147bcb..4a67536 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,20 +1,17 @@ [package] -name = "hpke_spec" +name = "hybrid_pke" version = "0.2.1-dev0" edition = "2021" publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] -name = "hpke_spec" +name = "hybrid_pke" crate-type = ["cdylib"] [dependencies] -hacspec-lib = { git = "https://github.com/hacspec/hacspec", package = "hacspec-lib" } -hpke = { git = "https://github.com/cryspen/hpke-spec" } -hpke_aead = { git = "https://github.com/cryspen/hpke-spec" } -hpke_errors = { git = "https://github.com/cryspen/hpke-spec" } -hpke_kdf = { git = "https://github.com/cryspen/hpke-spec" } -hpke_kem = { git = "https://github.com/cryspen/hpke-spec" } +hpke-rs = { version = "0.1.0", features = ["hazmat"] } +hpke-rs-crypto = { version = "0.1.1" } +hpke-rs-rust-crypto = { version = "0.1.1" } pyo3 = { version = "0.16.5", features = ["extension-module"] } rand = { version = "0.8" } diff --git a/Makefile b/Makefile index 93e823e..0799951 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: pydep pydep: - pip install maturin~=0.13.0 pytest + pip install maturin~=0.13.0 pytest absl-py .PHONY: pylib pylib: diff --git a/README.md b/README.md index 9c78723..e56539a 100644 --- a/README.md +++ b/README.md @@ -2,24 +2,21 @@ py-hpke-spec =============== The Hybrid Public Key Encryption (HPKE) standard in Python. -- [`hpke-spec`](https://github.com/cryspen/hpke-spec) = [HPKE](https://blog.cloudflare.com/hybrid-public-key-encryption/) :handshake: [`hacspec`](https://hacspec.github.io) +[`hpke-rs`](https://crates.io/crates/hpke-rs) :handshake: [`PyO3`](https://github.com/PyO3/pyo3) -- [`py-hpke-spec`](https://github.com/capeprivacy/py-hpke-spec) = [`hpke-spec`](https://github.com/cryspen/hpke-spec) :handshake: [`PyO3`](https://github.com/PyO3/pyo3) - - -This HPKE implementation is simply a thin Python wrapper around [`hpke-spec`](https://github.com/cryspen/hpke-spec), the hacspec implementation [written by Franziskus Kiefer](https://www.franziskuskiefer.de/p/tldr-hybrid-public-key-encryption/). This package mirrors the `hpke-spec` constructions as much as possible, to avoid any discrepancy from the HPKE standard. +This library provides Python bindings to the `hpke-rs` crate, which supports primitives from either [Rust Crypto](https://github.com/RustCrypto) or [EverCrypt](https://hacl-star.github.io/HaclValeEverCrypt.html). ## Features -The modes and features available match those found in the original `hpke-spec` code. For instance, SHA256 is the only hash algorithm implemented by the hacspec example crypto libs, and as a result some KEMs and KDFs from the original HPKE RFC are unsupported. +The modes and features available match those supported by `hpke-rs`. - Modes - [x] mode_base - - [ ] mode_psk - - [ ] mode_auth - - [ ] mode_auth_psk + - [x] mode_psk + - [x] mode_auth + - [x] mode_auth_psk - AEADs - [x] AES-128-GCM - - [ ] AES-256-GCM + - [x] AES-256-GCM - [x] ChaCha20Poly1305 - [ ] Export only - KEMs @@ -30,19 +27,12 @@ The modes and features available match those found in the original `hpke-spec` c - [ ] DHKEM(X448, HKDF-SHA512) - KDFs - [x] HKDF-SHA256 - - [ ] HKDF-SHA384 - - [ ] HKDF-SHA512 - -## Why `hpke-spec`? - -The `hpke-spec` library has two primary advantages: -- `hpke-spec` is written in [`hacspec`](https://hacspec.github.io/) which can be compiled into [F*](https://www.fstar-lang.org/) for formal verification. -- The cargo [documentation](https://tech.cryspen.com/hpke-spec/hpke/index.html) for `hpke-spec` is simply the text of the [HPKE RFC 9180](https://datatracker.ietf.org/doc/rfc9180/), with all the RFC's constructions linked directly to the hacspec code that implements it. + - [x] HKDF-SHA384 + - [x] HKDF-SHA512 -As a result, it's much more straightforward to evaluate `hpke-spec` for security and correctness. Indeed, both hacspec and RFC 9180 have received thorough vetting from cryptographers in [Project Everest](https://project-everest.github.io) and the [Internet Research Task Force](https://datatracker.ietf.org/doc/rfc9180/), respectively. ## Installation -Wheels for various platforms and architectures can be found on on [PyPI](https://pypi.org/project/hpke-spec/) or in the `wheelhouse.zip` archive from the [latest Github release](https://github.com/capeprivacy/py-hpke-spec/releases). +Wheels for various platforms and architectures can be found on [PyPI](https://pypi.org/project/hpke-spec/) or in the `wheelhouse.zip` archive from the [latest Github release](https://github.com/capeprivacy/py-hpke-spec/releases). The library can also be installed from source with [`maturin`](https://github.com/PyO3/maturin) -- see below. diff --git a/hpke_spec_test.py b/hpke_spec_test.py index 6610e2a..238b7e0 100644 --- a/hpke_spec_test.py +++ b/hpke_spec_test.py @@ -1,95 +1,99 @@ from absl.testing import parameterized -import hpke_spec as hpke +import hybrid_pke class TestHpkeSpec(parameterized.TestCase): def test_hpke_seal(self): pk = b"my fake public key is 32 bytes !" ptxt = b"hello, my name is Vincent Law" - config = hpke.default_config() - ciphertext = hpke.seal(pk, ptxt, config) + hpke = hybrid_pke.default_config() + info = b"" + aad = b"" + encap, ciphertext = hpke.seal(pk, info, aad, ptxt) # 32 bytes (KEM-derived public key) + 45 bytes (ciphertext of ptxt) = 77 bytes - assert len(ciphertext) == 77 + assert len(encap) == 32 + assert len(ciphertext) == 45 def test_wrong_pk_size(self): - try: - pk = b"my fake public key is greater than 32 bytes !" - ptxt = b"hello, my name is Vincent Law" - config = hpke.default_config() - _ = hpke.seal(pk, ptxt, config) - except: # noqa: E722 - # the exception type is pyo3_runtime.PanicException, - # which isn't accessible from Python. - return - raise AssertionError( - "hpke_seal failed to raise Exception on malformed public key" - ) + pk = b"my fake public key is greater than 32 bytes !" + ptxt = b"hello, my name is Vincent Law" + hpke = hybrid_pke.default_config() + info = b"" + aad = b"" + with self.assertRaises(hybrid_pke.errors.CryptoError): + _, _ = hpke.seal(pk, info, aad, ptxt) - def test_hpke_roundtrip(self): - config = hpke.default_config() - skR, pkR = hpke.generate_keypair(kem=config.kem) + def test_hpke_onetrip(self): + hpke = hybrid_pke.default_config() + skR, pkR = hpke.generate_key_pair() ptxt = b"my name is Vincent Law" - ctxt = hpke.seal(pkR, ptxt, config) - ptxt_roundtrip = hpke.open(skR, ctxt, config) + info = b"" + aad = b"" + encap, ctxt = hpke.seal(pkR, info, aad, ptxt) + ptxt_roundtrip = hpke.open(encap, skR, info, aad, ctxt) assert ptxt == ptxt_roundtrip @parameterized.parameters( - hpke.KEM.DHKEM_P384_HKDF_SHA384, - hpke.KEM.DHKEM_P521_HKDF_SHA512, - hpke.KEM.DHKEM_X448_HKDF_SHA512, + hybrid_pke.Kem.DHKEM_P384, + hybrid_pke.Kem.DHKEM_P521, + hybrid_pke.Kem.DHKEM_X448, ) def test_unsupported_keygen(self, kem): - with self.assertRaises(RuntimeError): - _, _ = hpke.generate_keypair(kem) + hpke = hybrid_pke.default_config() + hpke.kem = kem + with self.assertRaises(hybrid_pke.errors.CryptoError): + _, _ = hpke.generate_key_pair() @parameterized.parameters( - (hpke.KEM.DHKEM_P256_HKDF_SHA256, 32, 65), - (hpke.KEM.DHKEM_X25519_HKDF_SHA256, 32, 32), + (hybrid_pke.Kem.DHKEM_P256, 32, 65), + (hybrid_pke.Kem.DHKEM_X25519, 32, 32), ) def test_supported_keygen(self, kem, sk_len, pk_len): - sk, pk = hpke.generate_keypair(kem) + hpke = hybrid_pke.default_config() + hpke.kem = kem + sk, pk = hpke.generate_key_pair() assert len(sk) == sk_len assert len(pk) == pk_len class TestHpkeConfig(parameterized.TestCase): def test_default_config(self): - config = hpke.default_config() - assert config.mode == hpke.Mode.mode_base - assert config.kem == hpke.KEM.DHKEM_X25519_HKDF_SHA256 - assert config.kdf == hpke.KDF.HKDF_SHA256 - assert config.aead == hpke.AEAD.ChaCha20Poly1305 + hpke = hybrid_pke.default_config() + assert hpke.mode == hybrid_pke.Mode.BASE + assert hpke.kem == hybrid_pke.Kem.DHKEM_X25519 + assert hpke.kdf == hybrid_pke.Kdf.HKDF_SHA256 + assert hpke.aead == hybrid_pke.Aead.CHACHA20_POLY1305 def test_config_construct(self): - mode = hpke.Mode.mode_base - kem = hpke.KEM.DHKEM_X25519_HKDF_SHA256 - kdf = hpke.KDF.HKDF_SHA256 - aead = hpke.AEAD.ChaCha20Poly1305 - config = hpke.HPKEConfig(mode, kem, kdf, aead) - assert config.mode == mode - assert config.kem == kem - assert config.kdf == kdf - assert config.aead == aead + mode = hybrid_pke.Mode.BASE + kem = hybrid_pke.Kem.DHKEM_X25519 + kdf = hybrid_pke.Kdf.HKDF_SHA256 + aead = hybrid_pke.Aead.CHACHA20_POLY1305 + hpke = hybrid_pke.Hpke(mode, kem, kdf, aead) + assert hpke.mode == mode + assert hpke.kem == kem + assert hpke.kdf == kdf + assert hpke.aead == aead @parameterized.parameters( {"enum_type": ty, "variants": vrs} for ty, vrs in [ - (hpke.Mode, ["mode_base", "mode_psk", "mode_auth", "mode_auth_psk"]), + (hybrid_pke.Mode, ["BASE", "PSK", "AUTH", "AUTH_PSK"]), ( - hpke.KEM, + hybrid_pke.Kem, [ - "DHKEM_P256_HKDF_SHA256", - "DHKEM_P384_HKDF_SHA384", - "DHKEM_P521_HKDF_SHA512", - "DHKEM_X25519_HKDF_SHA256", - "DHKEM_X448_HKDF_SHA512", + "DHKEM_P256", + "DHKEM_P384", + "DHKEM_P521", + "DHKEM_X25519", + "DHKEM_X448", ], ), - (hpke.KDF, ["HKDF_SHA256", "HKDF_SHA384", "HKDF_SHA512"]), + (hybrid_pke.Kdf, ["HKDF_SHA256", "HKDF_SHA384", "HKDF_SHA512"]), ( - hpke.AEAD, - ["AES_128_GCM", "AES_256_GCM", "ChaCha20Poly1305", "Export_only"], + hybrid_pke.Aead, + ["AES_128_GCM", "AES_256_GCM", "CHACHA20_POLY1305", "HPKE_EXPORT"], ), ] ) diff --git a/pyproject.toml b/pyproject.toml index 6fc1133..2dc3204 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["maturin>=0.13,<0.14"] build-backend = "maturin" [project] -name = "hpke_spec" +name = "hybrid_pke" description = "The Hybrid Public Key Encryption (HPKE) standard in Python" version = "0.2.1-dev0" # NOTE: auto-updated during release requires-python = ">=3.8" diff --git a/src/config.rs b/src/config.rs index 232f1df..54a7138 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,148 +1,91 @@ -use hpke::{HPKEConfig, Mode}; -use hpke_aead::AEAD; -use hpke_kdf::KDF; -use hpke_kem::KEM; +use hpke_rs::Mode; +use hpke_rs_crypto::types::{AeadAlgorithm, KdfAlgorithm, KemAlgorithm}; use pyo3::prelude::*; -use std::convert::Into; -// Construct a reasonable default HPKEConfig -#[pyfunction] -pub(crate) fn default_config() -> PyHPKEConfig { - let mode = PyMode::mode_base; - let kem = PyKEM::DHKEM_X25519_HKDF_SHA256; - let kdf = PyKDF::HKDF_SHA256; - let aead = PyAEAD::ChaCha20Poly1305; - PyHPKEConfig { - mode, - kem, - kdf, - aead, - } -} - -// HPKEConfig contains the HPKE mode and ciphersuite needed to fully-specify & configure HPKE encryption. #[pyclass] -#[pyo3(name = "HPKEConfig", module = "hpke_spec")] +#[pyo3(name = "Mode", module = "hybrid_pke")] #[derive(Clone)] -pub(crate) struct PyHPKEConfig { - #[pyo3(get, set)] - mode: PyMode, - #[pyo3(get, set)] - kem: PyKEM, - #[pyo3(get, set)] - kdf: PyKDF, - #[pyo3(get, set)] - aead: PyAEAD, -} - -#[pymethods] -impl PyHPKEConfig { - #[new] - fn new(mode: PyMode, kem: PyKEM, kdf: PyKDF, aead: PyAEAD) -> Self { - PyHPKEConfig { - mode, - kem, - kdf, - aead, - } - } -} - -impl From for HPKEConfig { - fn from(pyconfig: PyHPKEConfig) -> Self { - HPKEConfig( - pyconfig.mode.into(), - pyconfig.kem.into(), - pyconfig.kdf.into(), - pyconfig.aead.into(), - ) - } -} - -#[pyclass] -#[pyo3(name = "Mode", module = "hpke_spec")] -#[derive(Clone)] -#[allow(non_camel_case_types)] +#[allow(clippy::upper_case_acronyms, non_camel_case_types)] pub(crate) enum PyMode { - mode_base, - mode_psk, - mode_auth, - mode_auth_psk, + BASE, + PSK, + AUTH, + AUTH_PSK, } -impl From for Mode { - fn from(pymode: PyMode) -> Self { +impl From<&PyMode> for Mode { + fn from(pymode: &PyMode) -> Self { match pymode { - PyMode::mode_base => Mode::mode_base, - PyMode::mode_psk => Mode::mode_psk, - PyMode::mode_auth => Mode::mode_auth, - PyMode::mode_auth_psk => Mode::mode_auth_psk, + PyMode::BASE => Mode::Base, + PyMode::PSK => Mode::Psk, + PyMode::AUTH => Mode::Auth, + PyMode::AUTH_PSK => Mode::AuthPsk, } } } #[pyclass] -#[pyo3(name = "KEM", module = "hpke_spec")] +#[pyo3(name = "Kem", module = "hybrid_pke")] #[derive(Clone)] #[allow(non_camel_case_types)] -pub(crate) enum PyKEM { - DHKEM_P256_HKDF_SHA256, - DHKEM_P384_HKDF_SHA384, - DHKEM_P521_HKDF_SHA512, - DHKEM_X25519_HKDF_SHA256, - DHKEM_X448_HKDF_SHA512, +pub(crate) enum PyKemAlgorithm { + DHKEM_P256, + DHKEM_P384, + DHKEM_P521, + DHKEM_X25519, + DHKEM_X448, } -impl From for KEM { - fn from(pykem: PyKEM) -> Self { +impl From<&PyKemAlgorithm> for KemAlgorithm { + fn from(pykem: &PyKemAlgorithm) -> Self { match pykem { - PyKEM::DHKEM_P256_HKDF_SHA256 => KEM::DHKEM_P256_HKDF_SHA256, - PyKEM::DHKEM_P384_HKDF_SHA384 => KEM::DHKEM_P384_HKDF_SHA384, - PyKEM::DHKEM_P521_HKDF_SHA512 => KEM::DHKEM_P521_HKDF_SHA512, - PyKEM::DHKEM_X25519_HKDF_SHA256 => KEM::DHKEM_X25519_HKDF_SHA256, - PyKEM::DHKEM_X448_HKDF_SHA512 => KEM::DHKEM_X448_HKDF_SHA512, + PyKemAlgorithm::DHKEM_P256 => KemAlgorithm::DhKemP256, + PyKemAlgorithm::DHKEM_P384 => KemAlgorithm::DhKemP384, + PyKemAlgorithm::DHKEM_P521 => KemAlgorithm::DhKemP521, + PyKemAlgorithm::DHKEM_X25519 => KemAlgorithm::DhKem25519, + PyKemAlgorithm::DHKEM_X448 => KemAlgorithm::DhKem448, } } } #[pyclass] -#[pyo3(name = "KDF", module = "hpke_spec")] +#[pyo3(name = "Kdf", module = "hybrid_pke")] #[derive(Clone)] #[allow(non_camel_case_types)] -pub(crate) enum PyKDF { +pub(crate) enum PyKdfAlgorithm { HKDF_SHA256, HKDF_SHA384, HKDF_SHA512, } -impl From for KDF { - fn from(pykdf: PyKDF) -> Self { +impl From<&PyKdfAlgorithm> for KdfAlgorithm { + fn from(pykdf: &PyKdfAlgorithm) -> Self { match pykdf { - PyKDF::HKDF_SHA256 => KDF::HKDF_SHA256, - PyKDF::HKDF_SHA384 => KDF::HKDF_SHA384, - PyKDF::HKDF_SHA512 => KDF::HKDF_SHA512, + PyKdfAlgorithm::HKDF_SHA256 => KdfAlgorithm::HkdfSha256, + PyKdfAlgorithm::HKDF_SHA384 => KdfAlgorithm::HkdfSha384, + PyKdfAlgorithm::HKDF_SHA512 => KdfAlgorithm::HkdfSha512, } } } #[pyclass] -#[pyo3(name = "AEAD", module = "hpke_spec")] +#[pyo3(name = "Aead", module = "hybrid_pke")] #[derive(Clone)] #[allow(non_camel_case_types)] -pub(crate) enum PyAEAD { +pub(crate) enum PyAeadAlgorithm { AES_128_GCM, AES_256_GCM, - ChaCha20Poly1305, - Export_only, + CHACHA20_POLY1305, + HPKE_EXPORT, } -impl From for AEAD { - fn from(pyaead: PyAEAD) -> Self { +impl From<&PyAeadAlgorithm> for AeadAlgorithm { + fn from(pyaead: &PyAeadAlgorithm) -> Self { match pyaead { - PyAEAD::AES_128_GCM => AEAD::AES_128_GCM, - PyAEAD::AES_256_GCM => AEAD::AES_256_GCM, - PyAEAD::ChaCha20Poly1305 => AEAD::ChaCha20Poly1305, - PyAEAD::Export_only => AEAD::Export_only, + PyAeadAlgorithm::AES_128_GCM => AeadAlgorithm::Aes128Gcm, + PyAeadAlgorithm::AES_256_GCM => AeadAlgorithm::Aes256Gcm, + PyAeadAlgorithm::CHACHA20_POLY1305 => AeadAlgorithm::ChaCha20Poly1305, + PyAeadAlgorithm::HPKE_EXPORT => AeadAlgorithm::HpkeExport, } } } diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..bffc36a --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,94 @@ +use hpke_rs::HpkeError; +use pyo3::exceptions::PyException; +use pyo3::{create_exception, PyErr}; + +create_exception!( + errors, + OpenError, + PyException, + "Error opening an HPKE ciphertext." +); +create_exception!( + errors, + InvalidConfig, + PyException, + "Invalid HPKE configuration or arguments." +); +create_exception!(errors, InvalidInput, PyException, "Invalid input."); +create_exception!(errors, UnknownMode, PyException, "Unknown HPKE mode."); +create_exception!( + errors, + InconsistentPsk, + PyException, + "Inconsistent PSK input." +); +create_exception!( + errors, + MissingPsk, + PyException, + "PSK input is required but missing." +); +create_exception!( + errors, + UnnecessaryPsk, + PyException, + "PSK input is provided but not needed." +); +create_exception!( + errors, + InsecurePsk, + PyException, + "PSK input is too short (needs to be at least 32 bytes)." +); +create_exception!( + errors, + CryptoError, + PyException, + "An error in the crypto library occurred." +); +create_exception!( + errors, + MessageLimitReached, + PyException, + "The message limit for this AEAD, key, and nonce." +); +create_exception!( + errors, + InsufficientRandomness, + PyException, + "Unable to collect enough randomness." +); +create_exception!( + errors, + LockPoisoned, + PyException, + "A concurrency issue with an RwLock." +); + +#[inline(always)] +pub(crate) fn handle_hpke_error(e: HpkeError) -> PyErr { + match e { + HpkeError::OpenError => OpenError::new_err("Error opening an HPKE ciphertext."), + HpkeError::InvalidConfig => { + InvalidConfig::new_err("Invalid HPKE configuration or arguments.") + } + HpkeError::InvalidInput => InvalidInput::new_err("Invalid input."), + HpkeError::UnknownMode => UnknownMode::new_err("Unknown HPKE mode."), + HpkeError::InconsistentPsk => InconsistentPsk::new_err("Inconsistent PSK input."), + HpkeError::MissingPsk => MissingPsk::new_err("PSK input is required but missing."), + HpkeError::UnnecessaryPsk => { + UnnecessaryPsk::new_err("PSK input is provided but not needed.") + } + HpkeError::InsecurePsk => { + InsecurePsk::new_err("PSK input is too short (needs to be at least 32 bytes).") + } + HpkeError::CryptoError(s) => CryptoError::new_err(s), + HpkeError::MessageLimitReached => { + MessageLimitReached::new_err("Hit the message limit for this AEAD, key, and nonce.") + } + HpkeError::InsufficientRandomness => { + InsufficientRandomness::new_err("Unable to collect enough randomness.") + } + HpkeError::LockPoisoned => LockPoisoned::new_err("A concurrency issue with an RwLock."), + } +} diff --git a/src/hpke.rs b/src/hpke.rs new file mode 100644 index 0000000..fff8aa8 --- /dev/null +++ b/src/hpke.rs @@ -0,0 +1,149 @@ +use hpke_rs::HpkePrivateKey; +use hpke_rs::{Hpke as HpkeRs, HpkePublicKey}; +use hpke_rs_rust_crypto::HpkeRustCrypto; +use pyo3::prelude::*; +use pyo3::types::PyBytes; + +use crate::config::*; +use crate::errors::*; + +pub(crate) type Hpke = HpkeRs; + +/// Hpke defines the mode and ciphersuite needed to fully specify an HPKE configuration. +/// The resulting Hpke configuration object exposes the primary HPKE protocols as instance methods. +#[pyclass] +#[pyo3(name = "Hpke", module = "hybrid_pke")] +#[derive(Clone)] +pub(crate) struct PyHpke { + #[pyo3(get, set)] + mode: PyMode, + #[pyo3(get, set)] + kem: PyKemAlgorithm, + #[pyo3(get, set)] + kdf: PyKdfAlgorithm, + #[pyo3(get, set)] + aead: PyAeadAlgorithm, +} + +#[pymethods] +impl PyHpke { + #[new] + pub fn new( + mode: PyMode, + kem: PyKemAlgorithm, + kdf: PyKdfAlgorithm, + aead: PyAeadAlgorithm, + ) -> Self { + PyHpke { + mode, + kem, + kdf, + aead, + } + } + + /// Generate a key-pair according to this Hpke config + fn generate_key_pair<'p>(&self, py: Python<'p>) -> PyResult<(&'p PyBytes, &'p PyBytes)> { + let cfg: Hpke = self.into(); + let keypair = cfg.generate_key_pair().map_err(handle_hpke_error)?; + let (sk, pk) = keypair.into_keys(); + let sk_py = PyBytes::new(py, sk.as_slice()); + let pk_py = PyBytes::new(py, pk.as_slice()); + Ok((sk_py, pk_py)) + } + + /// Use this Hpke config for single-shot encryption + #[allow(clippy::too_many_arguments)] + #[args(psk = "None", psk_id = "None", sk_s = "None")] + fn seal<'p>( + &self, + py: Python<'p>, + pk_r: &PyBytes, + info: &PyBytes, + aad: &PyBytes, + plain_txt: &PyBytes, + psk: Option<&PyBytes>, + psk_id: Option<&PyBytes>, + sk_s: Option<&PyBytes>, + ) -> PyResult<(&'p PyBytes, &'p PyBytes)> { + let cfg: Hpke = self.into(); + + // convert all args and drop py refs immediately + let pk_r = HpkePublicKey::new(pk_r.as_bytes().into()); + let info = info.as_bytes(); + let aad = aad.as_bytes(); + let plain_txt = plain_txt.as_bytes(); + let psk = psk.map(|x| x.as_bytes()); + let psk_id = psk_id.map(|x| x.as_bytes()); + + // perform single-shot seal + let (encap, cipher_txt) = match sk_s { + None => cfg.seal(&pk_r, info, aad, plain_txt, psk, psk_id, None), + // if sk_s is Some(b), we need to take ownership to create HpkePrivateKey + // so that we can give &HpkePrivateKey to Hpke::seal + // TODO(jason) would be great if we could go from &[u8] to &HpkePrivateKey here + Some(sk) => { + let sk = HpkePrivateKey::new(sk.as_bytes().into()); + cfg.seal(&pk_r, info, aad, plain_txt, psk, psk_id, Some(&sk)) + } + } + .map_err(handle_hpke_error)?; + + // convert return vals back to PyBytes + let encap_py = PyBytes::new(py, encap.as_slice()); + let cipher_txt_py = PyBytes::new(py, cipher_txt.as_slice()); + Ok((encap_py, cipher_txt_py)) + } + + /// Use this Hpke config for single-shot decryption + #[allow(clippy::too_many_arguments)] + #[args(psk = "None", psk_id = "None", pk_s = "None")] + fn open<'p>( + &self, + py: Python<'p>, + enc: &PyBytes, + sk_r: &PyBytes, + info: &PyBytes, + aad: &PyBytes, + cipher_txt: &PyBytes, + psk: Option<&PyBytes>, + psk_id: Option<&PyBytes>, + pk_s: Option<&PyBytes>, + ) -> PyResult<&'p PyBytes> { + let cfg: Hpke = self.into(); + + // convert all args and drop py refs immediately + let enc = enc.as_bytes(); + let sk_r = HpkePrivateKey::new(sk_r.as_bytes().into()); + let info = info.as_bytes(); + let aad = aad.as_bytes(); + let cipher_txt = cipher_txt.as_bytes(); + let psk = psk.map(|x| x.as_bytes()); + let psk_id = psk_id.map(|x| x.as_bytes()); + + // perform single-shot open + let plain_txt = match pk_s { + None => cfg.open(enc, &sk_r, info, aad, cipher_txt, psk, psk_id, None), + // TODO(jason) would be great if we could go from &[u8] to &HpkePublicKey here + Some(pk) => { + let pk = HpkePublicKey::new(pk.as_bytes().into()); + cfg.open(enc, &sk_r, info, aad, cipher_txt, psk, psk_id, Some(&pk)) + } + } + .map_err(handle_hpke_error)?; + + // convert return val back to PyBytes + let plain_txt_py = PyBytes::new(py, plain_txt.as_slice()); + Ok(plain_txt_py) + } +} + +impl From<&PyHpke> for Hpke { + fn from(pyconfig: &PyHpke) -> Self { + let mode = &pyconfig.mode; + let kem = &pyconfig.kem; + let kdf = &pyconfig.kdf; + let aead = &pyconfig.aead; + Hpke::new(mode.into(), kem.into(), kdf.into(), aead.into()) + } +} diff --git a/src/lib.rs b/src/lib.rs index ab67b9a..fe67a8a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,112 +1,53 @@ -use hacspec_lib::{ByteSeq, Seq, U8}; -use hpke::{ - AdditionalData, Ciphertext, HPKECiphertext, HPKEConfig, HpkeOpen, HpkePrivateKey, - HpkePublicKey, HpkeSeal, KemOutput, -}; -use hpke_errors::HpkeError; -use hpke_kdf::Info; -use hpke_kem::{GenerateKeyPair, Nenc, Nsk, Randomness, SerializePublicKey, KEM}; -use pyo3::exceptions::PyRuntimeError; use pyo3::prelude::*; -use pyo3::types::PyBytes; -use rand::{rngs::OsRng, RngCore}; +// use rand::{rngs::OsRng, RngCore}; -pub mod config; +mod config; +mod errors; +mod hpke; use crate::config::*; +use crate::errors::*; +use crate::hpke::*; -fn hpke_open_bytes(config: HPKEConfig, ctxtb: &[u8], skb: &[u8]) -> Result, HpkeError> { - let kem = config.1; - let n_enc = Nenc(kem); - let kem_output = KemOutput::from_public_slice(&ctxtb[..n_enc]); - let ctxt = Ciphertext::from_public_slice(&ctxtb[n_enc..]); - let ciphertext = HPKECiphertext(kem_output, ctxt); - let sk_r = HpkePrivateKey::from_public_slice(skb); - let info = Info::new(0); - let aad = AdditionalData::new(0); - let result: ByteSeq = HpkeOpen(config, &ciphertext, &sk_r, &info, &aad, None, None, None)?; - let plaintext = result.into_native(); - Ok(plaintext) -} - -fn hpke_seal_bytes(config: HPKEConfig, pkb: &[u8], ptxtb: &[u8]) -> Result, HpkeError> { - let pk = HpkePublicKey::from_public_slice(pkb); - let ptxt = Seq::::from_public_slice(ptxtb); - let info = Info::new(0); - let aad = AdditionalData::new(0); - let mut rand_bytes = [0u8; 32]; - OsRng.fill_bytes(&mut rand_bytes); - let randomness = Randomness::from_public_slice(&rand_bytes); - let result: HPKECiphertext = HpkeSeal( - config, &pk, &info, &aad, &ptxt, None, None, None, randomness, - )?; - let mut encapsulated: Vec = result.0.into_native(); - let mut ciphertext = result.1.into_native(); - encapsulated.append(&mut ciphertext); - Ok(encapsulated) -} - -fn generate_keypair(kem: KEM) -> Result<(Vec, Vec), HpkeError> { - let nbytes = Nsk(kem); - let mut rand_bytes = vec![0u8; nbytes]; - OsRng.fill_bytes(&mut rand_bytes); - let randomness = Randomness::from_public_slice(&rand_bytes); - let keypair = GenerateKeyPair(kem, randomness)?; - let priv_key = keypair.0; - let pub_key = SerializePublicKey(kem, &keypair.1); - Ok((priv_key.into_native(), pub_key.into_native())) -} - -#[pyfunction] -#[pyo3(name = "generate_keypair")] -fn generate_keypair_py(py: Python, kem: PyKEM) -> PyResult<(&PyBytes, &PyBytes)> { - let keypair_bytes = generate_keypair(kem.into()) - .map_err(|hpke_error| PyRuntimeError::new_err(format!("{hpke_error:#?}")))?; - let sk_py = PyBytes::new(py, &keypair_bytes.0); - let pk_py = PyBytes::new(py, &keypair_bytes.1); - Ok((sk_py, pk_py)) -} - -/// PyO3 binding to hpke-spec's Single-Shot API function hpke::HpkeSeal +/// Construct a reasonable default HPKEConfig #[pyfunction] -fn seal<'p>( - py: Python<'p>, - pk_py: &PyBytes, - ptxt_py: &PyBytes, - config_py: PyHPKEConfig, -) -> PyResult<&'p PyBytes> { - let pkb = pk_py.as_bytes(); - let ptxtb = ptxt_py.as_bytes(); - let ciphertext_bytes = hpke_seal_bytes(config_py.into(), pkb, ptxtb) - .map_err(|hpke_error| PyRuntimeError::new_err(format!("{hpke_error:#?}")))?; - Ok(PyBytes::new(py, &ciphertext_bytes)) +pub(crate) fn default_config() -> PyHpke { + let mode = PyMode::BASE; + let kem = PyKemAlgorithm::DHKEM_X25519; + let kdf = PyKdfAlgorithm::HKDF_SHA256; + let aead = PyAeadAlgorithm::CHACHA20_POLY1305; + PyHpke::new(mode, kem, kdf, aead) } -/// PyO3 binding to hpke-spec's Single-Shot API function hpke::HpkeOpen -#[pyfunction] -fn open<'p>( - py: Python<'p>, - sk_py: &PyBytes, - ctxt_py: &PyBytes, - config_py: PyHPKEConfig, -) -> PyResult<&'p PyBytes> { - let skb = sk_py.as_bytes(); - let ctxtb = ctxt_py.as_bytes(); - let plaintext_bytes = hpke_open_bytes(config_py.into(), ctxtb, skb) - .map_err(|hpke_error| PyRuntimeError::new_err(format!("{hpke_error:#?}")))?; - Ok(PyBytes::new(py, &plaintext_bytes)) +fn build_errors_module(py: Python) -> PyResult<&PyModule> { + let errors_module = PyModule::new(py, "errors")?; + errors_module.add("OpenError", py.get_type::())?; + errors_module.add("InvalidConfig", py.get_type::())?; + errors_module.add("InvalidInput", py.get_type::())?; + errors_module.add("UnknownMode", py.get_type::())?; + errors_module.add("InconsistentPsk", py.get_type::())?; + errors_module.add("MissingPsk", py.get_type::())?; + errors_module.add("UnnecessaryPsk", py.get_type::())?; + errors_module.add("InsecurePsk", py.get_type::())?; + errors_module.add("CryptoError", py.get_type::())?; + errors_module.add("MessageLimitReached", py.get_type::())?; + errors_module.add( + "InsufficientRandomness", + py.get_type::(), + )?; + errors_module.add("LockPoisoned", py.get_type::())?; + Ok(errors_module) } -/// PyO3 module for hpke-spec. +/// PyO3 module for hpke. #[pymodule] -fn hpke_spec(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; +fn hybrid_pke(py: Python, m: &PyModule) -> PyResult<()> { + let errors_module = build_errors_module(py)?; + m.add_submodule(errors_module)?; + m.add_class::()?; m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; m.add_function(wrap_pyfunction!(default_config, m)?)?; - m.add_function(wrap_pyfunction!(generate_keypair_py, m)?)?; - m.add_function(wrap_pyfunction!(open, m)?)?; - m.add_function(wrap_pyfunction!(seal, m)?)?; Ok(()) }