From 816ac40ead311507ade19d521e1069b065747b63 Mon Sep 17 00:00:00 2001 From: Jamie-Cui Date: Thu, 21 Dec 2023 13:39:09 +0800 Subject: [PATCH] repo-sync-2023-12-20T15:33:48+0800 (#176) * repo-sync-2023-12-20T15:33:48+0800 * repo-sync-2023-12-21T10:26:36+0800 * repo-sync-2023-12-21T12:51:40+0800 * repo-sync-2023-12-21T13:08:18+0800 --- .bazelrc | 5 +- .bazelversion | 2 +- ALGORITHMS.md | 31 +- CHANGELOG.md | 20 +- README.md | 14 +- bazel/hash_drbg.BUILD | 29 + bazel/openssl.BUILD | 73 +- bazel/patches/brpc.patch | 2 +- bazel/patches/ippcp.patch | 250 ------- bazel/repositories.bzl | 37 +- yacl/base/BUILD.bazel | 2 +- yacl/base/dynamic_bitset_test.cc | 6 +- yacl/base/exception.h | 96 +-- yacl/crypto/base/BUILD.bazel | 197 +----- yacl/crypto/base/aead/BUILD.bazel | 10 +- yacl/crypto/base/aead/gcm_crypto.cc | 107 ++- yacl/crypto/base/aead/gcm_crypto.h | 44 +- yacl/crypto/base/aead/gcm_crypto_test.cc | 4 +- yacl/crypto/base/aead/sm4_mac.cc | 4 +- yacl/crypto/base/aes/BUILD.bazel | 7 +- yacl/crypto/base/aes/aes_bench.cc | 117 +--- yacl/crypto/base/asymmetric_rsa_crypto.cc | 90 --- yacl/crypto/base/asymmetric_rsa_crypto.h | 74 -- .../crypto/base/asymmetric_rsa_crypto_test.cc | 40 -- yacl/crypto/base/asymmetric_sm2_crypto.cc | 93 --- yacl/crypto/base/asymmetric_sm2_crypto.h | 67 -- .../crypto/base/asymmetric_sm2_crypto_test.cc | 40 -- yacl/crypto/base/asymmetric_util.cc | 260 ------- yacl/crypto/base/asymmetric_util.h | 53 -- .../base/{test => block_cipher}/BUILD.bazel | 28 +- .../{ => block_cipher}/symmetric_crypto.cc | 53 +- .../{ => block_cipher}/symmetric_crypto.h | 33 +- .../symmetric_crypto_test.cc | 57 +- yacl/crypto/base/drbg/BUILD.bazel | 155 ----- yacl/crypto/base/drbg/entropy_source.h | 60 -- .../base/drbg/entropy_source_selector.cc | 35 - yacl/crypto/base/drbg/entropy_source_test.cc | 44 -- yacl/crypto/base/drbg/intel_entropy_source.cc | 82 --- yacl/crypto/base/drbg/intel_entropy_source.h | 44 -- yacl/crypto/base/drbg/nist_aes_drbg.cc | 254 ------- yacl/crypto/base/drbg/nist_aes_drbg.h | 109 --- yacl/crypto/base/drbg/nist_aes_drbg_test.cc | 329 --------- yacl/crypto/base/drbg/sm4_drbg.cc | 293 -------- yacl/crypto/base/drbg/sm4_drbg.h | 127 ---- yacl/crypto/base/drbg/sm4_drbg_test.cc | 70 -- yacl/crypto/base/drbg/std_entropy_source.cc | 56 -- yacl/crypto/base/ecc/ecc_spi.h | 2 +- yacl/crypto/base/ecc/mcl/mcl_ec_group.cc | 6 +- yacl/crypto/base/ecc/openssl/BUILD.bazel | 1 + yacl/crypto/base/ecc/openssl/openssl_group.h | 14 +- yacl/crypto/base/envelope/BUILD.bazel | 43 ++ .../base/{ => envelope}/digital_envelope.cc | 18 +- .../base/{ => envelope}/digital_envelope.h | 0 .../{ => envelope}/digital_envelope_test.cc | 18 +- yacl/crypto/base/hash/BUILD.bazel | 2 + yacl/crypto/base/hash/blake3.cc | 5 +- yacl/crypto/base/hash/blake3.h | 11 + yacl/crypto/base/hash/blake3_test.cc | 50 +- yacl/crypto/base/hash/hash_interface.h | 26 + yacl/crypto/base/hash/hash_utils.cc | 8 +- yacl/crypto/base/hash/ssl_hash.cc | 39 +- yacl/crypto/base/hash/ssl_hash.h | 5 +- yacl/crypto/base/hmac.cc | 108 --- .../crypto/base/hmac/BUILD.bazel | 48 +- yacl/crypto/base/hmac/hmac.cc | 79 +++ yacl/crypto/base/{ => hmac}/hmac.h | 12 +- yacl/crypto/base/{ => hmac}/hmac_all_test.cc | 29 +- yacl/crypto/base/{ => hmac}/hmac_sha256.h | 2 +- yacl/crypto/base/{ => hmac}/hmac_sm3.h | 2 +- yacl/crypto/base/key_utils.cc | 362 ++++++++++ yacl/crypto/base/key_utils.h | 152 ++++ yacl/crypto/base/key_utils_test.cc | 93 +++ yacl/crypto/base/openssl_wrappers.h | 113 +++ yacl/crypto/base/pke/BUILD.bazel | 65 ++ .../crypto/base/{ => pke}/asymmetric_crypto.h | 8 +- yacl/crypto/base/pke/asymmetric_rsa_crypto.cc | 83 +++ yacl/crypto/base/pke/asymmetric_rsa_crypto.h | 53 ++ .../asymmetric_rsa_crypto_test.cc} | 31 +- yacl/crypto/base/pke/asymmetric_sm2_crypto.cc | 73 ++ yacl/crypto/base/pke/asymmetric_sm2_crypto.h | 53 ++ .../asymmetric_sm2_crypto_test.cc} | 27 +- yacl/crypto/base/rsa_signing.cc | 113 --- yacl/crypto/base/rsa_signing.h | 71 -- yacl/crypto/base/rsa_signing_test.cc | 57 -- yacl/crypto/base/sign/BUILD.bazel | 63 ++ yacl/crypto/base/sign/rsa_signing.cc | 90 +++ yacl/crypto/base/sign/rsa_signing.h | 61 ++ yacl/crypto/base/sign/rsa_signing_test.cc | 105 +++ yacl/crypto/base/{ => sign}/signing.h | 4 +- yacl/crypto/base/sign/sm2_signing.cc | 95 +++ yacl/crypto/base/sign/sm2_signing.h | 61 ++ yacl/crypto/base/sign/sm2_signing_test.cc | 105 +++ yacl/crypto/base/sm2_signing.cc | 154 ----- yacl/crypto/base/sm2_signing.h | 92 --- yacl/crypto/base/sm2_signing_test.cc | 37 - yacl/crypto/base/test/alg_data_test.cc | 123 ---- yacl/crypto/primitives/code/BUILD.bazel | 115 ++++ yacl/crypto/primitives/code/benchmark.cc | 44 ++ yacl/crypto/primitives/code/benchmark.h | 119 ++++ .../code}/code_interface.h | 0 .../code/ea_code.h} | 11 +- .../code/ea_code_test.cc} | 2 +- .../{tools => primitives/code}/linear_code.h | 6 +- .../code}/linear_code_test.cc | 4 +- .../{tools => primitives/code}/silver_code.cc | 4 +- .../{tools => primitives/code}/silver_code.h | 2 +- .../code}/silver_code_test.cc | 22 +- yacl/crypto/primitives/ot/BUILD.bazel | 30 +- yacl/crypto/primitives/ot/base_ot.h | 4 +- yacl/crypto/primitives/ot/benchmark.cc | 7 +- yacl/crypto/primitives/ot/benchmark.h | 61 +- yacl/crypto/primitives/ot/ferret_ote.cc | 2 +- yacl/crypto/primitives/ot/ferret_ote.h | 29 +- yacl/crypto/primitives/ot/ferret_ote_rn.h | 4 +- yacl/crypto/primitives/ot/ferret_ote_test.cc | 13 +- yacl/crypto/primitives/ot/ferret_ote_un.h | 12 +- yacl/crypto/primitives/ot/gywz_ote.cc | 54 +- yacl/crypto/primitives/ot/gywz_ote.h | 34 +- yacl/crypto/primitives/ot/gywz_ote_test.cc | 6 +- yacl/crypto/primitives/ot/iknp_ote.cc | 2 +- yacl/crypto/primitives/ot/iknp_ote.h | 8 +- yacl/crypto/primitives/ot/kkrt_ote.cc | 4 +- yacl/crypto/primitives/ot/kkrt_ote.h | 6 +- yacl/crypto/primitives/ot/kos_ote.cc | 4 +- yacl/crypto/primitives/ot/kos_ote.h | 8 +- yacl/crypto/primitives/ot/ot_store.cc | 8 +- yacl/crypto/primitives/ot/ot_store_test.cc | 5 +- .../primitives/ot/portable_ot_interface.cc | 2 +- yacl/crypto/primitives/ot/sgrr_ote.cc | 88 ++- yacl/crypto/primitives/ot/sgrr_ote.h | 39 +- yacl/crypto/primitives/ot/sgrr_ote_test.cc | 40 +- yacl/crypto/primitives/ot/softspoken_ote.cc | 300 +++++--- yacl/crypto/primitives/ot/softspoken_ote.h | 29 +- .../primitives/ot/softspoken_ote_test.cc | 126 ++-- .../primitives/ot/x86_asm_ot_interface.cc | 2 +- yacl/crypto/primitives/vole/f2k/BUILD.bazel | 9 +- yacl/crypto/primitives/vole/f2k/base_vole.h | 5 + .../primitives/vole/f2k/base_vole_test.cc | 2 +- yacl/crypto/primitives/vole/f2k/benchmark.cc | 14 +- .../crypto/primitives/vole/f2k/silent_vole.cc | 237 ++++--- yacl/crypto/primitives/vole/f2k/silent_vole.h | 4 + .../crypto/primitives/vole/f2k/sparse_vole.cc | 247 +++---- yacl/crypto/primitives/vole/f2k/sparse_vole.h | 69 +- .../primitives/vole/f2k/sparse_vole_test.cc | 36 +- yacl/crypto/primitives/vss/poly.cc | 111 +-- yacl/crypto/primitives/vss/poly.h | 34 +- yacl/crypto/primitives/vss/vss.cc | 60 +- yacl/crypto/primitives/vss/vss.h | 34 +- yacl/crypto/primitives/vss/vss_test.cc | 6 +- yacl/crypto/primitives/zkp/BUILD.bazel | 2 +- yacl/crypto/primitives/zkp/sigma.cc | 2 +- yacl/crypto/provider/BUILD.bazel | 92 +++ yacl/crypto/provider/helper.h | 83 +++ yacl/crypto/provider/linux_exported_syms.lds | 9 + yacl/crypto/provider/macos_exported_syms.lds | 1 + yacl/crypto/provider/provider.cc | 111 +++ yacl/crypto/provider/provider_test.cc | 141 ++++ yacl/crypto/provider/rand_impl.h | 265 +++++++ .../version.h} | 12 +- yacl/crypto/tools/BUILD.bazel | 115 +--- yacl/crypto/tools/benchmark.cc | 48 +- yacl/crypto/tools/benchmark.h | 124 +--- yacl/crypto/tools/crhash.cc | 148 ++++ yacl/crypto/tools/crhash.h | 51 ++ ...dom_permutation_test.cc => crhash_test.cc} | 49 +- yacl/crypto/tools/prg.cc | 34 +- yacl/crypto/tools/prg.h | 194 +++--- yacl/crypto/tools/prg_test.cc | 650 +++++++++--------- yacl/crypto/tools/random_permutation.cc | 128 ---- yacl/crypto/tools/{random_oracle.h => ro.h} | 0 .../{random_oracle_test.cc => ro_test.cc} | 4 +- yacl/crypto/tools/rp.cc | 46 ++ .../tools/{random_permutation.h => rp.h} | 44 +- yacl/crypto/tools/rp_test.cc | 54 ++ yacl/crypto/utils/BUILD.bazel | 30 +- yacl/crypto/utils/compile_time_utils.h | 8 +- yacl/crypto/utils/drbg/BUILD.bazel | 94 +++ yacl/crypto/utils/drbg/drbg.h | 87 +++ yacl/crypto/utils/drbg/factory_test.cc | 121 ++++ yacl/crypto/utils/drbg/ic_factory.cc | 82 +++ yacl/crypto/utils/drbg/ic_factory.h | 80 +++ yacl/crypto/utils/drbg/openssl_factory.cc | 113 +++ yacl/crypto/utils/drbg/openssl_factory.h | 79 +++ yacl/crypto/utils/entropy_source/BUILD.bazel | 85 +++ .../utils/entropy_source/entropy_source.h | 66 ++ .../utils/entropy_source/factory_test.cc | 59 ++ .../utils/entropy_source/intel_factory.cc | 72 ++ .../utils/entropy_source/intel_factory.h | 56 ++ .../utils/entropy_source/urandom_factory.cc | 50 ++ .../utils/entropy_source/urandom_factory.h | 47 ++ yacl/crypto/utils/rand.cc | 174 ++--- yacl/crypto/utils/rand.h | 165 +++-- yacl/crypto/utils/rand_bench.cc | 130 ++-- yacl/crypto/utils/rand_test.cc | 44 ++ yacl/crypto/utils/secparam.h | 186 +++-- yacl/crypto/utils/secparam_test.cc | 5 +- yacl/io/msgpack/BUILD.bazel | 1 + yacl/io/msgpack/spec_traits.cc | 78 +++ yacl/io/msgpack/spec_traits.h | 61 +- yacl/link/BUILD.bazel | 2 +- yacl/link/context.h | 4 +- yacl/link/factory_brpc.cc | 1 + yacl/link/test_util.h | 7 +- yacl/link/transport/BUILD.bazel | 8 + .../blackbox_interconnect/mock_transport.h | 1 + yacl/link/transport/brpc_link.cc | 1 + yacl/link/transport/channel.cc | 35 +- yacl/link/transport/channel.h | 6 + yacl/link/transport/channel_mem.cc | 13 + yacl/link/transport/channel_mem.h | 15 +- yacl/link/transport/channel_mem_test.cc | 98 +++ yacl/math/galois_field/BUILD.bazel | 1 + .../{mpint_field/configs.h => gf_configs.h} | 32 +- yacl/math/galois_field/gf_scalar.h | 4 +- yacl/math/galois_field/gf_spi.cc | 4 + .../math/galois_field/mpint_field/BUILD.bazel | 11 - .../galois_field/mpint_field/mpint_field.cc | 14 +- .../mpint_field/mpint_field_bench.cc | 5 +- .../mpint_field/mpint_field_test.cc | 87 ++- yacl/math/mpint/mp_int.cc | 11 +- yacl/math/mpint/mp_int_test.cc | 2 + yacl/math/mpint/tommath_ext_types.cc | 2 +- yacl/utils/BUILD.bazel | 4 +- yacl/utils/cuckoo_index_test.cc | 1 - yacl/utils/{hash.h => hash_combine.h} | 0 yacl/utils/spi/item.cc | 8 +- yacl/utils/spi/item.h | 25 +- yacl/utils/spi/spi_factory.h | 1 + yacl/utils/spi/spi_factory_test.cc | 2 +- 229 files changed, 7170 insertions(+), 6214 deletions(-) create mode 100644 bazel/hash_drbg.BUILD delete mode 100644 bazel/patches/ippcp.patch delete mode 100644 yacl/crypto/base/asymmetric_rsa_crypto.cc delete mode 100644 yacl/crypto/base/asymmetric_rsa_crypto.h delete mode 100644 yacl/crypto/base/asymmetric_rsa_crypto_test.cc delete mode 100644 yacl/crypto/base/asymmetric_sm2_crypto.cc delete mode 100644 yacl/crypto/base/asymmetric_sm2_crypto.h delete mode 100644 yacl/crypto/base/asymmetric_sm2_crypto_test.cc delete mode 100644 yacl/crypto/base/asymmetric_util.cc delete mode 100644 yacl/crypto/base/asymmetric_util.h rename yacl/crypto/base/{test => block_cipher}/BUILD.bazel (59%) rename yacl/crypto/base/{ => block_cipher}/symmetric_crypto.cc (84%) rename yacl/crypto/base/{ => block_cipher}/symmetric_crypto.h (77%) rename yacl/crypto/base/{ => block_cipher}/symmetric_crypto_test.cc (88%) delete mode 100644 yacl/crypto/base/drbg/BUILD.bazel delete mode 100644 yacl/crypto/base/drbg/entropy_source.h delete mode 100644 yacl/crypto/base/drbg/entropy_source_selector.cc delete mode 100644 yacl/crypto/base/drbg/entropy_source_test.cc delete mode 100644 yacl/crypto/base/drbg/intel_entropy_source.cc delete mode 100644 yacl/crypto/base/drbg/intel_entropy_source.h delete mode 100644 yacl/crypto/base/drbg/nist_aes_drbg.cc delete mode 100644 yacl/crypto/base/drbg/nist_aes_drbg.h delete mode 100644 yacl/crypto/base/drbg/nist_aes_drbg_test.cc delete mode 100644 yacl/crypto/base/drbg/sm4_drbg.cc delete mode 100644 yacl/crypto/base/drbg/sm4_drbg.h delete mode 100644 yacl/crypto/base/drbg/sm4_drbg_test.cc delete mode 100644 yacl/crypto/base/drbg/std_entropy_source.cc create mode 100644 yacl/crypto/base/envelope/BUILD.bazel rename yacl/crypto/base/{ => envelope}/digital_envelope.cc (84%) rename yacl/crypto/base/{ => envelope}/digital_envelope.h (100%) rename yacl/crypto/base/{ => envelope}/digital_envelope_test.cc (72%) delete mode 100644 yacl/crypto/base/hmac.cc rename bazel/ipp.BUILD => yacl/crypto/base/hmac/BUILD.bazel (50%) create mode 100644 yacl/crypto/base/hmac/hmac.cc rename yacl/crypto/base/{ => hmac}/hmac.h (91%) rename yacl/crypto/base/{ => hmac}/hmac_all_test.cc (84%) rename yacl/crypto/base/{ => hmac}/hmac_sha256.h (95%) rename yacl/crypto/base/{ => hmac}/hmac_sm3.h (95%) create mode 100644 yacl/crypto/base/key_utils.cc create mode 100644 yacl/crypto/base/key_utils.h create mode 100644 yacl/crypto/base/key_utils_test.cc create mode 100644 yacl/crypto/base/openssl_wrappers.h create mode 100644 yacl/crypto/base/pke/BUILD.bazel rename yacl/crypto/base/{ => pke}/asymmetric_crypto.h (90%) create mode 100644 yacl/crypto/base/pke/asymmetric_rsa_crypto.cc create mode 100644 yacl/crypto/base/pke/asymmetric_rsa_crypto.h rename yacl/crypto/base/{drbg/drbg.h => pke/asymmetric_rsa_crypto_test.cc} (57%) create mode 100644 yacl/crypto/base/pke/asymmetric_sm2_crypto.cc create mode 100644 yacl/crypto/base/pke/asymmetric_sm2_crypto.h rename yacl/crypto/base/{drbg/std_entropy_source.h => pke/asymmetric_sm2_crypto_test.cc} (56%) delete mode 100644 yacl/crypto/base/rsa_signing.cc delete mode 100644 yacl/crypto/base/rsa_signing.h delete mode 100644 yacl/crypto/base/rsa_signing_test.cc create mode 100644 yacl/crypto/base/sign/BUILD.bazel create mode 100644 yacl/crypto/base/sign/rsa_signing.cc create mode 100644 yacl/crypto/base/sign/rsa_signing.h create mode 100644 yacl/crypto/base/sign/rsa_signing_test.cc rename yacl/crypto/base/{ => sign}/signing.h (93%) create mode 100644 yacl/crypto/base/sign/sm2_signing.cc create mode 100644 yacl/crypto/base/sign/sm2_signing.h create mode 100644 yacl/crypto/base/sign/sm2_signing_test.cc delete mode 100644 yacl/crypto/base/sm2_signing.cc delete mode 100644 yacl/crypto/base/sm2_signing.h delete mode 100644 yacl/crypto/base/sm2_signing_test.cc delete mode 100644 yacl/crypto/base/test/alg_data_test.cc create mode 100644 yacl/crypto/primitives/code/BUILD.bazel create mode 100644 yacl/crypto/primitives/code/benchmark.cc create mode 100644 yacl/crypto/primitives/code/benchmark.h rename yacl/crypto/{tools => primitives/code}/code_interface.h (100%) rename yacl/crypto/{tools/expand_accumulate_code.h => primitives/code/ea_code.h} (95%) rename yacl/crypto/{tools/expand_accumulate_code_test.cc => primitives/code/ea_code_test.cc} (99%) rename yacl/crypto/{tools => primitives/code}/linear_code.h (98%) rename yacl/crypto/{tools => primitives/code}/linear_code_test.cc (94%) rename yacl/crypto/{tools => primitives/code}/silver_code.cc (99%) rename yacl/crypto/{tools => primitives/code}/silver_code.h (98%) rename yacl/crypto/{tools => primitives/code}/silver_code_test.cc (88%) create mode 100644 yacl/crypto/provider/BUILD.bazel create mode 100644 yacl/crypto/provider/helper.h create mode 100644 yacl/crypto/provider/linux_exported_syms.lds create mode 100644 yacl/crypto/provider/macos_exported_syms.lds create mode 100644 yacl/crypto/provider/provider.cc create mode 100644 yacl/crypto/provider/provider_test.cc create mode 100644 yacl/crypto/provider/rand_impl.h rename yacl/crypto/{base/drbg/entropy_source_selector.h => provider/version.h} (77%) create mode 100644 yacl/crypto/tools/crhash.cc create mode 100644 yacl/crypto/tools/crhash.h rename yacl/crypto/tools/{random_permutation_test.cc => crhash_test.cc} (74%) delete mode 100644 yacl/crypto/tools/random_permutation.cc rename yacl/crypto/tools/{random_oracle.h => ro.h} (100%) rename yacl/crypto/tools/{random_oracle_test.cc => ro_test.cc} (97%) create mode 100644 yacl/crypto/tools/rp.cc rename yacl/crypto/tools/{random_permutation.h => rp.h} (63%) create mode 100644 yacl/crypto/tools/rp_test.cc create mode 100644 yacl/crypto/utils/drbg/BUILD.bazel create mode 100644 yacl/crypto/utils/drbg/drbg.h create mode 100644 yacl/crypto/utils/drbg/factory_test.cc create mode 100644 yacl/crypto/utils/drbg/ic_factory.cc create mode 100644 yacl/crypto/utils/drbg/ic_factory.h create mode 100644 yacl/crypto/utils/drbg/openssl_factory.cc create mode 100644 yacl/crypto/utils/drbg/openssl_factory.h create mode 100644 yacl/crypto/utils/entropy_source/BUILD.bazel create mode 100644 yacl/crypto/utils/entropy_source/entropy_source.h create mode 100644 yacl/crypto/utils/entropy_source/factory_test.cc create mode 100644 yacl/crypto/utils/entropy_source/intel_factory.cc create mode 100644 yacl/crypto/utils/entropy_source/intel_factory.h create mode 100644 yacl/crypto/utils/entropy_source/urandom_factory.cc create mode 100644 yacl/crypto/utils/entropy_source/urandom_factory.h create mode 100644 yacl/crypto/utils/rand_test.cc create mode 100644 yacl/io/msgpack/spec_traits.cc create mode 100644 yacl/link/transport/channel_mem_test.cc rename yacl/math/galois_field/{mpint_field/configs.h => gf_configs.h} (63%) rename yacl/utils/{hash.h => hash_combine.h} (100%) diff --git a/.bazelrc b/.bazelrc index 04806c9d..d332aaf1 100644 --- a/.bazelrc +++ b/.bazelrc @@ -13,6 +13,7 @@ # limitations under the License. common --experimental_repo_remote_exec +common --experimental_cc_shared_library build --incompatible_new_actions_api=false build --copt=-fdiagnostics-color=always @@ -31,7 +32,7 @@ build:macos --host_copt=-Wa,--noexecstack # platform specific config # Bazel will automatic pick platform config since we have enable_platform_specific_config set build:macos --features=-supports_dynamic_linker -build:macos --linkopt="-Wl,-no_warn_duplicate_libraries" +build:macos --linkopt="-Wl" build:macos --copt=-Wno-unused-command-line-argument build:macos --host_copt=-Wno-unused-command-line-argument @@ -40,4 +41,4 @@ build:ubsan --features=ubsan test --keep_going test --test_output=errors -test --test_timeout=180 +test --test_timeout=360 diff --git a/.bazelversion b/.bazelversion index c0be8a79..024b066c 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -6.4.0 \ No newline at end of file +6.2.1 diff --git a/ALGORITHMS.md b/ALGORITHMS.md index 9758ef4e..a0239281 100644 --- a/ALGORITHMS.md +++ b/ALGORITHMS.md @@ -1,8 +1,7 @@ # Supported Crypto Algorithms -TODO - ## Primitives + - OT - Simplest OT : https://eprint.iacr.org/2015/267.pdf - INKP OT Extension : https://www.iacr.org/archive/crypto2003/27290145/27290145.pdf @@ -14,20 +13,28 @@ TODO - Softspoken OT Extension : https://eprint.iacr.org/2022/192.pdf - VOLE(over f2k) - base VOLE : https://eprint.iacr.org/2016/505.pdf - - Silent VOLE : https://eprint.iacr.org/2019/1159.pdf, https://eprint.iacr.org/2021/1150.pdf, https://eprint.iacr.org/2022/1014.pdf + - Silent VOLE : https://eprint.iacr.org/2019/1159.pdf, https://eprint.iacr.org/2021/1150.pdf https://eprint.iacr.org/2022/1014.pdf + +- CODE + - Local Linear Code : https://eprint.iacr.org/2020/924.pdf + - Low Density Parity Check Code (Silver Code) : https://eprint.iacr.org/2021/1150.pdf + - Expanding Accumulation Code : https://eprint.iacr.org/2022/1014.pdf ## Theoretical Tools -- Random Oracle -- Random Permutation -- Local Linear Code : https://eprint.iacr.org/2020/924.pdf -- Low Density Parity Check Code (Silver Code) : https://eprint.iacr.org/2021/1150.pdf -- Expanding Accumulation Code : https://eprint.iacr.org/2022/1014.pdf -- Correlation-Robust Hash Function : https://eprint.iacr.org/2019/074.pdf -- Circular Correlation-Robust Hash Function : https://eprint.iacr.org/2019/074.pdf +- Random Oracle (RO) +- Random Permutation (RP) +- Pseudorandom Generator (PRG) +- Correlation-Robust Hash (CrHash) : https://eprint.iacr.org/2019/074.pdf +- Circular Correlation-Robust Hash (CcrHash) : https://eprint.iacr.org/2019/074.pdf ## Basic (Traditional) algorithms +- AEAD - AES -- Hash: SHA2, SM2 -- RSA +- Block Cipher +- ECC (TODO) +- Hash +- HMAC +- PKE: RSA, SM2 +- Signature: RSA, SM2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 18179825..244a9a38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,14 +8,22 @@ All notable changes to this project will be documented in this file. > - Add `[Bugfix]` prefix for bug fixes > - Add `[API]` prefix for API changes +## Staging +- [YACL] v0.4.2 +- [Dependency] Bump: Openssl 3.0.12 (experimental) +- [Feature] Add Softspoken OTe (malicious version) +- [API] Refactor entropy source, drbg, and rand; Refine traditional crypto APIs +- [Bugifx] Multiple bugfixes + + ## 2023-11-16 -- [YACL] 0.4.1.1 +- [YACL] v0.4.1.1 - [Feature] Init Global Security Parameters for Yacl [WIP: apply security parameter to all algorithms] - [Feature] Add Softspoken OTe (semi-honest version) - [Feature] Add Silent Vole [WIP: optimize MpVole and DualEncode] ## 2023-10-20 -- [YACL] 0.4.1 +- [YACL] v0.4.1 - [Feature] Add Sigma-type ZKP Protocols (An unified implementation) - [Feature] Add ECC Pairing SPI and support to libmcl(ecc, pairing) - [Feature] Add Multiplication for GF(2^64) and GF(2^128) @@ -23,20 +31,20 @@ All notable changes to this project will be documented in this file. - [Feature] Add AVX2 Matrix Transpose ## 2023-05-25 -- [YACL] 0.3.3 +- [YACL] v0.3.3 - [Feature] Add Ferret OTe - [Feature] Add Gywz OTe (Correlated GGM Tree) - [Feature] Add KOS OTe (warning: KOS still has potential security flaws) ## 2023-02-02 -- [YACL] 0.3.1 +- [YACL] v0.3.1 - [Feature] Add `dynamic_bitset` for manipulating bit vectors - [API] RO now can accept multiple inputs - [API] Add iknp cot api, improve iknp performance - [Bugfix] Fix Several m1 related bugs ## 2022-12-08 -- [YACL] 0.3.0 +- [YACL] v0.3.0 - [Feature] Add random permutation and correlation-robust hash function - [Feature] Add OT/OTe benchmark - [API] Fix randomness implementation @@ -44,6 +52,6 @@ All notable changes to this project will be documented in this file. - [Bugfix] Fix Random Oralce Usage ## 2022-12-01 -- [YACL] 0.2.0 +- [YACL] v0.2.0 - [API] Rename YASL to YACL - [API] Re-organize repo layout diff --git a/README.md b/README.md index c97c20e7..ed995ab5 100644 --- a/README.md +++ b/README.md @@ -8,16 +8,16 @@ Repo layout: - [base](yacl/base/): some basic types and utils in yacl. - [crypto](yacl/crypto/): a crypto library desigend for secure computation and so on. - - [base](yacl/crypto/base): **basic/standarized crypto**, i.e. AES, DRBG, hashing. + - [base](yacl/crypto/base): **basic/standarized crypto**, i.e. AES, hashing. - [primitives](yacl/crypto/primitives/): **crypto primitives**, i.e. OT, DPF. - [tools](yacl/crypto/tools/): **theoretical crypto tools**, i.e. Random Oracle (RO), PRG. - [utils](yacl/crypto/utils/): easy-to-use **crypto utilities**. - [io](yacl/io/): a simple streaming-based io library. - [link](yacl/link/): a simple rpc-based MPI framework, providing the [SPMD](https://en.wikipedia.org/wiki/SPMD) parallel programming capability. -## Supported Crypto Algorithms +## Supported crypto algorithms -See **Full List** of supported algorithms: [ALGORITHMS.md](ALGORITHMS.md) +See **Full List** of supported algorithms in: [ALGORITHMS.md](ALGORITHMS.md) **Selected algorithms**: @@ -26,14 +26,14 @@ See **Full List** of supported algorithms: [ALGORITHMS.md](ALGORITHMS.md) - Distributed Point Function: [BGI16](https://eprint.iacr.org/2018/707.pdf) - Threshold Proxy-Re-encryption: [umbral with GM](https://github.com/nucypher/umbral-doc/blob/master/umbral-doc.pdf). -## Build - -### Supported platforms +## Supported platforms | | Linux x86_64 | Linux aarch64 | macOS x86_64 | macOS Apple Silicon | Windows x86_64 | Windows WSL2 x86_64 | |-----|--------------|---------------|--------------|---------------------|----------------|---------------------| | CPU | yes | yes | yes | yes | no | yes | +## Build + ### Prerequisite #### Linux @@ -53,7 +53,7 @@ sudo xcode-select -s /Applications/Xcode.app/Contents/Developer https://brew.sh/ # Install dependencies -brew install bazel cmake ninja nasm automake libtool +brew install bazel cmake ninja nasm automake libtool libomp ``` ### Build & UnitTest diff --git a/bazel/hash_drbg.BUILD b/bazel/hash_drbg.BUILD new file mode 100644 index 00000000..26b8eef3 --- /dev/null +++ b/bazel/hash_drbg.BUILD @@ -0,0 +1,29 @@ +# Copyright 2023 Ant Group Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@rules_cc//cc:defs.bzl", "cc_library") + +cc_library( + name = "hash_drbg", + srcs = [ + "hash_drbg.c", + "hash_drbg_error_codes.h", + ], + hdrs = ["hash_drbg.h"], + copts = ["-Wno-parentheses"], + visibility = ["//visibility:public"], + deps = [ + "@com_github_openssl_openssl//:openssl", + ], +) diff --git a/bazel/openssl.BUILD b/bazel/openssl.BUILD index 558957ed..d69a8605 100644 --- a/bazel/openssl.BUILD +++ b/bazel/openssl.BUILD @@ -14,59 +14,58 @@ load("@yacl//bazel:yacl.bzl", "yacl_configure_make") -package(default_visibility = ["//visibility:public"]) +# An openssl build file based on a snippet found in the github issue: +# https://github.com/bazelbuild/rules_foreign_cc/issues/337 + +# Read https://wiki.openssl.org/index.php/Compilation_and_Installation filegroup( name = "all_srcs", - srcs = glob(["**"]), + srcs = glob( + include = ["**"], + exclude = ["*.bazel"], + ), ) -# This is the value defined by --config=android_arm64 -config_setting( - name = "cpu_arm64_v8a", - values = {"cpu": "arm64-v8a"}, - visibility = ["//visibility:private"], -) +CONFIGURE_OPTIONS = [ + # fixed openssl work dir for deterministic build. + "--openssldir=/tmp/openssl", + "--libdir=lib", + "no-legacy", + "no-weak-ssl-ciphers", + "no-shared", + "no-tests", + "no-ui-console", +] + +MAKE_TARGETS = [ + "build_programs", + "install_sw", +] yacl_configure_make( name = "openssl", - configure_command = select( - { - ":cpu_arm64_v8a": "Configure", # Use Configure for android build - "//conditions:default": "config", - }, - ), - configure_options = [ - # fixed openssl work dir for deterministic build. - "--openssldir=/tmp/openssl", - "--libdir=lib", - "no-shared", - # https://www.openssl.org/docs/man1.1.0/man3/OpenSSL_version.html - # OPENSSL_ENGINES_DIR point to /tmp path randomly generated. - "no-engine", - "no-tests", - ] + select( - { - ":cpu_arm64_v8a": ["android-arm64"], - "//conditions:default": [], - }, - ), - copts = ["-Wno-format"], + args = ["-j 4"], + configure_command = "Configure", + configure_in_place = True, + configure_options = CONFIGURE_OPTIONS, env = select({ - "@bazel_tools//src/conditions:darwin": { - "ARFLAGS": "-static -s -o", + "@platforms//os:macos": { + "AR": "", }, "//conditions:default": { + "MODULESDIR": "", }, }), + lib_name = "openssl", lib_source = ":all_srcs", - linkopts = ["-ldl"], + out_binaries = ["openssl"], + # Note that for Linux builds, libssl must come before libcrypto on the linker command-line. + # As such, libssl must be listed before libcrypto out_static_libs = [ "libssl.a", "libcrypto.a", ], - targets = [ - "-s", - "-s install_sw", - ], + targets = MAKE_TARGETS, + visibility = ["//visibility:public"], ) diff --git a/bazel/patches/brpc.patch b/bazel/patches/brpc.patch index 54b1a899..877069c7 100644 --- a/bazel/patches/brpc.patch +++ b/bazel/patches/brpc.patch @@ -87,7 +87,7 @@ index 5d317c90..5bb62a6e 100644 + "@bazel_tools//src/conditions:linux_aarch64": ["-O1"], + "//conditions:default": [""], }) - + LINKOPTS = [ "-pthread", "-ldl", diff --git a/bazel/patches/ippcp.patch b/bazel/patches/ippcp.patch deleted file mode 100644 index 87763608..00000000 --- a/bazel/patches/ippcp.patch +++ /dev/null @@ -1,250 +0,0 @@ -diff --git a/sources/cmake/linux/GNU8.2.0.cmake b/sources/cmake/linux/GNU8.2.0.cmake -index 24d7e0f..15dd433 100644 ---- a/sources/cmake/linux/GNU8.2.0.cmake -+++ b/sources/cmake/linux/GNU8.2.0.cmake -@@ -32,7 +32,7 @@ set(LINK_FLAG_DYNAMIC_LINUX "${LINK_FLAG_SECURITY} -nostdlib") - # Dynamically link lib c (libdl is for old apps) - set(LINK_FLAG_DYNAMIC_LINUX "${LINK_FLAG_DYNAMIC_LINUX} -Wl,-call_shared,-lc") - # Create a shared library --set(LINK_FLAG_DYNAMIC_LINUX "-Wl,-shared") -+set(LINK_FLAG_DYNAMIC_LINUX "-Wl,-shared,-fuse-ld=bfd") - if(${ARCH} MATCHES "ia32") - # Tells the compiler to generate code for a specific architecture (32) - set(LINK_FLAG_DYNAMIC_LINUX "${LINK_FLAG_DYNAMIC_LINUX} -m32") -@@ -74,7 +74,7 @@ if ((${ARCH} MATCHES "ia32") OR (NOT NONPIC_LIB)) - endif() - - # Security flag that adds compile-time and run-time checks --set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2") -+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2") - - if(NOT NONPIC_LIB) - # Position Independent Execution (PIE) -@@ -95,6 +95,8 @@ if(${ARCH} MATCHES "ia32") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") - endif(${ARCH} MATCHES "ia32") - -+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unknown-pragmas -Wno-missing-braces -Wno-comment -Wno-strict-aliasing -Wno-parentheses -Wno-array-parameter") -+ - # Optimization level = 3, no-debug definition (turns off asserts), warnings=errors - set (CMAKE_C_FLAGS_RELEASE " -O3 -DNDEBUG -Werror") - -diff --git a/sources/cmake/macosx/AppleClang11.0.0.cmake b/sources/cmake/macosx/AppleClang11.0.0.cmake -index 5b92877..ccb963e 100644 ---- a/sources/cmake/macosx/AppleClang11.0.0.cmake -+++ b/sources/cmake/macosx/AppleClang11.0.0.cmake -@@ -20,12 +20,6 @@ - - # Security Linker flags - set(LINK_FLAG_SECURITY "") --# Disallows undefined symbols in object files. Undefined symbols in shared libraries are still allowed --set(LINK_FLAG_SECURITY "${LINK_FLAG_SECURITY} -Wl,-z,defs") --# Stack execution protection --set(LINK_FLAG_SECURITY "${LINK_FLAG_SECURITY} -Wl,-z,noexecstack") --# Data relocation and protection (RELRO) --set(LINK_FLAG_SECURITY "${LINK_FLAG_SECURITY} -Wl,-z,relro -Wl,-z,now") - # Prevents the compiler from using standard libraries and startup files when linking. - set(LINK_FLAG_DYNAMIC_MACOSX "${LINK_FLAG_SECURITY} -nostdlib") - # Dynamically link lib c (libdl is for old apps) -@@ -79,7 +73,7 @@ if ((${ARCH} MATCHES "ia32") OR (NOT NONPIC_LIB)) - endif() - - # Security flag that adds compile-time and run-time checks --set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2") -+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2") - - if(NOT NONPIC_LIB) - # Position Independent Execution (PIE) -@@ -98,6 +92,8 @@ if(${ARCH} MATCHES "ia32") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") - endif(${ARCH} MATCHES "ia32") - -+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function -Wno-unused-variable -Wno-unknown-pragmas -Wno-missing-braces -Wno-unused-command-line-argument -Wno-unused-but-set-variable -Wno-unknown-warning-option") -+ - # Optimization level = 3, no-debug definition (turns off asserts), warnings=errors - set (CMAKE_C_FLAGS_RELEASE " -O3 -DNDEBUG -Werror") - -@@ -115,3 +111,5 @@ set(l9_opt "${l9_opt} -march=haswell -mavx2 -maes -mpclmul -msha -mrdrnd -mrdsee - set(n0_opt "${n0_opt} -march=knl -mavx2 -maes -mavx512f -mavx512cd -mavx512pf -mavx512er -mpclmul -msha -mrdrnd -mrdseed") - set(k0_opt "${k0_opt} -march=skylake-avx512") - set(k0_opt "${k0_opt} -maes -mavx512f -mavx512cd -mavx512vl -mavx512bw -mavx512dq -mavx512ifma -mpclmul -msha -mrdrnd -mrdseed -madx -mgfni -mvaes -mvpclmulqdq -mavx512vbmi -mavx512vbmi2") -+set(k1_opt "${k1_opt} -march=skylake-avx512") -+set(k1_opt "${k1_opt} -maes -mavx512f -mavx512cd -mavx512vl -mavx512bw -mavx512dq -mavx512ifma -mpclmul -msha -mrdrnd -mrdseed -madx -mgfni -mvaes -mvpclmulqdq -mavx512vbmi -mavx512vbmi2") -diff --git a/sources/cmake/macosx/common.cmake b/sources/cmake/macosx/common.cmake -index 85ec3ad..67bb9f9 100644 ---- a/sources/cmake/macosx/common.cmake -+++ b/sources/cmake/macosx/common.cmake -@@ -18,7 +18,7 @@ - # IntelĀ® Integrated Performance Primitives Cryptography (IntelĀ® IPP Cryptography) - # - --set(OS_DEFAULT_COMPILER Intel19.0.0) -+set(OS_DEFAULT_COMPILER AppleClang11.0.0) - - set(LIBRARY_DEFINES "${LIBRARY_DEFINES} -DIPP_PIC -DOSXEM64T -DLINUX32E -D_ARCH_EM64T") - #set(LIBRARY_DEFINES "${LIBRARY_DEFINES} -DBN_OPENSSL_DISABLE") -\ No newline at end of file -diff --git a/sources/ippcp/crypto_mb/src/cmake/linux/GNU.cmake b/sources/ippcp/crypto_mb/src/cmake/linux/GNU.cmake -index a2abeeb..67aca8b 100644 ---- a/sources/ippcp/crypto_mb/src/cmake/linux/GNU.cmake -+++ b/sources/ippcp/crypto_mb/src/cmake/linux/GNU.cmake -@@ -31,7 +31,7 @@ set(CMAKE_C_FLAGS_SECURITY "${CMAKE_C_FLAGS_SECURITY} -Wformat -Wformat-security - if(${CMAKE_BUILD_TYPE} STREQUAL "Release") - if(NOT DEFINED NO_FORTIFY_SOURCE) - # Security flag that adds compile-time and run-time checks. -- set(CMAKE_C_FLAGS_SECURITY "${CMAKE_C_FLAGS_SECURITY} -D_FORTIFY_SOURCE=2") -+ set(CMAKE_C_FLAGS_SECURITY "${CMAKE_C_FLAGS_SECURITY} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2") - endif() - endif() - -@@ -51,7 +51,7 @@ set(CMAKE_C_FLAGS_SECURITY "${CMAKE_C_FLAGS_SECURITY} -Werror") - # Linker flags - - # Create shared library --set(LINK_FLAGS_DYNAMIC " -Wl,-shared") -+set(LINK_FLAGS_DYNAMIC " -Wl,-shared,-fuse-ld=bfd") - # Add export files - set(LINK_FLAGS_DYNAMIC "${LINK_FLAGS_DYNAMIC} ${CRYPTO_MB_SOURCES_DIR}/cmake/dll_export/crypto_mb.linux.lib-export") - -@@ -69,6 +69,7 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") - - # Suppress warnings from casts from a pointer to an integer type of a different size - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-pointer-to-int-cast") -+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unknown-pragmas -Wno-missing-braces -Wno-comment -Wno-strict-aliasing -Wno-parentheses") - - # Optimization level = 3, no-debug definition (turns off asserts) - set(CMAKE_C_FLAGS_RELEASE " -O3 -DNDEBUG") -diff --git a/sources/ippcp/crypto_mb/src/cmake/macosx/AppleClang.cmake b/sources/ippcp/crypto_mb/src/cmake/macosx/AppleClang.cmake -index ea1641d..f98fc2d 100644 ---- a/sources/ippcp/crypto_mb/src/cmake/macosx/AppleClang.cmake -+++ b/sources/ippcp/crypto_mb/src/cmake/macosx/AppleClang.cmake -@@ -17,10 +17,6 @@ - # Security Linker flags - - set(LINK_FLAG_SECURITY "") --# Data relocation and protection (RELRO) --set(LINK_FLAG_SECURITY "${LINK_FLAG_SECURITY} -Wl,-z,relro -Wl,-z,now") --# Stack execution protection --set(LINK_FLAG_SECURITY "${LINK_FLAG_SECURITY} -Wl,-z,noexecstack") - - # Security Compiler flags - -@@ -30,7 +26,7 @@ set(CMAKE_C_FLAGS_SECURITY "${CMAKE_C_FLAGS_SECURITY} -Wformat -Wformat-security - - if(${CMAKE_BUILD_TYPE} STREQUAL "Release") - # Security flag that adds compile-time and run-time checks. -- set(CMAKE_C_FLAGS_SECURITY "${CMAKE_C_FLAGS_SECURITY} -D_FORTIFY_SOURCE=2") -+ set(CMAKE_C_FLAGS_SECURITY "${CMAKE_C_FLAGS_SECURITY} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2") - endif() - - # Stack-based Buffer Overrun Detection -@@ -65,6 +61,8 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") - # Suppress warnings from casts from a pointer to an integer type of a different size - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-pointer-to-int-cast") - -+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function -Wno-unused-variable -Wno-unknown-pragmas -Wno-missing-braces -Wno-unknown-warning-option") -+ - # Optimization level = 3, no-debug definition (turns off asserts) - set(CMAKE_C_FLAGS_RELEASE " -O3 -DNDEBUG") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") - -diff --git a/sources/cmake/linux/Clang9.0.0.cmake b/sources/cmake/linux/Clang9.0.0.cmake -index 0015431..f93411c 100644 ---- a/sources/cmake/linux/Clang9.0.0.cmake -+++ b/sources/cmake/linux/Clang9.0.0.cmake -@@ -79,7 +79,7 @@ endif() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcf-protection=full") - - # Security flag that adds compile-time and run-time checks --set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2") -+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") - - if(NOT NONPIC_LIB) - # Position Independent Execution (PIE) -@@ -107,7 +107,7 @@ if(SANITIZERS) - endif(SANITIZERS) - - # Optimization level = 3, no-debug definition (turns off asserts), warnings=errors --set (CMAKE_C_FLAGS_RELEASE " -O3 -DNDEBUG -Werror") -+set (CMAKE_C_FLAGS_RELEASE " -O3 -DNDEBUG -Werror -Wno-unused-function -Wno-missing-braces -Wno-unused-but-set-variable -Wno-unknown-pragmas") - - # DEBUG flags - optimization level = 0, generation GDB information (-g) - set (CMAKE_C_FLAGS_DEBUG " -O0 -g") - -diff --git a/sources/include/dispatcher.h b/sources/include/dispatcher.h -index 8290df6..a2f93d7 100644 ---- a/sources/include/dispatcher.h -+++ b/sources/include/dispatcher.h -@@ -92,9 +92,13 @@ extern "C" { - #define LIB_W7 LIB_S8 - #elif defined( _ARCH_EM64T ) && !defined( OSXEM64T ) && !defined( WIN32E ) /* Linux* OS Intel64 supports N0 */ - enum lib_enum { -- LIB_M7=0, LIB_N8=1, LIB_Y8=2, LIB_E9=3, LIB_L9=4, LIB_N0=5, LIB_K0=6, LIB_K1=7,LIB_NOMORE -+ LIB_E9=0, LIB_L9=1, LIB_K0=2, LIB_K1=3,LIB_NOMORE - }; -- #define LIB_PX LIB_M7 -+ #define LIB_PX LIB_E9 -+ #define LIB_M7 LIB_E9 -+ #define LIB_N8 LIB_E9 -+ #define LIB_Y8 LIB_E9 -+ #define LIB_N0 LIB_L9 - #elif defined( _ARCH_EM64T ) && !defined( OSXEM64T ) /* Windows* OS Intel64 doesn't support N0 */ - enum lib_enum { - LIB_M7=0, LIB_N8=1, LIB_Y8=2, LIB_E9=3, LIB_L9=4, LIB_K0=5, LIB_K1=6, LIB_NOMORE -@@ -103,11 +107,12 @@ extern "C" { - #define LIB_N0 LIB_L9 - #elif defined( OSXEM64T ) - enum lib_enum { -- LIB_Y8=0, LIB_E9=1, LIB_L9=2, LIB_K0=3, LIB_K1=4, LIB_NOMORE -+ LIB_E9=0, LIB_L9=1, LIB_K0=2, LIB_K1=3, LIB_NOMORE - }; -- #define LIB_PX LIB_Y8 -- #define LIB_M7 LIB_Y8 -- #define LIB_N8 LIB_Y8 -+ #define LIB_PX LIB_E9 -+ #define LIB_M7 LIB_E9 -+ #define LIB_N8 LIB_E9 -+ #define LIB_Y8 LIB_E9 - #define LIB_N0 LIB_L9 - #elif defined( _ARCH_LRB2 ) - enum lib_enum { -diff --git a/sources/include/owndefs.h b/sources/include/owndefs.h -index dcc1ede..7c1e93e 100644 ---- a/sources/include/owndefs.h -+++ b/sources/include/owndefs.h -@@ -632,14 +632,14 @@ extern double __intel_castu64_f64(unsigned __int64 val); - - #elif defined(linux) - /* LIN-32, LIN-64 */ -- #if ( defined(_W7) || defined(_M7) ) -+ #if ( defined(_W7) || defined(_E9) ) - #define _IPP_DATA 1 - #endif - - - /* OSX-32, OSX-64 */ - #elif defined(OSX32) || defined(OSXEM64T) -- #if ( defined(_Y8) ) -+ #if ( defined(_E9) ) - #define _IPP_DATA 1 - #endif - #endif -diff --git a/sources/ippcp/CMakeLists.txt b/sources/ippcp/CMakeLists.txt -index 315d1a3..8b11c7a 100644 ---- a/sources/ippcp/CMakeLists.txt -+++ b/sources/ippcp/CMakeLists.txt -@@ -40,12 +40,12 @@ if(WIN32) - endif(WIN32) - if(UNIX) - if(APPLE) -- set(BASE_PLATFORM_LIST ${BASE_PLATFORM_LIST} y8 e9 l9 k0 k1) -+ set(BASE_PLATFORM_LIST ${BASE_PLATFORM_LIST} e9 l9 k0 k1) - else() - if (${ARCH} MATCHES "ia32") - set(BASE_PLATFORM_LIST ${BASE_PLATFORM_LIST} w7 s8 p8 g9 h9) - else() -- set(BASE_PLATFORM_LIST ${BASE_PLATFORM_LIST} m7 n8 y8 e9 l9 n0 k0 k1) -+ set(BASE_PLATFORM_LIST ${BASE_PLATFORM_LIST} e9 l9 k0 k1) - endif(${ARCH} MATCHES "ia32") - endif(APPLE) - endif(UNIX) diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl index f318d2b8..7949ec41 100644 --- a/bazel/repositories.bzl +++ b/bazel/repositories.bzl @@ -38,11 +38,11 @@ def yacl_deps(): _com_github_google_cpu_features() _com_github_dltcollab_sse2neon() _com_github_msgpack_msgpack() + _com_github_greendow_hash_drbg() # crypto related _com_github_openssl_openssl() _com_github_blake3team_blake3() - _com_github_intel_ipp() _com_github_libsodium() _com_github_libtom_libtommath() _com_github_herumi_mcl() @@ -162,11 +162,11 @@ def _com_github_openssl_openssl(): maybe( http_archive, name = "com_github_openssl_openssl", - sha256 = "c0bb03960ba535e51726950853f0e01a0a92e107e202f417e7546ee5e59baee0", + sha256 = "9a7a7355f3d4b73f43b5730ce80371f9d1f97844ffc8c4b01c723ba0625d6aad", type = "tar.gz", - strip_prefix = "openssl-OpenSSL_1_1_1v", + strip_prefix = "openssl-openssl-3.0.12", urls = [ - "https://github.com/openssl/openssl/archive/refs/tags/OpenSSL_1_1_1v.tar.gz", + "https://github.com/openssl/openssl/archive/refs/tags/openssl-3.0.12.tar.gz", ], build_file = "@yacl//bazel:openssl.BUILD", ) @@ -255,22 +255,6 @@ def _rules_foreign_cc(): ], ) -def _com_github_intel_ipp(): - maybe( - http_archive, - name = "com_github_intel_ipp", - sha256 = "1ecfa70328221748ceb694debffa0106b92e0f9bf6a484f8e8512c2730c7d730", - strip_prefix = "ipp-crypto-ippcp_2021.8", - build_file = "@yacl//bazel:ipp.BUILD", - patch_args = ["-p1"], - patches = [ - "@yacl//bazel:patches/ippcp.patch", - ], - urls = [ - "https://github.com/intel/ipp-crypto/archive/refs/tags/ippcp_2021.8.tar.gz", - ], - ) - def _com_github_libsodium(): maybe( http_archive, @@ -340,6 +324,19 @@ def _com_github_msgpack_msgpack(): build_file = "@yacl//bazel:msgpack.BUILD", ) +def _com_github_greendow_hash_drbg(): + maybe( + http_archive, + name = "com_github_greendow_hash_drbg", + sha256 = "c03a3da5742d0f0c40232817d84f21d8eed4c4af498c4dff3a51b3bcadcb3787", + type = "tar.gz", + strip_prefix = "Hash-DRBG-2411fa9d0de81c69dce2a48555c30298253db15d", + urls = [ + "https://github.com/greendow/Hash-DRBG/archive/2411fa9d0de81c69dce2a48555c30298253db15d.tar.gz", + ], + build_file = "@yacl//bazel:hash_drbg.BUILD", + ) + def _com_github_herumi_mcl(): maybe( http_archive, diff --git a/yacl/base/BUILD.bazel b/yacl/base/BUILD.bazel index 36ca7810..f42bc0af 100644 --- a/yacl/base/BUILD.bazel +++ b/yacl/base/BUILD.bazel @@ -144,7 +144,7 @@ yacl_cc_library( yacl_cc_test( name = "dynamic_bitset_test", srcs = ["dynamic_bitset_test.cc"], - copts = ["-fno-rtti"], # for testing uint128_t + # copts = ["-fno-rtti"], # for testing uint128_t deps = [ ":dynamic_bitset", "//yacl/crypto/tools:prg", diff --git a/yacl/base/dynamic_bitset_test.cc b/yacl/base/dynamic_bitset_test.cc index 28787619..88c88d3a 100644 --- a/yacl/base/dynamic_bitset_test.cc +++ b/yacl/base/dynamic_bitset_test.cc @@ -42,7 +42,9 @@ class DynamicBitsetTest : public testing::Test { } }; -using TestTypes = ::testing::Types; +// FIXME: We temporarily removed the uint128_t typed test due to compile errors +// using TestTypes = ::testing::Types; +using TestTypes = ::testing::Types; TYPED_TEST_SUITE(DynamicBitsetTest, TestTypes); @@ -124,7 +126,7 @@ TYPED_TEST(DynamicBitsetTest, PushPopTest) { TYPED_TEST(DynamicBitsetTest, AppendTest) { // GIVEN auto bitset = dynamic_bitset("0100101"); - auto block = static_cast(crypto::RandU128()); + auto block = static_cast(crypto::FastRandU128()); // WHEN bitset.append(block); diff --git a/yacl/base/exception.h b/yacl/base/exception.h index 6a63e7ad..8f514397 100644 --- a/yacl/base/exception.h +++ b/yacl/base/exception.h @@ -86,8 +86,8 @@ class Exception : public std::exception { Exception() = default; explicit Exception(std::string msg) : msg_(std::move(msg)) {} explicit Exception(const char* msg) : msg_(msg) {} - explicit Exception(std::string msg, void** stacks, int dep) - : msg_(std::move(msg)) { + explicit Exception(std::string msg, void** stacks, int dep, + bool append_stack_to_msg = false) { for (int i = 0; i < dep; ++i) { std::array tmp; const char* symbol = "(unknown)"; @@ -96,6 +96,12 @@ class Exception : public std::exception { } stack_trace_.append(fmt::format("#{} {}+{}\n", i, symbol, stacks[i])); } + + if (append_stack_to_msg) { + msg_ = fmt::format("{}\nStacktrace:\n{}", msg, stack_trace_); + } else { + msg_ = std::move(msg); + } } const char* what() const noexcept override { return msg_.c_str(); } @@ -165,68 +171,39 @@ using stacktrace_t = std::array; // ... // } // -#define YACL_THROW(...) \ - do { \ - ::yacl::stacktrace_t __stacks__; \ - int __dep__ = absl::GetStackTrace(__stacks__.data(), \ - ::yacl::internal::kMaxStackTraceDep, 0); \ - throw ::yacl::RuntimeError(YACL_ERROR_MSG(__VA_ARGS__), __stacks__.data(), \ - __dep__); \ - } while (false) -#define YACL_THROW_LOGIC_ERROR(...) \ +#define YACL_THROW_HELPER(ExceptionName, AppendStack, ...) \ do { \ ::yacl::stacktrace_t __stacks__; \ int __dep__ = absl::GetStackTrace(__stacks__.data(), \ ::yacl::internal::kMaxStackTraceDep, 0); \ - throw ::yacl::LogicError(YACL_ERROR_MSG(__VA_ARGS__), __stacks__.data(), \ - __dep__); \ + throw ExceptionName(YACL_ERROR_MSG(__VA_ARGS__), __stacks__.data(), \ + __dep__, AppendStack); \ } while (false) -#define YACL_THROW_IO_ERROR(...) \ - do { \ - ::yacl::stacktrace_t __stacks__; \ - int __dep__ = absl::GetStackTrace(__stacks__.data(), \ - ::yacl::internal::kMaxStackTraceDep, 0); \ - throw ::yacl::IoError(YACL_ERROR_MSG(__VA_ARGS__), __stacks__.data(), \ - __dep__); \ - } while (false) +#define YACL_THROW(...) \ + YACL_THROW_HELPER(::yacl::RuntimeError, false, __VA_ARGS__) -#define YACL_THROW_NETWORK_ERROR(...) \ - do { \ - ::yacl::stacktrace_t __stacks__; \ - int __dep__ = absl::GetStackTrace(__stacks__.data(), \ - ::yacl::internal::kMaxStackTraceDep, 0); \ - throw ::yacl::NetworkError(YACL_ERROR_MSG(__VA_ARGS__), __stacks__.data(), \ - __dep__); \ - } while (false) +#define YACL_THROW_WITH_STACK(...) \ + YACL_THROW_HELPER(::yacl::RuntimeError, true, __VA_ARGS__) -#define YACL_THROW_LINK_ERROR(code, http_code, ...) \ - do { \ - ::yacl::stacktrace_t __stacks__; \ - int __dep__ = absl::GetStackTrace(__stacks__.data(), \ - ::yacl::internal::kMaxStackTraceDep, 0); \ - throw ::yacl::LinkError(YACL_ERROR_MSG(__VA_ARGS__), __stacks__.data(), \ - __dep__, code, http_code); \ - } while (false) +#define YACL_THROW_LOGIC_ERROR(...) \ + YACL_THROW_HELPER(::yacl::LogicError, false, __VA_ARGS__) -#define YACL_THROW_INVALID_FORMAT(...) \ - do { \ - ::yacl::stacktrace_t __stacks__; \ - int __dep__ = absl::GetStackTrace(__stacks__.data(), \ - ::yacl::internal::kMaxStackTraceDep, 0); \ - throw ::yacl::InvalidFormat(YACL_ERROR_MSG(__VA_ARGS__), \ - __stacks__.data(), __dep__); \ - } while (false) +#define YACL_THROW_IO_ERROR(...) \ + YACL_THROW_HELPER(::yacl::IoError, false, __VA_ARGS__) -#define YACL_THROW_ARGUMENT_ERROR(...) \ - do { \ - ::yacl::stacktrace_t __stacks__; \ - int __dep__ = absl::GetStackTrace(__stacks__.data(), \ - ::yacl::internal::kMaxStackTraceDep, 0); \ - throw ::yacl::ArgumentError(YACL_ERROR_MSG(__VA_ARGS__), \ - __stacks__.data(), __dep__); \ - } while (false) +#define YACL_THROW_NETWORK_ERROR(...) \ + YACL_THROW_HELPER(::yacl::NetworkError, false, __VA_ARGS__) + +#define YACL_THROW_LINK_ERROR(code, http_code, ...) \ + YACL_THROW_HELPER(::yacl::LinkError, false, __VA_ARGS__) + +#define YACL_THROW_INVALID_FORMAT(...) \ + YACL_THROW_HELPER(::yacl::InvalidFormat, false, __VA_ARGS__) + +#define YACL_THROW_ARGUMENT_ERROR(...) \ + YACL_THROW_HELPER(::yacl::ArgumentError, false, __VA_ARGS__) // For Status. #define CHECK_OR_THROW(statement) \ @@ -263,18 +240,13 @@ class EnforceNotMet : public Exception { public: EnforceNotMet(const char* file, int line, const char* condition, const std::string& msg) - : full_msg_(fmt::format("[Enforce fail at {}:{}] {}. {}", file, line, + : Exception(fmt::format("[Enforce fail at {}:{}] {}. {}", file, line, condition, msg)) {} EnforceNotMet(const char* file, int line, const char* condition, const std::string& msg, void** stacks, int dep) - : Exception(msg, stacks, dep), - full_msg_(fmt::format("[Enforce fail at {}:{}] {}. {}\nStacktrace:\n{}", - file, line, condition, msg, stack_trace())) {} - - const char* what() const noexcept override { return full_msg_.c_str(); } - - private: - std::string full_msg_; + : Exception(fmt::format("[Enforce fail at {}:{}] {}. {}", file, line, + condition, msg), + stacks, dep, true) {} }; // If you don't want to print stacktrace in error message, use diff --git a/yacl/crypto/base/BUILD.bazel b/yacl/crypto/base/BUILD.bazel index 4aa62086..c66de404 100644 --- a/yacl/crypto/base/BUILD.bazel +++ b/yacl/crypto/base/BUILD.bazel @@ -12,154 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:yacl.bzl", "AES_COPT_FLAGS", "yacl_cc_library", "yacl_cc_test") +load("//bazel:yacl.bzl", "yacl_cc_library", "yacl_cc_test") package(default_visibility = ["//visibility:public"]) yacl_cc_library( - name = "symmetric_crypto", - srcs = [ - "symmetric_crypto.cc", - ], + name = "openssl_wrappers", hdrs = [ - "symmetric_crypto.h", + "openssl_wrappers.h", ], - copts = AES_COPT_FLAGS, - deps = [ - "//yacl/base:byte_container_view", - "//yacl/base:exception", - "//yacl/base:int128", - "//yacl/crypto/base/aes:aes_intrinsics", - "@com_github_openssl_openssl//:openssl", - "@com_google_absl//absl/types:span", - ], -) - -yacl_cc_test( - name = "symmetric_crypto_test", - srcs = ["symmetric_crypto_test.cc"], - deps = [ - ":symmetric_crypto", - ], -) - -yacl_cc_library( - name = "asymmetric_util", - srcs = ["asymmetric_util.cc"], - hdrs = ["asymmetric_util.h"], - deps = [ - "//yacl/base:byte_container_view", - "//yacl/base:exception", - "//yacl/utils:scope_guard", - "@com_github_openssl_openssl//:openssl", - ], -) - -yacl_cc_library( - name = "asymmetric_crypto", - hdrs = ["asymmetric_crypto.h"], - deps = [ - "//yacl/base:byte_container_view", - ], -) - -yacl_cc_library( - name = "asymmetric_sm2_crypto", - srcs = ["asymmetric_sm2_crypto.cc"], - hdrs = ["asymmetric_sm2_crypto.h"], - deps = [ - ":asymmetric_crypto", - ":asymmetric_util", - "//yacl/base:exception", - "@com_github_openssl_openssl//:openssl", - "@com_google_absl//absl/memory", - ], -) - -yacl_cc_test( - name = "asymmetric_sm2_crypto_test", - srcs = ["asymmetric_sm2_crypto_test.cc"], - deps = [ - ":asymmetric_sm2_crypto", - ], -) - -yacl_cc_library( - name = "asymmetric_rsa_crypto", - srcs = ["asymmetric_rsa_crypto.cc"], - hdrs = ["asymmetric_rsa_crypto.h"], - deps = [ - ":asymmetric_crypto", - ":asymmetric_util", - "//yacl/base:exception", - "@com_github_openssl_openssl//:openssl", - "@com_google_absl//absl/memory", - ], -) - -yacl_cc_test( - name = "asymmetric_rsa_crypto_test", - srcs = ["asymmetric_rsa_crypto_test.cc"], - deps = [ - ":asymmetric_rsa_crypto", - ], -) - -yacl_cc_library( - name = "signing", - hdrs = ["signing.h"], - deps = [ - "//yacl/base:byte_container_view", - ], -) - -yacl_cc_library( - name = "sm2_signing", - srcs = ["sm2_signing.cc"], - hdrs = ["sm2_signing.h"], - deps = [ - ":asymmetric_util", - ":signing", - "//yacl/base:exception", - "@com_github_openssl_openssl//:openssl", - "@com_google_absl//absl/memory", - ], -) - -yacl_cc_test( - name = "sm2_signing_test", - srcs = ["sm2_signing_test.cc"], - deps = [ - ":sm2_signing", - ], -) - -yacl_cc_library( - name = "rsa_signing", - srcs = ["rsa_signing.cc"], - hdrs = ["rsa_signing.h"], - deps = [ - ":signing", - "//yacl/base:exception", - "//yacl/utils:scope_guard", - "@com_github_openssl_openssl//:openssl", - "@com_google_absl//absl/memory", - ], -) - -yacl_cc_test( - name = "rsa_signing_test", - srcs = ["rsa_signing_test.cc"], - deps = [ - ":asymmetric_util", - ":rsa_signing", - ], -) - -yacl_cc_library( - name = "hmac", - srcs = ["hmac.cc"], - hdrs = ["hmac.h"], deps = [ "//yacl/base:byte_container_view", "//yacl/base:exception", @@ -167,55 +28,27 @@ yacl_cc_library( "//yacl/utils:scope_guard", "@com_github_openssl_openssl//:openssl", ], + alwayslink = True, ) yacl_cc_library( - name = "hmac_sm3", - srcs = ["hmac_sm3.h"], - deps = [ - ":hmac", - ], -) - -yacl_cc_library( - name = "hmac_sha256", - srcs = ["hmac_sha256.h"], - deps = [ - ":hmac", - ], -) - -yacl_cc_test( - name = "hmac_all_test", - srcs = ["hmac_all_test.cc"], - deps = [ - ":hmac_sha256", - ":hmac_sm3", + name = "key_utils", + srcs = ["key_utils.cc"], + hdrs = [ + "key_utils.h", ], -) - -yacl_cc_library( - name = "digital_envelope", - srcs = ["digital_envelope.cc"], - hdrs = ["digital_envelope.h"], deps = [ - ":asymmetric_rsa_crypto", - ":asymmetric_sm2_crypto", - ":hmac_sm3", - ":symmetric_crypto", - "//yacl/crypto/base/aead:gcm_crypto", - "//yacl/crypto/base/aead:sm4_mac", - "//yacl/crypto/base/hash:ssl_hash", - "//yacl/crypto/tools:prg", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:span", + ":openssl_wrappers", + "//yacl/io/stream", ], ) yacl_cc_test( - name = "digital_envelope_test", - srcs = ["digital_envelope_test.cc"], + name = "key_utils_test", + srcs = ["key_utils_test.cc"], deps = [ - ":digital_envelope", + ":key_utils", + "//yacl/crypto/base/pke:asymmetric_rsa_crypto", # for test + "//yacl/crypto/base/sign:rsa_signing", # for test ], ) diff --git a/yacl/crypto/base/aead/BUILD.bazel b/yacl/crypto/base/aead/BUILD.bazel index 70ae1c3e..b7c21a0b 100644 --- a/yacl/crypto/base/aead/BUILD.bazel +++ b/yacl/crypto/base/aead/BUILD.bazel @@ -21,12 +21,8 @@ yacl_cc_library( srcs = ["gcm_crypto.cc"], hdrs = ["gcm_crypto.h"], deps = [ - "//yacl/base:byte_container_view", - "//yacl/base:exception", "//yacl/base:int128", - "//yacl/utils:scope_guard", - "@com_github_openssl_openssl//:openssl", - "@com_google_absl//absl/types:span", + "//yacl/crypto/base:key_utils", ], ) @@ -43,9 +39,9 @@ yacl_cc_library( srcs = ["sm4_mac.cc"], hdrs = ["sm4_mac.h"], deps = [ - "//yacl/crypto/base:hmac_sm3", - "//yacl/crypto/base:symmetric_crypto", + "//yacl/crypto/base/block_cipher:symmetric_crypto", "//yacl/crypto/base/hash:ssl_hash", + "//yacl/crypto/base/hmac:hmac_sm3", ], ) diff --git a/yacl/crypto/base/aead/gcm_crypto.cc b/yacl/crypto/base/aead/gcm_crypto.cc index d8d4b07b..4221c2f7 100644 --- a/yacl/crypto/base/aead/gcm_crypto.cc +++ b/yacl/crypto/base/aead/gcm_crypto.cc @@ -14,10 +14,7 @@ #include "yacl/crypto/base/aead/gcm_crypto.h" -#include "openssl/evp.h" - -#include "yacl/base/exception.h" -#include "yacl/utils/scope_guard.h" +#include "yacl/crypto/base/openssl_wrappers.h" namespace yacl::crypto { @@ -25,23 +22,13 @@ namespace { constexpr size_t kAesMacSize = 16; -const EVP_CIPHER* CreateEvpCipher(GcmCryptoSchema schema) { - switch (schema) { - case GcmCryptoSchema::AES128_GCM: - return EVP_aes_128_gcm(); - case GcmCryptoSchema::AES256_GCM: - return EVP_aes_256_gcm(); - default: - YACL_THROW("Unknown crypto schema: {}", static_cast(schema)); - } -} - size_t GetMacSize(GcmCryptoSchema schema) { switch (schema) { case GcmCryptoSchema::AES128_GCM: - return kAesMacSize; case GcmCryptoSchema::AES256_GCM: return kAesMacSize; + // case GcmCryptoSchema::SM4_GCM: + // return kAesMacSize; default: YACL_THROW("Unknown crypto schema: {}", static_cast(schema)); } @@ -55,32 +42,34 @@ void GcmCrypto::Encrypt(ByteContainerView plaintext, ByteContainerView aad, YACL_ENFORCE_EQ(ciphertext.size(), plaintext.size()); YACL_ENFORCE_EQ(mac.size(), GetMacSize(schema_)); - EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); - YACL_ENFORCE(ctx, "Failed to new evp cipher context."); - ON_SCOPE_EXIT([&] { EVP_CIPHER_CTX_free(ctx); }); - const EVP_CIPHER* cipher = CreateEvpCipher(schema_); - YACL_ENFORCE_EQ(key_.size(), (size_t)EVP_CIPHER_key_length(cipher)); - YACL_ENFORCE_EQ(iv_.size(), (size_t)EVP_CIPHER_iv_length(cipher)); - YACL_ENFORCE_EQ( - EVP_EncryptInit_ex(ctx, cipher, nullptr, key_.data(), iv_.data()), 1); - int out_length; + // init openssl evp cipher context + auto ctx = openssl::UniqueCipherCtx(EVP_CIPHER_CTX_new()); + YACL_ENFORCE(ctx != nullptr, "Failed to new evp cipher context."); + const auto cipher = openssl::FetchEvpCipher(ToString(schema_)); + YACL_ENFORCE(cipher != nullptr); + + YACL_ENFORCE(key_.size() == (size_t)EVP_CIPHER_key_length(cipher.get())); + YACL_ENFORCE(iv_.size() == (size_t)EVP_CIPHER_iv_length(cipher.get())); + YACL_ENFORCE(EVP_EncryptInit_ex(ctx.get(), cipher.get(), nullptr, key_.data(), + iv_.data()) > 0); + // Provide AAD data if exist - const int aad_len = aad.size(); - if (0 != aad_len) { - YACL_ENFORCE_EQ( - EVP_EncryptUpdate(ctx, nullptr, &out_length, aad.data(), aad_len), 1); - YACL_ENFORCE_EQ(out_length, (int)aad.size()); + int out_length = 0; + const auto aad_len = aad.size(); + if (aad_len > 0) { + YACL_ENFORCE(EVP_EncryptUpdate(ctx.get(), nullptr, &out_length, aad.data(), + aad_len) > 0); + YACL_ENFORCE(out_length == (int)aad.size()); } - YACL_ENFORCE_EQ(EVP_EncryptUpdate(ctx, ciphertext.data(), &out_length, - plaintext.data(), plaintext.size()), - 1); - YACL_ENFORCE_EQ(out_length, (int)plaintext.size(), - "Unexpected encrypte out length."); + YACL_ENFORCE(EVP_EncryptUpdate(ctx.get(), ciphertext.data(), &out_length, + plaintext.data(), plaintext.size()) > 0); + YACL_ENFORCE(out_length == (int)plaintext.size(), + "Unexpected encrypte out length."); + // Note that get no output here as the data is always aligned for GCM. - EVP_EncryptFinal_ex(ctx, nullptr, &out_length); - YACL_ENFORCE_EQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, - GetMacSize(schema_), mac.data()), - 1, "Failed to get mac."); + EVP_EncryptFinal_ex(ctx.get(), nullptr, &out_length); + YACL_ENFORCE(EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, + GetMacSize(schema_), mac.data()) > 0); } void GcmCrypto::Decrypt(ByteContainerView ciphertext, ByteContainerView aad, @@ -89,34 +78,34 @@ void GcmCrypto::Decrypt(ByteContainerView ciphertext, ByteContainerView aad, YACL_ENFORCE_EQ(ciphertext.size(), plaintext.size()); YACL_ENFORCE_EQ(mac.size(), GetMacSize(schema_)); + // init openssl evp cipher context EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); YACL_ENFORCE(ctx, "Failed to new evp cipher context."); ON_SCOPE_EXIT([&] { EVP_CIPHER_CTX_free(ctx); }); - const EVP_CIPHER* cipher = CreateEvpCipher(schema_); - YACL_ENFORCE_EQ(key_.size(), (size_t)EVP_CIPHER_key_length(cipher)); - YACL_ENFORCE_EQ(iv_.size(), (size_t)EVP_CIPHER_iv_length(cipher)); + const auto cipher = openssl::FetchEvpCipher(ToString(schema_)); + YACL_ENFORCE_EQ(key_.size(), (size_t)EVP_CIPHER_key_length(cipher.get())); + YACL_ENFORCE_EQ(iv_.size(), (size_t)EVP_CIPHER_iv_length(cipher.get())); YACL_ENFORCE( - EVP_DecryptInit_ex(ctx, cipher, nullptr, key_.data(), iv_.data())); + EVP_DecryptInit_ex(ctx, cipher.get(), nullptr, key_.data(), iv_.data())); - int out_length; // Provide AAD data if exist - const int aad_len = aad.size(); - if (0 != aad_len) { - YACL_ENFORCE_EQ( - EVP_DecryptUpdate(ctx, nullptr, &out_length, aad.data(), aad_len), 1); - YACL_ENFORCE_EQ(out_length, (int)aad.size()); + int out_length = 0; + const auto aad_len = aad.size(); + if (aad_len > 0) { + YACL_ENFORCE( + EVP_DecryptUpdate(ctx, nullptr, &out_length, aad.data(), aad_len) > 0); + YACL_ENFORCE(out_length == (int)aad.size()); } - YACL_ENFORCE_EQ(EVP_DecryptUpdate(ctx, plaintext.data(), &out_length, - ciphertext.data(), ciphertext.size()), - 1); - YACL_ENFORCE_EQ(out_length, (int)plaintext.size(), - "Unexpcted decryption out length."); - YACL_ENFORCE_EQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, - GetMacSize(schema_), (void*)mac.data()), - 1, "Failed to get mac."); + YACL_ENFORCE(EVP_DecryptUpdate(ctx, plaintext.data(), &out_length, + ciphertext.data(), ciphertext.size()) > 0); + YACL_ENFORCE(out_length == (int)plaintext.size(), + "Unexpcted decryption out length."); + YACL_ENFORCE(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, + GetMacSize(schema_), (void*)mac.data()) > 0); + // Note that get no output here as the data is always aligned for GCM. - YACL_ENFORCE_EQ(EVP_DecryptFinal_ex(ctx, nullptr, &out_length), 1, - "Failed to verfiy mac."); + YACL_ENFORCE(EVP_DecryptFinal_ex(ctx, nullptr, &out_length) > 0, + "Failed to verfiy mac."); } } // namespace yacl::crypto diff --git a/yacl/crypto/base/aead/gcm_crypto.h b/yacl/crypto/base/aead/gcm_crypto.h index 1ab58174..cf895534 100644 --- a/yacl/crypto/base/aead/gcm_crypto.h +++ b/yacl/crypto/base/aead/gcm_crypto.h @@ -22,8 +22,15 @@ namespace yacl::crypto { -enum class GcmCryptoSchema : int { AES128_GCM, AES256_GCM }; +enum class GcmCryptoSchema : int { + AES128_GCM, + AES256_GCM, + // SM4_GCM /* TODO openssl 3.2 supports SM4 GCM */ +}; +// ------------- +// GCM Interface +// ------------- class GcmCrypto { public: GcmCrypto(GcmCryptoSchema schema, ByteContainerView key, ByteContainerView iv) @@ -41,14 +48,14 @@ class GcmCrypto { ByteContainerView mac, absl::Span plaintext) const; private: - // GCM crypto schema - const GcmCryptoSchema schema_; - // Symmetric key - const std::vector key_; - // Initial vector - const std::vector iv_; + const GcmCryptoSchema schema_; // GCM crypto schema + const std::vector key_; // Symmetric key + const std::vector iv_; // Initialize vector }; +// --------------- +// Implementations +// --------------- class Aes128GcmCrypto : public GcmCrypto { public: Aes128GcmCrypto(ByteContainerView key, ByteContainerView iv) @@ -60,6 +67,25 @@ class Aes256GcmCrypto : public GcmCrypto { Aes256GcmCrypto(ByteContainerView key, ByteContainerView iv) : GcmCrypto(GcmCryptoSchema::AES256_GCM, key, iv) {} }; -// TODO: Add SM4 GCM when openssl supports. -} // namespace yacl::crypto \ No newline at end of file +// class Sm4GcmCrypto : public GcmCrypto { +// public: +// Sm4GcmCrypto(ByteContainerView key, ByteContainerView iv) +// : GcmCrypto(GcmCryptoSchema::SM4_GCM, key, iv) {} +// }; + +/* to a string which openssl recognizes */ +inline const char* ToString(GcmCryptoSchema scheme) { + switch (scheme) { + case GcmCryptoSchema::AES128_GCM: + return "aes-128-gcm"; + case GcmCryptoSchema::AES256_GCM: + return "aes-256-gcm"; + // case GcmCryptoSchema::SM4_GCM: + // return "sm4-gcm"; + default: + YACL_THROW("Unsupported gcm scheme: {}", static_cast(scheme)); + } +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/aead/gcm_crypto_test.cc b/yacl/crypto/base/aead/gcm_crypto_test.cc index b25af468..5062ed91 100644 --- a/yacl/crypto/base/aead/gcm_crypto_test.cc +++ b/yacl/crypto/base/aead/gcm_crypto_test.cc @@ -33,7 +33,9 @@ constexpr char iv_96[] = "000000000000"; template class AesGcmCryptoTest : public testing::Test {}; -using MyTypes = ::testing::Types; +using MyTypes = ::testing::Types; TYPED_TEST_SUITE(AesGcmCryptoTest, MyTypes); TYPED_TEST(AesGcmCryptoTest, EncryptDecrypt_ShouldOk) { diff --git a/yacl/crypto/base/aead/sm4_mac.cc b/yacl/crypto/base/aead/sm4_mac.cc index 02bce3bc..21ac01c3 100644 --- a/yacl/crypto/base/aead/sm4_mac.cc +++ b/yacl/crypto/base/aead/sm4_mac.cc @@ -15,9 +15,9 @@ #include "yacl/crypto/base/aead/sm4_mac.h" #include "yacl/base/exception.h" +#include "yacl/crypto/base/block_cipher/symmetric_crypto.h" #include "yacl/crypto/base/hash/ssl_hash.h" -#include "yacl/crypto/base/hmac_sm3.h" -#include "yacl/crypto/base/symmetric_crypto.h" +#include "yacl/crypto/base/hmac/hmac_sm3.h" namespace yacl::crypto { diff --git a/yacl/crypto/base/aes/BUILD.bazel b/yacl/crypto/base/aes/BUILD.bazel index 486d3001..81327008 100644 --- a/yacl/crypto/base/aes/BUILD.bazel +++ b/yacl/crypto/base/aes/BUILD.bazel @@ -25,12 +25,7 @@ yacl_cc_binary( "//yacl/crypto/tools:prg", "//yacl/crypto/utils:rand", "@com_github_google_benchmark//:benchmark_main", - ] + select({ - "@platforms//cpu:x86_64": [ - "@com_github_intel_ipp//:ipp", - ], - "//conditions:default": [], - }), + ], ) yacl_cc_library( diff --git a/yacl/crypto/base/aes/aes_bench.cc b/yacl/crypto/base/aes/aes_bench.cc index 16437c38..b364b22a 100644 --- a/yacl/crypto/base/aes/aes_bench.cc +++ b/yacl/crypto/base/aes/aes_bench.cc @@ -19,14 +19,8 @@ #include "benchmark/benchmark.h" #include "yacl/crypto/base/aes/aes_opt.h" -#include "yacl/crypto/utils/rand.h" - -#ifdef __x86_64 -#include "crypto_mb/sm4.h" // ipp-crypto multi-buffer -#include "ippcp.h" // ipp-crypto -#endif - #include "yacl/crypto/tools/prg.h" +#include "yacl/crypto/utils/rand.h" namespace yacl::crypto { @@ -38,8 +32,8 @@ static void BM_OpensslAesEcb(benchmark::State& state) { // setup input size_t n = state.range(0); - Prg prg(RandSeed()); - uint128_t key_u128 = RandU128(); + Prg prg(FastRandSeed()); + uint128_t key_u128 = FastRandU128(); std::vector plain_u128(n); std::vector cipher_u128(n); for (size_t i = 0; i < n; i++) { @@ -63,8 +57,8 @@ static void BM_AesNiEcb(benchmark::State& state) { // setup input size_t n = state.range(0); - Prg prg(RandSeed()); - uint128_t key_u128 = RandU128(); + Prg prg(FastRandSeed()); + uint128_t key_u128 = FastRandU128(); std::vector plain_u128(n); std::vector cipher_u128(n); for (size_t i = 0; i < n; i++) { @@ -112,81 +106,11 @@ static void BM_AesNiEcb(benchmark::State& state) { // } // } -#ifdef __x86_64 -static void BM_IppcpAes(benchmark::State& state) { - for (auto _ : state) { - state.PauseTiming(); - uint128_t key_u128; - uint128_t plain_u128; - - std::random_device rd; - Prg prg(rd()); - - key_u128 = prg(); - - plain_u128 = prg(); - - int aes_ctx_size; - IppStatus status = ippsAESGetSize(&aes_ctx_size); - - auto* aes_ctx_ptr = (IppsAESSpec*)(new Ipp8u[aes_ctx_size]); - status = ippsAESInit((Ipp8u*)&key_u128, 16, aes_ctx_ptr, aes_ctx_size); - YACL_ENFORCE(status == ippStsNoErr, "ippsAESInit error"); - - Ipp8u plain_data[16]; - Ipp8u encrypted_data[16]; - Ipp8u iv_data[16]; - std::memcpy(plain_data, (Ipp8u*)&plain_u128, 16); - std::memset(iv_data, 0, 16); - - size_t n = state.range(0); - state.ResumeTiming(); - for (size_t i = 0; i < n; i++) { - ippsAESEncryptCBC(plain_data, encrypted_data, 16, aes_ctx_ptr, iv_data); - std::memcpy(plain_data, encrypted_data, 16); - } - delete[] (Ipp8u*)aes_ctx_ptr; - } -} - -static void BM_IppcpSm4(benchmark::State& state) { - for (auto _ : state) { - state.PauseTiming(); - uint128_t key_u128; - uint128_t plain_u128; - - std::random_device rd; - Prg prg(rd()); - - key_u128 = prg(); - - plain_u128 = prg(); - - int sm4_ctx_size; - IppStatus status = ippsSMS4GetSize(&sm4_ctx_size); - - IppsSMS4Spec* sm4_ctx_ptr = (IppsSMS4Spec*)(new Ipp8u[sm4_ctx_size]); - status = ippsSMS4Init((Ipp8u*)&key_u128, 16, sm4_ctx_ptr, sm4_ctx_size); - YACL_ENFORCE(status == ippStsNoErr, "ippsSM4Init error"); - - Ipp8u plain_data[16]; - Ipp8u encrypted_data[16]; - Ipp8u iv_data[16]; - std::memcpy(plain_data, (Ipp8u*)&plain_u128, 16); - std::memset(iv_data, 0, 16); - size_t n = state.range(0); - state.ResumeTiming(); - for (size_t i = 0; i < n; i++) { - ippsSMS4EncryptCBC(plain_data, encrypted_data, 16, sm4_ctx_ptr, iv_data); - std::memcpy(plain_data, encrypted_data, 16); - } - delete[] (Ipp8u*)sm4_ctx_ptr; - } -} -#endif - BENCHMARK(BM_OpensslAesEcb) ->Unit(benchmark::kMillisecond) + ->Arg(128) // Buffer size for CrHash / CcrHash + ->Arg(256) + ->Arg(512) ->Arg(1024) ->Arg(5120) ->Arg(10240) @@ -197,6 +121,9 @@ BENCHMARK(BM_OpensslAesEcb) BENCHMARK(BM_AesNiEcb) ->Unit(benchmark::kMillisecond) + ->Arg(128) // Buffer size for CrHash / CcrHash + ->Arg(256) + ->Arg(512) ->Arg(1024) ->Arg(5120) ->Arg(10240) @@ -215,26 +142,4 @@ BENCHMARK(BM_AesNiEcb) // ->Arg(20480) // ->Arg(1 << 22); -#ifdef __x86_64 -BENCHMARK(BM_IppcpAes) - ->Unit(benchmark::kMillisecond) - ->Arg(1024) - ->Arg(5120) - ->Arg(10240) - ->Arg(20480) - ->Arg(40960) - ->Arg(81920) - ->Arg(1 << 24); - -BENCHMARK(BM_IppcpSm4) - ->Unit(benchmark::kMillisecond) - ->Arg(1024) - ->Arg(5120) - ->Arg(10240) - ->Arg(20480) - ->Arg(40960) - ->Arg(81920) - ->Arg(1 << 24); -#endif - } // namespace yacl::crypto diff --git a/yacl/crypto/base/asymmetric_rsa_crypto.cc b/yacl/crypto/base/asymmetric_rsa_crypto.cc deleted file mode 100644 index 1da99975..00000000 --- a/yacl/crypto/base/asymmetric_rsa_crypto.cc +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/asymmetric_rsa_crypto.h" - -#include - -#include "absl/memory/memory.h" -#include "openssl/pem.h" - -#include "yacl/base/exception.h" -#include "yacl/crypto/base/asymmetric_util.h" - -namespace yacl::crypto { - -namespace { - -constexpr int kRsaInputSizeLimitOffset = 41; -constexpr int kRsaPadding = RSA_PKCS1_OAEP_PADDING; - -} // namespace - -std::unique_ptr RsaEncryptor::CreateFromX509( - ByteContainerView x509_public_key) { - return std::unique_ptr( - new RsaEncryptor(CreateRsaFromX509(x509_public_key))); -} - -std::unique_ptr RsaEncryptor::CreateFromPem( - ByteContainerView public_key) { - UniqueBio pem_bio(BIO_new_mem_buf(public_key.data(), public_key.size()), - BIO_free); - RSA* rsa = - PEM_read_bio_RSAPublicKey(pem_bio.get(), nullptr, nullptr, nullptr); - YACL_ENFORCE(rsa, "No rsa from pem."); - return std::unique_ptr( - new RsaEncryptor(UniqueRsa(rsa, ::RSA_free))); -} - -AsymCryptoSchema RsaEncryptor::GetSchema() const { return schema_; } - -std::vector RsaEncryptor::Encrypt(ByteContainerView plaintext) { - int buf_size = RSA_size(rsa_.get()); - YACL_ENFORCE_GT(buf_size, 0, "Illegal RSA_size."); - YACL_ENFORCE_LT((int)plaintext.size() + kRsaInputSizeLimitOffset, buf_size, - "Invalid input size."); - std::vector ciphertext(buf_size); - int rc = RSA_public_encrypt(plaintext.size(), plaintext.data(), - ciphertext.data(), rsa_.get(), kRsaPadding); - YACL_ENFORCE_GT(rc, 0, "Rsa encrypt error."); - ciphertext.resize(rc); - return ciphertext; -} - -std::unique_ptr RsaDecryptor::CreateFromPem( - ByteContainerView private_key) { - UniqueBio pem_bio(BIO_new_mem_buf(private_key.data(), private_key.size()), - BIO_free); - RSA* rsa = - PEM_read_bio_RSAPrivateKey(pem_bio.get(), nullptr, nullptr, nullptr); - YACL_ENFORCE(rsa, "No rsa from string."); - return std::unique_ptr( - new RsaDecryptor(UniqueRsa(rsa, ::RSA_free))); -} - -AsymCryptoSchema RsaDecryptor::GetSchema() const { return schema_; } - -std::vector RsaDecryptor::Decrypt(ByteContainerView ciphertext) { - int buf_size = RSA_size(rsa_.get()); - YACL_ENFORCE_GT(buf_size, 0, "Illegal RSA_size."); - std::vector plaintext(buf_size); - int rc = RSA_private_decrypt(ciphertext.size(), ciphertext.data(), - plaintext.data(), rsa_.get(), kRsaPadding); - YACL_ENFORCE_GE(rc, 0, "Rsa decrypt error."); - plaintext.resize(rc); - return plaintext; -} - -} // namespace yacl::crypto \ No newline at end of file diff --git a/yacl/crypto/base/asymmetric_rsa_crypto.h b/yacl/crypto/base/asymmetric_rsa_crypto.h deleted file mode 100644 index 6748c7a0..00000000 --- a/yacl/crypto/base/asymmetric_rsa_crypto.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include - -#include "openssl/bio.h" -#include "openssl/evp.h" -#include "openssl/rsa.h" -#include "openssl/x509.h" - -#include "yacl/base/byte_container_view.h" -#include "yacl/crypto/base/asymmetric_crypto.h" - -namespace yacl::crypto { - -class RsaEncryptor : public crypto::AsymmetricEncryptor { - public: - using UniqueRsa = std::unique_ptr; - using UniqueBio = std::unique_ptr; - using UniqueX509 = std::unique_ptr; - using UniqueEVP = std::unique_ptr; - - static std::unique_ptr CreateFromX509( - ByteContainerView x509_public_key); - static std::unique_ptr CreateFromPem( - ByteContainerView public_key); - - AsymCryptoSchema GetSchema() const override; - - std::vector Encrypt(ByteContainerView plaintext) override; - - private: - explicit RsaEncryptor(UniqueRsa rsa) - : rsa_(std::move(rsa)), schema_(AsymCryptoSchema::RSA2048_OAEP) {} - - const UniqueRsa rsa_; - const AsymCryptoSchema schema_; -}; - -class RsaDecryptor : public crypto::AsymmetricDecryptor { - public: - using UniqueRsa = std::unique_ptr; - using UniqueBio = std::unique_ptr; - using UniqueX509 = std::unique_ptr; - - static std::unique_ptr CreateFromPem( - ByteContainerView private_key); - - AsymCryptoSchema GetSchema() const override; - - std::vector Decrypt(ByteContainerView ciphertext) override; - - private: - explicit RsaDecryptor(UniqueRsa rsa) - : rsa_(std::move(rsa)), schema_(AsymCryptoSchema::RSA2048_OAEP) {} - - const UniqueRsa rsa_; - const AsymCryptoSchema schema_; -}; - -} // namespace yacl::crypto \ No newline at end of file diff --git a/yacl/crypto/base/asymmetric_rsa_crypto_test.cc b/yacl/crypto/base/asymmetric_rsa_crypto_test.cc deleted file mode 100644 index 54459ffd..00000000 --- a/yacl/crypto/base/asymmetric_rsa_crypto_test.cc +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/asymmetric_rsa_crypto.h" - -#include "gtest/gtest.h" - -#include "yacl/crypto/base/asymmetric_util.h" - -namespace yacl::crypto { - -TEST(AsymmetricRsa, EncryptDecrypt_shouldOk) { - // GIVEN - auto [public_key, private_key] = CreateRsaKeyPair(); - std::string plaintext = "I am a plaintext."; - - // WHEN - auto encryptor = RsaEncryptor::CreateFromPem(public_key); - auto encrypted = encryptor->Encrypt(plaintext); - - auto decryptor = RsaDecryptor::CreateFromPem(private_key); - auto decrypted_bytes = decryptor->Decrypt(encrypted); - std::string decrypted(decrypted_bytes.begin(), decrypted_bytes.end()); - - // THEN - EXPECT_EQ(plaintext, decrypted); -} - -} // namespace yacl::crypto \ No newline at end of file diff --git a/yacl/crypto/base/asymmetric_sm2_crypto.cc b/yacl/crypto/base/asymmetric_sm2_crypto.cc deleted file mode 100644 index 6827373c..00000000 --- a/yacl/crypto/base/asymmetric_sm2_crypto.cc +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/asymmetric_sm2_crypto.h" - -#include - -#include "absl/memory/memory.h" -#include "openssl/pem.h" - -#include "yacl/base/exception.h" -#include "yacl/crypto/base/asymmetric_util.h" -#include "yacl/utils/scope_guard.h" - -namespace yacl::crypto { - -std::unique_ptr Sm2Encryptor::CreateFromPem( - ByteContainerView sm2_pem) { - // Using `new` to access a non-public constructor. - // ref https://abseil.io/tips/134 - return absl::WrapUnique( - new Sm2Encryptor(internal::CreatePubPkeyFromSm2Pem(sm2_pem))); -} - -AsymCryptoSchema Sm2Encryptor::GetSchema() const { return schema_; } - -std::vector Sm2Encryptor::Encrypt(ByteContainerView plaintext) { - EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey_.get(), nullptr); - YACL_ENFORCE(ctx != nullptr, "Failed to create EVP_PKEY_CTX"); - YACL_ENFORCE_GT(EVP_PKEY_encrypt_init(ctx), 0); - ON_SCOPE_EXIT([&] { EVP_PKEY_CTX_free(ctx); }); - size_t cipher_len; - // Determine buffer length. - // Note that cipher_len is the maximum but not exact size of the output - // buffer. Ref - // https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_encrypt.html - YACL_ENFORCE_GT(EVP_PKEY_encrypt(ctx, nullptr, &cipher_len, plaintext.data(), - plaintext.size()), - 0); - std::vector ciphertext(cipher_len); - // Do encryption - YACL_ENFORCE_GT(EVP_PKEY_encrypt(ctx, ciphertext.data(), &cipher_len, - plaintext.data(), plaintext.size()), - 0); - // Correct the size to actual size. - ciphertext.resize(cipher_len); - return ciphertext; -} - -std::unique_ptr Sm2Decryptor::CreateFromPem( - ByteContainerView sm2_pem) { - return absl::WrapUnique( - new Sm2Decryptor(internal::CreatePriPkeyFromSm2Pem(sm2_pem))); -} - -AsymCryptoSchema Sm2Decryptor::GetSchema() const { return schema_; } - -std::vector Sm2Decryptor::Decrypt(ByteContainerView ciphertext) { - EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey_.get(), nullptr); - YACL_ENFORCE(ctx != nullptr); - ON_SCOPE_EXIT([&] { EVP_PKEY_CTX_free(ctx); }); - YACL_ENFORCE_GT(EVP_PKEY_decrypt_init(ctx), 0); - - size_t plain_len; - // Determine buffer length. - // Note that plain_len is the maximum but not exact size of the output - // buffer. Ref - // https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_decrypt.html - YACL_ENFORCE_GT(EVP_PKEY_decrypt(ctx, nullptr, &plain_len, ciphertext.data(), - ciphertext.size()), - 0); - std::vector plaintext(plain_len); - // Do encryption - YACL_ENFORCE_GT(EVP_PKEY_decrypt(ctx, plaintext.data(), &plain_len, - ciphertext.data(), ciphertext.size()), - 0); - // Correct the size to actual size. - plaintext.resize(plain_len); - return plaintext; -} - -} // namespace yacl::crypto \ No newline at end of file diff --git a/yacl/crypto/base/asymmetric_sm2_crypto.h b/yacl/crypto/base/asymmetric_sm2_crypto.h deleted file mode 100644 index bc576e48..00000000 --- a/yacl/crypto/base/asymmetric_sm2_crypto.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include - -#include "openssl/bio.h" -#include "openssl/evp.h" - -#include "yacl/base/byte_container_view.h" -#include "yacl/crypto/base/asymmetric_crypto.h" - -namespace yacl::crypto { - -class Sm2Encryptor : public crypto::AsymmetricEncryptor { - public: - using UniqueBio = std::unique_ptr; - using UniquePkey = std::unique_ptr; - - static std::unique_ptr CreateFromPem(ByteContainerView sm2_pem); - - AsymCryptoSchema GetSchema() const override; - - std::vector Encrypt(ByteContainerView plaintext) override; - - private: - explicit Sm2Encryptor(UniquePkey pkey) - : pkey_(std::move(pkey)), schema_(AsymCryptoSchema::SM2) {} - - const UniquePkey pkey_; - const AsymCryptoSchema schema_; -}; - -class Sm2Decryptor : public crypto::AsymmetricDecryptor { - public: - using UniqueBio = std::unique_ptr; - using UniquePkey = std::unique_ptr; - - static std::unique_ptr CreateFromPem(ByteContainerView sm2_pem); - - AsymCryptoSchema GetSchema() const override; - - std::vector Decrypt(ByteContainerView ciphertext) override; - - private: - explicit Sm2Decryptor(UniquePkey pkey) - : pkey_(std::move(pkey)), schema_(AsymCryptoSchema::SM2) {} - - const UniquePkey pkey_; - const AsymCryptoSchema schema_; -}; - -// TODO @raofei: support sm2 certificate - -} // namespace yacl::crypto \ No newline at end of file diff --git a/yacl/crypto/base/asymmetric_sm2_crypto_test.cc b/yacl/crypto/base/asymmetric_sm2_crypto_test.cc deleted file mode 100644 index 240d42e4..00000000 --- a/yacl/crypto/base/asymmetric_sm2_crypto_test.cc +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/asymmetric_sm2_crypto.h" - -#include "gtest/gtest.h" - -#include "yacl/crypto/base/asymmetric_util.h" - -namespace yacl::crypto { - -TEST(AsymmetricSm2, EncryptDecrypt_shouldOk) { - // GIVEN - auto [public_key, private_key] = CreateSm2KeyPair(); - std::string plaintext = "I am a plaintext."; - - // WHEN - auto sm2_encryptor = Sm2Encryptor::CreateFromPem(public_key); - auto encrypted = sm2_encryptor->Encrypt(plaintext); - - auto sm2_decryptor = Sm2Decryptor::CreateFromPem(private_key); - auto decrypted_bytes = sm2_decryptor->Decrypt(encrypted); - std::string decrypted(decrypted_bytes.begin(), decrypted_bytes.end()); - - // THEN - EXPECT_EQ(plaintext, decrypted); -} - -} // namespace yacl::crypto \ No newline at end of file diff --git a/yacl/crypto/base/asymmetric_util.cc b/yacl/crypto/base/asymmetric_util.cc deleted file mode 100644 index 1b2076b3..00000000 --- a/yacl/crypto/base/asymmetric_util.cc +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/asymmetric_util.h" - -#include - -#include "openssl/bio.h" -#include "openssl/bn.h" -#include "openssl/pem.h" -#include "openssl/rsa.h" -#include "openssl/x509v3.h" - -#include "yacl/base/exception.h" -#include "yacl/utils/scope_guard.h" - -namespace yacl::crypto { - -using UniqueBio = std::unique_ptr; -using UniqueRsa = std::unique_ptr; -using UniqueEVP = std::unique_ptr; -using UniqueX509 = std::unique_ptr; - -namespace { - -constexpr int kRsaKeyBitSize = 2048; -constexpr int kCertVersion = 2; -constexpr unsigned kSecondsInDay = 24 * 60 * 60; - -constexpr std::array kSubjectFields = {"C", "ST", "L", - "O", "OU", "CN"}; - -inline std::string BioToString(const UniqueBio& bio) { - int size = BIO_pending(bio.get()); - YACL_ENFORCE_GT(size, 0, "BIO_pending failed."); - std::string out; - out.resize(size); - YACL_ENFORCE_EQ(BIO_read(bio.get(), out.data(), size), size, - "Read bio failed."); - return out; -} - -inline void AddX509Extension(X509* cert, int nid, char* value) { - X509V3_CTX ctx; - /* This sets the 'context' of the extensions. */ - /* No configuration database */ - X509V3_set_ctx_nodb(&ctx); - // self signed - X509V3_set_ctx(&ctx, cert, cert, nullptr, nullptr, 0); - X509_EXTENSION* ex = X509V3_EXT_nconf_nid(nullptr, &ctx, nid, value); - YACL_ENFORCE(ex != nullptr); - X509_add_ext(cert, ex, -1); - X509_EXTENSION_free(ex); -} - -} // namespace - -namespace internal { - -UniquePkey CreatePriPkeyFromSm2Pem(ByteContainerView pem) { - UniqueBio pem_bio(BIO_new_mem_buf(pem.data(), pem.size()), BIO_free); - EC_KEY* ec_key = - PEM_read_bio_ECPrivateKey(pem_bio.get(), nullptr, nullptr, nullptr); - YACL_ENFORCE(ec_key != nullptr, "No ec private key from pem."); - ON_SCOPE_EXIT([&] { EC_KEY_free(ec_key); }); - EVP_PKEY* pri_key = EVP_PKEY_new(); - YACL_ENFORCE(pri_key != nullptr); - YACL_ENFORCE_GT(EVP_PKEY_set1_EC_KEY(pri_key, ec_key), 0); - YACL_ENFORCE_GT(EVP_PKEY_set_alias_type(pri_key, EVP_PKEY_SM2), 0); - - return UniquePkey(pri_key, ::EVP_PKEY_free); -} - -UniquePkey CreatePubPkeyFromSm2Pem(ByteContainerView pem) { - UniqueBio pem_bio(BIO_new_mem_buf(pem.data(), pem.size()), BIO_free); - EC_KEY* ec_key = - PEM_read_bio_EC_PUBKEY(pem_bio.get(), nullptr, nullptr, nullptr); - YACL_ENFORCE(ec_key != nullptr, "No ec public key from pem."); - ON_SCOPE_EXIT([&] { EC_KEY_free(ec_key); }); - EVP_PKEY* pub_key = EVP_PKEY_new(); - YACL_ENFORCE(pub_key != nullptr); - YACL_ENFORCE_GT(EVP_PKEY_set1_EC_KEY(pub_key, ec_key), 0); - YACL_ENFORCE_GT(EVP_PKEY_set_alias_type(pub_key, EVP_PKEY_SM2), 0); - - return UniquePkey(pub_key, ::EVP_PKEY_free); -} - -} // namespace internal - -std::tuple CreateSm2KeyPair() { - // Create sm2 curve - EC_KEY* ec_key = EC_KEY_new(); - YACL_ENFORCE(ec_key != nullptr); - ON_SCOPE_EXIT([&] { EC_KEY_free(ec_key); }); - EC_GROUP* ec_group = EC_GROUP_new_by_curve_name(NID_sm2); - YACL_ENFORCE(ec_group != nullptr); - ON_SCOPE_EXIT([&] { EC_GROUP_free(ec_group); }); - YACL_ENFORCE_GT(EC_KEY_set_group(ec_key, ec_group), 0); - YACL_ENFORCE_GT(EC_KEY_generate_key(ec_key), 0); - - // Read private key - BIO* pri_bio = BIO_new(BIO_s_mem()); - ON_SCOPE_EXIT([&] { BIO_free(pri_bio); }); - YACL_ENFORCE_GT(PEM_write_bio_ECPrivateKey(pri_bio, ec_key, nullptr, nullptr, - 0, nullptr, nullptr), - 0); - std::string private_key(BIO_pending(pri_bio), '\0'); - YACL_ENFORCE_GT(BIO_read(pri_bio, private_key.data(), private_key.size()), 0); - - // Read public key - BIO* pub_bio = BIO_new(BIO_s_mem()); - ON_SCOPE_EXIT([&] { BIO_free(pub_bio); }); - YACL_ENFORCE_GT(PEM_write_bio_EC_PUBKEY(pub_bio, ec_key), 0); - std::string public_key(BIO_pending(pub_bio), '\0'); - YACL_ENFORCE_GT(BIO_read(pub_bio, public_key.data(), public_key.size()), 0); - - return std::make_tuple(public_key, private_key); -} - -UniqueRsa CreateRsaFromX509(ByteContainerView x509_public_key) { - UniqueBio pem_bio( - BIO_new_mem_buf(x509_public_key.data(), x509_public_key.size()), - BIO_free); - X509* cert = PEM_read_bio_X509(pem_bio.get(), nullptr, nullptr, nullptr); - YACL_ENFORCE(cert, "No X509 from cert."); - UniqueX509 unique_cert(cert, ::X509_free); - EVP_PKEY* pubkey = X509_get_pubkey(unique_cert.get()); - YACL_ENFORCE(pubkey, "No pubkey in x509."); - UniqueEVP unique_pkey(pubkey, ::EVP_PKEY_free); - RSA* rsa = EVP_PKEY_get1_RSA(unique_pkey.get()); - YACL_ENFORCE(rsa, "No Rsa from pem string."); - - return UniqueRsa(rsa, ::RSA_free); -} - -std::string GetPublicKeyFromRsa(const UniqueRsa& rsa, bool x509_pkey) { - std::string public_key; - { - UniqueBio bio(BIO_new(BIO_s_mem()), BIO_free); - YACL_ENFORCE(bio, "New bio failed."); - if (x509_pkey) { - UniqueEVP unique_pkey(EVP_PKEY_new(), ::EVP_PKEY_free); - YACL_ENFORCE(EVP_PKEY_set1_RSA(unique_pkey.get(), rsa.get()), - "Convert rsa to pubkey failed."); - YACL_ENFORCE(PEM_write_bio_PUBKEY(bio.get(), unique_pkey.get()), - "Write public key failed."); - } else { - YACL_ENFORCE(PEM_write_bio_RSAPublicKey(bio.get(), rsa.get()), - "Write public key failed."); - } - int size = BIO_pending(bio.get()); - YACL_ENFORCE_GT(size, 0, "Bad key size."); - public_key.resize(size); - YACL_ENFORCE_GT(BIO_read(bio.get(), public_key.data(), size), 0, - "Cannot read bio."); - } - return public_key; -} - -std::tuple CreateRsaKeyPair(bool x509_pkey) { - std::unique_ptr exp(BN_new(), BN_free); - YACL_ENFORCE_EQ(BN_set_word(exp.get(), RSA_F4), 1, "BN_set_word failed."); - UniqueRsa rsa(RSA_new(), RSA_free); - YACL_ENFORCE( - RSA_generate_key_ex(rsa.get(), kRsaKeyBitSize, exp.get(), nullptr), - "Generate rsa key pair failed."); - - std::string public_key = GetPublicKeyFromRsa(rsa, x509_pkey); - - std::string private_key; - { - UniqueBio bio(BIO_new(BIO_s_mem()), BIO_free); - YACL_ENFORCE(bio, "New bio failed."); - YACL_ENFORCE(PEM_write_bio_RSAPrivateKey(bio.get(), rsa.get(), nullptr, - nullptr, 0, 0, nullptr), - "Write private key failed."); - int size = BIO_pending(bio.get()); - YACL_ENFORCE_GT(size, 0, "Bad key size."); - private_key.resize(size); - YACL_ENFORCE_GT(BIO_read(bio.get(), private_key.data(), size), 0, - "Cannot read bio."); - } - - return std::make_tuple(public_key, private_key); -} - -std::tuple CreateRsaCertificateAndPrivateKey( - const std::unordered_map& subject_map, - unsigned bit_length, unsigned days) { - // 1. Create key pair. - std::unique_ptr exp(BN_new(), BN_free); - YACL_ENFORCE_EQ(BN_set_word(exp.get(), RSA_F4), 1, "BN_set_word failed."); - UniqueRsa rsa(RSA_new(), ::RSA_free); - YACL_ENFORCE(RSA_generate_key_ex(rsa.get(), bit_length, exp.get(), nullptr), - "Generate rsa key pair failed."); - - // 2. Assign to EVP_PKEY. - UniqueEVP evp_pkey(EVP_PKEY_new(), ::EVP_PKEY_free); - YACL_ENFORCE(EVP_PKEY_assign_RSA(evp_pkey.get(), rsa.get()), - "Cannot assign rsa."); - // Ownership transferred to EVP. Let us release ownership from rsa. - rsa.release(); - // 3. Generate X509 Certificate. - UniqueX509 x509(X509_new(), ::X509_free); - // 3.1 v3 & serial number - // - V3 - X509_set_version(x509.get(), kCertVersion); - // - random serial number - std::random_device rd; - YACL_ENFORCE(ASN1_INTEGER_set(X509_get_serialNumber(x509.get()), rd()) == 1, - "ASN1_INTEGER_set failed."); - // 3.2 valid range - X509_gmtime_adj(X509_get_notBefore(x509.get()), 0); - X509_gmtime_adj(X509_get_notAfter(x509.get()), days * kSecondsInDay); - // 3.3 fill rsa public key - X509_set_pubkey(x509.get(), evp_pkey.get()); - X509_NAME* name = X509_get_subject_name(x509.get()); - // 3.4 set subject fields. - for (auto& field : kSubjectFields) { - auto it = subject_map.find(field); - YACL_ENFORCE(it != subject_map.end(), "Cannot find subject field {}.", - field); - YACL_ENFORCE(X509_NAME_add_entry_by_txt( - name, it->first.c_str(), MBSTRING_ASC, - reinterpret_cast(it->second.c_str()), - -1, -1, 0), - "Set x509 name failed."); - } - - // 3.5 self-signed: issuer name == name. - YACL_ENFORCE(X509_set_issuer_name(x509.get(), name) == 1, - "X509_set_issuer_name failed."); - AddX509Extension(x509.get(), NID_basic_constraints, (char*)"CA:TRUE"); - AddX509Extension(x509.get(), NID_subject_key_identifier, (char*)"hash"); - // 3.6 Do self signing with sha256-rsa. - YACL_ENFORCE(X509_sign(x509.get(), evp_pkey.get(), EVP_sha256()), - "Perform self-signing failed."); - // 4. Write as string. - UniqueBio pkey_bio(BIO_new(BIO_s_mem()), BIO_free); - YACL_ENFORCE(PEM_write_bio_PrivateKey(pkey_bio.get(), evp_pkey.get(), nullptr, - nullptr, 0, nullptr, nullptr), - "Failed PEM_write_bio_PrivateKey."); - UniqueBio cert_bio(BIO_new(BIO_s_mem()), BIO_free); - YACL_ENFORCE(PEM_write_bio_X509(cert_bio.get(), x509.get()), - "Failed PEM_write_bio_X509."); - return std::make_tuple(BioToString(cert_bio), BioToString(pkey_bio)); -} - -} // namespace yacl::crypto \ No newline at end of file diff --git a/yacl/crypto/base/asymmetric_util.h b/yacl/crypto/base/asymmetric_util.h deleted file mode 100644 index ed7813d6..00000000 --- a/yacl/crypto/base/asymmetric_util.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include - -#include "openssl/bio.h" -#include "openssl/evp.h" -#include "openssl/rsa.h" - -#include "yacl/base/byte_container_view.h" - -namespace yacl::crypto { - -using UniqueRsa = std::unique_ptr; - -namespace internal { - -using UniquePkey = std::unique_ptr; - -UniquePkey CreatePriPkeyFromSm2Pem(ByteContainerView pem); - -UniquePkey CreatePubPkeyFromSm2Pem(ByteContainerView pem); - -} // namespace internal - -std::tuple CreateSm2KeyPair(); - -std::tuple CreateRsaKeyPair(bool x509_pkey = false); - -UniqueRsa CreateRsaFromX509(ByteContainerView x509_public_key); - -std::string GetPublicKeyFromRsa(const UniqueRsa& rsa, bool x509_pkey = false); - -std::tuple CreateRsaCertificateAndPrivateKey( - const std::unordered_map& subject_map, - unsigned bit_length, unsigned days); - -} // namespace yacl::crypto \ No newline at end of file diff --git a/yacl/crypto/base/test/BUILD.bazel b/yacl/crypto/base/block_cipher/BUILD.bazel similarity index 59% rename from yacl/crypto/base/test/BUILD.bazel rename to yacl/crypto/base/block_cipher/BUILD.bazel index b3f25999..ec057090 100644 --- a/yacl/crypto/base/test/BUILD.bazel +++ b/yacl/crypto/base/block_cipher/BUILD.bazel @@ -12,22 +12,30 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:yacl.bzl", "yacl_cc_binary") +load("//bazel:yacl.bzl", "AES_COPT_FLAGS", "yacl_cc_library", "yacl_cc_test") package(default_visibility = ["//visibility:public"]) -yacl_cc_binary( - name = "alg_data_test", +yacl_cc_library( + name = "symmetric_crypto", srcs = [ - "alg_data_test.cc", + "symmetric_crypto.cc", ], + hdrs = [ + "symmetric_crypto.h", + ], + copts = AES_COPT_FLAGS, deps = [ "//yacl/base:int128", - "//yacl/crypto/base:symmetric_crypto", - "//yacl/crypto/base/hash:ssl_hash", - "//yacl/crypto/tools:prg", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:span", - "@com_google_googletest//:gtest", + "//yacl/crypto/base:openssl_wrappers", + "//yacl/crypto/base/aes:aes_intrinsics", + ], +) + +yacl_cc_test( + name = "symmetric_crypto_test", + srcs = ["symmetric_crypto_test.cc"], + deps = [ + ":symmetric_crypto", ], ) diff --git a/yacl/crypto/base/symmetric_crypto.cc b/yacl/crypto/base/block_cipher/symmetric_crypto.cc similarity index 84% rename from yacl/crypto/base/symmetric_crypto.cc rename to yacl/crypto/base/block_cipher/symmetric_crypto.cc index d84a7f95..163a506b 100644 --- a/yacl/crypto/base/symmetric_crypto.cc +++ b/yacl/crypto/base/block_cipher/symmetric_crypto.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "yacl/crypto/base/symmetric_crypto.h" +#include "yacl/crypto/base/block_cipher/symmetric_crypto.h" #include #include @@ -25,57 +25,40 @@ #include "spdlog/spdlog.h" #include "yacl/base/exception.h" +#include "yacl/crypto/base/openssl_wrappers.h" namespace yacl::crypto { namespace { -const EVP_CIPHER* CreateEvpCipher(SymmetricCrypto::CryptoType type) { - switch (type) { - case SymmetricCrypto::CryptoType::AES128_ECB: - return EVP_aes_128_ecb(); - case SymmetricCrypto::CryptoType::AES128_CBC: - return EVP_aes_128_cbc(); - case SymmetricCrypto::CryptoType::AES128_CTR: - return EVP_aes_128_ctr(); - case SymmetricCrypto::CryptoType::SM4_ECB: - return EVP_sm4_ecb(); - case SymmetricCrypto::CryptoType::SM4_CBC: - return EVP_sm4_cbc(); - case SymmetricCrypto::CryptoType::SM4_CTR: - return EVP_sm4_ctr(); - default: - YACL_THROW("unknown crypto type: {}", static_cast(type)); - } -} - -EVP_CIPHER_CTX* CreateEVPCipherCtx(SymmetricCrypto::CryptoType type, - uint128_t key, uint128_t iv, int enc) { - EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); +openssl::UniqueCipherCtx CreateEVPCipherCtx(SymmetricCrypto::CryptoType type, + uint128_t key, uint128_t iv, + int enc) { + auto ctx = openssl::UniqueCipherCtx(EVP_CIPHER_CTX_new()); - EVP_CIPHER_CTX_init(ctx); + EVP_CIPHER_CTX_init(ctx.get()); // This uses AES-128, so the key must be 128 bits. - const EVP_CIPHER* cipher = CreateEvpCipher(type); - YACL_ENFORCE(sizeof(key) == EVP_CIPHER_key_length(cipher)); + const auto cipher = openssl::FetchEvpCipher(ToString(type)); + YACL_ENFORCE(sizeof(key) == EVP_CIPHER_key_length(cipher.get())); const auto* key_data = reinterpret_cast(&key); // cbc mode need to set iv if ((type == SymmetricCrypto::CryptoType::AES128_ECB) || (type == SymmetricCrypto::CryptoType::SM4_ECB)) { - YACL_ENFORCE( - EVP_CipherInit_ex(ctx, cipher, nullptr, key_data, nullptr, enc)); + YACL_ENFORCE(EVP_CipherInit_ex(ctx.get(), cipher.get(), nullptr, key_data, + nullptr, enc)); } else { /** * @brief cbc and ctr mode set iv * for ctr the iv is the initiator counter, most case counter set 0 */ const auto* iv_data = reinterpret_cast(&iv); - YACL_ENFORCE( - EVP_CipherInit_ex(ctx, cipher, nullptr, key_data, iv_data, enc)); + YACL_ENFORCE(EVP_CipherInit_ex(ctx.get(), cipher.get(), nullptr, key_data, + iv_data, enc)); } // No padding needed for aligned blocks. - YACL_ENFORCE(EVP_CIPHER_CTX_set_padding(ctx, 0)); + YACL_ENFORCE(EVP_CIPHER_CTX_set_padding(ctx.get(), 0)); return ctx; } @@ -120,11 +103,11 @@ void SymmetricCrypto::Decrypt(absl::Span ciphertext, EVP_CIPHER_CTX* ctx; if ((type_ == SymmetricCrypto::CryptoType::AES128_ECB) || (type_ == SymmetricCrypto::CryptoType::SM4_ECB)) { - ctx = dec_ctx_; + ctx = dec_ctx_.get(); } else { ctx = EVP_CIPHER_CTX_new(); EVP_CIPHER_CTX_init(ctx); - EVP_CIPHER_CTX_copy(ctx, dec_ctx_); + EVP_CIPHER_CTX_copy(ctx, dec_ctx_.get()); } EVP_CIPHER_CTX_set_padding(ctx, plaintext.size() % BlockSize()); @@ -173,11 +156,11 @@ void SymmetricCrypto::Encrypt(absl::Span plaintext, EVP_CIPHER_CTX* ctx; if ((type_ == SymmetricCrypto::CryptoType::AES128_ECB) || (type_ == SymmetricCrypto::CryptoType::SM4_ECB)) { - ctx = enc_ctx_; + ctx = enc_ctx_.get(); } else { ctx = EVP_CIPHER_CTX_new(); EVP_CIPHER_CTX_init(ctx); - EVP_CIPHER_CTX_copy(ctx, enc_ctx_); + EVP_CIPHER_CTX_copy(ctx, enc_ctx_.get()); } EVP_CIPHER_CTX_set_padding(ctx, ciphertext.size() % BlockSize()); diff --git a/yacl/crypto/base/symmetric_crypto.h b/yacl/crypto/base/block_cipher/symmetric_crypto.h similarity index 77% rename from yacl/crypto/base/symmetric_crypto.h rename to yacl/crypto/base/block_cipher/symmetric_crypto.h index 2e8adc7f..afa5a19a 100644 --- a/yacl/crypto/base/symmetric_crypto.h +++ b/yacl/crypto/base/block_cipher/symmetric_crypto.h @@ -27,6 +27,7 @@ #include "yacl/base/byte_container_view.h" #include "yacl/base/int128.h" #include "yacl/crypto/base/aes/aes_intrinsics.h" +#include "yacl/crypto/base/openssl_wrappers.h" namespace yacl::crypto { namespace internal { @@ -52,11 +53,6 @@ class SymmetricCrypto { SymmetricCrypto(CryptoType type, uint128_t key, uint128_t iv = 0); SymmetricCrypto(CryptoType type, ByteContainerView key, ByteContainerView iv); - ~SymmetricCrypto() { - EVP_CIPHER_CTX_free(enc_ctx_); - EVP_CIPHER_CTX_free(dec_ctx_); - } - // CBC Block Size. static constexpr int BlockSize() { return 128 / 8; } @@ -92,8 +88,8 @@ class SymmetricCrypto { // Initial vector cbc mode need const uint128_t initial_vector_; - EVP_CIPHER_CTX* enc_ctx_; - EVP_CIPHER_CTX* dec_ctx_; + openssl::UniqueCipherCtx enc_ctx_; + openssl::UniqueCipherCtx dec_ctx_; }; class AesCbcCrypto : public SymmetricCrypto { @@ -116,4 +112,27 @@ inline uint64_t DummyUpdateRandomCount(uint64_t count, size_t buffer_size) { return count + nblock; } +/* to a string which openssl recognizes */ +inline const char* ToString(SymmetricCrypto::CryptoType type) { + switch (type) { + // see: https://www.openssl.org/docs/manmaster/man7/EVP_CIPHER-AES.html + // see: https://www.openssl.org/docs/man3.0/man7/EVP_CIPHER-SM4.html + case SymmetricCrypto::CryptoType::AES128_ECB: + return "aes-128-ecb"; + case SymmetricCrypto::CryptoType::AES128_CBC: + return "aes-128-cbc"; + case SymmetricCrypto::CryptoType::AES128_CTR: + return "aes-128-ctr"; + case SymmetricCrypto::CryptoType::SM4_ECB: + return "sm4-ecb"; + case SymmetricCrypto::CryptoType::SM4_CBC: + return "sm4-cbc"; + case SymmetricCrypto::CryptoType::SM4_CTR: + return "sm4-ctr"; + default: + YACL_THROW("Unsupported symmetric encryption algo: {}", + static_cast(type)); + } +} + } // namespace yacl::crypto diff --git a/yacl/crypto/base/symmetric_crypto_test.cc b/yacl/crypto/base/block_cipher/symmetric_crypto_test.cc similarity index 88% rename from yacl/crypto/base/symmetric_crypto_test.cc rename to yacl/crypto/base/block_cipher/symmetric_crypto_test.cc index 17471b93..720ae2fd 100644 --- a/yacl/crypto/base/symmetric_crypto_test.cc +++ b/yacl/crypto/base/block_cipher/symmetric_crypto_test.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "yacl/crypto/base/symmetric_crypto.h" +#include "yacl/crypto/base/block_cipher/symmetric_crypto.h" #include #include @@ -38,46 +38,46 @@ constexpr uint128_t kIv2 = 2; // data from nist website // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_Core128.pdf constexpr uint8_t kKeyExample[16] = { - 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; std::vector kPlaintextExample = { - 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, - 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, - 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, - 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, - 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, - 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, - 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 }; std::vector kCiphertextExample = { - 0x3A, 0xD7, 0x7B, 0xB4, 0x0D, 0x7A, 0x36, 0x60, - 0xA8, 0x9E, 0xCA, 0xF3, 0x24, 0x66, 0xEF, 0x97, - 0xF5, 0xD3, 0xD5, 0x85, 0x03, 0xB9, 0x69, 0x9D, - 0xE7, 0x85, 0x89, 0x5A, 0x96, 0xFD, 0xBA, 0xAF, - 0x43, 0xB1, 0xCD, 0x7F, 0x59, 0x8E, 0xCE, 0x23, - 0x88, 0x1B, 0x00, 0xE3, 0xED, 0x03, 0x06, 0x88, - 0x7B, 0x0C, 0x78, 0x5E, 0x27, 0xE8, 0xAD, 0x3F, + 0x3A, 0xD7, 0x7B, 0xB4, 0x0D, 0x7A, 0x36, 0x60, + 0xA8, 0x9E, 0xCA, 0xF3, 0x24, 0x66, 0xEF, 0x97, + 0xF5, 0xD3, 0xD5, 0x85, 0x03, 0xB9, 0x69, 0x9D, + 0xE7, 0x85, 0x89, 0x5A, 0x96, 0xFD, 0xBA, 0xAF, + 0x43, 0xB1, 0xCD, 0x7F, 0x59, 0x8E, 0xCE, 0x23, + 0x88, 0x1B, 0x00, 0xE3, 0xED, 0x03, 0x06, 0x88, + 0x7B, 0x0C, 0x78, 0x5E, 0x27, 0xE8, 0xAD, 0x3F, 0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5D, 0xD4 }; // aes-128 CBC mode standard vector // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CBC.pdf constexpr uint8_t kIvExample[16] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; std::vector kCbcCiphertextExample = { - 0x76, 0x49, 0xAB, 0xAC, 0x81, 0x19, 0xB2, 0x46, - 0xCE, 0xE9, 0x8E, 0x9B, 0x12, 0xE9, 0x19, 0x7D, - 0x50, 0x86, 0xCB, 0x9B, 0x50, 0x72, 0x19, 0xEE, - 0x95, 0xDB, 0x11, 0x3A, 0x91, 0x76, 0x78, 0xB2, - 0x73, 0xBE, 0xD6, 0xB8, 0xE3, 0xC1, 0x74, 0x3B, - 0x71, 0x16, 0xE6, 0x9E, 0x22, 0x22, 0x95, 0x16, - 0x3F, 0xF1, 0xCA, 0xA1, 0x68, 0x1F, 0xAC, 0x09, + 0x76, 0x49, 0xAB, 0xAC, 0x81, 0x19, 0xB2, 0x46, + 0xCE, 0xE9, 0x8E, 0x9B, 0x12, 0xE9, 0x19, 0x7D, + 0x50, 0x86, 0xCB, 0x9B, 0x50, 0x72, 0x19, 0xEE, + 0x95, 0xDB, 0x11, 0x3A, 0x91, 0x76, 0x78, 0xB2, + 0x73, 0xBE, 0xD6, 0xB8, 0xE3, 0xC1, 0x74, 0x3B, + 0x71, 0x16, 0xE6, 0x9E, 0x22, 0x22, 0x95, 0x16, + 0x3F, 0xF1, 0xCA, 0xA1, 0x68, 0x1F, 0xAC, 0x09, 0x12, 0x0E, 0xCA, 0x30, 0x75, 0x86, 0xE1, 0xA7 }; @@ -86,19 +86,19 @@ std::vector kCbcCiphertextExample = { * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CTR.pdf */ constexpr uint8_t kCtrCounter[16] = { - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; std::vector kCtrCipherExample = { 0x87, 0x4D, 0x61, 0x91, 0xB6, 0x20, 0xE3, 0x26, 0x1B, 0xEF, 0x68, 0x64, 0x99, 0x0D, 0xB6, 0xCE, - 0x98, 0x06, 0xF6, 0x6B, 0x79, 0x70, 0xFD, 0xFF, + 0x98, 0x06, 0xF6, 0x6B, 0x79, 0x70, 0xFD, 0xFF, 0x86, 0x17, 0x18, 0x7B, 0xB9, 0xFF, 0xFD, 0xFF, 0x5A, 0xE4, 0xDF, 0x3E, 0xDB, 0xD5, 0xD3, 0x5E, 0x5B, 0x4F, 0x09, 0x02, 0x0D, 0xB0, 0x3E, 0xAB, 0x1E, 0x03, 0x1D, 0xDA, 0x2F, 0xBE, 0x03, 0xD1, - 0x79, 0x21, 0x70, 0xA0, 0xF3, 0x00, 0x9C, 0xEE + 0x79, 0x21, 0x70, 0xA0, 0xF3, 0x00, 0x9C, 0xEE }; // clang-format on @@ -351,4 +351,5 @@ TEST(SymmetricCrypto, AesCtrExampleKey) { EXPECT_EQ(encrypted, kCtrCipherExample); } } + } // namespace yacl::crypto diff --git a/yacl/crypto/base/drbg/BUILD.bazel b/yacl/crypto/base/drbg/BUILD.bazel deleted file mode 100644 index 37281144..00000000 --- a/yacl/crypto/base/drbg/BUILD.bazel +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2022 Ant Group Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("//bazel:yacl.bzl", "yacl_cc_library", "yacl_cc_test") - -package(default_visibility = ["//visibility:public"]) - -yacl_cc_library( - name = "drbg", - hdrs = [ - "drbg.h", - ], - deps = [ - "@com_google_absl//absl/types:span", - ], -) - -yacl_cc_library( - name = "nist_aes_drbg", - srcs = [ - "nist_aes_drbg.cc", - ], - hdrs = [ - "nist_aes_drbg.h", - ], - deps = [ - ":drbg", - ":entropy_source_selector", - "//yacl/base:byte_container_view", - "//yacl/base:exception", - "//yacl/base:int128", - "@com_github_openssl_openssl//:openssl", - "@com_google_absl//absl/types:span", - ], -) - -yacl_cc_test( - name = "nist_aes_drbg_test", - srcs = ["nist_aes_drbg_test.cc"], - deps = [ - ":nist_aes_drbg", - ], -) - -yacl_cc_library( - name = "entropy_source", - hdrs = [ - "entropy_source.h", - ], - deps = [ - "//yacl/base:exception", - "@com_google_absl//absl/strings", - ], -) - -yacl_cc_library( - name = "intel_entropy_source", - srcs = [ - "intel_entropy_source.cc", - ], - hdrs = [ - "intel_entropy_source.h", - ], - target_compatible_with = [ - "@platforms//cpu:x86_64", - ], - deps = [ - ":entropy_source", - "@com_github_google_cpu_features//:cpu_features", - "@com_github_intel_ipp//:ipp", - "@com_google_absl//absl/strings", - ], -) - -yacl_cc_library( - name = "std_entropy_source", - srcs = [ - "std_entropy_source.cc", - ], - hdrs = [ - "std_entropy_source.h", - ], - deps = [ - ":entropy_source", - "@com_google_absl//absl/strings", - ], -) - -yacl_cc_library( - name = "entropy_source_selector", - srcs = [ - "entropy_source_selector.cc", - ], - hdrs = [ - "entropy_source_selector.h", - ], - deps = [ - ":entropy_source", - ] + select({ - "@platforms//cpu:aarch64": [ - ":std_entropy_source", - ], - "//conditions:default": [ - ":intel_entropy_source", - ], - }), -) - -yacl_cc_test( - name = "entropy_source_test", - srcs = ["entropy_source_test.cc"], - deps = [ - ":entropy_source_selector", - ], -) - -yacl_cc_library( - name = "sm4_drbg", - srcs = [ - "sm4_drbg.cc", - ], - hdrs = [ - "sm4_drbg.h", - ], - deps = [ - ":drbg", - ":entropy_source", - ":entropy_source_selector", - "//yacl/base:byte_container_view", - "//yacl/base:exception", - "//yacl/base:int128", - "//yacl/crypto/base:symmetric_crypto", - "@com_github_openssl_openssl//:openssl", - "@com_google_absl//absl/types:span", - ], -) - -yacl_cc_test( - name = "sm4_drbg_test", - srcs = ["sm4_drbg_test.cc"], - deps = [ - ":sm4_drbg", - ], -) diff --git a/yacl/crypto/base/drbg/entropy_source.h b/yacl/crypto/base/drbg/entropy_source.h deleted file mode 100644 index c2c84ef8..00000000 --- a/yacl/crypto/base/drbg/entropy_source.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include - -#include "yacl/base/exception.h" - -namespace yacl::crypto { - -// EntropySource abstract class - -enum class SecurityStrengthFlags { kStrength128, kStrength192, kStrength256 }; - -class IEntropySource { - public: - IEntropySource() = default; - virtual ~IEntropySource() = default; - - virtual std::string GetEntropy(size_t entropy_bytes) = 0; - virtual uint64_t GetEntropy() = 0; - - int GetStrengthBit(SecurityStrengthFlags security_strength) { - switch (security_strength) { - case SecurityStrengthFlags::kStrength256: - return 256; - case SecurityStrengthFlags::kStrength192: - return 192; - case SecurityStrengthFlags::kStrength128: - return 128; - default: - YACL_THROW("Unknown security strength: {}", - static_cast(security_strength)); - } - } - - int GetEntropyBytes(SecurityStrengthFlags security_strength) { - // key size + block size - return GetStrengthBit(security_strength) / 8 + 16; - } - - // - int GetNonceBytes(SecurityStrengthFlags security_strength) { - return GetStrengthBit(security_strength) / 16; - } -}; - -} // namespace yacl::crypto diff --git a/yacl/crypto/base/drbg/entropy_source_selector.cc b/yacl/crypto/base/drbg/entropy_source_selector.cc deleted file mode 100644 index 251aa97c..00000000 --- a/yacl/crypto/base/drbg/entropy_source_selector.cc +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2022 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/drbg/entropy_source_selector.h" - -#include - -#ifdef __x86_64 -#include "yacl/crypto/base/drbg/intel_entropy_source.h" -#else -#include "yacl/crypto/base/drbg/std_entropy_source.h" -#endif - -namespace yacl::crypto { - -std::shared_ptr makeEntropySource() { -#ifdef __x86_64 - return std::make_shared(); -#else - return std::make_shared(); -#endif -} - -} // namespace yacl::crypto diff --git a/yacl/crypto/base/drbg/entropy_source_test.cc b/yacl/crypto/base/drbg/entropy_source_test.cc deleted file mode 100644 index 3b31215e..00000000 --- a/yacl/crypto/base/drbg/entropy_source_test.cc +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include - -#include "absl/strings/escaping.h" -#include "gtest/gtest.h" - -#include "yacl/crypto/base/drbg/entropy_source_selector.h" - -namespace yacl::crypto { - -// Entropy from RNG -TEST(EntropySourceTest, TestWithRNGEntropy) { - auto entropy_source = makeEntropySource(); - - // get string - std::string entropy_str1 = entropy_source->GetEntropy(128); - std::string entropy_str2 = entropy_source->GetEntropy(128); - - EXPECT_NE(entropy_str1, entropy_str2); - - // get uint64 - uint64_t entropy_u64_1 = entropy_source->GetEntropy(); - uint64_t entropy_u64_2 = entropy_source->GetEntropy(); - - EXPECT_NE(entropy_u64_1, entropy_u64_2); -} - -} // namespace yacl::crypto diff --git a/yacl/crypto/base/drbg/intel_entropy_source.cc b/yacl/crypto/base/drbg/intel_entropy_source.cc deleted file mode 100644 index 6947f314..00000000 --- a/yacl/crypto/base/drbg/intel_entropy_source.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/drbg/intel_entropy_source.h" - -#include -#include -#include -#include - -#include "ippcp.h" - -#ifdef __x86_64 -#include "cpu_features/cpuinfo_x86.h" -#endif - -#include "yacl/base/exception.h" - -namespace yacl::crypto { - -IntelEntropySource::IntelEntropySource() { -#ifdef __x86_64 - // check RDSEED support - has_rdseed_ = cpu_features::GetX86Info().features.rdseed; -#else - has_rdseed_ = false; -#endif -} - -std::string IntelEntropySource::GetEntropy(size_t entropy_bytes) { - std::string entropy_buf; - - if (entropy_bytes == 0) { - return entropy_buf; - } - - entropy_buf.resize(entropy_bytes); - - uint64_t temp_rand; - - size_t batch_bytes = sizeof(uint64_t); - size_t batch_size = (entropy_bytes + batch_bytes - 1) / batch_bytes; - - for (size_t idx = 0; idx < batch_size; idx++) { - size_t current_pos = idx * batch_bytes; - size_t current_batch_bytes = - std::min(entropy_bytes - current_pos, batch_bytes); - - temp_rand = GetEntropy(); - std::memcpy(&entropy_buf[current_pos], &temp_rand, current_batch_bytes); - } - - return entropy_buf; -} - -uint64_t IntelEntropySource::GetEntropy() { - uint64_t temp_rand; - - if (has_rdseed_) { - IppStatus status = ippsTRNGenRDSEED(reinterpret_cast(&temp_rand), - sizeof(temp_rand) * 8, NULL); - YACL_ENFORCE(status == ippStsNoErr); - - } else { - std::random_device rd("/dev/urandom"); - temp_rand = static_cast(rd()) << 32 | rd(); - } - return temp_rand; -} - -} // namespace yacl::crypto diff --git a/yacl/crypto/base/drbg/intel_entropy_source.h b/yacl/crypto/base/drbg/intel_entropy_source.h deleted file mode 100644 index 3f334019..00000000 --- a/yacl/crypto/base/drbg/intel_entropy_source.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include - -#include "yacl/crypto/base/drbg/entropy_source.h" - -namespace yacl::crypto { -// Intel Digital Random Number Generator (DRNG) Software Implementation Guide -// reference: -// https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide/ -// use intel DRNG as entropy source -// libdrng-1.0.zip -// https://software.intel.com/content/www/us/en/develop/articles/the-drng-library-and-manual.html -// intel ipp-crypto -// https://www.intel.com/content/www/us/en/develop/documentation/ipp-crypto-reference/top/public-key-cryptography-functions/pseudorandom-number-generation-functions/trngenrdseed.html -// - -class IntelEntropySource : public IEntropySource { - public: - IntelEntropySource(); - ~IntelEntropySource() override = default; - - std::string GetEntropy(size_t entropy_bytes) override; - uint64_t GetEntropy() override; - - private: - bool has_rdseed_; -}; - -} // namespace yacl::crypto diff --git a/yacl/crypto/base/drbg/nist_aes_drbg.cc b/yacl/crypto/base/drbg/nist_aes_drbg.cc deleted file mode 100644 index 03bd5b44..00000000 --- a/yacl/crypto/base/drbg/nist_aes_drbg.cc +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/drbg/nist_aes_drbg.h" - -#include -#include -#include -#include - -#include "absl/types/span.h" -#include "openssl/err.h" -#include "spdlog/spdlog.h" - -#include "yacl/crypto/base/drbg/entropy_source.h" -#include "yacl/crypto/base/drbg/entropy_source_selector.h" - -namespace yacl::crypto { - -namespace { - -// 128 32B; 192 40B; 256 48B -constexpr int kDefaultEntropyBytes = 48; -// 128 8B; 192 12B; 256 16B -constexpr int kDefaultNonceBytes = 16; -// health check data size -constexpr size_t kDefaultHealthCheckSize = 10; - -// -// NIST SP800-90A Table 3 -// max request between reseed(reseed_interval) = 2^48; -// GB draft sm4_ctr_drbg reseed_interval is 210 -// openssl aes_ctr_drbgdefault reseed_interval is 1<<16 -constexpr int kReseedInterval = 1 << 8; - -/* - * Test context data, attached as EXDATA to the RAND_DRBG - */ -using ENTROPY_CTX = struct entropy_st { - std::array entropy; - size_t entropy_len = kDefaultEntropyBytes; - int entropy_cnt = 0; - std::array nonce; - size_t nonce_len = kDefaultNonceBytes; - int nonce_cnt = 0; - std::shared_ptr entropy_source; -}; - -size_t GetEntropy(RAND_DRBG *drbg, unsigned char **pout, int entropy_bits, - size_t min_len, size_t /*max_len*/, - int /*prediction_resistance*/) { - auto *ctx = reinterpret_cast( - RAND_DRBG_get_ex_data(drbg, NistAesDrbg::app_data_index_)); - - ctx->entropy_cnt++; - // key size + block size - int entropy_bytes = - std::max(min_len, static_cast(entropy_bits / 8 + 16)); - - std::string entropy_buffer = ctx->entropy_source->GetEntropy(entropy_bytes); - - YACL_ENFORCE((size_t)entropy_bytes == entropy_buffer.length()); - std::memcpy(ctx->entropy.data(), entropy_buffer.data(), - entropy_buffer.length()); - - *pout = static_cast(ctx->entropy.data()); - - return entropy_bytes; -} - -size_t GetNonce(RAND_DRBG *drbg, unsigned char **pout, int nonce_bits, - size_t min_len, size_t /*max_len*/) { - auto *ctx = reinterpret_cast( - RAND_DRBG_get_ex_data(drbg, NistAesDrbg::app_data_index_)); - - ctx->nonce_cnt++; - int nonce_bytes = std::max(min_len, static_cast(nonce_bits / 8)); - - std::string nonce_buffer = ctx->entropy_source->GetEntropy(nonce_bytes); - std::memcpy(ctx->nonce.data(), nonce_buffer.data(), nonce_buffer.length()); - - *pout = static_cast(ctx->nonce.data()); - return nonce_bytes; -} - -void SetEntropyExData(RAND_DRBG *drbg, - const std::shared_ptr &entropy_source, - SecurityStrengthFlags security_strength) { - auto *ctx = reinterpret_cast( - RAND_DRBG_get_ex_data(drbg, NistAesDrbg::app_data_index_)); - - if (ctx == nullptr) { - ctx = new ENTROPY_CTX(); - ctx->entropy_source = entropy_source; - - ctx->entropy_len = entropy_source->GetEntropyBytes(security_strength); - ctx->entropy_cnt = 0; - - ctx->nonce_len = entropy_source->GetNonceBytes(security_strength); - ctx->nonce_cnt = 0; - YACL_ENFORCE( - RAND_DRBG_set_ex_data(drbg, NistAesDrbg::app_data_index_, ctx)); - } -} - -inline int GetPredictionResistance( - PredictionResistanceFlags prediction_resistance) { - int prediction_resistance_flag; - switch (prediction_resistance) { - case PredictionResistanceFlags::kYes: - prediction_resistance_flag = 1; - break; - case PredictionResistanceFlags::kNo: - default: - prediction_resistance_flag = 0; - break; - } - return prediction_resistance_flag; -} - -} // namespace - -int NistAesDrbg::app_data_index_ = - RAND_DRBG_get_ex_new_index(0L, nullptr, nullptr, nullptr, nullptr); - -NistAesDrbg::NistAesDrbg(uint128_t personal_data, - SecurityStrengthFlags security_strength) - : NistAesDrbg(nullptr, personal_data, security_strength) {} - -NistAesDrbg::NistAesDrbg(std::shared_ptr entropy_source_ptr, - uint128_t personal_data, - SecurityStrengthFlags security_strength) - : security_strength_(security_strength), - entropy_source_(std::move(entropy_source_ptr)) { - if (entropy_source_ == nullptr) { - entropy_source_ = makeEntropySource(); - } - - unsigned int drbg_type; - switch (security_strength_) { - case SecurityStrengthFlags::kStrength256: - drbg_type = NID_aes_256_ctr; - break; - case SecurityStrengthFlags::kStrength192: - drbg_type = NID_aes_192_ctr; - break; - // now use aes key length 128 ctr mode - case SecurityStrengthFlags::kStrength128: - default: - drbg_type = NID_aes_128_ctr; - break; - } - - ERR_load_ERR_strings(); - ERR_load_crypto_strings(); - ERR_load_BIO_strings(); - - RAND_DRBG *drbg_ptr = RAND_DRBG_new(drbg_type, RAND_DRBG_FLAGS, nullptr); - YACL_ENFORCE(drbg_ptr != nullptr); - drbg_ = NistAesDrbg::RandDrbgPtr(drbg_ptr); - - SetEntropyExData(drbg_.get(), entropy_source_, security_strength_); - - YACL_ENFORCE(RAND_DRBG_set_callbacks(drbg_.get(), GetEntropy, nullptr, - GetNonce, nullptr)); - - ReSeed(kReseedInterval); - - Instantiate(personal_data); -} - -NistAesDrbg::~NistAesDrbg() { - if (drbg_ != nullptr) { - UnInstantiate(); - } -} - -std::vector NistAesDrbg::Generate( - size_t rand_len, PredictionResistanceFlags prediction_resistance) { - std::vector random_buf(rand_len); - int prediction_resistance_flag = - GetPredictionResistance(prediction_resistance); - - size_t out_len = 0; - while (out_len < rand_len) { - size_t request_len = std::min(max_rand_request_, rand_len - out_len); - YACL_ENFORCE(RAND_DRBG_generate(drbg_.get(), random_buf.data() + out_len, - request_len, prediction_resistance_flag, - NULL, 0)); - out_len += request_len; - } - - return random_buf; -} - -void NistAesDrbg::Instantiate(uint128_t personal_string) { - if (personal_string == 0) { - YACL_ENFORCE(RAND_DRBG_instantiate(drbg_.get(), nullptr, 0)); - } else { - YACL_ENFORCE(RAND_DRBG_instantiate(drbg_.get(), - (const unsigned char *)&personal_string, - sizeof(personal_string))); - } -} - -void NistAesDrbg::UnInstantiate() { - auto *ctx = reinterpret_cast( - RAND_DRBG_get_ex_data(drbg_.get(), app_data_index_)); - - delete ctx; -} - -void NistAesDrbg::ReSeed(int reseed_interval) { - RAND_DRBG_set_reseed_interval(drbg_.get(), reseed_interval); -} - -bool NistAesDrbg::HealthCheck() { - auto *ctx = reinterpret_cast( - RAND_DRBG_get_ex_data(drbg_.get(), NistAesDrbg::app_data_index_)); - - std::array random_buffer; - std::array entropy_buffer; - - FillPRand(absl::MakeSpan(reinterpret_cast(random_buffer.data()), - random_buffer.size() * sizeof(uint64_t))); - - for (size_t idx = 0; idx < kDefaultHealthCheckSize; idx++) { - ctx->entropy_cnt++; - entropy_buffer[idx] = ctx->entropy_source->GetEntropy(); - } - - for (size_t i = 0; i < kDefaultHealthCheckSize; i++) { - for (size_t j = i + 1; j < kDefaultHealthCheckSize; j++) { - if ((random_buffer[i] == random_buffer[j]) || - (entropy_buffer[i] == entropy_buffer[j])) { - return false; - } - } - } - return true; -} - -} // namespace yacl::crypto diff --git a/yacl/crypto/base/drbg/nist_aes_drbg.h b/yacl/crypto/base/drbg/nist_aes_drbg.h deleted file mode 100644 index 076277a2..00000000 --- a/yacl/crypto/base/drbg/nist_aes_drbg.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2020 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include -#include - -#include "absl/types/span.h" -#include "openssl/crypto.h" -#include "openssl/rand.h" -#include "openssl/rand_drbg.h" - -#include "yacl/base/byte_container_view.h" -#include "yacl/base/exception.h" -#include "yacl/base/int128.h" -#include "yacl/crypto/base/drbg/drbg.h" -#include "yacl/crypto/base/drbg/entropy_source.h" - -namespace yacl::crypto { - -enum class PredictionResistanceFlags { kNo, kYes }; - -// -// based on NIST SP 800-90A ctr-drbg -// Recommendation for Random Number Generation Using Deterministic Random Bit -// Generators -// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf -// -class NistAesDrbg : public IDrbg { - public: - NistAesDrbg(uint128_t personal_data = 0, - SecurityStrengthFlags security_strength = - SecurityStrengthFlags::kStrength128); - - NistAesDrbg(std::shared_ptr entropy_source_ptr, - uint128_t personal_data = 0, - SecurityStrengthFlags security_strength = - SecurityStrengthFlags::kStrength128); - - ~NistAesDrbg(); - - SecurityStrengthFlags GetSecurityStrength() const { - return security_strength_; - } - - // rand_len: random bytes - // PredictionResistance enabled will immediately call reseed - // PredictionResistance not enabled, check reseed_interval - // default PredictionResistance not enabled - std::vector Generate( - size_t rand_len, PredictionResistanceFlags prediction_resistance = - PredictionResistanceFlags::kNo); - - void FillPRandBytes(absl::Span out) override { - const size_t nbytes = out.size(); - - size_t out_len = 0; - while (out_len < nbytes) { - size_t reqeust_len = std::min(max_rand_request_, nbytes - out_len); - YACL_ENFORCE(RAND_DRBG_generate(drbg_.get(), - (unsigned char*)out.data() + out_len, - reqeust_len, 0, NULL, 0)); - out_len += reqeust_len; - } - } - - bool HealthCheck(); - - static int app_data_index_; - - class RandDrbgDeleter { - public: - void operator()(RAND_DRBG* drbg) { - RAND_DRBG_uninstantiate(drbg); - RAND_DRBG_free(drbg); - } - }; - using RandDrbgPtr = std::unique_ptr; - - private: - void Instantiate(uint128_t personal_string = 0); - void UnInstantiate(); - - void ReSeed(int reseed_interval); - - RandDrbgPtr drbg_; - - // strength: 128, 192, 256 - const SecurityStrengthFlags security_strength_; - std::shared_ptr entropy_source_; - - size_t max_rand_request_ = 1 << 16; -}; - -} // namespace yacl::crypto diff --git a/yacl/crypto/base/drbg/nist_aes_drbg_test.cc b/yacl/crypto/base/drbg/nist_aes_drbg_test.cc deleted file mode 100644 index 910c3403..00000000 --- a/yacl/crypto/base/drbg/nist_aes_drbg_test.cc +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/drbg/nist_aes_drbg.h" - -#include -#include -#include -#include - -#include "absl/strings/escaping.h" -#include "gtest/gtest.h" -#include "spdlog/spdlog.h" - -#include "yacl/crypto/base/drbg/entropy_source.h" - -// test vector from NIST Cryptographic-Standards-and-Guidelines -// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/CTR_DRBG_withDF.pdf -// -namespace yacl::crypto { - -namespace { - -struct TestData { - // entropy input - std::array entropy; - int entropy_count = 0; - // nonce - std::string nonce; - // PredictionResistance NOT ENABLED returned random bytes - std::array returned_bytes; - - // PredictionResistance ENABLED returned random bytes - std::array pr_returned_bytes; -}; - -TestData strength128_test_vector = { - {"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", - "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F", - "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"}, - 0, - "2021222324252627", - {"8cf59c8cf6888b96eb1c1e3e79d82387af08a9e5ff75e23f1fbcd4559b6b997e", - "69cdef912c692d61b1da4c05146b52eb7b8849bd87937835328254ec25a9180e"}, - {"bff4b85d68c84529f24f69f9acf1756e29ba648ddeb825c225fa32ba490ef4a9", - "9BD2635137A52AF7D0FCBEFEFB97EA93A0F4C438BD98956C0DACB04F15EE25B3"} // -}; - -TestData strength192_test_vector = { - {"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2" - "021222324252627", - "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA" - "0A1A2A3A4A5A6A7", - "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE" - "0E1E2E3E4E5E6E7"}, // - 0, - "202122232425262728292A2B", - {"1A646BB1D38BD2AEA30CF5C5D812A624B50D3ECA99E508B25B5448A8B96C0F2E", - "0920CB32A773E0FF4BBBF90ACB1D7044E15B629AFB3C7F9FE26673E3E7BE4727"}, - {"D1C68E369E5AE5CFB656431713DC972E54B87DA6326D0D49D1C1165370049FDB", - "615A26371F46583EA33ED75709D0EE555C62EC04433648A7C62FD43D2764D52F"} // -}; - -TestData strength256_test_vector = { - {"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232" - "425262728292A2B2C2D2E2F", - "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A" - "4A5A6A7A8A9AAABACADAEAF", - "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E" - "4E5E6E7E8E9EAEBECEDEEEF"}, // - 0, - "202122232425262728292A2B2C2D2E2F", // - {"E686DD55F758FD91BA7CB726FE0B573A180AB67439FFBDFE5EC28FB37A16A53B", - "8DA6CC59E703CED07D58D96E5B6D7836C32599735B734F88C1A73B53C7A6D82E"}, // - {"D1E9C737B6EBAED765A0D4E4C6EAEBE267F5E9193680FDFFA62F4865B3F009EC", - "259DC78CCFAEC4210C30AF815E4F75A5662B7DA4B41013BDC00302DFB6076492"} // -}; - -TestData *GetTestDataByEntropyLen(int entropy_bits) { - TestData *test_data_ptr; - switch (entropy_bits) { - case 256: - test_data_ptr = &strength256_test_vector; - break; - case 192: - test_data_ptr = &strength192_test_vector; - break; - case 128: - default: - test_data_ptr = &strength128_test_vector; - break; - } - return test_data_ptr; -} - -SecurityStrengthFlags GetTestDataByStrengthFlag(int bits) { - switch (bits) { - case 256: - return SecurityStrengthFlags::kStrength256; - case 192: - return SecurityStrengthFlags::kStrength192; - case 128: - default: - return SecurityStrengthFlags::kStrength128; - } -} - -class NistFixEntropySource : public IEntropySource { - public: - NistFixEntropySource(int strength_bit) { - SecurityStrengthFlags strength_flag = - GetTestDataByStrengthFlag(strength_bit); - data_ = GetTestDataByEntropyLen(strength_bit); - entropy_bytes_ = GetEntropyBytes(strength_flag); - nonce_bytes_ = GetNonceBytes(strength_flag); - } - - ~NistFixEntropySource() override = default; - - std::string GetEntropy(size_t entropy_bytes) override { - std::string ret; - - if (entropy_bytes == static_cast(entropy_bytes_)) { - ret = absl::HexStringToBytes(data_->entropy[entropy_count_]); - entropy_count_++; - entropy_count_ %= 3; - } else if (entropy_bytes == static_cast(nonce_bytes_)) { - ret = absl::HexStringToBytes(data_->nonce); - } else { - YACL_THROW("not support entropy_bytes:{}", entropy_bytes); - } - return ret; - } - - uint64_t GetEntropy() override { return 0; } - - private: - int entropy_bytes_ = 0; - int nonce_bytes_ = 0; - int entropy_count_ = 0; - TestData *data_; -}; - -// with fix entropy from NIST standard -// No PR -void NistAesDrbgFixEntropy(int strength_bit) { - SecurityStrengthFlags strength_flag = GetTestDataByStrengthFlag(strength_bit); - - std::shared_ptr fix_seed_entropy_source = - std::make_shared(strength_bit); - NistAesDrbg ctr_drbg(fix_seed_entropy_source, 0, strength_flag); - - size_t random_size = 32; - std::vector random_buf1 = ctr_drbg.Generate(random_size); - absl::string_view random_buf_strview = - absl::string_view((const char *)random_buf1.data(), random_buf1.size()); - - TestData *test_data_ptr = GetTestDataByEntropyLen(strength_bit); - std::string returned_str1 = - absl::HexStringToBytes(test_data_ptr->returned_bytes[0]); - EXPECT_EQ(std::string_view(returned_str1), random_buf_strview); - - std::vector random_buf2 = ctr_drbg.Generate(random_size); - - absl::string_view random_buf_strview2 = - absl::string_view((const char *)random_buf2.data(), random_buf2.size()); - - EXPECT_NE(random_buf1, random_buf2); - - std::string returned_str2 = - absl::HexStringToBytes(test_data_ptr->returned_bytes[1]); - EXPECT_EQ(std::string_view(returned_str2), random_buf_strview2); -} - -// with fix entropy from NIST standard -// PR Enabled -void NistAesDrbgFixEntropyPREnable(int strength_bit) { - SecurityStrengthFlags strength_flag = GetTestDataByStrengthFlag(strength_bit); - std::shared_ptr nist_aes_entropy_source = - std::make_shared(strength_bit); - NistAesDrbg ctr_drbg(nist_aes_entropy_source, 0, strength_flag); - - size_t random_size = 32; - std::vector random_buf1 = - ctr_drbg.Generate(random_size, PredictionResistanceFlags::kYes); - absl::string_view random_buf_strview = - absl::string_view((const char *)random_buf1.data(), random_buf1.size()); - - TestData *test_data_ptr = GetTestDataByEntropyLen(strength_bit); - - std::string returned_str1 = - absl::HexStringToBytes(test_data_ptr->pr_returned_bytes[0]); - EXPECT_EQ(std::string_view(returned_str1), random_buf_strview); - - std::vector random_buf2 = - ctr_drbg.Generate(random_size, PredictionResistanceFlags::kYes); - absl::string_view random_buf_strview2 = - absl::string_view((const char *)random_buf2.data(), random_buf2.size()); - - EXPECT_NE(random_buf1, random_buf2); - - std::string returned_str2 = - absl::HexStringToBytes(test_data_ptr->pr_returned_bytes[1]); - EXPECT_EQ(std::string_view(returned_str2), random_buf_strview2); -} - -// Entropy from intel RNG -void NistAesDrbgIntelRNGEntropy(uint128_t seed, int strength_bit) { - SecurityStrengthFlags strength_flag = GetTestDataByStrengthFlag(strength_bit); - - NistAesDrbg ctr_drbg(seed, strength_flag); - - size_t random_size = 32; - std::vector random_buf1 = ctr_drbg.Generate(random_size); - - std::vector random_buf2 = ctr_drbg.Generate(random_size); - - EXPECT_NE(random_buf1, random_buf2); - - ctr_drbg.FillPRand(absl::MakeSpan(random_buf1)); - ctr_drbg.FillPRand(absl::MakeSpan(random_buf2)); - EXPECT_NE(random_buf1, random_buf2); - - for (size_t idx = 0; idx < 100; idx++) { - std::vector random_buf3 = ctr_drbg.Generate(random_size); - std::vector random_buf4 = ctr_drbg.Generate(random_size); - EXPECT_NE(random_buf3, random_buf4); - } - for (size_t idx = 0; idx < 100; idx++) { - std::vector random_buf3 = - ctr_drbg.Generate(random_size, PredictionResistanceFlags::kYes); - std::vector random_buf4 = - ctr_drbg.Generate(random_size, PredictionResistanceFlags::kYes); - EXPECT_NE(random_buf3, random_buf4); - } -} - -} // namespace - -// Entropy from intel RNG -TEST(CtrDrngTest, TestWithIntelRNGEntropy) { - std::vector stength_vec = {128, 192, 256}; - for (auto &iter : stength_vec) { - NistAesDrbgIntelRNGEntropy(0, iter); - } - - std::random_device rd; - std::mt19937 mt19937_random(rd()); - uint64_t seed1, seed2; - seed1 = mt19937_random(); - seed2 = mt19937_random(); - uint128_t seed = MakeUint128(seed1, seed2); - for (auto &iter : stength_vec) { - NistAesDrbgIntelRNGEntropy(seed, iter); - } -} - -// with fix entropy from NIST standard -// PredictionResistance NOT ENABLED -TEST(CtrDrngTest, TestWithFixEntropy) { - std::vector stength_vec = {128, 192, 256}; - for (auto &iter : stength_vec) { - NistAesDrbgFixEntropy(iter); - } -} - -// with fix entropy from NIST standard -// PredictionResistance ENABLED -TEST(CtrDrngTest, TestWithFixEntropyPREnabled) { - std::vector stength_vec = {128, 192, 256}; - for (auto &iter : stength_vec) { - NistAesDrbgFixEntropyPREnable(iter); - } -} - -TEST(CtrDrngTest, TestMultiThreadWithFixEntropy) { - std::future f_ctr_drbg_128 = - std::async([&] { NistAesDrbgFixEntropy(128); }); - std::future f_ctr_drbg_192 = - std::async([&] { NistAesDrbgFixEntropy(192); }); - std::future f_ctr_drbg_256 = - std::async([&] { NistAesDrbgFixEntropy(256); }); - - f_ctr_drbg_128.get(); - f_ctr_drbg_192.get(); - f_ctr_drbg_256.get(); -} - -TEST(CtrDrngTest, TestMultiThreadWithPREnabled) { - std::future f_ctr_drbg_128 = - std::async([&] { NistAesDrbgFixEntropyPREnable(128); }); - std::future f_ctr_drbg_192 = - std::async([&] { NistAesDrbgFixEntropyPREnable(192); }); - std::future f_ctr_drbg_256 = - std::async([&] { NistAesDrbgFixEntropyPREnable(256); }); - - f_ctr_drbg_128.get(); - f_ctr_drbg_192.get(); - f_ctr_drbg_256.get(); -} - -TEST(CtrDrngTest, TestHealthCheck) { - SecurityStrengthFlags strength_flag = GetTestDataByStrengthFlag(128); - - NistAesDrbg ctr_drbg(0, strength_flag); - - size_t random_size = (1 << 17) + 13; - std::vector random_buf1 = ctr_drbg.Generate(random_size); - - std::vector random_buf2(random_size); - ctr_drbg.FillPRandBytes(absl::MakeSpan(random_buf2)); - - EXPECT_NE(random_buf1, random_buf2); - - EXPECT_EQ(true, ctr_drbg.HealthCheck()); -} - -} // namespace yacl::crypto diff --git a/yacl/crypto/base/drbg/sm4_drbg.cc b/yacl/crypto/base/drbg/sm4_drbg.cc deleted file mode 100644 index ec4296ce..00000000 --- a/yacl/crypto/base/drbg/sm4_drbg.cc +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/drbg/sm4_drbg.h" - -#include -#include -#include - -#include "absl/strings/escaping.h" -#include "openssl/aes.h" -#include "openssl/crypto.h" -#include "openssl/err.h" -#include "openssl/evp.h" -#include "spdlog/spdlog.h" - -#include "yacl/base/int128.h" - -namespace yacl::crypto { - -namespace { -const EVP_CIPHER* GetEvpCipher(SymmetricCrypto::CryptoType type) { - switch (type) { - case SymmetricCrypto::CryptoType::AES128_ECB: - return EVP_aes_128_ecb(); - case SymmetricCrypto::CryptoType::AES128_CTR: - return EVP_aes_128_ctr(); - case SymmetricCrypto::CryptoType::SM4_ECB: - return EVP_sm4_ecb(); - case SymmetricCrypto::CryptoType::SM4_CTR: - return EVP_sm4_ctr(); - default: - YACL_THROW("unknown crypto type: {}", static_cast(type)); - } -} -} // namespace - -void Sm4Drbg::Instantiate(ByteContainerView personal_string) { - min_entropy_ = min_length_; - - // Get Entrpoy - entropy_input_ = entropy_source_->GetEntropy(min_entropy_); - - seed_material_ = entropy_input_; - - std::string personal_buffer(personal_string.begin(), personal_string.end()); - seed_material_.append(personal_buffer); - - seed_material_ = RngDf(seed_material_); - - std::memset(key_.data(), 0, key_.size()); - std::memset(v_.data(), 0, v_.size()); - - const EVP_CIPHER* cipher = GetEvpCipher(crypto_type_); - - YACL_ENFORCE( - EVP_CipherInit_ex(ecb_ctx_.get(), cipher, NULL, key_.data(), NULL, 1)); - - RngUpdate(); - - reseed_counter_ = 1; - - return; -} - -std::string Sm4Drbg::RngDf(ByteContainerView seed_material) { - std::vector s(seed_length_ + 9, 0x80); - size_t inlen = seed_material.size(); - - uint8_t* p = reinterpret_cast(&s[0]); - - *p++ = (inlen >> 24) & 0xff; - *p++ = (inlen >> 16) & 0xff; - *p++ = (inlen >> 8) & 0xff; - *p++ = inlen & 0xff; - - /* NB keylen is at most 32 bytes */ - *p++ = 0; - *p++ = 0; - *p++ = 0; - *p++ = (unsigned char)((2 * kBlockSize) & 0xff); - std::memcpy(p, seed_material.data(), seed_material.length()); - - std::array key = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f}; - - std::vector iv0(kBlockSize), iv1(kBlockSize); - std::memset(iv0.data(), 0, iv0.size()); - std::memset(iv1.data(), 0, iv1.size()); - iv1[3] = 1; - iv0.insert(iv0.end(), s.begin(), s.end()); - iv1.insert(iv1.end(), s.begin(), s.end()); - - std::array mac0 = CbcMac(key, iv0); - std::array mac1 = CbcMac(key, iv1); - - std::string ret; - - EvpCipherPtr enc_ctx(EVP_CIPHER_CTX_new()); - EVP_CIPHER_CTX_init(enc_ctx.get()); - const EVP_CIPHER* cipher = GetEvpCipher(crypto_type_); - - YACL_ENFORCE( - EVP_CipherInit_ex(enc_ctx.get(), cipher, NULL, mac0.data(), NULL, 1)); - - while (ret.length() < seed_length_) { - std::string cipher(kBlockSize, '\0'); - int enc_out_len = kBlockSize; - YACL_ENFORCE(EVP_CipherUpdate(enc_ctx.get(), (unsigned char*)cipher.data(), - &enc_out_len, mac1.data(), mac1.size())); - ret.append(cipher); - std::memcpy(mac1.data(), cipher.data(), cipher.length()); - } - - return ret; -} - -std::array Sm4Drbg::CbcMac( - absl::Span key, absl::Span data_to_mac) { - EvpCipherPtr ctx_cbc(EVP_CIPHER_CTX_new()); - EVP_CIPHER_CTX_init(ctx_cbc.get()); - - const EVP_CIPHER* cipher = GetEvpCipher(crypto_type_); - YACL_ENFORCE( - EVP_CipherInit_ex(ctx_cbc.get(), cipher, NULL, key.data(), NULL, 1)); - - std::array chaining_value; - std::memset(chaining_value.data(), 0, chaining_value.size()); - - size_t n = data_to_mac.size() / kBlockSize; - - for (size_t idx = 0; idx < n; ++idx) { - absl::Span block = - absl::MakeSpan(data_to_mac.data() + idx * kBlockSize, kBlockSize); - std::array input_block; - int enc_out_len = input_block.size(); - - for (size_t j = 0; j < kBlockSize; ++j) { - input_block[j] = block[j] ^ chaining_value[j]; - } - - YACL_ENFORCE(EVP_CipherUpdate(ctx_cbc.get(), chaining_value.data(), - &enc_out_len, input_block.data(), - input_block.size())); - } - - return chaining_value; -} - -// inc_128 openssl drbg -// https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/crypto/rand/drbg_ctr.c#L23 -// -void Sm4Drbg::Inc128() { - uint8_t* p = &v_[0]; - uint32_t n = kBlockSize, c = 1; - - do { - --n; - c += p[n]; - p[n] = (uint8_t)c; - c >>= 8; - } while (n); -} - -void Sm4Drbg::RngUpdate() { - reseed_counter_++; - - std::string temp; - - std::array enc_in; - std::array enc_out; - int enc_out_len = enc_out.size(); - - Inc128(); - std::memcpy(&enc_in[0], v_.data(), kBlockSize); - - Inc128(); - std::memcpy(&enc_in[kBlockSize], v_.data(), kBlockSize); - - YACL_ENFORCE(EVP_CipherUpdate(ecb_ctx_.get(), enc_out.data(), &enc_out_len, - enc_in.data(), enc_in.size())); - YACL_ENFORCE(enc_out_len == enc_in.size()); - - for (int idx = 0; idx < enc_out_len; ++idx) { - enc_out[idx] ^= seed_material_[idx]; - } - - std::memcpy(key_.data(), &enc_out[0], kBlockSize); - std::memcpy(v_.data(), &enc_out[kBlockSize], kBlockSize); - - const EVP_CIPHER* cipher = GetEvpCipher(crypto_type_); - - YACL_ENFORCE( - EVP_CipherInit_ex(ecb_ctx_.get(), cipher, NULL, key_.data(), NULL, 1)); - - return; -} - -void Sm4Drbg::ReSeed(absl::Span /*seed*/, - absl::Span additional_input) { - min_entropy_ = min_length_; - entropy_input_ = entropy_source_->GetEntropy(min_entropy_); - - std::vector seed_material(entropy_input_.length()); - std::memcpy(seed_material.data(), entropy_input_.data(), - entropy_input_.length()); - seed_material.insert(seed_material.end(), additional_input.begin(), - additional_input.end()); - - seed_material_ = RngDf(seed_material); - RngUpdate(); - - reseed_counter_ = 1; -} - -// ReSeed with no additional input -void Sm4Drbg::ReSeed(absl::Span seed) { - std::vector additional_input; - - return ReSeed(seed, additional_input); -} - -// Generate with no additional input -std::vector Sm4Drbg::Generate(size_t rand_length) { - std::vector additional_input; - - return Generate(rand_length, additional_input); -} - -std::vector Sm4Drbg::Generate( - size_t rand_length, absl::Span additional_input) { - YACL_ENFORCE(rand_length <= kBlockSize); - - if (reseed_counter_ > reseed_interval_) { - ReSeed(absl::MakeSpan(reinterpret_cast(entropy_input_.data()), - entropy_input_.length()), - additional_input); - } - - std::string df_add_input(seed_length_, '\0'); - if (additional_input.size() > 0) { - df_add_input = RngDf(additional_input); - } - - reseed_counter_++; - - Inc128(); - - std::vector ret(rand_length); - std::vector enc_out(df_add_input.length()); - - int enc_out_len = enc_out.size(); - - YACL_ENFORCE(EVP_CipherUpdate(ecb_ctx_.get(), enc_out.data(), &enc_out_len, - (const unsigned char*)df_add_input.data(), - df_add_input.length())); - - std::memcpy(ret.data(), enc_out.data(), rand_length); - - RngUpdate(); - - return ret; -} - -// override IDrbg FillPRandBytes -void Sm4Drbg::FillPRandBytes(absl::Span out) { - const size_t nbytes = out.size(); - - if (nbytes > 0) { - size_t block_size = (nbytes + kBlockSize - 1) / kBlockSize; - for (size_t idx = 0; idx < block_size; ++idx) { - size_t current_pos = idx * kBlockSize; - size_t current_size = std::min(kBlockSize, nbytes - current_pos); - std::vector rand_buf = Generate(current_size); - YACL_ENFORCE(rand_buf.size() == current_size); - std::memcpy(out.data() + current_pos, rand_buf.data(), current_size); - } - } -} - -} // namespace yacl::crypto diff --git a/yacl/crypto/base/drbg/sm4_drbg.h b/yacl/crypto/base/drbg/sm4_drbg.h deleted file mode 100644 index 5a314183..00000000 --- a/yacl/crypto/base/drbg/sm4_drbg.h +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include - -#include "absl/types/span.h" -#include "spdlog/spdlog.h" - -#include "yacl/base/byte_container_view.h" -#include "yacl/base/exception.h" -#include "yacl/crypto/base/drbg/drbg.h" -#include "yacl/crypto/base/drbg/entropy_source.h" -#include "yacl/crypto/base/drbg/entropy_source_selector.h" -#include "yacl/crypto/base/symmetric_crypto.h" - -namespace yacl::crypto { - -class EvpCipherDeleter { - public: - void operator()(EVP_CIPHER_CTX* ctx) { EVP_CIPHER_CTX_free(ctx); } -}; - -typedef std::unique_ptr EvpCipherPtr; - -inline constexpr size_t kBlockSize = 16; - -// -// 怊č½Æ件随ęœŗę•°č®¾č®”ęŒ‡å—ć€‹- å¾ę±‚ę„č§ēØæ -// 附录B åŸŗäŗŽSM4_CTRēš„RNGč®¾č®” -// -class Sm4Drbg : public IDrbg { - public: - Sm4Drbg(uint128_t personal_data, SymmetricCrypto::CryptoType crypto_type = - SymmetricCrypto::CryptoType::SM4_ECB) - : Sm4Drbg(crypto_type) { - // call Instantiate - if (personal_data != 0) { - Instantiate(ByteContainerView(reinterpret_cast(&personal_data), - sizeof(personal_data))); - } else { - Instantiate(); - } - } - - Sm4Drbg(const std::shared_ptr& entropy_source_ptr, - SymmetricCrypto::CryptoType crypto_type = - SymmetricCrypto::CryptoType::SM4_ECB) - : ecb_ctx_(EVP_CIPHER_CTX_new()), - entropy_source_(entropy_source_ptr), - crypto_type_(crypto_type) { - if (entropy_source_ == nullptr) { - entropy_source_ = makeEntropySource(); - } - - EVP_CIPHER_CTX_init(ecb_ctx_.get()); - } - - Sm4Drbg(SymmetricCrypto::CryptoType crypto_type = - SymmetricCrypto::CryptoType::SM4_ECB) - : Sm4Drbg(nullptr, crypto_type) {} - - void Instantiate(ByteContainerView personal_string = ""); - - std::vector Generate(size_t rand_length); - std::vector Generate(size_t rand_length, - absl::Span additional_input); - - void FillPRandBytes(absl::Span out) override; - - private: - void RngUpdate(); - void Inc128(); - - void ReSeed(absl::Span seed); - void ReSeed(absl::Span seed, - absl::Span additional_input); - - // output seed_length_ new seed_material - std::string RngDf(ByteContainerView seed_material); - - // - std::array CbcMac(absl::Span key, - absl::Span data_to_mac); - - EvpCipherPtr ecb_ctx_; - - // - std::array key_; - std::array v_; - - uint64_t reseed_counter_ = 0; - - // security level 1 2^10 - // security level 2 1 - uint64_t reseed_interval_ = 1 << 10; - - uint64_t seed_length_ = 32; - - uint64_t min_length_ = 16; - - uint64_t min_entropy_ = 0; - std::string entropy_input_; - - std::string seed_material_; - - std::shared_ptr entropy_source_; - - SymmetricCrypto::CryptoType crypto_type_ = - SymmetricCrypto::CryptoType::SM4_ECB; -}; - -} // namespace yacl::crypto diff --git a/yacl/crypto/base/drbg/sm4_drbg_test.cc b/yacl/crypto/base/drbg/sm4_drbg_test.cc deleted file mode 100644 index 8dc6e033..00000000 --- a/yacl/crypto/base/drbg/sm4_drbg_test.cc +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/drbg/sm4_drbg.h" - -#include -#include -#include -#include -#include - -#include "absl/strings/escaping.h" -#include "absl/types/span.h" -#include "gtest/gtest.h" - -#include "yacl/crypto/base/drbg/entropy_source_selector.h" - -namespace yacl::crypto { - -TEST(GmSm4DrbgTest, TestGenerate) { - Sm4Drbg drbg; - - std::vector add_input(8); - drbg.Instantiate(add_input); - std::vector random_buf1 = drbg.Generate(16, add_input); - std::vector random_buf2 = drbg.Generate(16, add_input); - - EXPECT_NE(random_buf1, random_buf2); -} - -TEST(GmSm4DrbgTest, TestFillPRand) { - Sm4Drbg drbg; - - std::vector add_input(8); - drbg.Instantiate(add_input); - std::vector random_buf1(80); - std::vector random_buf2(80); - drbg.FillPRand(absl::MakeSpan(random_buf1)); - drbg.FillPRand(absl::MakeSpan(random_buf2)); - - EXPECT_NE(random_buf1, random_buf2); -} - -TEST(GmSm4DrbgTest, TestEntropySource) { - auto entropy_source = makeEntropySource(); - - Sm4Drbg drbg(std::move(entropy_source)); - - std::vector add_input(8); - drbg.Instantiate(add_input); - std::vector random_buf1(80); - std::vector random_buf2(80); - drbg.FillPRand(absl::MakeSpan(random_buf1)); - drbg.FillPRand(absl::MakeSpan(random_buf2)); - - EXPECT_NE(random_buf1, random_buf2); -} - -} // namespace yacl::crypto diff --git a/yacl/crypto/base/drbg/std_entropy_source.cc b/yacl/crypto/base/drbg/std_entropy_source.cc deleted file mode 100644 index 900eacce..00000000 --- a/yacl/crypto/base/drbg/std_entropy_source.cc +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/drbg/std_entropy_source.h" - -#include -#include -#include -#include - -namespace yacl::crypto { - -std::string StdEntropySource::GetEntropy(size_t entropy_bytes) { - std::string entropy_buf; - - if (entropy_bytes == 0) { - return entropy_buf; - } - - entropy_buf.resize(entropy_bytes); - - uint64_t temp_rand; - - size_t batch_bytes = sizeof(uint64_t); - size_t batch_size = (entropy_bytes + batch_bytes - 1) / batch_bytes; - - for (size_t idx = 0; idx < batch_size; idx++) { - size_t current_pos = idx * batch_bytes; - size_t current_batch_bytes = - std::min(entropy_bytes - current_pos, batch_bytes); - - temp_rand = GetEntropy(); - std::memcpy(&entropy_buf[current_pos], &temp_rand, current_batch_bytes); - } - - return entropy_buf; -} - -uint64_t StdEntropySource::GetEntropy() { - std::random_device rd("/dev/urandom"); - - return static_cast(rd()) << 32 | rd(); -} - -} // namespace yacl::crypto diff --git a/yacl/crypto/base/ecc/ecc_spi.h b/yacl/crypto/base/ecc/ecc_spi.h index ef562cc7..b5a91c0f 100644 --- a/yacl/crypto/base/ecc/ecc_spi.h +++ b/yacl/crypto/base/ecc/ecc_spi.h @@ -15,7 +15,7 @@ #pragma once #include -#include +#include #include #include diff --git a/yacl/crypto/base/ecc/mcl/mcl_ec_group.cc b/yacl/crypto/base/ecc/mcl/mcl_ec_group.cc index 7db01080..2fe3b9e3 100644 --- a/yacl/crypto/base/ecc/mcl/mcl_ec_group.cc +++ b/yacl/crypto/base/ecc/mcl/mcl_ec_group.cc @@ -141,9 +141,9 @@ EcPoint MclGroupT::MulDoubleBase(const MPInt& s1, const MPInt& s2, } ps2.setMpz(scalar2); - Ec::mulVecMT(*CastAny(ret), - new Ec[]{*CastAny(GetGenerator()), *CastAny(p2)}, - new Fr[]{ps1, ps2}, 2, 2); + Ec ecs[] = {*CastAny(GetGenerator()), *CastAny(p2)}; + Fr frs[] = {ps1, ps2}; + Ec::mulVecMT(*CastAny(ret), ecs, frs, 2, 2); return ret; } diff --git a/yacl/crypto/base/ecc/openssl/BUILD.bazel b/yacl/crypto/base/ecc/openssl/BUILD.bazel index 44ff34fc..340f7f91 100644 --- a/yacl/crypto/base/ecc/openssl/BUILD.bazel +++ b/yacl/crypto/base/ecc/openssl/BUILD.bazel @@ -26,6 +26,7 @@ yacl_cc_library( "openssl_group.h", ], deps = [ + "//yacl/crypto/base:openssl_wrappers", "//yacl/crypto/base/ecc:spi", "//yacl/crypto/base/hash:blake3", "//yacl/crypto/base/hash:ssl_hash", diff --git a/yacl/crypto/base/ecc/openssl/openssl_group.h b/yacl/crypto/base/ecc/openssl/openssl_group.h index 9050fd2b..37b31b98 100644 --- a/yacl/crypto/base/ecc/openssl/openssl_group.h +++ b/yacl/crypto/base/ecc/openssl/openssl_group.h @@ -18,19 +18,13 @@ #include "openssl/ec.h" #include "yacl/crypto/base/ecc/group_sketch.h" +#include "yacl/crypto/base/openssl_wrappers.h" namespace yacl::crypto::openssl { -#define INTERNAL_WRAP_SSL_ECC_TYPE(TYPE, DELETER) \ - struct TYPE##_DELETER { \ - public: \ - void operator()(TYPE* x) { DELETER(x); } \ - }; \ - using TYPE##_PTR = std::unique_ptr; - -INTERNAL_WRAP_SSL_ECC_TYPE(EC_GROUP, EC_GROUP_free) -INTERNAL_WRAP_SSL_ECC_TYPE(BN_CTX, BN_CTX_free) -INTERNAL_WRAP_SSL_ECC_TYPE(BIGNUM, BN_free) +using EC_GROUP_PTR = internal::TyHelper; +using BN_CTX_PTR = internal::TyHelper; +using BIGNUM_PTR = internal::TyHelper; class OpensslGroup : public EcGroupSketch { public: diff --git a/yacl/crypto/base/envelope/BUILD.bazel b/yacl/crypto/base/envelope/BUILD.bazel new file mode 100644 index 00000000..5043b62c --- /dev/null +++ b/yacl/crypto/base/envelope/BUILD.bazel @@ -0,0 +1,43 @@ +# Copyright 2023 Ant Group Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//bazel:yacl.bzl", "AES_COPT_FLAGS", "yacl_cc_library", "yacl_cc_test") + +package(default_visibility = ["//visibility:public"]) + +yacl_cc_library( + name = "digital_envelope", + srcs = ["digital_envelope.cc"], + hdrs = ["digital_envelope.h"], + deps = [ + "//yacl/crypto/base/aead:gcm_crypto", + "//yacl/crypto/base/aead:sm4_mac", + "//yacl/crypto/base/block_cipher:symmetric_crypto", + "//yacl/crypto/base/hash:ssl_hash", + "//yacl/crypto/base/hmac:hmac_sm3", + "//yacl/crypto/base/pke:asymmetric_rsa_crypto", + "//yacl/crypto/base/pke:asymmetric_sm2_crypto", + "//yacl/crypto/tools:prg", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:span", + ], +) + +yacl_cc_test( + name = "digital_envelope_test", + srcs = ["digital_envelope_test.cc"], + deps = [ + ":digital_envelope", + ], +) diff --git a/yacl/crypto/base/digital_envelope.cc b/yacl/crypto/base/envelope/digital_envelope.cc similarity index 84% rename from yacl/crypto/base/digital_envelope.cc rename to yacl/crypto/base/envelope/digital_envelope.cc index 7d4fefb3..4378f5e0 100644 --- a/yacl/crypto/base/digital_envelope.cc +++ b/yacl/crypto/base/envelope/digital_envelope.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "yacl/crypto/base/digital_envelope.h" +#include "yacl/crypto/base/envelope/digital_envelope.h" #include @@ -20,11 +20,11 @@ #include "yacl/crypto/base/aead/gcm_crypto.h" #include "yacl/crypto/base/aead/sm4_mac.h" -#include "yacl/crypto/base/asymmetric_rsa_crypto.h" -#include "yacl/crypto/base/asymmetric_sm2_crypto.h" +#include "yacl/crypto/base/block_cipher/symmetric_crypto.h" #include "yacl/crypto/base/hash/ssl_hash.h" -#include "yacl/crypto/base/hmac_sm3.h" -#include "yacl/crypto/base/symmetric_crypto.h" +#include "yacl/crypto/base/hmac/hmac_sm3.h" +#include "yacl/crypto/base/pke/asymmetric_rsa_crypto.h" +#include "yacl/crypto/base/pke/asymmetric_sm2_crypto.h" #include "yacl/crypto/tools/prg.h" namespace yacl::crypto { @@ -51,14 +51,14 @@ void SmEnvSeal(ByteContainerView pub_key, ByteContainerView iv, *ciphertext = Sm4MteEncrypt(symmetric_key, iv, plaintext); // Step 3. Encrypte symmetric key using SM2 - *encrypted_key = Sm2Encryptor::CreateFromPem(pub_key)->Encrypt(symmetric_key); + *encrypted_key = Sm2Encryptor(pub_key).Encrypt(symmetric_key); } void SmEnvOpen(ByteContainerView pri_key, ByteContainerView iv, ByteContainerView encrypted_key, ByteContainerView ciphertext, std::vector* plaintext) { std::vector symmetric_key = - Sm2Decryptor::CreateFromPem(pri_key)->Decrypt(encrypted_key); + Sm2Decryptor(pri_key).Decrypt(encrypted_key); *plaintext = Sm4MteDecrypt(symmetric_key, iv, ciphertext); } @@ -73,14 +73,14 @@ void RsaEnvSeal(ByteContainerView pub_key, ByteContainerView iv, Aes128GcmCrypto(symmetric_key, iv) .Encrypt(plaintext, "", absl::Span(*ciphertext), absl::Span(*mac)); - *encrypted_key = RsaEncryptor::CreateFromPem(pub_key)->Encrypt(symmetric_key); + *encrypted_key = RsaEncryptor(pub_key).Encrypt(symmetric_key); } void RsaEnvOpen(ByteContainerView pri_key, ByteContainerView iv, ByteContainerView encrypted_key, ByteContainerView ciphertext, ByteContainerView mac, std::vector* plaintext) { std::vector symmetric_key = - RsaDecryptor::CreateFromPem(pri_key)->Decrypt(encrypted_key); + RsaDecryptor(pri_key).Decrypt(encrypted_key); plaintext->resize(ciphertext.size()); Aes128GcmCrypto(symmetric_key, iv) .Decrypt(ciphertext, "", mac, absl::Span(*plaintext)); diff --git a/yacl/crypto/base/digital_envelope.h b/yacl/crypto/base/envelope/digital_envelope.h similarity index 100% rename from yacl/crypto/base/digital_envelope.h rename to yacl/crypto/base/envelope/digital_envelope.h diff --git a/yacl/crypto/base/digital_envelope_test.cc b/yacl/crypto/base/envelope/digital_envelope_test.cc similarity index 72% rename from yacl/crypto/base/digital_envelope_test.cc rename to yacl/crypto/base/envelope/digital_envelope_test.cc index 7f2d07d8..029a1049 100644 --- a/yacl/crypto/base/digital_envelope_test.cc +++ b/yacl/crypto/base/envelope/digital_envelope_test.cc @@ -12,27 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "yacl/crypto/base/digital_envelope.h" +#include "yacl/crypto/base/envelope/digital_envelope.h" #include "gtest/gtest.h" -#include "yacl/crypto/base/asymmetric_util.h" +#include "yacl/crypto/base/key_utils.h" namespace yacl::crypto { TEST(SmDigitalEnvelope, SealOpen_shouldOk) { // GIVEN - auto [public_key, private_key] = CreateSm2KeyPair(); + auto [pk, sk] = GenSm2KeyPairToPemBuf(); std::string plaintext = "I am a plaintext."; std::string iv = "1234567812345678"; // WHEN std::vector ciphertext; std::vector encrypted_key; - SmEnvSeal(public_key, iv, plaintext, &encrypted_key, &ciphertext); + SmEnvSeal(pk, iv, plaintext, &encrypted_key, &ciphertext); std::vector decrypted; - SmEnvOpen(private_key, iv, encrypted_key, ciphertext, &decrypted); + SmEnvOpen(sk, iv, encrypted_key, ciphertext, &decrypted); // THEN EXPECT_EQ(plaintext, std::string(decrypted.begin(), decrypted.end())); @@ -40,7 +40,7 @@ TEST(SmDigitalEnvelope, SealOpen_shouldOk) { TEST(RsaDigitalEnvelope, SealOpen_shouldOk) { // GIVEN - auto [public_key, private_key] = CreateRsaKeyPair(); + auto [pk, sk] = GenRsaKeyPairToPemBuf(); std::string plaintext = "I am a plaintext."; std::string iv = "123456781234"; @@ -48,13 +48,13 @@ TEST(RsaDigitalEnvelope, SealOpen_shouldOk) { std::vector ciphertext; std::vector encrypted_key; std::vector mac; - RsaEnvSeal(public_key, iv, plaintext, &encrypted_key, &ciphertext, &mac); + RsaEnvSeal(pk, iv, plaintext, &encrypted_key, &ciphertext, &mac); std::vector decrypted; - RsaEnvOpen(private_key, iv, encrypted_key, ciphertext, mac, &decrypted); + RsaEnvOpen(sk, iv, encrypted_key, ciphertext, mac, &decrypted); // THEN EXPECT_EQ(plaintext, std::string(decrypted.begin(), decrypted.end())); } -} // namespace yacl::crypto \ No newline at end of file +} // namespace yacl::crypto diff --git a/yacl/crypto/base/hash/BUILD.bazel b/yacl/crypto/base/hash/BUILD.bazel index b12b8e74..15477339 100644 --- a/yacl/crypto/base/hash/BUILD.bazel +++ b/yacl/crypto/base/hash/BUILD.bazel @@ -23,6 +23,7 @@ yacl_cc_library( deps = [ ":hash_interface", "//yacl/base:exception", + "//yacl/crypto/base:openssl_wrappers", "//yacl/utils:scope_guard", "@com_github_openssl_openssl//:openssl", ], @@ -70,6 +71,7 @@ yacl_cc_library( srcs = ["hash_interface.h"], deps = [ "//yacl/base:byte_container_view", + "@com_github_openssl_openssl//:openssl", ], ) diff --git a/yacl/crypto/base/hash/blake3.cc b/yacl/crypto/base/hash/blake3.cc index c922bb04..133a8a48 100644 --- a/yacl/crypto/base/hash/blake3.cc +++ b/yacl/crypto/base/hash/blake3.cc @@ -25,10 +25,11 @@ Blake3Hash::Blake3Hash() Init(); } +// Blake3 caller can extract as much output as needed, reference: +// https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf +// Section 2.6 Blake3Hash::Blake3Hash(size_t output_len) : hash_algo_(HashAlgorithm::BLAKE3), digest_size_(output_len) { - YACL_ENFORCE((output_len > 0) && (output_len <= BLAKE3_OUT_LEN), - "blake3 hash out length shoud be in (0, {}]", BLAKE3_OUT_LEN); Init(); } diff --git a/yacl/crypto/base/hash/blake3.h b/yacl/crypto/base/hash/blake3.h index 96ad363b..087a5cae 100644 --- a/yacl/crypto/base/hash/blake3.h +++ b/yacl/crypto/base/hash/blake3.h @@ -24,6 +24,17 @@ namespace yacl::crypto { // https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf // https://github.com/BLAKE3-team/BLAKE3 // blake3 hash implements HashInterface. +// +// Notice: output_len would affect security level (default output_len = 32, 256 +// bits). An N-bits Blake3 would provide N bits of first and second preimage +// resistance and N/2 bits of collision resistance (N <= 256). +// +// For more discussions, see: +// 1. https://github.com/BLAKE3-team/BLAKE3/blob/master/c/README.md Security +// Notes +// 2. https://github.com/BLAKE3-team/BLAKE3/issues/194 +// 3. https://github.com/BLAKE3-team/BLAKE3/issues/278 +// class Blake3Hash : public HashInterface { public: Blake3Hash(); diff --git a/yacl/crypto/base/hash/blake3_test.cc b/yacl/crypto/base/hash/blake3_test.cc index cc731aae..905065e1 100644 --- a/yacl/crypto/base/hash/blake3_test.cc +++ b/yacl/crypto/base/hash/blake3_test.cc @@ -14,6 +14,7 @@ #include "yacl/crypto/base/hash/blake3.h" +#include #include #include @@ -105,24 +106,55 @@ TEST(Blake3HashTest, MultipleUpdates) { test_data_blake3.result2); } +// Verify that blacke3 could extract different output length as needed. +// The blow testing would set the output length from 1 byte (8-bit) to 8 * 32 = +// 256 bytes (2048-bit). +// Besdies, the output length would affect the security level, see +// yacl/crypto/base/hash/blake3.h for more details. TEST(Blake3HashTest, CustomOutLength) { - for (size_t i = 0; i <= (BLAKE3_OUT_LEN + 1); i++) { - if ((i == 0) || (i > BLAKE3_OUT_LEN)) { - EXPECT_THROW(Blake3Hash blake3(i), yacl::EnforceNotMet); - continue; - } + for (size_t i = 0; i <= (8 * BLAKE3_OUT_LEN); i++) { Blake3Hash blake3(i); std::string vector1_bytes = absl::HexStringToBytes(test_data_blake3.vector1); - std::string std_result = test_data_blake3.result1.substr(0, 2 * i); + // Shorter outputs are prefixes of longer ones. + // reference + // https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf + // Section 2.6 std::vector result = blake3.Update(vector1_bytes).CumulativeHash(); + auto cur_result = absl::BytesToHexString( + absl::string_view((const char*)result.data(), result.size())); - EXPECT_EQ(absl::BytesToHexString( - absl::string_view((const char*)result.data(), result.size())), - std_result); + // find minimum length + auto len = std::min(i, static_cast(BLAKE3_OUT_LEN)); + EXPECT_EQ(cur_result.substr(0, 2 * len), + test_data_blake3.result1.substr(0, 2 * len)); } } +// +// Blake3 support arbitrary output length +// reference: +// 1. https://en.wikipedia.org/wiki/List_of_hash_functions +// 2. https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf +// Section 2.6 +// +TEST(Blake3HashTest, MaximumLength) { + size_t max_size = 1 << 25; // 2^25 bytes, 2^28-bit + + Blake3Hash blake3(max_size); + + std::string vector1_bytes = absl::HexStringToBytes(test_data_blake3.vector1); + + auto len = std::min(max_size, static_cast(BLAKE3_OUT_LEN)); + + std::string std_result = test_data_blake3.result1.substr(0, 2 * len); + std::vector result = blake3.Update(vector1_bytes).CumulativeHash(); + auto cur_result = absl::BytesToHexString( + absl::string_view((const char*)result.data(), result.size())); + + EXPECT_EQ(cur_result.substr(0, 2 * len), std_result); +} + } // namespace yacl::crypto diff --git a/yacl/crypto/base/hash/hash_interface.h b/yacl/crypto/base/hash/hash_interface.h index 9166cff3..043f6e06 100644 --- a/yacl/crypto/base/hash/hash_interface.h +++ b/yacl/crypto/base/hash/hash_interface.h @@ -16,6 +16,8 @@ #include +#include "openssl/evp.h" /* for evp type conversions */ + #include "yacl/base/byte_container_view.h" namespace yacl::crypto { @@ -76,4 +78,28 @@ class HashInterface { virtual std::vector CumulativeHash() const = 0; }; +/* to a string which openssl recognizes */ +inline const char *ToString(HashAlgorithm hash_algo) { + switch (hash_algo) { + // see: https://www.openssl.org/docs/man3.0/man7/EVP_MD-SHA3.html + // see: https://www.openssl.org/docs/man3.0/man7/EVP_MD-SHA2.html + case HashAlgorithm::SHA224: + return "sha2-224"; + case HashAlgorithm::SHA256: + return "sha2-256"; + case HashAlgorithm::SHA384: + return "sha2-384"; + case HashAlgorithm::SHA512: + return "sha2-512"; + case HashAlgorithm::SHA_1: + return "sha1"; + case HashAlgorithm::SM3: + return "sm3"; + case HashAlgorithm::BLAKE2B: + return "blake2b-512"; + default: + YACL_THROW("Unsupported hash algo: {}", static_cast(hash_algo)); + } +} + } // namespace yacl::crypto diff --git a/yacl/crypto/base/hash/hash_utils.cc b/yacl/crypto/base/hash/hash_utils.cc index 0322a281..d8d02593 100644 --- a/yacl/crypto/base/hash/hash_utils.cc +++ b/yacl/crypto/base/hash/hash_utils.cc @@ -27,7 +27,7 @@ namespace yacl::crypto { std::array Sha256(ByteContainerView data) { auto buf = SslHash(HashAlgorithm::SHA256).Update(data).CumulativeHash(); YACL_ENFORCE(buf.size() >= 32); - std::array out; + std::array out{}; memcpy(out.data(), buf.data(), 32); return out; } @@ -35,7 +35,7 @@ std::array Sha256(ByteContainerView data) { std::array Sm3(ByteContainerView data) { auto buf = SslHash(HashAlgorithm::SM3).Update(data).CumulativeHash(); YACL_ENFORCE(buf.size() >= 32); - std::array out; + std::array out{}; memcpy(out.data(), buf.data(), 32); return out; } @@ -43,7 +43,7 @@ std::array Sm3(ByteContainerView data) { std::array Blake2(ByteContainerView data) { auto buf = SslHash(HashAlgorithm::BLAKE2B).Update(data).CumulativeHash(); YACL_ENFORCE(buf.size() >= 64); - std::array out; + std::array out{}; memcpy(out.data(), buf.data(), 64); return out; } @@ -53,7 +53,7 @@ std::array Blake3(ByteContainerView data) { blake3_hasher hasher; blake3_hasher_init(&hasher); blake3_hasher_update(&hasher, data.data(), data.size()); - std::array digest; + std::array digest{}; blake3_hasher_finalize(&hasher, digest.data(), BLAKE3_OUT_LEN); return digest; } diff --git a/yacl/crypto/base/hash/ssl_hash.cc b/yacl/crypto/base/hash/ssl_hash.cc index 45920bad..9508a9f7 100644 --- a/yacl/crypto/base/hash/ssl_hash.cc +++ b/yacl/crypto/base/hash/ssl_hash.cc @@ -15,55 +15,36 @@ #include "yacl/crypto/base/hash/ssl_hash.h" #include "yacl/base/exception.h" +#include "yacl/crypto/base/openssl_wrappers.h" #include "yacl/utils/scope_guard.h" namespace yacl::crypto { -const EVP_MD* CreateEvpMD(HashAlgorithm hash_algo_) { - switch (hash_algo_) { - case HashAlgorithm::SHA224: - case HashAlgorithm::SHA256: - return EVP_sha256(); - case HashAlgorithm::SHA384: - return EVP_sha384(); - case HashAlgorithm::SHA512: - return EVP_sha512(); - case HashAlgorithm::SHA_1: - return EVP_sha1(); - case HashAlgorithm::SM3: - return EVP_sm3(); - case HashAlgorithm::BLAKE2B: - return EVP_blake2b512(); - default: - YACL_THROW("Unsupported hash algo: {}", static_cast(hash_algo_)); - } -} - SslHash::SslHash(HashAlgorithm hash_algo) : hash_algo_(hash_algo), - digest_size_(EVP_MD_size(CreateEvpMD(hash_algo))), - context_(CheckNotNull(EVP_MD_CTX_new())) { + md_(openssl::FetchEvpMd(ToString(hash_algo))), + context_(EVP_MD_CTX_new()), + digest_size_(EVP_MD_size(md_.get())) { Reset(); } -SslHash::~SslHash() { EVP_MD_CTX_free(context_); } - HashAlgorithm SslHash::GetHashAlgorithm() const { return hash_algo_; } size_t SslHash::DigestSize() const { return digest_size_; } SslHash& SslHash::Reset() { - YACL_ENFORCE_EQ(EVP_MD_CTX_reset(context_), 1); + YACL_ENFORCE_EQ(EVP_MD_CTX_reset(context_.get()), 1); int res = 0; - const EVP_MD* md = CreateEvpMD(hash_algo_); - res = EVP_DigestInit_ex(context_, md, nullptr); + const auto md = openssl::FetchEvpMd(ToString(hash_algo_)); + res = EVP_DigestInit_ex(context_.get(), md.get(), nullptr); YACL_ENFORCE_EQ(res, 1, "EVP_DigestInit_ex failed."); return *this; } SslHash& SslHash::Update(ByteContainerView data) { - YACL_ENFORCE_EQ(EVP_DigestUpdate(context_, data.data(), data.size()), 1); + YACL_ENFORCE_EQ(EVP_DigestUpdate(context_.get(), data.data(), data.size()), + 1); return *this; } @@ -75,7 +56,7 @@ std::vector SslHash::CumulativeHash() const { YACL_ENFORCE(context_snapshot != nullptr); ON_SCOPE_EXIT([&] { EVP_MD_CTX_free(context_snapshot); }); EVP_MD_CTX_init(context_snapshot); - YACL_ENFORCE_EQ(EVP_MD_CTX_copy_ex(context_snapshot, context_), 1); + YACL_ENFORCE_EQ(EVP_MD_CTX_copy_ex(context_snapshot, context_.get()), 1); std::vector digest(DigestSize()); unsigned int digest_len; YACL_ENFORCE_EQ( diff --git a/yacl/crypto/base/hash/ssl_hash.h b/yacl/crypto/base/hash/ssl_hash.h index f9ad7f0d..5ded3f5d 100644 --- a/yacl/crypto/base/hash/ssl_hash.h +++ b/yacl/crypto/base/hash/ssl_hash.h @@ -18,6 +18,7 @@ #include "yacl/base/byte_container_view.h" #include "yacl/crypto/base/hash/hash_interface.h" +#include "yacl/crypto/base/openssl_wrappers.h" namespace yacl::crypto { @@ -25,7 +26,6 @@ namespace yacl::crypto { class SslHash : public HashInterface { public: explicit SslHash(HashAlgorithm hash_algo); - ~SslHash() override; // From HashInterface. HashAlgorithm GetHashAlgorithm() const override; @@ -36,8 +36,9 @@ class SslHash : public HashInterface { private: const HashAlgorithm hash_algo_; + openssl::UniqueMd md_; + openssl::UniqueMdCtx context_; const size_t digest_size_; - EVP_MD_CTX* context_; }; // Sm3Hash implements HashInterface for the SM3 hash function. diff --git a/yacl/crypto/base/hmac.cc b/yacl/crypto/base/hmac.cc deleted file mode 100644 index 1e5d7f22..00000000 --- a/yacl/crypto/base/hmac.cc +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2022 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/hmac.h" - -#include "openssl/evp.h" - -#include "yacl/base/exception.h" -#include "yacl/utils/scope_guard.h" - -namespace yacl::crypto { - -namespace { - -void Init_HMAC(HashAlgorithm hash_algo, ByteContainerView key, - HMAC_CTX* context) { - int res = 0; - switch (hash_algo) { - case HashAlgorithm::SHA224: - res = - HMAC_Init_ex(context, key.data(), key.size(), EVP_sha224(), nullptr); - break; - case HashAlgorithm::SHA256: - res = - HMAC_Init_ex(context, key.data(), key.size(), EVP_sha256(), nullptr); - break; - case HashAlgorithm::SHA384: - res = - HMAC_Init_ex(context, key.data(), key.size(), EVP_sha384(), nullptr); - break; - case HashAlgorithm::SHA512: - res = - HMAC_Init_ex(context, key.data(), key.size(), EVP_sha512(), nullptr); - break; - case HashAlgorithm::SHA_1: - res = HMAC_Init_ex(context, key.data(), key.size(), EVP_sha1(), nullptr); - break; - case HashAlgorithm::SM3: - res = HMAC_Init_ex(context, key.data(), key.size(), EVP_sm3(), nullptr); - break; - case HashAlgorithm::UNKNOWN: - default: - YACL_THROW("Unsupported hash algo: {}", static_cast(hash_algo)); - break; - } - - YACL_ENFORCE_EQ(res, 1, "Failed to HMAC_Init_ex."); -} - -} // namespace - -Hmac::Hmac(HashAlgorithm hash_algo, ByteContainerView key) - : hash_algo_(hash_algo), - key_(key.begin(), key.end()), - context_(CheckNotNull(HMAC_CTX_new())) { - Reset(); -} - -Hmac::~Hmac() { HMAC_CTX_free(context_); } - -HashAlgorithm Hmac::GetHashAlgorithm() const { return hash_algo_; } - -Hmac& Hmac::Reset() { - YACL_ENFORCE_EQ(HMAC_CTX_reset(context_), 1); - Init_HMAC(hash_algo_, key_, context_); - return *this; -} - -Hmac& Hmac::Update(ByteContainerView data) { - YACL_ENFORCE(HMAC_Update(context_, data.data(), data.size()) == 1, - "HMAC_Update failed"); - return *this; -} - -std::vector Hmac::CumulativeMac() const { - // Do not finalize the internally stored hash context. Instead, finalize a - // copy of the current context so that the current context can be updated in - // future calls to Update. - HMAC_CTX* context_snapshot = HMAC_CTX_new(); - YACL_ENFORCE(context_snapshot != nullptr); - ON_SCOPE_EXIT([&] { HMAC_CTX_free(context_snapshot); }); - Init_HMAC(hash_algo_, key_, context_snapshot); - YACL_ENFORCE_EQ(HMAC_CTX_copy(context_snapshot, context_), 1); - size_t mac_size = HMAC_size(context_snapshot); - YACL_ENFORCE_GT(mac_size, (size_t)0); - std::vector mac(mac_size); - unsigned int len; - YACL_ENFORCE_EQ(HMAC_Final(context_snapshot, mac.data(), &len), 1); - // Correct the mac size if needed. - if (mac_size != len) { - mac.resize(len); - } - - return mac; -} - -} // namespace yacl::crypto diff --git a/bazel/ipp.BUILD b/yacl/crypto/base/hmac/BUILD.bazel similarity index 50% rename from bazel/ipp.BUILD rename to yacl/crypto/base/hmac/BUILD.bazel index 56e308fd..6ca96c8b 100644 --- a/bazel/ipp.BUILD +++ b/yacl/crypto/base/hmac/BUILD.bazel @@ -12,30 +12,42 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@yacl//bazel:yacl.bzl", "yacl_cmake_external") +load("//bazel:yacl.bzl", "AES_COPT_FLAGS", "yacl_cc_library", "yacl_cc_test") package(default_visibility = ["//visibility:public"]) -filegroup( - name = "all_srcs", - srcs = glob(["**"]), +yacl_cc_library( + name = "hmac", + srcs = ["hmac.cc"], + hdrs = ["hmac.h"], + deps = [ + "//yacl/base:exception", + "//yacl/crypto/base:openssl_wrappers", + "//yacl/crypto/base/hash:hash_interface", + ], ) -yacl_cmake_external( - name = "ipp", - cache_entries = { - "ARCH": "intel64", - "OPENSSL_INCLUDE_DIR": "$EXT_BUILD_DEPS/openssl/include", - "OPENSSL_LIBRARIES": "$EXT_BUILD_DEPS/openssl/lib", - "OPENSSL_ROOT_DIR": "$EXT_BUILD_DEPS/openssl", - "CMAKE_BUILD_TYPE": "Release", - }, - lib_source = ":all_srcs", - out_static_libs = [ - "intel64/libippcp.a", - "intel64/libcrypto_mb.a", +yacl_cc_library( + name = "hmac_sm3", + srcs = ["hmac_sm3.h"], + deps = [ + ":hmac", ], +) + +yacl_cc_library( + name = "hmac_sha256", + srcs = ["hmac_sha256.h"], + deps = [ + ":hmac", + ], +) + +yacl_cc_test( + name = "hmac_all_test", + srcs = ["hmac_all_test.cc"], deps = [ - "@com_github_openssl_openssl//:openssl", + ":hmac_sha256", + ":hmac_sm3", ], ) diff --git a/yacl/crypto/base/hmac/hmac.cc b/yacl/crypto/base/hmac/hmac.cc new file mode 100644 index 00000000..51f6cf44 --- /dev/null +++ b/yacl/crypto/base/hmac/hmac.cc @@ -0,0 +1,79 @@ +// Copyright 2022 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/base/hmac/hmac.h" + +#include "yacl/base/exception.h" +#include "yacl/crypto/base/openssl_wrappers.h" + +namespace yacl::crypto { + +Hmac::Hmac(HashAlgorithm hash_algo, ByteContainerView key) + : hash_algo_(hash_algo), key_(key.begin(), key.end()) { + mac_ = openssl::FetchEvpHmac(); + ctx_ = openssl::UniqueMacCtx(EVP_MAC_CTX_new(mac_.get())); + YACL_ENFORCE(ctx_ != nullptr); + + // Set up the underlying context ctx with information given via the key + // and params arguments + std::array params; + params[0] = OSSL_PARAM_construct_utf8_string( + "digest", const_cast(ToString(hash_algo)), + /* the length of previous param is determined using strlen() */ 0); + params[1] = OSSL_PARAM_construct_end(); + YACL_ENFORCE(EVP_MAC_init(ctx_.get(), key_.data(), key_.size(), + /* params */ params.data()) > 0); +} + +HashAlgorithm Hmac::GetHashAlgorithm() const { return hash_algo_; } + +Hmac& Hmac::Reset() { + YACL_ENFORCE(mac_ != nullptr); + const auto* params = EVP_MAC_gettable_ctx_params(mac_.get()); + YACL_ENFORCE(params != nullptr); + + // re-init the mac context + YACL_ENFORCE(EVP_MAC_init(ctx_.get(), key_.data(), key_.size(), + /* params */ params) > 0); + return *this; +} + +Hmac& Hmac::Update(ByteContainerView data) { + YACL_ENFORCE(ctx_ != nullptr); + YACL_ENFORCE(EVP_MAC_update(ctx_.get(), data.data(), data.size()) > 0); + return *this; +} + +std::vector Hmac::CumulativeMac() const { + YACL_ENFORCE(ctx_ != nullptr); + // Do not finalize the internally stored hash context. Instead, finalize a + // copy of the current context so that the current context can be updated in + // future calls to Update. + auto ctx_copy = openssl::UniqueMacCtx(EVP_MAC_CTX_dup(ctx_.get())); + YACL_ENFORCE(ctx_copy != nullptr); + + // get the outptut size + size_t outlen = 0; + YACL_ENFORCE(EVP_MAC_final(ctx_copy.get(), nullptr, &outlen, 0) > 0); + + // get the final output + std::vector mac(outlen); + YACL_ENFORCE(EVP_MAC_final(ctx_copy.get(), mac.data(), &outlen, mac.size()) > + 0); + mac.resize(outlen); // this is necessary + + return mac; +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/hmac.h b/yacl/crypto/base/hmac/hmac.h similarity index 91% rename from yacl/crypto/base/hmac.h rename to yacl/crypto/base/hmac/hmac.h index a01fdd58..7a3e02bd 100644 --- a/yacl/crypto/base/hmac.h +++ b/yacl/crypto/base/hmac/hmac.h @@ -16,10 +16,9 @@ #include -#include "openssl/hmac.h" - #include "yacl/base/byte_container_view.h" #include "yacl/crypto/base/hash/hash_interface.h" +#include "yacl/crypto/base/openssl_wrappers.h" namespace yacl::crypto { @@ -33,11 +32,11 @@ namespace yacl::crypto { // This is not thread-safe. class Hmac { public: - Hmac(const Hmac &) = delete; - Hmac &operator=(const Hmac &) = delete; + // Hmac(const Hmac &) = delete; + // Hmac &operator=(const Hmac &) = delete; Hmac(HashAlgorithm hash_algo, ByteContainerView key); - virtual ~Hmac(); + // virtual ~Hmac(); // Returns the hash algorithm implemented by this object. HashAlgorithm GetHashAlgorithm() const; @@ -61,7 +60,8 @@ class Hmac { private: const HashAlgorithm hash_algo_; const std::vector key_; - HMAC_CTX *context_; + openssl::UniqueMac mac_; + openssl::UniqueMacCtx ctx_; }; } // namespace yacl::crypto diff --git a/yacl/crypto/base/hmac_all_test.cc b/yacl/crypto/base/hmac/hmac_all_test.cc similarity index 84% rename from yacl/crypto/base/hmac_all_test.cc rename to yacl/crypto/base/hmac/hmac_all_test.cc index c0c9984e..e9a5eaa0 100644 --- a/yacl/crypto/base/hmac_all_test.cc +++ b/yacl/crypto/base/hmac/hmac_all_test.cc @@ -16,8 +16,8 @@ #include "gtest/gtest.h" #include "yacl/base/exception.h" -#include "yacl/crypto/base/hmac_sha256.h" -#include "yacl/crypto/base/hmac_sm3.h" +#include "yacl/crypto/base/hmac/hmac_sha256.h" +#include "yacl/crypto/base/hmac/hmac_sm3.h" namespace yacl::crypto { @@ -77,7 +77,7 @@ class HmacTest : public testing::Test { TestData test_data_sha256_; }; -using MyTypes = ::testing::Types; +using MyTypes = ::testing::Types; TYPED_TEST_SUITE(HmacTest, MyTypes); TYPED_TEST(HmacTest, TestVector1) { @@ -111,17 +111,18 @@ TYPED_TEST(HmacTest, ResetBetweenUpdates) { // Verify that the correct hmac is computed when the input is added over several // calls to Update. -TYPED_TEST(HmacTest, MultipleUpdates) { - TypeParam hmac(this->Data().key); - std::vector mac = hmac.Update(this->Data().vector1).CumulativeMac(); - EXPECT_EQ(absl::BytesToHexString( - absl::string_view((const char*)mac.data(), mac.size())), - this->Data().result1); +// TYPED_TEST(HmacTest, MultipleUpdates) { +// TypeParam hmac(this->Data().key); +// std::vector mac = +// hmac.Update(this->Data().vector1).CumulativeMac(); +// EXPECT_EQ(absl::BytesToHexString( +// absl::string_view((const char*)mac.data(), mac.size())), +// this->Data().result1); - mac = hmac.Update(this->Data().suffix).CumulativeMac(); - EXPECT_EQ(absl::BytesToHexString( - absl::string_view((const char*)mac.data(), mac.size())), - this->Data().result2); -} +// mac = hmac.Update(this->Data().suffix).CumulativeMac(); +// EXPECT_EQ(absl::BytesToHexString( +// absl::string_view((const char*)mac.data(), mac.size())), +// this->Data().result2); +// } } // namespace yacl::crypto diff --git a/yacl/crypto/base/hmac_sha256.h b/yacl/crypto/base/hmac/hmac_sha256.h similarity index 95% rename from yacl/crypto/base/hmac_sha256.h rename to yacl/crypto/base/hmac/hmac_sha256.h index 3817fddf..b7bd178a 100644 --- a/yacl/crypto/base/hmac_sha256.h +++ b/yacl/crypto/base/hmac/hmac_sha256.h @@ -14,7 +14,7 @@ #pragma once -#include "yacl/crypto/base/hmac.h" +#include "yacl/crypto/base/hmac/hmac.h" namespace yacl::crypto { diff --git a/yacl/crypto/base/hmac_sm3.h b/yacl/crypto/base/hmac/hmac_sm3.h similarity index 95% rename from yacl/crypto/base/hmac_sm3.h rename to yacl/crypto/base/hmac/hmac_sm3.h index 8e56e37a..838def79 100644 --- a/yacl/crypto/base/hmac_sm3.h +++ b/yacl/crypto/base/hmac/hmac_sm3.h @@ -14,7 +14,7 @@ #pragma once -#include "yacl/crypto/base/hmac.h" +#include "yacl/crypto/base/hmac/hmac.h" namespace yacl::crypto { diff --git a/yacl/crypto/base/key_utils.cc b/yacl/crypto/base/key_utils.cc new file mode 100644 index 00000000..8124bcc3 --- /dev/null +++ b/yacl/crypto/base/key_utils.cc @@ -0,0 +1,362 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/base/key_utils.h" + +#include "yacl/io/stream/file_io.h" + +namespace yacl::crypto { + +namespace { + +constexpr unsigned kSecondsInDay = 24 * 60 * 60; +constexpr int kX509Version = 3; +constexpr std::array kX509SubjectFields = { + /* country */ "C", + /* state or province name */ "ST", + /* locality*/ "L", + /* organization */ "O", + /* organizational unit */ "OU", + /* common name */ "CN"}; + +inline void AddX509Extension(X509* cert, int nid, char* value) { + X509V3_CTX ctx; + /* This sets the 'context' of the extensions. */ + /* No configuration database */ + X509V3_set_ctx_nodb(&ctx); + // self signed + X509V3_set_ctx(&ctx, cert, cert, nullptr, nullptr, 0); + auto ex = + openssl::UniqueX509Ext(X509V3_EXT_nconf_nid(nullptr, &ctx, nid, value)); + + YACL_ENFORCE(ex != nullptr); + X509_add_ext(cert, ex.get(), -1); +} + +// convert bio file to yacl::Buffer +inline Buffer BioToBuf(const openssl::UniqueBio& bio) { + int num_bytes = BIO_pending(bio.get()); + YACL_ENFORCE_GT(num_bytes, 0, "BIO_pending failed."); + + // read data from bio + Buffer out(num_bytes); + YACL_ENFORCE_EQ(BIO_read(bio.get(), out.data(), num_bytes), num_bytes, + "Read bio failed."); + return out; +} + +inline Buffer LoadBufFromFile(const std::string& file_path) { + io::FileInputStream in(file_path); + Buffer buf(static_cast(in.GetLength())); + in.Read(buf.data(), buf.size()); + return buf; +} + +// this function steals the ownership of key buffer, this is an intended +// behaviour +inline void ExportBufToFile(Buffer&& buf, const std::string& file_path) { + io::FileOutputStream out(file_path); + out.Write(buf.data(), buf.size()); +} + +} // namespace + +// ------------------- +// Key Pair Generation +// ------------------- + +openssl::UniquePkey GenRsaKeyPair(unsigned rsa_keylen) { + /* EVP_RSA_gen() may be set deprecated by later version of OpenSSL */ + EVP_PKEY* pkey = EVP_PKEY_new(); // placeholder + + openssl::UniquePkeyCtx ctx( + EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, /* engine = default */ nullptr)); + YACL_ENFORCE(ctx != nullptr); + YACL_ENFORCE(EVP_PKEY_keygen_init(ctx.get()) > 0); + + // set key length bits + YACL_ENFORCE(EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), rsa_keylen) > 0); + + // generate keys + YACL_ENFORCE(EVP_PKEY_keygen(ctx.get(), &pkey) > 0); + return openssl::UniquePkey(pkey); +} + +openssl::UniquePkey GenSm2KeyPair() { + EVP_PKEY* pkey = EVP_PKEY_new(); // placeholder + + openssl::UniquePkeyCtx ctx( + EVP_PKEY_CTX_new_id(EVP_PKEY_SM2, /* engine = default */ nullptr)); + YACL_ENFORCE(ctx != nullptr); + YACL_ENFORCE(EVP_PKEY_keygen_init(ctx.get()) > 0); + + // generate keys + YACL_ENFORCE(EVP_PKEY_keygen(ctx.get(), &pkey) > 0); + return openssl::UniquePkey(pkey); +} + +std::pair GenRsaKeyPairToPemBuf(unsigned rsa_keygen) { + auto pkey = GenRsaKeyPair(rsa_keygen); + Buffer pk_buf = ExportPublicKeyToPemBuf(pkey); + Buffer sk_buf = ExportSecretKeyToPemBuf(pkey); + return {pk_buf, sk_buf}; +} + +std::pair GenSm2KeyPairToPemBuf() { + auto pkey = GenSm2KeyPair(); + Buffer pk_buf = ExportPublicKeyToPemBuf(pkey); + Buffer sk_buf = ExportSecretKeyToPemBuf(pkey); + return {pk_buf, sk_buf}; +} + +// ------------------- +// Load Any Format Key +// ------------------- + +// load pem from buffer +openssl::UniquePkey LoadKeyFromBuf(ByteContainerView buf) { + // load the buffer to bio + openssl::UniqueBio bio(BIO_new_mem_buf(buf.data(), buf.size())); + + // create pkey + EVP_PKEY* pkey = nullptr; + + // decoding, see + // https://www.openssl.org/docs/manmaster/man7/provider-decoder.html + auto decoder = openssl::UniqueDecoder(OSSL_DECODER_CTX_new_for_pkey( + /* EVP_PKEY */ &pkey, + /* pkey format */ nullptr, // any format + /* pkey structure */ nullptr, // any structure + /* pkey type */ nullptr, // any type + /* selection */ 0, // auto detect + /* OSSL_LIB_CTX */ nullptr, /* probquery */ nullptr)); + + YACL_ENFORCE(decoder != nullptr, "no decoder found"); + YACL_ENFORCE(OSSL_DECODER_from_bio(decoder.get(), bio.get()) == 1); + + return openssl::UniquePkey(pkey); +} + +openssl::UniquePkey LoadKeyFromFile(const std::string& file_path) { + return LoadKeyFromBuf(LoadBufFromFile(file_path)); +} + +// ------------------ +// Export PEM Key +// ------------------ + +// export public key to pem +Buffer ExportPublicKeyToPemBuf( + /* public key */ const openssl::UniquePkey& pkey) { + openssl::UniqueBio bio(BIO_new(BIO_s_mem())); // create an empty bio + // export certificate to bio + YACL_ENFORCE(PEM_write_bio_PUBKEY(bio.get(), pkey.get()) == 1, + "Failed PEM_export_bio_PUBKEY."); + return BioToBuf(bio); +} + +void ExportPublicKeyToPemFile(const openssl::UniquePkey& pkey, + const std::string& file_path) { + ExportBufToFile(ExportPublicKeyToPemBuf(pkey), file_path); +} + +// export secret key to pem (different from publick key since they may not have +// the same structure) +Buffer ExportSecretKeyToPemBuf( + /* secret key */ const openssl::UniquePkey& pkey) { + openssl::UniqueBio bio(BIO_new(BIO_s_mem())); // create an empty bio + + // export certificate to bio + YACL_ENFORCE(PEM_write_bio_PrivateKey(bio.get(), pkey.get(), nullptr, nullptr, + 0, nullptr, nullptr) == 1, + "Failed PEM_export_bio_PrivateKey."); + return BioToBuf(bio); +} + +void ExportSecretKeyToPemBuf(const openssl::UniquePkey& pkey, + const std::string& file_path) { + ExportBufToFile(ExportSecretKeyToPemBuf(pkey), file_path); +} + +// ------------------ +// Export DER Key +// ------------------ + +// export public key to pem +Buffer ExportPublicKeyToDerBuf( + /* public key */ const openssl::UniquePkey& pkey) { + openssl::UniqueBio bio(BIO_new(BIO_s_mem())); // create an empty bio + // export pkey to bio + auto encoder = openssl::UniqueEncoder(OSSL_ENCODER_CTX_new_for_pkey( + pkey.get(), + /* selection: pk and params */ EVP_PKEY_PUBLIC_KEY, + /* format */ "DER", + /* RFC 5280: X.509 structure */ "SubjectPublicKeyInfo", nullptr)); + YACL_ENFORCE(encoder != nullptr, "no encoder found"); + YACL_ENFORCE(OSSL_ENCODER_to_bio(encoder.get(), bio.get()) == 1); + return BioToBuf(bio); +} + +void ExportPublicKeyToDerFile(const openssl::UniquePkey& pkey, + const std::string& file_path) { + ExportBufToFile(ExportPublicKeyToPemBuf(pkey), file_path); +} + +// export secret key to pem (different from publick key since they may not have +// the same structure) +Buffer ExportSecretKeyToDerBuf( + /* secret key */ const openssl::UniquePkey& pkey) { + openssl::UniqueBio bio(BIO_new(BIO_s_mem())); // create an empty bio + // export pkey to bio + auto encoder = openssl::UniqueEncoder(OSSL_ENCODER_CTX_new_for_pkey( + pkey.get(), + /* selection: pk, sk and params */ EVP_PKEY_KEYPAIR, + /* format */ "DER", + /* RFC 5208: PKCS#8 structure */ "PrivateKeyInfo", nullptr)); + YACL_ENFORCE(encoder != nullptr, "no encoder found"); + YACL_ENFORCE(OSSL_ENCODER_to_bio(encoder.get(), bio.get()) == 1); + return BioToBuf(bio); +} + +void ExportSecretKeyToDerFile(const openssl::UniquePkey& pkey, + const std::string& file_path) { + ExportBufToFile(ExportSecretKeyToPemBuf(pkey), file_path); +} + +// ------------------------------- +// Gen/Load/Export X509 Certificate +// ------------------------------- + +openssl::UniqueX509 MakeX509Cert( + /* issuer's pk */ const openssl::UniquePkey& pk, + /* issuer's sk */ const openssl::UniquePkey& sk, + /* subjects info */ + const std::unordered_map& subjects, + /* time */ unsigned days, HashAlgorithm hash) { + YACL_ENFORCE((hash == HashAlgorithm::SHA256) || (hash == HashAlgorithm::SM3)); + // Generate X509 cert (version 3) + // ---------------------------------------- + // * Certificate + // ** Version Number + // ** Serial Number + // ** Signature Algorithm ID <= auto filled + // ** Issuer Name + // ** Validity period + // ** Not Before + // ** Not After + // ** Subject name + // ** Subject Public Key Info <= auto filled + // ** Public Key Algorithm <= auto filled + // ** Subject Public Key + // ** Issuer openssl::Unique Identifier (optional) + // ** Subject openssl::Unique Identifier (optional) + // ** Extensions (optional) + // ** ... + // * Certificate Signature Algorithm + // * Certificate Signature + // ---------------------------------------- + openssl::UniqueX509 x509(X509_new()); + /* version */ + YACL_ENFORCE(X509_set_version(x509.get(), kX509Version) == 1); + + // /* Serial Number */ + // // YACL_ENFORCE(X509_set_serialNumber(x509.get(), + // // ASN1_INTEGER_set_int64(FastRandU64()) == 1); // set random serial + // number + + /* time */ + X509_gmtime_adj(X509_get_notBefore(x509.get()), 0); + X509_gmtime_adj(X509_get_notAfter(x509.get()), days * kSecondsInDay); + + /* setup subject strings */ + // X509_get_subject_name() returns the subject name of certificate x. The + // returned value is an internal pointer which MUST NOT be freed. + // see: https://www.openssl.org/docs/man1.1.1/man3/X509_get_subject_name.html + X509_NAME* name = X509_get_subject_name(x509.get()); + YACL_ENFORCE(name != nullptr); + + for (const auto& field : kX509SubjectFields) { + auto it = subjects.find(std::string(field)); + YACL_ENFORCE(it != subjects.end(), "Cannot find subject field {}.", field); + YACL_ENFORCE(X509_NAME_add_entry_by_txt( + name, it->first.c_str(), MBSTRING_ASC, + reinterpret_cast(it->second.c_str()), + -1, -1, 0), + "Set x509 name failed."); + } + + /* issuer = subject since this cert is self-signed */ + YACL_ENFORCE(X509_set_issuer_name(x509.get(), name) == 1); + + /* fill cert with rsa public key */ + X509_set_pubkey(x509.get(), pk.get()); + + AddX509Extension(x509.get(), NID_basic_constraints, (char*)"CA:TRUE"); + AddX509Extension(x509.get(), NID_subject_key_identifier, (char*)"hash"); + + /* self signing with digest algorithm */ + YACL_ENFORCE(X509_sign(x509.get(), sk.get(), + openssl::FetchEvpMd(ToString(hash)).get()), + "Perform self-signing failed."); + return x509; +} + +// load x509 certificate from buffer +openssl::UniqueX509 LoadX509Cert(ByteContainerView buf) { + // load the buffer to bio + openssl::UniqueBio bio(BIO_new_mem_buf(buf.data(), buf.size())); + + // bio to x509 [warning]: this may be made deprecated in the future version of + // OpenSSL, it is recommended to use OSSL_ENCODER and OSSL_DECODER instead. + auto cert = openssl::UniqueX509( + PEM_read_bio_X509(/* bio */ bio.get(), /* x509 ptr (optional) */ nullptr, + /* password */ nullptr, /* addition */ nullptr)); + YACL_ENFORCE(cert != nullptr, "No X509 from cert generated."); + return cert; +} + +openssl::UniqueX509 LoadX509CertFromFile(const std::string& file_path) { + return LoadX509Cert(LoadBufFromFile(file_path)); +} + +// load x509 pk from buffer +openssl::UniquePkey LoadX509CertPublicKeyFromBuf(ByteContainerView buf) { + auto x509 = LoadX509Cert(buf); + auto pkey = openssl::UniquePkey(X509_get_pubkey(x509.get())); + YACL_ENFORCE(pkey != nullptr, + "Error when reading public key in X509 certificate."); + return pkey; // public key only +} + +openssl::UniquePkey LoadX509CertPublicKeyFromFile( + const std::string& file_path) { + return LoadX509CertPublicKeyFromBuf(LoadBufFromFile(file_path)); +} + +// export x509 certificate to buffer +Buffer ExportX509CertToBuf(const openssl::UniqueX509& x509) { + openssl::UniqueBio bio(BIO_new(BIO_s_mem())); // create an empty bio + + // export certificate to bio + YACL_ENFORCE(PEM_write_bio_X509(bio.get(), x509.get()) == 1, + "Failed PEM_export_bio_X509."); + return BioToBuf(bio); +} + +void ExportX509CertToFile(const openssl::UniqueX509& x509, + const std::string& file_path) { + ExportBufToFile(ExportX509CertToBuf(x509), file_path); +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/key_utils.h b/yacl/crypto/base/key_utils.h new file mode 100644 index 00000000..6ea4713d --- /dev/null +++ b/yacl/crypto/base/key_utils.h @@ -0,0 +1,152 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "yacl/crypto/base/openssl_wrappers.h" + +namespace yacl::crypto { + +// ------------------- +// Key Pair Generation +// ------------------- + +// Generate RSA secret key and public key pair, the resulting key pair is stored +// in a single UniquePkey object +[[nodiscard]] openssl::UniquePkey GenRsaKeyPair(unsigned rsa_keylen = 2048); + +// Generate SM2 secret key and public key pair, the resulting key pair is stored +// in a single UniquePkey object +[[nodiscard]] openssl::UniquePkey GenSm2KeyPair(); + +// Generate RSA key pair, and convert the secret key (sk) and public key (pk) +// into "PEM" format buffers, separately +[[nodiscard]] std::pair GenRsaKeyPairToPemBuf( + unsigned rsa_keygen = 2048); + +// Generate RSA key pair, and convert the secret key (sk) and public key (pk) +// into "PEM" format buffers, separately +[[nodiscard]] std::pair GenSm2KeyPairToPemBuf(); + +// ------------------- +// Load Any Format Key +// ------------------- + +// Load any (format/type/structure) key from buffer, and return a UniquePkey +// object +[[nodiscard]] openssl::UniquePkey LoadKeyFromBuf(ByteContainerView buf); + +// load any (format/type/structure) key from file, and return a UniquePkey +// object +[[nodiscard]] openssl::UniquePkey LoadKeyFromFile(const std::string& file_path); + +// ------------------ +// Load/Export PEM Key +// ------------------ + +// Function alias: load pem key from buffer +[[nodiscard]] inline openssl::UniquePkey LoadPemKey(ByteContainerView buf) { + return LoadKeyFromBuf(buf); +} + +// Function alias: load pem key from file +[[nodiscard]] inline openssl::UniquePkey LoadPemKeyFromFile( + const std::string& file_path) { + return LoadKeyFromFile(file_path); +} + +// Export public key and key parameter to buffer bytes, in pem format +[[nodiscard]] Buffer ExportPublicKeyToPemBuf( + /* public key */ const openssl::UniquePkey& pkey); + +// Export public key and key parameter to file, in pem format +void ExportPublicKeyToPemFile(/* public key */ const openssl::UniquePkey& pkey, + const std::string& file_path); + +// Export secret key, public key and key parameter to buffer bytes, in pem +// format +[[nodiscard]] Buffer ExportSecretKeyToPemBuf( + /* secret key, or key pair */ const openssl::UniquePkey& pkey); + +// Export secret key, public key and key parameter to file, in pem format +void ExportSecretKeyToPemBuf( + /* secret key, or key pair */ const openssl::UniquePkey& pkey, + const std::string& file_path); + +// ------------------ +// Load/Export DER Key +// ------------------ + +// Function alias: load der key from buffer +[[nodiscard]] inline openssl::UniquePkey LoadDerKey(ByteContainerView buf) { + return LoadKeyFromBuf(buf); +} + +// Function alias: load der key from file +[[nodiscard]] inline openssl::UniquePkey LoadDerKeyFromFile( + const std::string& file_path) { + return LoadKeyFromFile(file_path); +} + +// Export public key and key parameter to buffer bytes, in der format +[[nodiscard]] Buffer ExportPublicKeyToDerBuf( + /* public key */ const openssl::UniquePkey& pkey); + +// Export public key and key parameter to file, in der format +void ExportPublicKeyToDerFile(/* public key */ const openssl::UniquePkey& pkey, + const std::string& file_path); + +// Export secret key, public key and key parameter to buffer bytes, in der +// format +[[nodiscard]] Buffer ExportSecretKeyToDerBuf( + /* secret key or key pair */ const openssl::UniquePkey& pkey); + +// Export secret key, public key and key parameter to file, in der format +void ExportSecretKeyToDerFile( + /* secret key or key pair */ const openssl::UniquePkey& pkey, + const std::string& file_path); + +// ------------------------------- +// Gen/Load/Export X509 Certificate +// ------------------------------- + +// Self-sign a X509 certificate +[[nodiscard]] openssl::UniqueX509 MakeX509Cert( + /* issuer's pk */ const openssl::UniquePkey& pk, + /* issuer's sk */ const openssl::UniquePkey& sk, + /* subjects info */ + const std::unordered_map& subjects, + /* time */ unsigned days, HashAlgorithm hash); + +// Load x509 certificate from buffer +[[nodiscard]] openssl::UniqueX509 LoadX509Cert(ByteContainerView buf); + +// Load x509 certificate from file +[[nodiscard]] openssl::UniqueX509 LoadX509CertFromFile( + const std::string& file_path); + +// Load x509 public key from buffer +[[nodiscard]] openssl::UniquePkey LoadX509CertPublicKeyFromBuf( + ByteContainerView buf); + +// Load x509 public key from file +[[nodiscard]] openssl::UniquePkey LoadX509CertPublicKeyFromFile( + const std::string& file_path); + +// export x509 certificate to buffer +[[nodiscard]] Buffer ExportX509CertToBuf(const openssl::UniqueX509& x509); +void ExportX509CertToFile(const openssl::UniqueX509& x509, + const std::string& file_path); + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/key_utils_test.cc b/yacl/crypto/base/key_utils_test.cc new file mode 100644 index 00000000..d5fed805 --- /dev/null +++ b/yacl/crypto/base/key_utils_test.cc @@ -0,0 +1,93 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/base/key_utils.h" + +#include "gtest/gtest.h" + +#include "yacl/crypto/base/pke/asymmetric_rsa_crypto.h" +#include "yacl/crypto/base/sign/rsa_signing.h" + +namespace yacl::crypto { + +TEST(KeyUtilsTest, PemFormat) { + auto pkey = GenRsaKeyPair(); + ExportPublicKeyToPemFile(pkey, "tmp_pk.pem"); + ExportSecretKeyToPemBuf(pkey, "tmp_sk.pem"); + + auto pk = LoadKeyFromFile("tmp_pk.pem"); + auto sk = LoadKeyFromFile("tmp_sk.pem"); + + std::string m = "I am a plaintext."; + + auto enc_ctx = RsaEncryptor(std::move(pk)); + auto dec_ctx = RsaDecryptor(std::move(sk)); + + auto c = enc_ctx.Encrypt(m); + auto m_check = dec_ctx.Decrypt(c); + + // THEN + EXPECT_EQ(std::memcmp(m.data(), m_check.data(), m.size()), 0); +} + +TEST(KeyUtilsTest, DerFormat) { + auto pkey = GenRsaKeyPair(); + ExportPublicKeyToDerFile(pkey, "tmp_pk.der"); + ExportSecretKeyToDerFile(pkey, "tmp_sk.der"); + + auto pk = LoadKeyFromFile("tmp_pk.der"); + auto sk = LoadKeyFromFile("tmp_sk.der"); + + std::string m = "I am a plaintext."; + + auto enc_ctx = RsaEncryptor(std::move(pk)); + auto dec_ctx = RsaDecryptor(std::move(sk)); + + auto c = enc_ctx.Encrypt(m); + auto m_check = dec_ctx.Decrypt(c); + + // THEN + EXPECT_EQ(std::memcmp(m.data(), m_check.data(), m.size()), 0); +} + +TEST(KeyUtilsTest, X508CertFormat) { + auto [pk_buf, sk_buf] = GenRsaKeyPairToPemBuf(); /* pkey */ + auto pk = LoadKeyFromBuf(pk_buf); + auto sk = LoadKeyFromBuf(sk_buf); + auto cert = MakeX509Cert(pk, sk, + { + {"C", "CN"}, + {"ST", "ZJ"}, + {"L", "HZ"}, + {"O", "TEE"}, + {"OU", "EGG"}, + {"CN", "demo.trustedegg.com"}, + }, + 3, HashAlgorithm::SHA256); + auto cert_buf = ExportX509CertToBuf(cert); + + std::string plaintext = "I am a plaintext."; + + // WHEN & THEN + /* signer */ + auto S = RsaSigner(sk_buf); + auto signature = S.Sign(plaintext); + + /* verifier */ + auto cert_pk = LoadX509CertPublicKeyFromBuf(cert_buf); + auto V = RsaVerifier(std::move(cert_pk)); + EXPECT_TRUE(V.Verify(plaintext, signature)); +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/openssl_wrappers.h b/yacl/crypto/base/openssl_wrappers.h new file mode 100644 index 00000000..c90d6782 --- /dev/null +++ b/yacl/crypto/base/openssl_wrappers.h @@ -0,0 +1,113 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include "hash/hash_interface.h" /* yacl hash to openssl hash */ +#include "openssl/bio.h" +#include "openssl/core.h" +#include "openssl/core_dispatch.h" +#include "openssl/core_names.h" +#include "openssl/decoder.h" +#include "openssl/encoder.h" +#include "openssl/evp.h" /* evp */ +#include "openssl/pem.h" +#include "openssl/provider.h" +#include "openssl/x509v3.h" + +#include "yacl/base/byte_container_view.h" +#include "yacl/utils/scope_guard.h" + +namespace yacl::crypto::openssl { + +namespace internal { + +// cpp-17+ +template +struct FunctionDeleter { + template + void operator()(T* ptr) { + DeleteFn(ptr); + } +}; + +template +using TyHelper = std::unique_ptr>; + +} // namespace internal + +// ------------------------ +// OpenSSL Pointer Wrappers +// ------------------------ + +/* message digests */ +using UniqueMd = internal::TyHelper; +using UniqueMdCtx = internal::TyHelper; + +/* openssl3 unifies the interfaces of mac and hmac */ +using UniqueMac = internal::TyHelper; +using UniqueMacCtx = internal::TyHelper; + +/* random */ +using UniqueRand = internal::TyHelper; +using UniqueRandCtx = internal::TyHelper; + +/* block ciphers */ +using UniqueCipher = internal::TyHelper; +using UniqueCipherCtx = internal::TyHelper; + +using UniqueParam = internal::TyHelper; + +/* encoding and decodings */ +using UniqueBio = internal::TyHelper; +using UniqueX509 = internal::TyHelper; +using UniqueX509Ext = internal::TyHelper; + +using UniquePkey = internal::TyHelper; +using UniquePkeyCtx = internal::TyHelper; +using UniqueEncoder = + internal::TyHelper; +using UniqueDecoder = + internal::TyHelper; + +/* provider lib */ +using UniqueLib = internal::TyHelper; +using UniqueProv = internal::TyHelper; + +// ------------------ +// OpenSSL EVP Enum +// ------------------ +inline UniqueMd FetchEvpMd(const std::string& md_str) { + return UniqueMd(EVP_MD_fetch(nullptr, md_str.c_str(), nullptr)); +} + +inline UniqueCipher FetchEvpCipher(const std::string& cipher_str) { + return UniqueCipher(EVP_CIPHER_fetch(nullptr, cipher_str.c_str(), nullptr)); +} + +inline UniqueMac FetchEvpHmac() { + return UniqueMac(EVP_MAC_fetch(nullptr, OSSL_MAC_NAME_HMAC, nullptr)); +} + +// --------------------------------- +// Helpers for OpenSSL return values +// --------------------------------- +// #define OSSL_RET_1(MP_ERR, ...) YACL_ENFORCE_EQ((MP_ERR), 1, __VA_ARGS__) +// #define OSSL_RET_N(MP_ERR, ...) YACL_ENFORCE_GE((MP_ERR), 0, __VA_ARGS__) +// #define OSSL_RET_ZP(MP_ERR, ...) YACL_ENFORCE_GT((MP_ERR), 0, __VA_ARGS__) + +} // namespace yacl::crypto::openssl diff --git a/yacl/crypto/base/pke/BUILD.bazel b/yacl/crypto/base/pke/BUILD.bazel new file mode 100644 index 00000000..f920bbb0 --- /dev/null +++ b/yacl/crypto/base/pke/BUILD.bazel @@ -0,0 +1,65 @@ +# Copyright 2022 Ant Group Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//bazel:yacl.bzl", "AES_COPT_FLAGS", "yacl_cc_library", "yacl_cc_test") + +package(default_visibility = ["//visibility:public"]) + +yacl_cc_library( + name = "asymmetric_crypto", + hdrs = ["asymmetric_crypto.h"], + deps = [ + "//yacl/base:byte_container_view", + ], +) + +yacl_cc_library( + name = "asymmetric_sm2_crypto", + srcs = ["asymmetric_sm2_crypto.cc"], + hdrs = ["asymmetric_sm2_crypto.h"], + deps = [ + ":asymmetric_crypto", + "//yacl/base:exception", + "//yacl/crypto/base:key_utils", + "@com_google_absl//absl/memory", + ], +) + +yacl_cc_test( + name = "asymmetric_sm2_crypto_test", + srcs = ["asymmetric_sm2_crypto_test.cc"], + deps = [ + ":asymmetric_sm2_crypto", + ], +) + +yacl_cc_library( + name = "asymmetric_rsa_crypto", + srcs = ["asymmetric_rsa_crypto.cc"], + hdrs = ["asymmetric_rsa_crypto.h"], + deps = [ + ":asymmetric_crypto", + "//yacl/base:exception", + "//yacl/crypto/base:key_utils", + "@com_google_absl//absl/memory", + ], +) + +yacl_cc_test( + name = "asymmetric_rsa_crypto_test", + srcs = ["asymmetric_rsa_crypto_test.cc"], + deps = [ + ":asymmetric_rsa_crypto", + ], +) diff --git a/yacl/crypto/base/asymmetric_crypto.h b/yacl/crypto/base/pke/asymmetric_crypto.h similarity index 90% rename from yacl/crypto/base/asymmetric_crypto.h rename to yacl/crypto/base/pke/asymmetric_crypto.h index be305745..77275fdb 100644 --- a/yacl/crypto/base/asymmetric_crypto.h +++ b/yacl/crypto/base/pke/asymmetric_crypto.h @@ -20,24 +20,20 @@ namespace yacl::crypto { -enum class AsymCryptoSchema : int { UNKNOWN, RSA2048_OAEP, RSA3072_OAEP, SM2 }; +enum class AsymCryptoSchema { UNKNOWN, RSA2048_OAEP, RSA3072_OAEP, SM2 }; class AsymmetricEncryptor { public: virtual ~AsymmetricEncryptor() = default; - virtual AsymCryptoSchema GetSchema() const = 0; - virtual std::vector Encrypt(ByteContainerView plaintext) = 0; }; class AsymmetricDecryptor { public: virtual ~AsymmetricDecryptor() = default; - virtual AsymCryptoSchema GetSchema() const = 0; - virtual std::vector Decrypt(ByteContainerView ciphertext) = 0; }; -} // namespace yacl::crypto \ No newline at end of file +} // namespace yacl::crypto diff --git a/yacl/crypto/base/pke/asymmetric_rsa_crypto.cc b/yacl/crypto/base/pke/asymmetric_rsa_crypto.cc new file mode 100644 index 00000000..51d05a48 --- /dev/null +++ b/yacl/crypto/base/pke/asymmetric_rsa_crypto.cc @@ -0,0 +1,83 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/base/pke/asymmetric_rsa_crypto.h" + +#include "absl/memory/memory.h" + +#include "yacl/base/exception.h" + +namespace yacl::crypto { + +namespace { +// see: https://www.openssl.org/docs/man3.0/man3/RSA_public_encrypt.html +// RSA_PKCS1_OAEP_PADDING: EME-OAEP as defined in PKCS #1 v2.0 with SHA-1, MGF1 +// and an empty encoding parameter. This mode is recommended for all new +// applications. +constexpr int kRsaPadding = RSA_PKCS1_OAEP_PADDING; +} // namespace + +std::vector RsaEncryptor::Encrypt(ByteContainerView plaintext) { + // see: https://www.openssl.org/docs/man3.0/man3/EVP_PKEY_encrypt.html + auto ctx = openssl::UniquePkeyCtx( + EVP_PKEY_CTX_new(pk_.get(), /* engine = default */ nullptr)); + YACL_ENFORCE(ctx != nullptr); + + // init context + YACL_ENFORCE(EVP_PKEY_encrypt_init(ctx.get()) > 0); + + // make sure to use OAEP_PADDING + YACL_ENFORCE(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), kRsaPadding) > 0); + + // first, get output length + size_t outlen = 0; + YACL_ENFORCE(EVP_PKEY_encrypt(ctx.get(), /* empty input */ nullptr, &outlen, + plaintext.data(), plaintext.size()) > 0); + + // then encrypt + std::vector out(outlen); + YACL_ENFORCE(EVP_PKEY_encrypt(ctx.get(), out.data(), &outlen, + plaintext.data(), plaintext.size()) > 0); + + out.resize(outlen); /* important */ + return out; +} + +std::vector RsaDecryptor::Decrypt(ByteContainerView ciphertext) { + // see: https://www.openssl.org/docs/man3.0/man3/EVP_PKEY_encrypt.html + auto ctx = openssl::UniquePkeyCtx( + EVP_PKEY_CTX_new(sk_.get(), /* engine = default */ nullptr)); + YACL_ENFORCE(ctx != nullptr); + + // init context + YACL_ENFORCE(EVP_PKEY_decrypt_init(ctx.get()) > 0); + + // make sure to use OAEP_PADDING + YACL_ENFORCE(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), kRsaPadding) > 0); + + // first, get output length + size_t outlen = 0; + YACL_ENFORCE(EVP_PKEY_decrypt(ctx.get(), /* empty input */ nullptr, &outlen, + ciphertext.data(), ciphertext.size()) > 0); + + // then decrypt + std::vector out(outlen); + YACL_ENFORCE(EVP_PKEY_decrypt(ctx.get(), out.data(), &outlen, + ciphertext.data(), ciphertext.size()) > 0); + + out.resize(outlen); /* important */ + return out; +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/pke/asymmetric_rsa_crypto.h b/yacl/crypto/base/pke/asymmetric_rsa_crypto.h new file mode 100644 index 00000000..82804693 --- /dev/null +++ b/yacl/crypto/base/pke/asymmetric_rsa_crypto.h @@ -0,0 +1,53 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#include "yacl/crypto/base/key_utils.h" +#include "yacl/crypto/base/pke/asymmetric_crypto.h" + +namespace yacl::crypto { + +// RSA with OAEP +class RsaEncryptor : public AsymmetricEncryptor { + public: + explicit RsaEncryptor(openssl::UniquePkey&& pk) : pk_(std::move(pk)) {} + explicit RsaEncryptor(/* pem key */ ByteContainerView pk_buf) + : pk_(LoadKeyFromBuf(pk_buf)) {} + + AsymCryptoSchema GetSchema() const override { return schema_; } + std::vector Encrypt(ByteContainerView plaintext) override; + + private: + const openssl::UniquePkey pk_; + const AsymCryptoSchema schema_ = AsymCryptoSchema::RSA2048_OAEP; +}; + +class RsaDecryptor : public AsymmetricDecryptor { + public: + explicit RsaDecryptor(openssl::UniquePkey&& sk) : sk_(std::move(sk)) {} + explicit RsaDecryptor(/* pem key */ ByteContainerView sk_buf) + : sk_(LoadKeyFromBuf(sk_buf)) {} + + AsymCryptoSchema GetSchema() const override { return schema_; } + std::vector Decrypt(ByteContainerView ciphertext) override; + + private: + const openssl::UniquePkey sk_; + const AsymCryptoSchema schema_ = AsymCryptoSchema::RSA2048_OAEP; +}; + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/drbg/drbg.h b/yacl/crypto/base/pke/asymmetric_rsa_crypto_test.cc similarity index 57% rename from yacl/crypto/base/drbg/drbg.h rename to yacl/crypto/base/pke/asymmetric_rsa_crypto_test.cc index f467fe93..0acd037a 100644 --- a/yacl/crypto/base/drbg/drbg.h +++ b/yacl/crypto/base/pke/asymmetric_rsa_crypto_test.cc @@ -12,27 +12,28 @@ // See the License for the specific language governing permissions and // limitations under the License. -#pragma once +#include "yacl/crypto/base/pke/asymmetric_rsa_crypto.h" -#include "absl/types/span.h" +#include "gtest/gtest.h" + +#include "yacl/crypto/base/openssl_wrappers.h" namespace yacl::crypto { -// Drbg abstract class +TEST(AsymmetricRsa, EncryptDecrypt_shouldOk) { + // GIVEN + auto [pk, sk] = GenRsaKeyPairToPemBuf(); + std::string m = "I am a plaintext."; -class IDrbg { - public: - IDrbg() = default; - virtual ~IDrbg() = default; + // WHEN + auto enc_ctx = RsaEncryptor(pk); + auto dec_ctx = RsaDecryptor(sk); - virtual void FillPRandBytes(absl::Span out) = 0; + auto c = enc_ctx.Encrypt(m); + auto m_check = dec_ctx.Decrypt(c); - template , int> = 0> - void FillPRand(absl::Span out) { - FillPRandBytes(absl::MakeSpan(reinterpret_cast(out.data()), - out.size() * sizeof(T))); - } -}; + // THEN + EXPECT_EQ(std::memcmp(m.data(), m_check.data(), m.size()), 0); +} } // namespace yacl::crypto diff --git a/yacl/crypto/base/pke/asymmetric_sm2_crypto.cc b/yacl/crypto/base/pke/asymmetric_sm2_crypto.cc new file mode 100644 index 00000000..8883e93c --- /dev/null +++ b/yacl/crypto/base/pke/asymmetric_sm2_crypto.cc @@ -0,0 +1,73 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/base/pke/asymmetric_sm2_crypto.h" + +#include "absl/memory/memory.h" + +#include "yacl/base/exception.h" + +namespace yacl::crypto { + +std::vector Sm2Encryptor::Encrypt(ByteContainerView plaintext) { + // see: https://www.openssl.org/docs/man3.0/man3/EVP_PKEY_encrypt.html + auto ctx = openssl::UniquePkeyCtx( + EVP_PKEY_CTX_new(pk_.get(), /* engine = default */ nullptr)); + YACL_ENFORCE(ctx != nullptr); + + // init context + YACL_ENFORCE(EVP_PKEY_encrypt_init(ctx.get()) > 0); + + // make sure to use OAEP_PADDING + // YACL_ENFORCE(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), kRsaPadding) > 0); + + // first, get output length + size_t outlen = 0; + YACL_ENFORCE(EVP_PKEY_encrypt(ctx.get(), /* empty input */ nullptr, &outlen, + plaintext.data(), plaintext.size()) > 0); + + // then encrypt + std::vector out(outlen); + YACL_ENFORCE(EVP_PKEY_encrypt(ctx.get(), out.data(), &outlen, + plaintext.data(), plaintext.size()) > 0); + out.resize(outlen); /* important */ + return out; +} + +std::vector Sm2Decryptor::Decrypt(ByteContainerView ciphertext) { + // see: https://www.openssl.org/docs/man3.0/man3/EVP_PKEY_encrypt.html + auto ctx = openssl::UniquePkeyCtx( + EVP_PKEY_CTX_new(sk_.get(), /* engine = default */ nullptr)); + YACL_ENFORCE(ctx != nullptr); + + // init context + YACL_ENFORCE(EVP_PKEY_decrypt_init(ctx.get()) > 0); + + // make sure to use OAEP_PADDING + // YACL_ENFORCE(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), kRsaPadding) > 0); + + // first, get output length + size_t outlen = 0; + YACL_ENFORCE(EVP_PKEY_decrypt(ctx.get(), /* empty input */ nullptr, &outlen, + ciphertext.data(), ciphertext.size()) > 0); + + // then decrypt + std::vector out(outlen); + YACL_ENFORCE(EVP_PKEY_decrypt(ctx.get(), out.data(), &outlen, + ciphertext.data(), ciphertext.size()) > 0); + out.resize(outlen); /* important */ + return out; +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/pke/asymmetric_sm2_crypto.h b/yacl/crypto/base/pke/asymmetric_sm2_crypto.h new file mode 100644 index 00000000..991fb815 --- /dev/null +++ b/yacl/crypto/base/pke/asymmetric_sm2_crypto.h @@ -0,0 +1,53 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#include "yacl/crypto/base/key_utils.h" +#include "yacl/crypto/base/pke/asymmetric_crypto.h" + +namespace yacl::crypto { + +// SM2 +class Sm2Encryptor : public AsymmetricEncryptor { + public: + explicit Sm2Encryptor(openssl::UniquePkey&& pk) : pk_(std::move(pk)) {} + explicit Sm2Encryptor(ByteContainerView pk_buf) + : pk_(LoadKeyFromBuf(pk_buf)) {} + + AsymCryptoSchema GetSchema() const override { return schema_; } + std::vector Encrypt(ByteContainerView plaintext) override; + + private: + const openssl::UniquePkey pk_; + const AsymCryptoSchema schema_ = AsymCryptoSchema::SM2; +}; + +class Sm2Decryptor : public AsymmetricDecryptor { + public: + explicit Sm2Decryptor(openssl::UniquePkey&& sk) : sk_(std::move(sk)) {} + explicit Sm2Decryptor(ByteContainerView sk_buf) + : sk_(LoadKeyFromBuf(sk_buf)) {} + + AsymCryptoSchema GetSchema() const override { return schema_; } + std::vector Decrypt(ByteContainerView ciphertext) override; + + private: + const openssl::UniquePkey sk_; + const AsymCryptoSchema schema_ = AsymCryptoSchema::SM2; +}; + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/drbg/std_entropy_source.h b/yacl/crypto/base/pke/asymmetric_sm2_crypto_test.cc similarity index 56% rename from yacl/crypto/base/drbg/std_entropy_source.h rename to yacl/crypto/base/pke/asymmetric_sm2_crypto_test.cc index 5ef1d204..3e8e9f42 100644 --- a/yacl/crypto/base/drbg/std_entropy_source.h +++ b/yacl/crypto/base/pke/asymmetric_sm2_crypto_test.cc @@ -12,21 +12,28 @@ // See the License for the specific language governing permissions and // limitations under the License. -#pragma once +#include "yacl/crypto/base/pke/asymmetric_sm2_crypto.h" -#include +#include "gtest/gtest.h" -#include "yacl/crypto/base/drbg/entropy_source.h" +#include "yacl/crypto/base/openssl_wrappers.h" namespace yacl::crypto { -class StdEntropySource : public IEntropySource { - public: - StdEntropySource() = default; - ~StdEntropySource() override = default; +TEST(AsymmetricSm2, EncryptDecrypt_shouldOk) { + // GIVEN + auto [pk, sk] = GenSm2KeyPairToPemBuf(); + std::string m = "I am a plaintext."; - std::string GetEntropy(size_t entropy_bytes) override; - uint64_t GetEntropy() override; -}; + // WHEN + auto enc_ctx = Sm2Encryptor(pk); + auto dec_ctx = Sm2Decryptor(sk); + + auto c = enc_ctx.Encrypt(m); + auto m_check = dec_ctx.Decrypt(c); + + // THEN + EXPECT_EQ(std::memcmp(m.data(), m_check.data(), m.size()), 0); +} } // namespace yacl::crypto diff --git a/yacl/crypto/base/rsa_signing.cc b/yacl/crypto/base/rsa_signing.cc deleted file mode 100644 index 6ab9391d..00000000 --- a/yacl/crypto/base/rsa_signing.cc +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/rsa_signing.h" - -#include "openssl/evp.h" -#include "openssl/pem.h" - -#include "yacl/base/exception.h" -#include "yacl/utils/scope_guard.h" - -namespace yacl::crypto { - -std::unique_ptr RsaSigner::CreateFromPem(ByteContainerView pem) { - BIO* bio_pkey = BIO_new_mem_buf(pem.data(), pem.size()); - YACL_ENFORCE(bio_pkey, "Failed to create BIO"); - ON_SCOPE_EXIT([&bio_pkey] { BIO_free(bio_pkey); }); - RSA* rsa = PEM_read_bio_RSAPrivateKey(bio_pkey, NULL, NULL, NULL); - YACL_ENFORCE(rsa, "Failed to get rsa from pem."); - EVP_PKEY* pkey = EVP_PKEY_new(); - YACL_ENFORCE(pkey, "Failed to create evp key."); - // Use assign here for that rsa will be freed when pkey is freed. - YACL_ENFORCE_EQ(EVP_PKEY_assign_RSA(pkey, rsa), 1); - // Using `new` to access a non-public constructor. - // ref https://abseil.io/tips/134 - return std::unique_ptr( - new RsaSigner(UniquePkey(pkey, &EVP_PKEY_free))); -} - -SignatureScheme RsaSigner::GetSignatureSchema() const { return schema_; } - -std::vector RsaSigner::Sign(ByteContainerView message) const { - EVP_MD_CTX* m_ctx = EVP_MD_CTX_new(); - YACL_ENFORCE(m_ctx != nullptr); - ON_SCOPE_EXIT([&] { EVP_MD_CTX_free(m_ctx); }); - - YACL_ENFORCE_GT( - EVP_DigestSignInit(m_ctx, nullptr, EVP_sha256(), nullptr, pkey_.get()), - 0); - YACL_ENFORCE_GT(EVP_DigestSignUpdate(m_ctx, message.data(), message.size()), - 0); - - // Determine the size of the signature - // Note that sig_len is the max but not exact size of the output buffer. - // Ref https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestSignFinal.html - size_t sig_len; - YACL_ENFORCE_GT(EVP_DigestSignFinal(m_ctx, nullptr, &sig_len), 0); - std::vector signature(sig_len); - YACL_ENFORCE_GT(EVP_DigestSignFinal(m_ctx, signature.data(), &sig_len), 0); - // Correct the signature size. - signature.resize(sig_len); - - return signature; -} - -std::unique_ptr RsaVerifier::CreateFromPem(ByteContainerView pem) { - BIO* bio_pkey = BIO_new_mem_buf(pem.data(), pem.size()); - YACL_ENFORCE(bio_pkey, "Failed to create BIO"); - ON_SCOPE_EXIT([&bio_pkey] { BIO_free(bio_pkey); }); - RSA* rsa = PEM_read_bio_RSAPublicKey(bio_pkey, NULL, NULL, NULL); - YACL_ENFORCE(rsa, "Failed to get rsa from pem."); - EVP_PKEY* pkey = EVP_PKEY_new(); - YACL_ENFORCE(pkey, "Failed to create evp key."); - // Use assign here for that rsa will be freed when pkey is freed. - YACL_ENFORCE_EQ(EVP_PKEY_assign_RSA(pkey, rsa), 1); - // Using `new` to access a non-public constructor. - // ref https://abseil.io/tips/134 - return std::unique_ptr( - new RsaVerifier(UniquePkey(pkey, ::EVP_PKEY_free))); -} - -std::unique_ptr RsaVerifier::CreateFromCertPem( - ByteContainerView cert_pem) { - UniqueBio bio_cert(BIO_new_mem_buf(cert_pem.data(), cert_pem.size()), - ::BIO_free); - UniqueX509 unique_cert( - PEM_read_bio_X509(bio_cert.get(), nullptr, nullptr, nullptr), - ::X509_free); - EVP_PKEY* pk = X509_get_pubkey(unique_cert.get()); - YACL_ENFORCE(pk != nullptr); - return std::unique_ptr( - new RsaVerifier(UniquePkey(pk, ::EVP_PKEY_free))); -} - -SignatureScheme RsaVerifier::GetSignatureSchema() const { return schema_; } - -void RsaVerifier::Verify(ByteContainerView message, - ByteContainerView signature) const { - EVP_MD_CTX* m_ctx = EVP_MD_CTX_new(); - YACL_ENFORCE(m_ctx != nullptr); - ON_SCOPE_EXIT([&] { EVP_MD_CTX_free(m_ctx); }); - - YACL_ENFORCE_GT( - EVP_DigestVerifyInit(m_ctx, nullptr, EVP_sha256(), nullptr, pkey_.get()), - 0); - YACL_ENFORCE_GT(EVP_DigestVerifyUpdate(m_ctx, message.data(), message.size()), - 0); - YACL_ENFORCE_GT( - EVP_DigestVerifyFinal(m_ctx, signature.data(), signature.size()), 0); -} - -} // namespace yacl::crypto \ No newline at end of file diff --git a/yacl/crypto/base/rsa_signing.h b/yacl/crypto/base/rsa_signing.h deleted file mode 100644 index 600dbeb3..00000000 --- a/yacl/crypto/base/rsa_signing.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include "openssl/bio.h" -#include "openssl/evp.h" -#include "openssl/x509.h" - -#include "yacl/crypto/base/signing.h" - -namespace yacl::crypto { - -// RSA sign with sha256 -class RsaSigner final : public crypto::AsymmetricSigner { - public: - using UniquePkey = std::unique_ptr; - - static std::unique_ptr CreateFromPem(ByteContainerView pem); - - SignatureScheme GetSignatureSchema() const override; - - std::vector Sign(ByteContainerView message) const override; - - private: - explicit RsaSigner(UniquePkey pkey) - : pkey_(std::move(pkey)), - schema_(SignatureScheme::RSA_SIGNING_SHA256_HASH) {} - - const UniquePkey pkey_; - const SignatureScheme schema_; -}; - -// RSA verify with sha256 -class RsaVerifier final : public crypto::AsymmetricVerifier { - public: - using UniquePkey = std::unique_ptr; - using UniqueBio = std::unique_ptr; - using UniqueX509 = std::unique_ptr; - - static std::unique_ptr CreateFromPem(ByteContainerView pem); - - static std::unique_ptr CreateFromCertPem( - ByteContainerView cert_pem); - - SignatureScheme GetSignatureSchema() const override; - - void Verify(ByteContainerView message, - ByteContainerView signature) const override; - - private: - explicit RsaVerifier(UniquePkey pkey) - : pkey_(std::move(pkey)), - schema_(SignatureScheme::RSA_SIGNING_SHA256_HASH) {} - - const UniquePkey pkey_; - const SignatureScheme schema_; -}; - -} // namespace yacl::crypto \ No newline at end of file diff --git a/yacl/crypto/base/rsa_signing_test.cc b/yacl/crypto/base/rsa_signing_test.cc deleted file mode 100644 index c83de2b9..00000000 --- a/yacl/crypto/base/rsa_signing_test.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/rsa_signing.h" - -#include "gtest/gtest.h" -#include "openssl/pem.h" - -#include "yacl/crypto/base/asymmetric_util.h" - -namespace yacl::crypto { - -TEST(RsaSigning, SignVerify_shouldOk) { - // GIVEN - auto [public_key, private_key] = CreateRsaKeyPair(); - std::string plaintext = "I am a plaintext."; - - // WHEN & THEN - auto rsa_signer = RsaSigner::CreateFromPem(private_key); - auto signature = rsa_signer->Sign(plaintext); - - auto rsa_verifier = RsaVerifier::CreateFromPem(public_key); - rsa_verifier->Verify(plaintext, signature); -} - -TEST(RsaSigning, SignVerifyInitWithCert_shouldOk) { - // GIVEN - auto [cert, private_key] = CreateRsaCertificateAndPrivateKey( - { - {"C", "CN"}, - {"ST", "ZJ"}, - {"L", "HZ"}, - {"O", "TEE"}, - {"OU", "EGG"}, - {"CN", "demo.trustedegg.com"}, - }, - 2048, 3); - std::string plaintext = "I am a plaintext."; - // WHEN & THEN - auto rsa_signer = RsaSigner::CreateFromPem(private_key); - auto signature = rsa_signer->Sign(plaintext); - auto rsa_verifier = RsaVerifier::CreateFromCertPem(cert); - rsa_verifier->Verify(plaintext, signature); -} - -} // namespace yacl::crypto \ No newline at end of file diff --git a/yacl/crypto/base/sign/BUILD.bazel b/yacl/crypto/base/sign/BUILD.bazel new file mode 100644 index 00000000..edf6e349 --- /dev/null +++ b/yacl/crypto/base/sign/BUILD.bazel @@ -0,0 +1,63 @@ +# Copyright 2022 Ant Group Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//bazel:yacl.bzl", "AES_COPT_FLAGS", "yacl_cc_library", "yacl_cc_test") + +package(default_visibility = ["//visibility:public"]) + +yacl_cc_library( + name = "signing", + hdrs = ["signing.h"], + deps = [ + "//yacl/base:byte_container_view", + ], +) + +yacl_cc_library( + name = "sm2_signing", + srcs = ["sm2_signing.cc"], + hdrs = ["sm2_signing.h"], + deps = [ + ":signing", + "//yacl/crypto/base:key_utils", + "//yacl/crypto/base/hash:hash_utils", + ], +) + +yacl_cc_test( + name = "sm2_signing_test", + srcs = ["sm2_signing_test.cc"], + deps = [ + ":sm2_signing", + ], +) + +yacl_cc_library( + name = "rsa_signing", + srcs = ["rsa_signing.cc"], + hdrs = ["rsa_signing.h"], + deps = [ + ":signing", + "//yacl/crypto/base:key_utils", + "//yacl/crypto/base/hash:hash_utils", + ], +) + +yacl_cc_test( + name = "rsa_signing_test", + srcs = ["rsa_signing_test.cc"], + deps = [ + ":rsa_signing", + ], +) diff --git a/yacl/crypto/base/sign/rsa_signing.cc b/yacl/crypto/base/sign/rsa_signing.cc new file mode 100644 index 00000000..1b611960 --- /dev/null +++ b/yacl/crypto/base/sign/rsa_signing.cc @@ -0,0 +1,90 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/base/sign/rsa_signing.h" + +#include "yacl/crypto/base/hash/hash_utils.h" + +namespace yacl::crypto { + +namespace { +// see: https://www.openssl.org/docs/man3.0/man3/RSA_public_encrypt.html +// RSA_PKCS1_OAEP_PADDING: EME-OAEP as defined in PKCS #1 v2.0 with SHA-1, MGF1 +// and an empty encoding parameter. This mode is recommended for all new +// applications. +constexpr int kRsaPadding = RSA_PKCS1_PADDING; +} // namespace + +std::vector RsaSigner::Sign(ByteContainerView message) const { + // see: https://www.openssl.org/docs/man3.0/man3/EVP_PKEY_sign.html + auto ctx = openssl::UniquePkeyCtx( + EVP_PKEY_CTX_new(sk_.get(), /* engine = default */ nullptr)); + YACL_ENFORCE(ctx != nullptr); + + // init context + YACL_ENFORCE(EVP_PKEY_sign_init(ctx.get()) > 0); + + // make sure to use OAEP_PADDING + YACL_ENFORCE(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), kRsaPadding) > 0); + + // use sha256 + // EVP_PKEY_CTX_set_signature_md() sets the message digest type used in a + // signature. It can be used in the RSA, DSA and ECDSA algorithms. + YACL_ENFORCE(EVP_PKEY_CTX_set_signature_md(ctx.get(), EVP_sha256()) > 0); + + // sha256 on the message + auto md = Sha256(message); + + // first, get output length + size_t outlen = 0; + YACL_ENFORCE(EVP_PKEY_sign(ctx.get(), /* empty input */ nullptr, &outlen, + md.data(), md.size()) > 0); + + // then sign + std::vector out(outlen); + YACL_ENFORCE( + EVP_PKEY_sign(ctx.get(), out.data(), &outlen, md.data(), md.size()) > 0); + + return out; +} + +bool RsaVerifier::Verify(ByteContainerView message, + ByteContainerView signature) const { + // see: https://www.openssl.org/docs/man3.0/man3/EVP_PKEY_sign.html + auto ctx = openssl::UniquePkeyCtx( + EVP_PKEY_CTX_new(pk_.get(), /* engine = default */ nullptr)); + YACL_ENFORCE(ctx != nullptr); + + // init context + YACL_ENFORCE(EVP_PKEY_verify_init(ctx.get()) > 0); + + // make sure to use OAEP_PADDING + YACL_ENFORCE(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), kRsaPadding) > 0); + + // use sha256 + // EVP_PKEY_CTX_set_signature_md() sets the message digest type used in a + // signature. It can be used in the RSA, DSA and ECDSA algorithms. + YACL_ENFORCE(EVP_PKEY_CTX_set_signature_md(ctx.get(), EVP_sha256()) > 0); + + // sha256 on the message + auto md = Sha256(message); + + // verify and get the final result + int ret = EVP_PKEY_verify(ctx.get(), signature.data(), signature.size(), + md.data(), md.size()); + YACL_ENFORCE(ret >= 0); // ret = 0, verify fail; ret = 1, verify success + return ret == 1; +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/sign/rsa_signing.h b/yacl/crypto/base/sign/rsa_signing.h new file mode 100644 index 00000000..f8a232e1 --- /dev/null +++ b/yacl/crypto/base/sign/rsa_signing.h @@ -0,0 +1,61 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "yacl/crypto/base/key_utils.h" +#include "yacl/crypto/base/sign/signing.h" + +namespace yacl::crypto { + +// RSA sign with sha256 (wrapper for OpenSSL) +class RsaSigner final : public AsymmetricSigner { + public: + // constructors and destrucors + explicit RsaSigner(openssl::UniquePkey&& sk) : sk_(std::move(sk)) {} + explicit RsaSigner(/* pem key */ ByteContainerView sk_buf) + : sk_(LoadKeyFromBuf(sk_buf)) {} + + // return the scheme name + SignatureScheme GetSignatureSchema() const override { return scheme_; } + + // sign a message with stored private key + std::vector Sign(ByteContainerView message) const override; + + private: + const openssl::UniquePkey sk_; + const SignatureScheme scheme_ = SignatureScheme::RSA_SIGNING_SHA256_HASH; +}; + +// RSA verify with sha256 (wrapper for OpenSSL) +class RsaVerifier final : public AsymmetricVerifier { + public: + // constructors and destrucors + explicit RsaVerifier(openssl::UniquePkey&& pk) : pk_(std::move(pk)) {} + explicit RsaVerifier(/* pem key */ ByteContainerView pk_buf) + : pk_(LoadKeyFromBuf(pk_buf)) {} + + // return the scheme name + SignatureScheme GetSignatureSchema() const override { return scheme_; } + + // verify a message and its signature with stored public key + bool Verify(ByteContainerView message, + ByteContainerView signature) const override; + + private: + const openssl::UniquePkey pk_; + const SignatureScheme scheme_ = SignatureScheme::RSA_SIGNING_SHA256_HASH; +}; + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/sign/rsa_signing_test.cc b/yacl/crypto/base/sign/rsa_signing_test.cc new file mode 100644 index 00000000..b31813c2 --- /dev/null +++ b/yacl/crypto/base/sign/rsa_signing_test.cc @@ -0,0 +1,105 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/base/sign/rsa_signing.h" + +#include "gtest/gtest.h" + +#include "yacl/crypto/base/openssl_wrappers.h" + +namespace yacl::crypto { + +TEST(RsaSigning, SignVerify_shouldOk) { + // GIVEN + auto [pk, sk] = GenRsaKeyPairToPemBuf(); + std::string plaintext = "I am a plaintext."; + + // WHEN & THEN + auto S = RsaSigner(sk); + auto signature = S.Sign(plaintext); + auto V = RsaVerifier(pk); + EXPECT_TRUE(V.Verify(plaintext, signature)); +} + +TEST(RsaSigning, SignVerify_shouldFail_wrong_message) { + // GIVEN + auto [pk, sk] = GenRsaKeyPairToPemBuf(); + std::string plaintext = "I am a plaintext."; + std::string faketext = "I am a faketext."; + + // WHEN & THEN + auto S = RsaSigner(sk); + auto signature = S.Sign(plaintext); + auto V = RsaVerifier(pk); + EXPECT_FALSE(V.Verify(faketext, signature)); +} + +TEST(RsaSigning, SignVerify_shouldFail_wrong_signature) { + // GIVEN + auto [pk, sk] = GenRsaKeyPairToPemBuf(); + std::string plaintext = "I am a plaintext."; + std::string faketext = "I am a faketext."; + + // WHEN & THEN + auto S = RsaSigner(sk); + auto fake_signature = S.Sign(faketext); + auto V = RsaVerifier(pk); + EXPECT_FALSE(V.Verify(plaintext, fake_signature)); +} + +TEST(RsaSigning, SignVerify_shouldFail_wrong_key) { + // GIVEN + auto [pk1, sk1] = GenRsaKeyPairToPemBuf(); + auto [pk2, sk2] = GenRsaKeyPairToPemBuf(); + + std::string plaintext = "I am a plaintext."; + + // WHEN & THEN + auto S = RsaSigner(sk1); + auto signature = S.Sign(plaintext); + auto V = RsaVerifier(pk2); + EXPECT_FALSE(V.Verify(plaintext, signature)); +} + +TEST(RsaSigning, SignVerifyInitWithCert_shouldOk) { + // GIVEN + auto [pk_buf, sk_buf] = GenRsaKeyPairToPemBuf(); /* pkey */ + auto pk = LoadKeyFromBuf(pk_buf); + auto sk = LoadKeyFromBuf(sk_buf); + auto cert = MakeX509Cert(pk, sk, + { + {"C", "CN"}, + {"ST", "ZJ"}, + {"L", "HZ"}, + {"O", "TEE"}, + {"OU", "EGG"}, + {"CN", "demo.trustedegg.com"}, + }, + 3, HashAlgorithm::SHA256); + auto cert_buf = ExportX509CertToBuf(cert); + + std::string plaintext = "I am a plaintext."; + + // WHEN & THEN + /* signer */ + auto S = RsaSigner(sk_buf); + auto signature = S.Sign(plaintext); + + /* verifier */ + auto cert_pk = LoadX509CertPublicKeyFromBuf(cert_buf); + auto V = RsaVerifier(std::move(cert_pk)); + EXPECT_TRUE(V.Verify(plaintext, signature)); +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/signing.h b/yacl/crypto/base/sign/signing.h similarity index 93% rename from yacl/crypto/base/signing.h rename to yacl/crypto/base/sign/signing.h index d0ab5e7a..a7abb820 100644 --- a/yacl/crypto/base/signing.h +++ b/yacl/crypto/base/sign/signing.h @@ -41,8 +41,8 @@ class AsymmetricVerifier { virtual SignatureScheme GetSignatureSchema() const = 0; - virtual void Verify(ByteContainerView message, + virtual bool Verify(ByteContainerView message, ByteContainerView signature) const = 0; }; -} // namespace yacl::crypto \ No newline at end of file +} // namespace yacl::crypto diff --git a/yacl/crypto/base/sign/sm2_signing.cc b/yacl/crypto/base/sign/sm2_signing.cc new file mode 100644 index 00000000..bbbd5f32 --- /dev/null +++ b/yacl/crypto/base/sign/sm2_signing.cc @@ -0,0 +1,95 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/base/sign/sm2_signing.h" + +#include "yacl/crypto/base/hash/hash_utils.h" + +namespace yacl::crypto { + +namespace { +// The default sm2 id. see: +// http://www.gmbz.org.cn/main/viewfile/2018011001400692565.html +constexpr std::string_view kDefaultSm2Id = {"1234567812345678"}; +} // namespace + +std::vector Sm2Signer::Sign(ByteContainerView message) const { + // SM2 signatures can be generated by using the ā€˜DigestSignā€™ series of APIs, + // for instance, EVP_DigestSignInit(), EVP_DigestSignUpdate() and + // EVP_DigestSignFinal(). Ditto for the verification process by calling the + // ā€˜DigestVerifyā€™ series of APIs. + // + // That is, EVP_PKEY_sign() and EVP_PKEY_verify() does not work on sm2 + // + // see: https://www.openssl.org/docs/man3.0/man7/EVP_PKEY-SM2.html + auto ctx = openssl::UniquePkeyCtx( + EVP_PKEY_CTX_new(sk_.get(), /* engine = default */ nullptr)); + YACL_ENFORCE(ctx != nullptr); + EVP_PKEY_CTX_set1_id(ctx.get(), kDefaultSm2Id.data(), kDefaultSm2Id.size()); + + // create message digest context + auto mctx = openssl::UniqueMdCtx(EVP_MD_CTX_new()); + YACL_ENFORCE(mctx != nullptr); + EVP_MD_CTX_set_pkey_ctx(mctx.get(), ctx.get()); // set it related to pkey ctx + + // init sign + YACL_ENFORCE(EVP_DigestSignInit( + mctx.get(), /* pkey ctx has already been inited */ nullptr, + EVP_sm3(), + /* engine */ nullptr, sk_.get()) > 0); + + // write hashes of message into mctx + YACL_ENFORCE( + EVP_DigestSignUpdate(mctx.get(), message.data(), message.size()) > 0); + + // get output size + size_t outlen = 0; + YACL_ENFORCE(EVP_DigestSignFinal(mctx.get(), nullptr, &outlen) > 0); + + std::vector out(outlen); + YACL_ENFORCE(EVP_DigestSignFinal(mctx.get(), out.data(), &outlen) > 0); + + // Correct the signature size (this is necessary! TODO: find out why) + out.resize(outlen); + + return out; +} + +bool Sm2Verifier::Verify(ByteContainerView message, + ByteContainerView signature) const { + auto ctx = openssl::UniquePkeyCtx( + EVP_PKEY_CTX_new(pk_.get(), /* engine = default */ nullptr)); + YACL_ENFORCE(ctx != nullptr); + EVP_PKEY_CTX_set1_id(ctx.get(), kDefaultSm2Id.data(), kDefaultSm2Id.size()); + + // create message digest context + auto mctx = openssl::UniqueMdCtx(EVP_MD_CTX_new()); + YACL_ENFORCE(mctx != nullptr); + + EVP_MD_CTX_set_pkey_ctx(mctx.get(), ctx.get()); + + YACL_ENFORCE(EVP_DigestVerifyInit( + mctx.get(), /* pkey ctx has already been inited */ nullptr, + EVP_sm3(), /* engine */ nullptr, pk_.get()) > 0); + + YACL_ENFORCE( + EVP_DigestVerifyUpdate(mctx.get(), message.data(), message.size()) > 0); + + int rc = + EVP_DigestVerifyFinal(mctx.get(), signature.data(), signature.size()); + YACL_ENFORCE(rc >= 0); // ret = 0, verify fail; ret = 1, verify success + return rc == 1; +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/sign/sm2_signing.h b/yacl/crypto/base/sign/sm2_signing.h new file mode 100644 index 00000000..3b540b20 --- /dev/null +++ b/yacl/crypto/base/sign/sm2_signing.h @@ -0,0 +1,61 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "yacl/crypto/base/key_utils.h" +#include "yacl/crypto/base/sign/signing.h" + +namespace yacl::crypto { + +class Sm2Signer final : public AsymmetricSigner { + public: + // constructors and destrucors + explicit Sm2Signer(openssl::UniquePkey&& sk) : sk_(std::move(sk)) {} + explicit Sm2Signer(/* pem key */ ByteContainerView sk_buf) + : sk_(LoadKeyFromBuf(sk_buf)) {} + + SignatureScheme GetSignatureSchema() const override { return scheme_; }; + + // Sign message with the default id. + std::vector Sign(ByteContainerView message) const override; + + private: + const openssl::UniquePkey sk_; + const SignatureScheme scheme_ = SignatureScheme::SM2_SIGNING_SM3_HASH; +}; + +// SM2 verify with SM3 (wrapper for OpenSSL) +class Sm2Verifier final : public AsymmetricVerifier { + public: + // constructors and destrucors + explicit Sm2Verifier(openssl::UniquePkey&& pk) : pk_(std::move(pk)) {} + explicit Sm2Verifier(/* pem key */ ByteContainerView pk_buf) + : pk_(LoadKeyFromBuf(pk_buf)) {} + + // return the scheme name + SignatureScheme GetSignatureSchema() const override { return scheme_; } + + // verify a message and its signature with stored public key + bool Verify(ByteContainerView message, + ByteContainerView signature) const override; + + private: + const openssl::UniquePkey pk_; + const SignatureScheme scheme_ = SignatureScheme::SM2_SIGNING_SM3_HASH; +}; + +// TODO @raofei: support sm2 certificate + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/sign/sm2_signing_test.cc b/yacl/crypto/base/sign/sm2_signing_test.cc new file mode 100644 index 00000000..44aff363 --- /dev/null +++ b/yacl/crypto/base/sign/sm2_signing_test.cc @@ -0,0 +1,105 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/base/sign/sm2_signing.h" + +#include "gtest/gtest.h" + +#include "yacl/crypto/base/openssl_wrappers.h" + +namespace yacl::crypto { + +TEST(Sm2Signing, SignVerify_shouldOk) { + // GIVEN + auto [pk, sk] = GenSm2KeyPairToPemBuf(); + std::string plaintext = "I am a plaintext."; + + // WHEN & THEN + auto S = Sm2Signer(sk); + auto signature = S.Sign(plaintext); + auto V = Sm2Verifier(pk); + EXPECT_EQ(V.Verify(plaintext, signature), true); +} + +TEST(Sm2Signing, SignVerify_shouldFail_wrong_message) { + // GIVEN + auto [pk, sk] = GenSm2KeyPairToPemBuf(); + std::string plaintext = "I am a plaintext."; + std::string faketext = "I am a faketext."; + + // WHEN & THEN + auto S = Sm2Signer(sk); + auto signature = S.Sign(plaintext); + auto V = Sm2Verifier(pk); + EXPECT_EQ(V.Verify(faketext, signature), false); +} + +TEST(Sm2Signing, SignVerify_shouldFail_wrong_signature) { + // GIVEN + auto [pk, sk] = GenSm2KeyPairToPemBuf(); + std::string plaintext = "I am a plaintext."; + std::string faketext = "I am a faketext."; + + // WHEN & THEN + auto S = Sm2Signer(sk); + auto fake_signature = S.Sign(faketext); + auto V = Sm2Verifier(pk); + EXPECT_EQ(V.Verify(plaintext, fake_signature), false); +} + +TEST(Sm2Signing, SignVerify_shouldFail_wrong_key) { + // GIVEN + auto [pk1, sk1] = GenSm2KeyPairToPemBuf(); + auto [pk2, sk2] = GenSm2KeyPairToPemBuf(); + + std::string plaintext = "I am a plaintext."; + + // WHEN & THEN + auto S = Sm2Signer(sk1); + auto signature = S.Sign(plaintext); + auto V = Sm2Verifier(pk2); + EXPECT_EQ(V.Verify(plaintext, signature), false); +} + +TEST(Sm2Signing, SignVerifyInitWithCert_shouldOk) { + // GIVEN + auto [pk_buf, sk_buf] = GenSm2KeyPairToPemBuf(); /* pkey */ + auto pk = LoadKeyFromBuf(pk_buf); + auto sk = LoadKeyFromBuf(sk_buf); + auto cert = MakeX509Cert(pk, sk, + { + {"C", "CN"}, + {"ST", "ZJ"}, + {"L", "HZ"}, + {"O", "TEE"}, + {"OU", "EGG"}, + {"CN", "demo.trustedegg.com"}, + }, + 3, HashAlgorithm::SM3); + auto cert_buf = ExportX509CertToBuf(cert); + + std::string plaintext = "I am a plaintext."; + + // WHEN & THEN + /* signer */ + auto S = Sm2Signer(sk_buf); + auto signature = S.Sign(plaintext); + + /* verifier */ + auto cert_pk = LoadX509CertPublicKeyFromBuf(cert_buf); + auto V = Sm2Verifier(std::move(cert_pk)); + EXPECT_EQ(V.Verify(plaintext, signature), true); +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/base/sm2_signing.cc b/yacl/crypto/base/sm2_signing.cc deleted file mode 100644 index 1d89fc71..00000000 --- a/yacl/crypto/base/sm2_signing.cc +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/sm2_signing.h" - -#include "absl/memory/memory.h" -#include "openssl/pem.h" - -#include "yacl/base/exception.h" -#include "yacl/crypto/base/asymmetric_util.h" -#include "yacl/utils/scope_guard.h" - -namespace yacl::crypto { - -std::unique_ptr Sm2Signer::CreateFromPem(ByteContainerView sm2_pem) { - // Using `new` to access a non-public constructor. - // ref https://abseil.io/tips/134 - return std::unique_ptr( - new Sm2Signer(internal::CreatePriPkeyFromSm2Pem(sm2_pem))); -} - -SignatureScheme Sm2Signer::GetSignatureSchema() const { return schema_; } - -std::vector Sm2Signer::Sign(ByteContainerView message) const { - return Sign(message, - ByteContainerView(SM2_ID_DEFAULT, SM2_ID_DEFAULT_LENGTH)); -} - -std::vector Sm2Signer::Sign(ByteContainerView message, - ByteContainerView id) const { - EVP_PKEY_CTX* p_ctx = EVP_PKEY_CTX_new(pkey_.get(), nullptr); - YACL_ENFORCE(p_ctx != nullptr); - ON_SCOPE_EXIT([&] { EVP_PKEY_CTX_free(p_ctx); }); - EVP_PKEY_CTX_set1_id(p_ctx, id.data(), id.size()); - EVP_MD_CTX* m_ctx = EVP_MD_CTX_new(); - YACL_ENFORCE(m_ctx != nullptr); - ON_SCOPE_EXIT([&] { EVP_MD_CTX_free(m_ctx); }); - EVP_MD_CTX_init(m_ctx); - EVP_MD_CTX_set_pkey_ctx(m_ctx, p_ctx); - - YACL_ENFORCE_GT( - EVP_DigestSignInit(m_ctx, nullptr, EVP_sm3(), nullptr, pkey_.get()), 0); - YACL_ENFORCE_GT(EVP_DigestSignUpdate(m_ctx, message.data(), message.size()), - 0); - - // Determine the size of the signature - // Note that sig_len is the max but not exact size of the output buffer. - // Ref https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestSignFinal.html - size_t sig_len; - YACL_ENFORCE_GT(EVP_DigestSignFinal(m_ctx, nullptr, &sig_len), 0); - std::vector signature(sig_len); - YACL_ENFORCE_GT(EVP_DigestSignFinal(m_ctx, signature.data(), &sig_len), 0); - // Correct the signature size. - signature.resize(sig_len); - - return signature; -} - -std::unique_ptr Sm2Verifier::CreateFromPem( - ByteContainerView sm2_pem) { - return std::unique_ptr( - new Sm2Verifier(internal::CreatePubPkeyFromSm2Pem(sm2_pem))); -} - -std::unique_ptr Sm2Verifier::CreateFromCertPem( - ByteContainerView sm2_cert_pem) { - UniqueBio bio_cert(BIO_new_mem_buf(sm2_cert_pem.data(), sm2_cert_pem.size()), - BIO_free); - X509* cert = PEM_read_bio_X509(bio_cert.get(), nullptr, nullptr, nullptr); - YACL_ENFORCE(cert != nullptr); - UniqueX509 unique_cert(cert, ::X509_free); - EVP_PKEY* pk = X509_get_pubkey(unique_cert.get()); - YACL_ENFORCE(pk != nullptr); - return std::unique_ptr( - new Sm2Verifier(UniquePkey(pk, ::EVP_PKEY_free))); -} - -std::unique_ptr Sm2Verifier::CreateFromOct( - ByteContainerView sm2_oct) { - EC_GROUP* group = EC_GROUP_new_by_curve_name(NID_sm2); - YACL_ENFORCE(nullptr != group); - ON_SCOPE_EXIT([&] { EC_GROUP_free(group); }); - - EC_POINT* ec_pub_key_pt = EC_POINT_new(group); - YACL_ENFORCE(nullptr != ec_pub_key_pt); - ON_SCOPE_EXIT([&] { EC_POINT_free(ec_pub_key_pt); }); - YACL_ENFORCE(EC_POINT_oct2point(group, ec_pub_key_pt, sm2_oct.data(), - sm2_oct.size(), nullptr)); - - EC_KEY* ec_key = EC_KEY_new(); - YACL_ENFORCE(nullptr != ec_key); - ON_SCOPE_EXIT([&] { EC_KEY_free(ec_key); }); - YACL_ENFORCE(EC_KEY_set_group(ec_key, group)); - YACL_ENFORCE(EC_KEY_set_public_key(ec_key, ec_pub_key_pt)); - EVP_PKEY* pk = EVP_PKEY_new(); - YACL_ENFORCE(nullptr != pk); - UniquePkey unique_pk(pk, ::EVP_PKEY_free); - YACL_ENFORCE(EVP_PKEY_set1_EC_KEY(unique_pk.get(), ec_key)); - YACL_ENFORCE(EVP_PKEY_set_alias_type(unique_pk.get(), EVP_PKEY_SM2)); - return std::unique_ptr(new Sm2Verifier(std::move(unique_pk))); -} - -std::unique_ptr Sm2Verifier::CreateFromCertDer( - ByteContainerView sm2_cert_der) { - UniqueBio bio_cert(BIO_new_mem_buf(sm2_cert_der.data(), sm2_cert_der.size()), - BIO_free); - X509* cert = d2i_X509_bio(bio_cert.get(), nullptr); - YACL_ENFORCE(cert != nullptr); - UniqueX509 unique_cert(cert, ::X509_free); - EVP_PKEY* pk = X509_get_pubkey(unique_cert.get()); - YACL_ENFORCE(pk != nullptr); - UniquePkey unique_pk(pk, ::EVP_PKEY_free); - return std::unique_ptr(new Sm2Verifier(std::move(unique_pk))); -} - -SignatureScheme Sm2Verifier::GetSignatureSchema() const { return schema_; } - -void Sm2Verifier::Verify(ByteContainerView message, - ByteContainerView signature) const { - return Verify(message, signature, - ByteContainerView(SM2_ID_DEFAULT, SM2_ID_DEFAULT_LENGTH)); -} - -void Sm2Verifier::Verify(ByteContainerView message, ByteContainerView signature, - ByteContainerView id) const { - EVP_PKEY_CTX* p_ctx = EVP_PKEY_CTX_new(pkey_.get(), nullptr); - YACL_ENFORCE(p_ctx != nullptr); - ON_SCOPE_EXIT([&] { EVP_PKEY_CTX_free(p_ctx); }); - EVP_PKEY_CTX_set1_id(p_ctx, id.data(), id.size()); - EVP_MD_CTX* m_ctx = EVP_MD_CTX_new(); - YACL_ENFORCE(m_ctx != nullptr); - ON_SCOPE_EXIT([&] { EVP_MD_CTX_free(m_ctx); }); - EVP_MD_CTX_set_pkey_ctx(m_ctx, p_ctx); - - YACL_ENFORCE_GT( - EVP_DigestVerifyInit(m_ctx, nullptr, EVP_sm3(), nullptr, pkey_.get()), 0); - YACL_ENFORCE_GT(EVP_DigestVerifyUpdate(m_ctx, message.data(), message.size()), - 0); - YACL_ENFORCE_GT( - EVP_DigestVerifyFinal(m_ctx, signature.data(), signature.size()), 0); -} - -} // namespace yacl::crypto \ No newline at end of file diff --git a/yacl/crypto/base/sm2_signing.h b/yacl/crypto/base/sm2_signing.h deleted file mode 100644 index c1f4fed2..00000000 --- a/yacl/crypto/base/sm2_signing.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include - -#include "openssl/bio.h" -#include "openssl/evp.h" -#include "openssl/x509.h" - -#include "yacl/crypto/base/signing.h" - -namespace yacl::crypto { - -// The length of default sm2 id. -inline constexpr size_t SM2_ID_DEFAULT_LENGTH = 16; -// The default sm2 id. -// Ref the last chapter of -// http://www.gmbz.org.cn/main/viewfile/2018011001400692565.html -inline constexpr char SM2_ID_DEFAULT[SM2_ID_DEFAULT_LENGTH + 1] = - "1234567812345678"; - -class Sm2Signer final : public crypto::AsymmetricSigner { - public: - using UniquePkey = std::unique_ptr; - - static std::unique_ptr CreateFromPem(ByteContainerView sm2_pem); - - SignatureScheme GetSignatureSchema() const override; - - // Sign message with the default id. - std::vector Sign(ByteContainerView message) const override; - // Sign message with the specific id. - std::vector Sign(ByteContainerView message, - ByteContainerView id) const; - - private: - explicit Sm2Signer(UniquePkey pkey) - : pkey_(std::move(pkey)), - schema_(SignatureScheme::SM2_SIGNING_SM3_HASH) {} - - const UniquePkey pkey_; - const SignatureScheme schema_; -}; - -class Sm2Verifier final : public crypto::AsymmetricVerifier { - public: - using UniquePkey = std::unique_ptr; - using UniqueBio = std::unique_ptr; - using UniqueX509 = std::unique_ptr; - - static std::unique_ptr CreateFromPem(ByteContainerView sm2_pem); - static std::unique_ptr CreateFromOct(ByteContainerView sm2_oct); - static std::unique_ptr CreateFromCertPem( - ByteContainerView sm2_cert_pem); - static std::unique_ptr CreateFromCertDer( - ByteContainerView sm2_cert_der); - - SignatureScheme GetSignatureSchema() const override; - - // Verify signature with the default id. - void Verify(ByteContainerView message, - ByteContainerView signature) const override; - - // Verify signature with the specific id. - void Verify(ByteContainerView message, ByteContainerView signature, - ByteContainerView id) const; - - private: - explicit Sm2Verifier(UniquePkey pkey) - : pkey_(std::move(pkey)), - schema_(SignatureScheme::SM2_SIGNING_SM3_HASH) {} - - const UniquePkey pkey_; - const SignatureScheme schema_; -}; - -// TODO @raofei: support sm2 certificate - -} // namespace yacl::crypto \ No newline at end of file diff --git a/yacl/crypto/base/sm2_signing_test.cc b/yacl/crypto/base/sm2_signing_test.cc deleted file mode 100644 index a66cdce2..00000000 --- a/yacl/crypto/base/sm2_signing_test.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/base/sm2_signing.h" - -#include "gtest/gtest.h" -#include "openssl/pem.h" - -#include "yacl/crypto/base/asymmetric_util.h" - -namespace yacl::crypto { - -TEST(Sm2Signing, SignVerify_shouldOk) { - // GIVEN - auto [public_key, private_key] = CreateSm2KeyPair(); - std::string plaintext = "I am a plaintext."; - - // WHEN & THEN - auto sm2_signer = Sm2Signer::CreateFromPem(private_key); - auto signature = sm2_signer->Sign(plaintext); - - auto sm2_verifier = Sm2Verifier::CreateFromPem(public_key); - sm2_verifier->Verify(plaintext, signature); -} - -} // namespace yacl::crypto \ No newline at end of file diff --git a/yacl/crypto/base/test/alg_data_test.cc b/yacl/crypto/base/test/alg_data_test.cc deleted file mode 100644 index 5f85b620..00000000 --- a/yacl/crypto/base/test/alg_data_test.cc +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2022 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "absl/strings/escaping.h" -#include "gtest/gtest.h" - -#include "yacl/base/int128.h" -#include "yacl/crypto/base/hash/ssl_hash.h" -#include "yacl/crypto/base/symmetric_crypto.h" -#include "yacl/crypto/tools/prg.h" - -namespace yacl::crypto { - -constexpr int kDataNum = 10; -std::vector aes_data_len = {16, 16, 16, 32, 32, 32, 48, 48, 48, 64}; -std::vector sha256_data_len = {3, 6, 9, 12, 15, 16, 16, 16, 32, 32}; - -void AesTestData(std::string &file_name, - SymmetricCrypto::CryptoType crypto_mode) { - uint128_t aes_key; - std::ofstream out_file; - out_file.open(file_name, std::ios::out /*| std::ios::app*/); - - Prg prg(0, PRG_MODE::kNistAesCtrDrbg); - - for (int i = 0; i < kDataNum; ++i) { - std::string aes_plain; - std::string aes_cipher; - std::string aes_decrypt; - - aes_key = prg(); - - aes_plain.resize(aes_data_len[i]); - aes_cipher.resize(aes_data_len[i]); - aes_decrypt.resize(aes_data_len[i]); - prg.Fill(absl::MakeSpan(aes_plain.data(), aes_plain.size())); - - SymmetricCrypto crypto(crypto_mode, aes_key, 0); - - crypto.Encrypt( - absl::MakeConstSpan(reinterpret_cast(aes_plain.data()), - aes_plain.size()), - absl::MakeSpan(reinterpret_cast(aes_cipher.data()), - aes_cipher.size())); - crypto.Decrypt( - absl::MakeConstSpan( - reinterpret_cast(aes_cipher.data()), - aes_cipher.size()), - absl::MakeSpan(reinterpret_cast(aes_decrypt.data()), - aes_decrypt.size())); - - out_file << std::endl << "=====" << i << "=====" << std::endl; - - out_file << "key(" << sizeof(uint128_t) << "): " << std::endl; - - out_file << absl::BytesToHexString( - absl::string_view(reinterpret_cast(&aes_key), - sizeof(uint128_t))) - << std::endl; - out_file << "plain(" << aes_plain.length() << "): " << std::endl; - out_file << absl::BytesToHexString(aes_plain) << std::endl; - out_file << "cipher(" << aes_cipher.length() << "): " << std::endl; - out_file << absl::BytesToHexString(aes_cipher) << std::endl; - - EXPECT_EQ(aes_decrypt, aes_plain); - } -} - -void Sha256TestData(std::string &file_name) { - std::ofstream out_file; - out_file.open(file_name, std::ios::out /*| std::ios::app*/); - - // prg - Prg prg(0, PRG_MODE::kNistAesCtrDrbg); - - for (size_t i = 0; i < sha256_data_len.size(); ++i) { - Sha256Hash sha256; - std::string hash_data(sha256_data_len[i], '\0'); - prg.Fill(absl::MakeSpan(hash_data.data(), hash_data.size())); - - sha256.Update(hash_data); - std::vector hash_result = sha256.CumulativeHash(); - out_file << "=====" << i << "=====" << std::endl; - out_file << "data(" << hash_data.length() << "):" << std::endl; - out_file << absl::BytesToHexString(hash_data) << std::endl; - out_file << "hash(" << hash_result.size() << "):" << std::endl; - out_file << absl::BytesToHexString(std::string_view( - reinterpret_cast(hash_result.data()), - hash_result.size())) - << std::endl; - } -} - -} // namespace yacl::crypto - -int main(int /*argc*/, char ** /*argv*/) { - std::string aes_ecb_file_name = "aes_ecb_data.txt"; - std::string aes_ctr_file_name = "aes_ctr_data.txt"; - std::string sha256_file_name = "sha256_data.txt"; - std::string curve25519_file_name = "curve25519_data.txt"; - - AesTestData(aes_ecb_file_name, - yacl::crypto::SymmetricCrypto::CryptoType::AES128_ECB); - AesTestData(aes_ctr_file_name, - yacl::crypto::SymmetricCrypto::CryptoType::AES128_CTR); - yacl::crypto::Sha256TestData(sha256_file_name); - - return 0; -} diff --git a/yacl/crypto/primitives/code/BUILD.bazel b/yacl/crypto/primitives/code/BUILD.bazel new file mode 100644 index 00000000..87e4daa3 --- /dev/null +++ b/yacl/crypto/primitives/code/BUILD.bazel @@ -0,0 +1,115 @@ +# Copyright 2021 Ant Group Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//bazel:yacl.bzl", "yacl_cc_binary", "yacl_cc_library", "yacl_cc_test") + +package(default_visibility = ["//visibility:public"]) + +yacl_cc_library( + name = "code_interface", + hdrs = ["code_interface.h"], +) + +yacl_cc_library( + name = "linear_code", + hdrs = ["linear_code.h"], + deps = [ + ":code_interface", + "//yacl/crypto/tools:rp", + "//yacl/math:gadget", + "//yacl/utils:thread_pool", + ] + select({ + "@platforms//cpu:aarch64": [ + "@com_github_dltcollab_sse2neon//:sse2neon", + ], + "//conditions:default": [], + }), +) + +yacl_cc_test( + name = "linear_code_test", + srcs = ["linear_code_test.cc"], + deps = [ + ":linear_code", + "//yacl/crypto/utils:rand", + ], +) + +yacl_cc_library( + name = "silver_code", + srcs = ["silver_code.cc"], + hdrs = ["silver_code.h"], + deps = [ + ":code_interface", + "//yacl/base:block", + "//yacl/base:int128", + "//yacl/utils:thread_pool", + ] + select({ + "@platforms//cpu:aarch64": [ + "@com_github_dltcollab_sse2neon//:sse2neon", + ], + "//conditions:default": [], + }), +) + +yacl_cc_test( + name = "silver_code_test", + srcs = ["silver_code_test.cc"], + deps = [ + ":silver_code", + "//yacl/crypto/utils:rand", + ], +) + +yacl_cc_library( + name = "ea_code", + hdrs = ["ea_code.h"], + deps = [ + ":code_interface", + ":linear_code", + "//yacl/base:block", + "//yacl/base:int128", + "//yacl/utils:thread_pool", + ] + select({ + "@platforms//cpu:aarch64": [ + "@com_github_dltcollab_sse2neon//:sse2neon", + ], + "//conditions:default": [], + }), +) + +yacl_cc_test( + name = "ea_code_test", + srcs = ["ea_code_test.cc"], + deps = [ + ":ea_code", + "//yacl/crypto/utils:rand", + ], +) + +yacl_cc_binary( + name = "benchmark", + srcs = [ + "benchmark.cc", + "benchmark.h", + ], + deps = [ + ":ea_code", + ":linear_code", + ":silver_code", + "//yacl/base:aligned_vector", + "//yacl/crypto/utils:rand", + "@com_github_google_benchmark//:benchmark_main", + ], +) diff --git a/yacl/crypto/primitives/code/benchmark.cc b/yacl/crypto/primitives/code/benchmark.cc new file mode 100644 index 00000000..9075f128 --- /dev/null +++ b/yacl/crypto/primitives/code/benchmark.cc @@ -0,0 +1,44 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/primitives/code/benchmark.h" + +namespace yacl::crypto { + +void BM_DualEncodeArguments(benchmark::internal::Benchmark* b) { + b->Unit(benchmark::kMillisecond) + ->Iterations(10) + ->Arg(100000) + ->Arg(1000000) // one million + ->Arg(10000000) // ten million + ->Arg(22437250); +} + +// Register benchmarks for local linear code +BENCHMARK_REGISTER_F(CodeBench, LLC) + ->Unit(benchmark::kMillisecond) + ->Iterations(10) + ->Args({10485760, 452000}); + +// Register benchmarks for dual LPN +BENCHMARK_REGISTER_F(CodeBench, Silver5)->Apply(BM_DualEncodeArguments); +BENCHMARK_REGISTER_F(CodeBench, Silver5Inplace)->Apply(BM_DualEncodeArguments); +BENCHMARK_REGISTER_F(CodeBench, Silver11)->Apply(BM_DualEncodeArguments); +BENCHMARK_REGISTER_F(CodeBench, Silver11Inplace)->Apply(BM_DualEncodeArguments); +BENCHMARK_REGISTER_F(CodeBench, ExAcc7)->Apply(BM_DualEncodeArguments); +BENCHMARK_REGISTER_F(CodeBench, ExAcc11)->Apply(BM_DualEncodeArguments); +BENCHMARK_REGISTER_F(CodeBench, ExAcc21)->Apply(BM_DualEncodeArguments); +BENCHMARK_REGISTER_F(CodeBench, ExAcc40)->Apply(BM_DualEncodeArguments); + +} // namespace yacl::crypto diff --git a/yacl/crypto/primitives/code/benchmark.h b/yacl/crypto/primitives/code/benchmark.h new file mode 100644 index 00000000..914dc3f9 --- /dev/null +++ b/yacl/crypto/primitives/code/benchmark.h @@ -0,0 +1,119 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include "benchmark/benchmark.h" + +#include "yacl/base/aligned_vector.h" +#include "yacl/crypto/primitives/code/ea_code.h" +#include "yacl/crypto/primitives/code/linear_code.h" +#include "yacl/crypto/primitives/code/silver_code.h" +#include "yacl/crypto/utils/rand.h" + +namespace yacl::crypto { + +class CodeBench : public benchmark::Fixture {}; + +// 1st arg = n (generor matrix) +// 2nd arg = k (generor matrix) +BENCHMARK_DEFINE_F(CodeBench, LLC)(benchmark::State& state) { + for (auto _ : state) { + state.PauseTiming(); + { + auto n = state.range(0); + auto k = state.range(1); + uint128_t seed = FastRandSeed(); + LocalLinearCode<10> llc(seed, n, k); + auto input = RandVec(k); + std::vector out(n); + + state.ResumeTiming(); + + llc.Encode(input, absl::MakeSpan(out)); + + state.PauseTiming(); + } + state.ResumeTiming(); + } +} + +// 1st arg = n (output size) +#define DELCARE_SLV_INPLACE_BENCH(weight) \ + BENCHMARK_DEFINE_F(CodeBench, Silver##weight##Inplace) \ + (benchmark::State & state) { \ + for (auto _ : state) { \ + state.PauseTiming(); \ + { \ + auto n = state.range(0); \ + SilverCode slv(n, weight); \ + auto input = RandVec(n * 2); \ + state.ResumeTiming(); \ + slv.DualEncodeInplace(absl::MakeSpan(input)); \ + state.PauseTiming(); \ + } \ + state.ResumeTiming(); \ + } \ + } + +// 1st arg = n (output size) +#define DELCARE_SLV_BENCH(weight) \ + BENCHMARK_DEFINE_F(CodeBench, Silver##weight)(benchmark::State & state) { \ + for (auto _ : state) { \ + state.PauseTiming(); \ + { \ + auto n = state.range(0); \ + SilverCode slv(n, weight); \ + auto input = RandVec(n * 2); \ + auto output = std::vector(n); \ + state.ResumeTiming(); \ + slv.DualEncode(absl::MakeSpan(input), absl::MakeSpan(output)); \ + state.PauseTiming(); \ + } \ + state.ResumeTiming(); \ + } \ + } + +DELCARE_SLV_BENCH(5); +DELCARE_SLV_INPLACE_BENCH(5); +DELCARE_SLV_BENCH(11); +DELCARE_SLV_INPLACE_BENCH(11); + +// 1st arg = n (output size) +#define DELCARE_EXACC_BENCH(weight) \ + BENCHMARK_DEFINE_F(CodeBench, ExAcc##weight)(benchmark::State & state) { \ + for (auto _ : state) { \ + state.PauseTiming(); \ + { \ + auto n = state.range(0); \ + ExAccCode acc(n); \ + auto input = RandVec(n * 2); \ + auto output = std::vector(n); \ + state.ResumeTiming(); \ + acc.DualEncode(absl::MakeSpan(input), absl::MakeSpan(output)); \ + state.PauseTiming(); \ + } \ + state.ResumeTiming(); \ + } \ + } + +DELCARE_EXACC_BENCH(7); +DELCARE_EXACC_BENCH(11); +DELCARE_EXACC_BENCH(21); +DELCARE_EXACC_BENCH(40); + +} // namespace yacl::crypto diff --git a/yacl/crypto/tools/code_interface.h b/yacl/crypto/primitives/code/code_interface.h similarity index 100% rename from yacl/crypto/tools/code_interface.h rename to yacl/crypto/primitives/code/code_interface.h diff --git a/yacl/crypto/tools/expand_accumulate_code.h b/yacl/crypto/primitives/code/ea_code.h similarity index 95% rename from yacl/crypto/tools/expand_accumulate_code.h rename to yacl/crypto/primitives/code/ea_code.h index af74f35b..ecb837f8 100644 --- a/yacl/crypto/tools/expand_accumulate_code.h +++ b/yacl/crypto/primitives/code/ea_code.h @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include "absl/types/span.h" @@ -27,8 +29,8 @@ #include "yacl/base/block.h" #include "yacl/base/exception.h" #include "yacl/base/int128.h" -#include "yacl/crypto/tools/code_interface.h" -#include "yacl/crypto/tools/linear_code.h" +#include "yacl/crypto/primitives/code/code_interface.h" +#include "yacl/crypto/primitives/code/linear_code.h" namespace yacl::crypto { @@ -157,9 +159,8 @@ class ExAccCode : public ExAccCodeInterface { template inline void Accumulate(absl::Span inout) const { - for (uint32_t i = 1; i < m_; ++i) { - inout[i] ^= inout[i - 1]; - } + std::partial_sum(inout.cbegin(), inout.cend(), inout.begin(), + std::bit_xor()); } template diff --git a/yacl/crypto/tools/expand_accumulate_code_test.cc b/yacl/crypto/primitives/code/ea_code_test.cc similarity index 99% rename from yacl/crypto/tools/expand_accumulate_code_test.cc rename to yacl/crypto/primitives/code/ea_code_test.cc index 4d014102..1de220eb 100644 --- a/yacl/crypto/tools/expand_accumulate_code_test.cc +++ b/yacl/crypto/primitives/code/ea_code_test.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "yacl/crypto/tools/expand_accumulate_code.h" +#include "yacl/crypto/primitives/code/ea_code.h" #include diff --git a/yacl/crypto/tools/linear_code.h b/yacl/crypto/primitives/code/linear_code.h similarity index 98% rename from yacl/crypto/tools/linear_code.h rename to yacl/crypto/primitives/code/linear_code.h index 37943201..a940ce20 100644 --- a/yacl/crypto/tools/linear_code.h +++ b/yacl/crypto/primitives/code/linear_code.h @@ -21,8 +21,8 @@ #include "yacl/base/exception.h" #include "yacl/base/int128.h" -#include "yacl/crypto/tools/code_interface.h" -#include "yacl/crypto/tools/random_permutation.h" +#include "yacl/crypto/primitives/code/code_interface.h" +#include "yacl/crypto/tools/rp.h" #include "yacl/math/gadget.h" #ifndef __aarch64__ @@ -233,7 +233,7 @@ class LocalLinearCode : public LinearCodeInterface { private: uint32_t n_; // num uint32_t k_; // dimention - RandomPerm rp_; + RP rp_; uint32_t mask_; uint128_t extend_mask_; uint128_t extend_k_; diff --git a/yacl/crypto/tools/linear_code_test.cc b/yacl/crypto/primitives/code/linear_code_test.cc similarity index 94% rename from yacl/crypto/tools/linear_code_test.cc rename to yacl/crypto/primitives/code/linear_code_test.cc index b5161910..5a1f36f1 100644 --- a/yacl/crypto/tools/linear_code_test.cc +++ b/yacl/crypto/primitives/code/linear_code_test.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "yacl/crypto/tools/linear_code.h" +#include "yacl/crypto/primitives/code/linear_code.h" #include @@ -24,7 +24,7 @@ namespace yacl::crypto { TEST(Llc, LlcWorks) { // GIVEN - uint128_t seed = RandSeed(); + uint128_t seed = FastRandSeed(); uint32_t n = 102400; uint32_t k = 1024; LocalLinearCode<10> llc(seed, n, k); diff --git a/yacl/crypto/tools/silver_code.cc b/yacl/crypto/primitives/code/silver_code.cc similarity index 99% rename from yacl/crypto/tools/silver_code.cc rename to yacl/crypto/primitives/code/silver_code.cc index 8140492d..2e522ebf 100644 --- a/yacl/crypto/tools/silver_code.cc +++ b/yacl/crypto/primitives/code/silver_code.cc @@ -12,9 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "yacl/crypto/tools/silver_code.h" - -#include +#include "yacl/crypto/primitives/code/silver_code.h" #include #include diff --git a/yacl/crypto/tools/silver_code.h b/yacl/crypto/primitives/code/silver_code.h similarity index 98% rename from yacl/crypto/tools/silver_code.h rename to yacl/crypto/primitives/code/silver_code.h index def390d6..246dfea7 100644 --- a/yacl/crypto/tools/silver_code.h +++ b/yacl/crypto/primitives/code/silver_code.h @@ -27,7 +27,7 @@ #include "yacl/base/block.h" #include "yacl/base/exception.h" #include "yacl/base/int128.h" -#include "yacl/crypto/tools/code_interface.h" +#include "yacl/crypto/primitives/code/code_interface.h" namespace yacl::crypto { diff --git a/yacl/crypto/tools/silver_code_test.cc b/yacl/crypto/primitives/code/silver_code_test.cc similarity index 88% rename from yacl/crypto/tools/silver_code_test.cc rename to yacl/crypto/primitives/code/silver_code_test.cc index 21ae6264..94388d76 100644 --- a/yacl/crypto/tools/silver_code_test.cc +++ b/yacl/crypto/primitives/code/silver_code_test.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "yacl/crypto/tools/silver_code.h" +#include "yacl/crypto/primitives/code/silver_code.h" #include @@ -104,16 +104,16 @@ DECLARE_SILVER_TEST_BY_WEIGHT(5); DECLARE_SILVER_TEST_BY_WEIGHT(11); INSTANTIATE_TEST_SUITE_P(Works_Instances, SilverCodeTest, - testing::Values(TestParams{11}, // edge - TestParams{47}, // - TestParams{48}, // - TestParams{63}, // - TestParams{64}, // - TestParams{99}, // - TestParams{100}, // - TestParams{101}, // - TestParams{10000}, // ten thousand - TestParams{1000000} // one million + testing::Values(TestParams{11}, // edge + TestParams{47}, // + TestParams{48}, // + TestParams{63}, // + TestParams{64}, // + TestParams{99}, // + TestParams{100}, // + TestParams{101}, // + TestParams{10000} // ten thousand + // TestParams{1000000} // one million )); } // namespace yacl::crypto diff --git a/yacl/crypto/primitives/ot/BUILD.bazel b/yacl/crypto/primitives/ot/BUILD.bazel index d083b47e..b49e1a22 100644 --- a/yacl/crypto/primitives/ot/BUILD.bazel +++ b/yacl/crypto/primitives/ot/BUILD.bazel @@ -24,6 +24,7 @@ yacl_cc_library( "//yacl/base:aligned_vector", "//yacl/base:dynamic_bitset", "//yacl/base:int128", + "//yacl/crypto/tools:prg", "//yacl/crypto/utils:rand", "//yacl/link:context", ], @@ -51,7 +52,7 @@ yacl_cc_library( deps = [ ":base_ot_interface", "//yacl/base:exception", - "//yacl/crypto/tools:random_oracle", + "//yacl/crypto/tools:ro", "//yacl/link", "@simplest_ot//:simplest_ot_portable", ], @@ -68,7 +69,7 @@ yacl_cc_library( deps = [ ":base_ot_interface", "//yacl/base:exception", - "//yacl/crypto/tools:random_oracle", + "//yacl/crypto/tools:ro", "//yacl/link", "//yacl/math:gadget", "@simplest_ot//:simplest_ot_x86_asm", @@ -111,8 +112,9 @@ yacl_cc_library( hdrs = ["iknp_ote.h"], deps = [ ":ot_store", + "//yacl/crypto/tools:crhash", "//yacl/crypto/tools:prg", - "//yacl/crypto/tools:random_permutation", + "//yacl/crypto/tools:rp", "//yacl/crypto/utils:secparam", "//yacl/link", "//yacl/utils:matrix_utils", @@ -141,8 +143,8 @@ yacl_cc_library( "//yacl/crypto/base/aes:aes_opt", "//yacl/crypto/base/hash:hash_utils", "//yacl/crypto/tools:prg", - "//yacl/crypto/tools:random_oracle", - "//yacl/crypto/tools:random_permutation", + "//yacl/crypto/tools:ro", + "//yacl/crypto/tools:rp", "//yacl/crypto/utils:rand", "//yacl/crypto/utils:secparam", "//yacl/link", @@ -168,8 +170,10 @@ yacl_cc_library( deps = [ ":ot_store", "//yacl/crypto/base/aes:aes_opt", + "//yacl/crypto/tools:crhash", "//yacl/crypto/tools:prg", - "//yacl/crypto/tools:random_permutation", + "//yacl/crypto/tools:ro", + "//yacl/crypto/tools:rp", "//yacl/crypto/utils:rand", "//yacl/crypto/utils:secparam", "//yacl/link", @@ -197,8 +201,9 @@ yacl_cc_library( ":ot_store", "//yacl/base:aligned_vector", "//yacl/crypto/base/aes:aes_opt", + "//yacl/crypto/tools:crhash", "//yacl/crypto/tools:prg", - "//yacl/crypto/tools:random_permutation", + "//yacl/crypto/tools:rp", "//yacl/crypto/utils:rand", "//yacl/crypto/utils:secparam", "//yacl/link", @@ -228,11 +233,11 @@ yacl_cc_library( deps = [ ":ot_store", "//yacl/base:exception", + "//yacl/crypto/primitives/code:linear_code", "//yacl/crypto/primitives/ot:gywz_ote", "//yacl/crypto/primitives/ot:sgrr_ote", - "//yacl/crypto/tools:linear_code", "//yacl/crypto/tools:prg", - "//yacl/crypto/tools:random_permutation", + "//yacl/crypto/tools:rp", "//yacl/crypto/utils:rand", "//yacl/crypto/utils:secparam", "//yacl/link", @@ -261,8 +266,9 @@ yacl_cc_library( "//yacl/base:dynamic_bitset", "//yacl/base:exception", "//yacl/base:int128", + "//yacl/crypto/tools:crhash", "//yacl/crypto/tools:prg", - "//yacl/crypto/tools:random_permutation", + "//yacl/crypto/tools:rp", "//yacl/crypto/utils:rand", "//yacl/crypto/utils:secparam", "//yacl/link", @@ -292,9 +298,11 @@ yacl_cc_library( ":sgrr_ote", "//yacl/base:exception", "//yacl/base:int128", + "//yacl/crypto/tools:crhash", "//yacl/crypto/tools:prg", - "//yacl/crypto/tools:random_permutation", + "//yacl/crypto/tools:rp", "//yacl/link", + "//yacl/math/f2k", "//yacl/utils:matrix_utils", ] + select({ "@platforms//cpu:aarch64": [ diff --git a/yacl/crypto/primitives/ot/base_ot.h b/yacl/crypto/primitives/ot/base_ot.h index d69b73ad..44b74e8b 100644 --- a/yacl/crypto/primitives/ot/base_ot.h +++ b/yacl/crypto/primitives/ot/base_ot.h @@ -25,10 +25,10 @@ #include "yacl/crypto/utils/secparam.h" #include "yacl/link/link.h" -namespace yacl::crypto { - YACL_MODULE_DECLARE("base_ot", SecParam::C::k128, SecParam::S::INF); +namespace yacl::crypto { + using Block = uint128_t; void BaseOtRecv(const std::shared_ptr& ctx, diff --git a/yacl/crypto/primitives/ot/benchmark.cc b/yacl/crypto/primitives/ot/benchmark.cc index 4de052c2..280dd9f2 100644 --- a/yacl/crypto/primitives/ot/benchmark.cc +++ b/yacl/crypto/primitives/ot/benchmark.cc @@ -25,7 +25,7 @@ namespace yacl::crypto { void BM_DefaultArguments(benchmark::internal::Benchmark* b) { - b->Arg(8192)->Unit(benchmark::kMillisecond); + b->Arg(8192)->Unit(benchmark::kMillisecond)->Iterations(1); } void BM_PerfArguments(benchmark::internal::Benchmark* b) { @@ -39,7 +39,7 @@ void BM_PerfArguments(benchmark::internal::Benchmark* b) { ->Iterations(10); } -// BM_REGISTER_ALL_OT(BM_DefaultArguments); +BM_REGISTER_ALL_OT(BM_DefaultArguments); // Equivalent to the following // BM_REGISTER_SIMPLEST_OT(BM_DefaultArguments); @@ -48,7 +48,8 @@ void BM_PerfArguments(benchmark::internal::Benchmark* b) { // BM_REGISTER_KKRT_OTE(BM_DefaultArguments); // BM_REGISTER_SGRR_OTE(BM_DefaultArguments); // BM_REGISTER_GYWZ_OTE(BM_PerfArguments); +// BM_REGISTER_FERRET_OTE(BM_PerfArguments); // BM_REGISTER_SOFTSPOKEN_OTE(BM_PerfArguments); -BM_REGISTER_FERRET_OTE(BM_PerfArguments); +// BM_REGISTER_MAL_SOFTSPOKEN_OTE(BM_PerfArguments); } // namespace yacl::crypto diff --git a/yacl/crypto/primitives/ot/benchmark.h b/yacl/crypto/primitives/ot/benchmark.h index c4f2937a..a2ef2166 100644 --- a/yacl/crypto/primitives/ot/benchmark.h +++ b/yacl/crypto/primitives/ot/benchmark.h @@ -311,6 +311,54 @@ BENCHMARK_DEFINE_F(OtBench, FerretOTe)(benchmark::State& state) { state.ResumeTiming(); } } +#define DELCARE_MAL_SOFTSPOKEN_BENCH(K) \ + BENCHMARK_DEFINE_F(OtBench, MalSoftspokenOTe##K)(benchmark::State & state) { \ + YACL_ENFORCE(lctxs_.size() == 2); \ + for (auto _ : state) { \ + state.PauseTiming(); \ + { \ + const auto num_ot = state.range(0); \ + std::vector> send_blocks(num_ot); \ + std::vector recv_blocks(num_ot); \ + auto choices = RandBits>(num_ot); \ + auto base_ot = MockRots(128); \ + auto ssSenderTask = std::async([&] { \ + auto ssSender = SoftspokenOtExtSender(K, 0, true); \ + ssSender.OneTimeSetup(lctxs_[0], base_ot.recv); \ + return ssSender; \ + }); \ + auto ssReceiverTask = std::async([&] { \ + auto ssReceiver = SoftspokenOtExtReceiver(K, 0, true); \ + ssReceiver.OneTimeSetup(lctxs_[1], base_ot.send); \ + return ssReceiver; \ + }); \ + auto ssSender = ssSenderTask.get(); \ + auto ssReceiver = ssReceiverTask.get(); \ + state.ResumeTiming(); \ + /* true (default) for COT, false for ROT */ \ + auto sender = std::async([&] { \ + ssSender.Send(lctxs_[0], absl::MakeSpan(send_blocks), true); \ + }); \ + auto receiver = std::async([&] { \ + ssReceiver.Recv(lctxs_[1], choices, absl::MakeSpan(recv_blocks), \ + true); \ + }); \ + sender.get(); \ + receiver.get(); \ + state.PauseTiming(); \ + } \ + state.ResumeTiming(); \ + } \ + } + +DELCARE_MAL_SOFTSPOKEN_BENCH(1) +DELCARE_MAL_SOFTSPOKEN_BENCH(2) +DELCARE_MAL_SOFTSPOKEN_BENCH(3) +DELCARE_MAL_SOFTSPOKEN_BENCH(4) +DELCARE_MAL_SOFTSPOKEN_BENCH(5) +DELCARE_MAL_SOFTSPOKEN_BENCH(6) +DELCARE_MAL_SOFTSPOKEN_BENCH(7) +DELCARE_MAL_SOFTSPOKEN_BENCH(8) #define BM_REGISTER_SIMPLEST_OT(Arguments) \ BENCHMARK_REGISTER_F(OtBench, SimplestOT)->Apply(Arguments); @@ -340,6 +388,16 @@ BENCHMARK_DEFINE_F(OtBench, FerretOTe)(benchmark::State& state) { BENCHMARK_REGISTER_F(OtBench, SoftspokenOTe7)->Apply(Arguments); \ BENCHMARK_REGISTER_F(OtBench, SoftspokenOTe8)->Apply(Arguments); +#define BM_REGISTER_MAL_SOFTSPOKEN_OTE(Arguments) \ + BENCHMARK_REGISTER_F(OtBench, MalSoftspokenOTe1)->Apply(Arguments); \ + BENCHMARK_REGISTER_F(OtBench, MalSoftspokenOTe2)->Apply(Arguments); \ + BENCHMARK_REGISTER_F(OtBench, MalSoftspokenOTe3)->Apply(Arguments); \ + BENCHMARK_REGISTER_F(OtBench, MalSoftspokenOTe4)->Apply(Arguments); \ + BENCHMARK_REGISTER_F(OtBench, MalSoftspokenOTe5)->Apply(Arguments); \ + BENCHMARK_REGISTER_F(OtBench, MalSoftspokenOTe6)->Apply(Arguments); \ + BENCHMARK_REGISTER_F(OtBench, MalSoftspokenOTe7)->Apply(Arguments); \ + BENCHMARK_REGISTER_F(OtBench, MalSoftspokenOTe8)->Apply(Arguments); + #define BM_REGISTER_FERRET_OTE(Arguments) \ BENCHMARK_REGISTER_F(OtBench, FerretOTe)->Apply(Arguments); @@ -350,6 +408,7 @@ BENCHMARK_DEFINE_F(OtBench, FerretOTe)(benchmark::State& state) { BM_REGISTER_KKRT_OTE(Arguments) \ BM_REGISTER_SGRR_OTE(Arguments) \ BM_REGISTER_GYWZ_OTE(Arguments) \ + BM_REGISTER_FERRET_OTE(Arguments) \ BM_REGISTER_SOFTSPOKEN_OTE(Arguments) \ - BM_REGISTER_FERRET_OTE(Arguments) + BM_REGISTER_MAL_SOFTSPOKEN_OTE(Arguments) } // namespace yacl::crypto diff --git a/yacl/crypto/primitives/ot/ferret_ote.cc b/yacl/crypto/primitives/ot/ferret_ote.cc index 71f58c75..fb80b78d 100644 --- a/yacl/crypto/primitives/ot/ferret_ote.cc +++ b/yacl/crypto/primitives/ot/ferret_ote.cc @@ -20,11 +20,11 @@ #include #include "yacl/base/aligned_vector.h" +#include "yacl/crypto/primitives/code/linear_code.h" #include "yacl/crypto/primitives/ot/ferret_ote_rn.h" #include "yacl/crypto/primitives/ot/ferret_ote_un.h" #include "yacl/crypto/primitives/ot/gywz_ote.h" #include "yacl/crypto/primitives/ot/ot_store.h" -#include "yacl/crypto/tools/linear_code.h" #include "yacl/math/gadget.h" #include "yacl/utils/cuckoo_index.h" #include "yacl/utils/serialize.h" diff --git a/yacl/crypto/primitives/ot/ferret_ote.h b/yacl/crypto/primitives/ot/ferret_ote.h index f4a4a6ff..359aa476 100644 --- a/yacl/crypto/primitives/ot/ferret_ote.h +++ b/yacl/crypto/primitives/ot/ferret_ote.h @@ -20,30 +20,11 @@ #include #include "yacl/crypto/primitives/ot/ot_store.h" +#include "yacl/crypto/utils/secparam.h" #include "yacl/math/gadget.h" #include "yacl/utils/cuckoo_index.h" - namespace yacl::crypto { -enum class LpnNoiseAsm { RegularNoise, UniformNoise }; - -// For more parameter choices, see results in -// https://eprint.iacr.org/2019/273.pdf Page 20, Table 1. -class LpnParam { - public: - uint64_t n = 10485760; // primal lpn, security param = 128 - uint64_t k = 452000; // primal lpn, security param = 128 - uint64_t t = 1280; // primal lpn, security param = 128 - LpnNoiseAsm noise_asm = LpnNoiseAsm::RegularNoise; - - LpnParam(uint64_t n, uint64_t k, uint64_t t, LpnNoiseAsm noise_asm) - : n(n), k(k), t(t), noise_asm(noise_asm) {} - - static LpnParam GetDefault() { - return {10485760, 452000, 1280, LpnNoiseAsm::RegularNoise}; - } -}; - // Ferret OT Extension Implementation // // This implementation bases on Ferret OTE, for more theoretical details, see @@ -63,7 +44,7 @@ class LpnParam { // // Security assumptions: // > Correlation-robust hash function, for more details about its -// implementation, see `yacl/crypto-tools/random_permutation.h` +// implementation, see `yacl/crypto-tools/rp.h` // > Primal LPN, for more details, please see the original paper uint64_t FerretCotHelper(const LpnParam& lpn_param, uint64_t ot_num); @@ -76,6 +57,12 @@ OtRecvStore FerretOtExtRecv(const std::shared_ptr& ctx, const OtRecvStore& base_cot, const LpnParam& lpn_param, uint64_t ot_num); +// +// -------------------------- +// Customized +// -------------------------- +// +// [Warning] for cheetah only void FerretOtExtSend_cheetah(const std::shared_ptr& ctx, const OtSendStore& base_cot, const LpnParam& lpn_param, uint64_t ot_num, diff --git a/yacl/crypto/primitives/ot/ferret_ote_rn.h b/yacl/crypto/primitives/ot/ferret_ote_rn.h index 1e4fd28d..7721d13c 100644 --- a/yacl/crypto/primitives/ot/ferret_ote_rn.h +++ b/yacl/crypto/primitives/ot/ferret_ote_rn.h @@ -22,10 +22,10 @@ #include "yacl/crypto/primitives/ot/gywz_ote.h" #include "yacl/crypto/utils/secparam.h" -namespace yacl::crypto { - YACL_MODULE_DECLARE("ferret_ote_rn", SecParam::C::k128, SecParam::S::INF); +namespace yacl::crypto { + uint64_t MpCotRNHelper(uint64_t idx_num, uint64_t idx_range) { const auto batch_size = (idx_range + idx_num - 1) / idx_num; const auto last_size = idx_range - batch_size * (idx_num - 1); diff --git a/yacl/crypto/primitives/ot/ferret_ote_test.cc b/yacl/crypto/primitives/ot/ferret_ote_test.cc index 17db6761..aac9462f 100644 --- a/yacl/crypto/primitives/ot/ferret_ote_test.cc +++ b/yacl/crypto/primitives/ot/ferret_ote_test.cc @@ -122,12 +122,13 @@ INSTANTIATE_TEST_SUITE_P( Works_Instances, FerretOtExtTest, testing::Values(FerretParams{10485760, LpnNoiseAsm::RegularNoise}, FerretParams{10485761, LpnNoiseAsm::RegularNoise}, - FerretParams{1 << 20, LpnNoiseAsm::RegularNoise}, - FerretParams{1 << 21, LpnNoiseAsm::RegularNoise}, - FerretParams{1 << 22, LpnNoiseAsm::RegularNoise}, - FerretParams{1 << 23, LpnNoiseAsm::RegularNoise}, - FerretParams{1 << 24, LpnNoiseAsm::RegularNoise}, - FerretParams{1 << 25, LpnNoiseAsm::RegularNoise})); + FerretParams{1 << 20, LpnNoiseAsm::RegularNoise} + // FerretParams{1 << 21, LpnNoiseAsm::RegularNoise}, + // FerretParams{1 << 22, LpnNoiseAsm::RegularNoise}, + // FerretParams{1 << 23, LpnNoiseAsm::RegularNoise}, + // FerretParams{1 << 24, LpnNoiseAsm::RegularNoise}, + // FerretParams{1 << 25, LpnNoiseAsm::RegularNoise} + )); TEST(FerretOtExtEdgeTest, Test1) { // GIVEN diff --git a/yacl/crypto/primitives/ot/ferret_ote_un.h b/yacl/crypto/primitives/ot/ferret_ote_un.h index b4fe6f9a..3583ed8c 100644 --- a/yacl/crypto/primitives/ot/ferret_ote_un.h +++ b/yacl/crypto/primitives/ot/ferret_ote_un.h @@ -21,22 +21,22 @@ #include "yacl/crypto/primitives/ot/ferret_ote.h" #include "yacl/crypto/primitives/ot/gywz_ote.h" -#include "yacl/crypto/tools/random_permutation.h" +#include "yacl/crypto/tools/rp.h" #include "yacl/crypto/utils/secparam.h" #include "yacl/math/gadget.h" #include "yacl/utils/cuckoo_index.h" -namespace yacl::crypto { - YACL_MODULE_DECLARE("ferret_ote_un", SecParam::C::k128, SecParam::S::INF); +namespace yacl::crypto { + using FerretSimpleMap = std::vector>; constexpr auto kFerretRpType = SymmetricCrypto::CryptoType::AES128_ECB; constexpr auto kFerretRpSeed = 0x12345678; // FIXME: use different seeds constexpr auto kFerretCuckooHashNum = 3; constexpr auto kFerretCuckooStashNum = 0; -const auto RP = RandomPerm(kFerretRpType, kFerretRpSeed); // for cuckoo +const auto kRP = RP(kFerretRpType, kFerretRpSeed); // for cuckoo // create simple map std::unique_ptr MakeSimpleMap( @@ -50,7 +50,7 @@ std::unique_ptr MakeSimpleMap( std::iota(idx_blocks.begin(), idx_blocks.end(), 0); // random permutation - auto idxes_h = RP.Gen(idx_blocks); + auto idxes_h = kRP.Gen(idx_blocks); // for each index (value), calculate its cuckoo bin_idx for (uint64_t i = 0; i < n; ++i) { @@ -147,7 +147,7 @@ void MpCotUNRecv(const std::shared_ptr& ctx, // random permutation AlignedVector idx_blocks(idxes.begin(), idxes.end()); - auto idxes_h = RP.Gen(idx_blocks); + auto idxes_h = kRP.Gen(idx_blocks); CuckooIndex cuckoo_index(cuckoo_option); cuckoo_index.Insert(absl::MakeSpan(idxes_h)); diff --git a/yacl/crypto/primitives/ot/gywz_ote.cc b/yacl/crypto/primitives/ot/gywz_ote.cc index 9de27730..5fed04a6 100644 --- a/yacl/crypto/primitives/ot/gywz_ote.cc +++ b/yacl/crypto/primitives/ot/gywz_ote.cc @@ -17,15 +17,13 @@ #include #include "yacl/base/aligned_vector.h" -#include "yacl/base/buffer.h" #include "yacl/base/byte_container_view.h" #include "yacl/base/dynamic_bitset.h" #include "yacl/base/exception.h" -#include "yacl/base/int128.h" #include "yacl/crypto/base/aes/aes_opt.h" #include "yacl/crypto/primitives/ot/ot_store.h" +#include "yacl/crypto/tools/crhash.h" #include "yacl/crypto/tools/prg.h" -#include "yacl/crypto/tools/random_permutation.h" #include "yacl/math/gadget.h" namespace yacl::crypto { @@ -55,13 +53,13 @@ void CggmFullEval(uint128_t delta, uint128_t seed, uint32_t n, for (uint32_t level = 1; level < height; ++level) { // the number of node in next level should be double prev_size <<= 1; - uint128_t left_child_sum = 0; + uint128_t left_side_sum = 0; auto left_side = working_seeds.subspan(0, prev_size); auto right_side = working_seeds.subspan(prev_size, prev_size); if (!is_two_power && level == height - 1) { // all_msgs doesn't have enough space to store all leaves - extra_buff.resize(static_cast(1) << (height - 1)); - right_side = absl::MakeSpan(extra_buff.data(), prev_size); + extra_buff.resize(prev_size); // pre_size = 1 << (height - 1) + right_side = absl::MakeSpan(extra_buff); } // copy previous seeds into right side @@ -72,9 +70,9 @@ void CggmFullEval(uint128_t delta, uint128_t seed, uint32_t n, for (uint32_t i = 0; i < prev_size; ++i) { left_side[i] &= one; right_side[i] ^= left_side[i]; - left_child_sum ^= left_side[i]; + left_side_sum ^= left_side[i]; } - left_sums[level] = left_child_sum; + left_sums[level] = left_side_sum; } // copy right side leaves to all_msgs if (!is_two_power) { @@ -106,13 +104,13 @@ void CggmPuncFullEval(uint32_t index, absl::Span sibling_sums, // the number of seeds in next level prev_size <<= 1; uint128_t left_side_sum = sibling_sums[level]; - uint128_t right_side_sum = sibling_sums[level]; + // uint128_t right_side_sum = sibling_sums[level]; auto left_side = working_seeds.subspan(0, prev_size); auto right_side = working_seeds.subspan(prev_size, prev_size); if (!is_two_power && level == height - 1) { // punctured_msgs doesn't have enough space to store all leaves - extra_buff.resize(static_cast(1) << (height - 1)); - right_side = absl::MakeSpan(extra_buff.data(), prev_size); + extra_buff.resize(prev_size); // pre_size = 1 << (height - 1) + right_side = absl::MakeSpan(extra_buff); } // copy previous seeds into right side @@ -124,10 +122,11 @@ void CggmPuncFullEval(uint32_t index, absl::Span sibling_sums, left_side[i] &= one; left_side_sum ^= left_side[i]; right_side[i] ^= left_side[i]; - right_side_sum ^= right_side[i]; + // meaningless, right_side_sum == left_side_sum + // right_side_sum ^= right_side[i]; } left_side[punctured_idx] ^= left_side_sum; - right_side[punctured_idx] ^= right_side_sum; + right_side[punctured_idx] ^= left_side_sum; // update punctured index punctured_idx |= index & mask; } @@ -256,9 +255,9 @@ void GywzOtExtSend_ferret(const std::shared_ptr& ctx, "GYWZ_OTE: messages"); } -void GywzOtExtRecv_fixindex(const std::shared_ptr& ctx, - const OtRecvStore& cot, uint32_t n, - absl::Span output) { +void GywzOtExtRecv_fixed_index(const std::shared_ptr& ctx, + const OtRecvStore& cot, uint32_t n, + absl::Span output) { const uint32_t height = math::Log2Ceil(n); YACL_ENFORCE(cot.Size() == height); YACL_ENFORCE_GE(n, (uint32_t)1); @@ -269,18 +268,18 @@ void GywzOtExtRecv_fixindex(const std::shared_ptr& ctx, auto recv_msgs = absl::MakeSpan(reinterpret_cast(recv_buf.data()), height); - GywzOtExtRecv_fixindex(cot, n, output, recv_msgs); + GywzOtExtRecv_fixed_index(cot, n, output, recv_msgs); } -void GywzOtExtSend_fixindex(const std::shared_ptr& ctx, - const OtSendStore& cot, uint32_t n, - absl::Span output) { +void GywzOtExtSend_fixed_index(const std::shared_ptr& ctx, + const OtSendStore& cot, uint32_t n, + absl::Span output) { uint32_t height = math::Log2Ceil(n); YACL_ENFORCE(cot.Size() == height); YACL_ENFORCE_GE(n, (uint32_t)1); AlignedVector left_sums(height); - GywzOtExtSend_fixindex(cot, n, output, absl::MakeSpan(left_sums)); + GywzOtExtSend_fixed_index(cot, n, output, absl::MakeSpan(left_sums)); ctx->SendAsync( ctx->NextRank(), @@ -288,9 +287,9 @@ void GywzOtExtSend_fixindex(const std::shared_ptr& ctx, "GYWZ_OTE: messages"); } -void GywzOtExtRecv_fixindex(const OtRecvStore& cot, uint32_t n, - absl::Span output, - absl::Span recv_msgs) { +void GywzOtExtRecv_fixed_index(const OtRecvStore& cot, uint32_t n, + absl::Span output, + absl::Span recv_msgs) { const uint32_t height = math::Log2Ceil(n); YACL_ENFORCE(cot.Size() == height); YACL_ENFORCE_GE(n, (uint32_t)1); @@ -309,9 +308,9 @@ void GywzOtExtRecv_fixindex(const OtRecvStore& cot, uint32_t n, CggmPuncFullEval(index, absl::MakeConstSpan(sibling_sums), n, output); } -void GywzOtExtSend_fixindex(const OtSendStore& cot, uint32_t n, - absl::Span output, - absl::Span send_msgs) { +void GywzOtExtSend_fixed_index(const OtSendStore& cot, uint32_t n, + absl::Span output, + absl::Span send_msgs) { uint32_t height = math::Log2Ceil(n); YACL_ENFORCE(cot.Size() == height); YACL_ENFORCE_GE(n, (uint32_t)1); @@ -320,7 +319,6 @@ void GywzOtExtSend_fixindex(const OtSendStore& cot, uint32_t n, uint128_t delta = cot.GetDelta(); uint128_t seed = SecureRandSeed(); CggmFullEval(delta, seed, n, output, send_msgs); - for (uint32_t i = 0; i < height; ++i) { send_msgs[i] ^= cot.GetBlock(i, 1); } diff --git a/yacl/crypto/primitives/ot/gywz_ote.h b/yacl/crypto/primitives/ot/gywz_ote.h index f24f287f..6d1f2edd 100644 --- a/yacl/crypto/primitives/ot/gywz_ote.h +++ b/yacl/crypto/primitives/ot/gywz_ote.h @@ -25,6 +25,8 @@ #include "yacl/crypto/utils/secparam.h" #include "yacl/link/link.h" +YACL_MODULE_DECLARE("gywz_ote", SecParam::C::INF, SecParam::S::INF); + namespace yacl::crypto { // // GYWZ OT Extension (Half Tree) Implementation @@ -43,10 +45,8 @@ namespace yacl::crypto { // // Security assumptions: // - Circular correlation-robust Hash, for more details -// see yacl/crypto/tools/random_permutation.h +// see yacl/crypto/tools/rp.h // -YACL_MODULE_DECLARE("gywz_ote", SecParam::C::INF, SecParam::S::INF); - void GywzOtExtRecv(const std::shared_ptr& ctx, const OtRecvStore& cot, uint32_t n, uint32_t index, absl::Span output); @@ -55,6 +55,10 @@ void GywzOtExtSend(const std::shared_ptr& ctx, const OtSendStore& cot, uint32_t n, absl::Span output); +// -------------------------- +// Customized +// -------------------------- +// // [Warning] For ferretOTe only // Random single-point COT, where punctured index is determined by cot choices // The output for sender and receiver would be SAME, when punctured @@ -73,22 +77,22 @@ void GywzOtExtSend_ferret(const std::shared_ptr& ctx, // Notice that: // > In such cases, punctured index would be the choice of cot // > punctured index might be greater than n -void GywzOtExtRecv_fixindex(const std::shared_ptr& ctx, - const OtRecvStore& cot, uint32_t n, - absl::Span output); +void GywzOtExtRecv_fixed_index(const std::shared_ptr& ctx, + const OtRecvStore& cot, uint32_t n, + absl::Span output); -void GywzOtExtSend_fixindex(const std::shared_ptr& ctx, - const OtSendStore& cot, uint32_t n, - absl::Span output); +void GywzOtExtSend_fixed_index(const std::shared_ptr& ctx, + const OtSendStore& cot, uint32_t n, + absl::Span output); // non-interactive function, Receiver should receive "recv_msgs" from Sender -void GywzOtExtRecv_fixindex(const OtRecvStore& cot, uint32_t n, - absl::Span output, - absl::Span recv_msgs); +void GywzOtExtRecv_fixed_index(const OtRecvStore& cot, uint32_t n, + absl::Span output, + absl::Span recv_msgs); // non-interactive function, Sender should send "send_msgs" to Receiver -void GywzOtExtSend_fixindex(const OtSendStore& cot, uint32_t n, - absl::Span output, - absl::Span send_msgs); +void GywzOtExtSend_fixed_index(const OtSendStore& cot, uint32_t n, + absl::Span output, + absl::Span send_msgs); } // namespace yacl::crypto diff --git a/yacl/crypto/primitives/ot/gywz_ote_test.cc b/yacl/crypto/primitives/ot/gywz_ote_test.cc index bd584b19..1e1d8666 100644 --- a/yacl/crypto/primitives/ot/gywz_ote_test.cc +++ b/yacl/crypto/primitives/ot/gywz_ote_test.cc @@ -123,10 +123,12 @@ TEST_P(GywzParamTest, FixIndexSpCotWork) { std::vector recv_out(n); std::future sender = std::async([&] { - GywzOtExtRecv_fixindex(lctxs[0], base_ot.recv, n, absl::MakeSpan(recv_out)); + GywzOtExtRecv_fixed_index(lctxs[0], base_ot.recv, n, + absl::MakeSpan(recv_out)); }); std::future receiver = std::async([&] { - GywzOtExtSend_fixindex(lctxs[1], base_ot.send, n, absl::MakeSpan(send_out)); + GywzOtExtSend_fixed_index(lctxs[1], base_ot.send, n, + absl::MakeSpan(send_out)); }); sender.get(); receiver.get(); diff --git a/yacl/crypto/primitives/ot/iknp_ote.cc b/yacl/crypto/primitives/ot/iknp_ote.cc index b15d77b0..61aac5d5 100644 --- a/yacl/crypto/primitives/ot/iknp_ote.cc +++ b/yacl/crypto/primitives/ot/iknp_ote.cc @@ -19,7 +19,7 @@ #include #include "yacl/crypto/tools/prg.h" -#include "yacl/crypto/tools/random_permutation.h" +#include "yacl/crypto/tools/rp.h" #include "yacl/utils/matrix_utils.h" namespace yacl::crypto { diff --git a/yacl/crypto/primitives/ot/iknp_ote.h b/yacl/crypto/primitives/ot/iknp_ote.h index 5543e6e2..ff86312a 100644 --- a/yacl/crypto/primitives/ot/iknp_ote.h +++ b/yacl/crypto/primitives/ot/iknp_ote.h @@ -21,9 +21,12 @@ #include "yacl/base/dynamic_bitset.h" #include "yacl/crypto/primitives/ot/ot_store.h" +#include "yacl/crypto/tools/crhash.h" #include "yacl/crypto/utils/secparam.h" #include "yacl/link/link.h" +YACL_MODULE_DECLARE("iknp_ote", SecParam::C::k128, SecParam::S::INF); + namespace yacl::crypto { // IKNP OT Extension Implementation @@ -43,10 +46,7 @@ namespace yacl::crypto { // // Security assumptions: // *. correlation-robust hash function, for more details about its -// implementation, see `yacl/crypto-tools/random_permutation.h` - -// iknp's security param declaration -YACL_MODULE_DECLARE("iknp_ote", SecParam::C::k128, SecParam::S::INF); +// implementation, see `yacl/crypto-tools/rp.h` void IknpOtExtSend(const std::shared_ptr &ctx, const OtRecvStore &base_ot, diff --git a/yacl/crypto/primitives/ot/kkrt_ote.cc b/yacl/crypto/primitives/ot/kkrt_ote.cc index 726ed70c..805d5b97 100644 --- a/yacl/crypto/primitives/ot/kkrt_ote.cc +++ b/yacl/crypto/primitives/ot/kkrt_ote.cc @@ -24,10 +24,10 @@ #include "yacl/base/byte_container_view.h" #include "yacl/base/int128.h" #include "yacl/crypto/base/aes/aes_opt.h" +#include "yacl/crypto/base/block_cipher/symmetric_crypto.h" #include "yacl/crypto/base/hash/hash_utils.h" -#include "yacl/crypto/base/symmetric_crypto.h" #include "yacl/crypto/tools/prg.h" -#include "yacl/crypto/tools/random_oracle.h" +#include "yacl/crypto/tools/ro.h" #include "yacl/crypto/utils/rand.h" #include "yacl/utils/matrix_utils.h" #include "yacl/utils/serialize.h" diff --git a/yacl/crypto/primitives/ot/kkrt_ote.h b/yacl/crypto/primitives/ot/kkrt_ote.h index 425b2c3e..2462a9ba 100644 --- a/yacl/crypto/primitives/ot/kkrt_ote.h +++ b/yacl/crypto/primitives/ot/kkrt_ote.h @@ -24,6 +24,8 @@ #include "yacl/crypto/utils/secparam.h" #include "yacl/link/link.h" +YACL_MODULE_DECLARE("kkrt_ote", SecParam::C::k128, SecParam::S::INF); + namespace yacl::crypto { inline constexpr int kKkrtWidth = 4; // KKRT width @@ -45,7 +47,7 @@ using KkrtRow = std::array; // // Security assumptions: // *. correlation-robust hash function, for more details about its -// implementation, see `yacl/crypto-tools/random_permutation.h` +// implementation, see `yacl/crypto/tools/rp.h` // // NOTE // * OT Extension sender requires receiver base ot context. @@ -107,8 +109,6 @@ class IGroupPRF { // - This function requires base ot width to 512 now. Let us cut this to 128 // by implicitly calling IKNP inside KKRT. -YACL_MODULE_DECLARE("kkrt_ote", SecParam::C::k128, SecParam::S::INF); - std::unique_ptr KkrtOtExtSend( const std::shared_ptr& ctx, const OtRecvStore& base_ot, size_t num_ot); diff --git a/yacl/crypto/primitives/ot/kos_ote.cc b/yacl/crypto/primitives/ot/kos_ote.cc index 464f6029..ea17bfe0 100644 --- a/yacl/crypto/primitives/ot/kos_ote.cc +++ b/yacl/crypto/primitives/ot/kos_ote.cc @@ -22,9 +22,9 @@ #include "yacl/base/byte_container_view.h" #include "yacl/base/int128.h" -#include "yacl/crypto/base/drbg/sm4_drbg.h" +#include "yacl/crypto/tools/crhash.h" #include "yacl/crypto/tools/prg.h" -#include "yacl/crypto/tools/random_permutation.h" +#include "yacl/crypto/tools/rp.h" #include "yacl/crypto/utils/rand.h" #include "yacl/math/f2k/f2k.h" #include "yacl/utils/matrix_utils.h" diff --git a/yacl/crypto/primitives/ot/kos_ote.h b/yacl/crypto/primitives/ot/kos_ote.h index 7ec383b0..cf3e6400 100644 --- a/yacl/crypto/primitives/ot/kos_ote.h +++ b/yacl/crypto/primitives/ot/kos_ote.h @@ -23,6 +23,10 @@ #include "yacl/crypto/utils/secparam.h" #include "yacl/link/link.h" +YACL_MODULE_DECLARE("kos_ote", SecParam::C::k128, SecParam::S::k64); + +namespace yacl::crypto { + // KOS OT Extension Implementation (Malicious Secure) // // This implementation bases on KOS OTE, for more theoretical details, see @@ -50,10 +54,6 @@ // - KOS security proof (asymptotic) https://eprint.iacr.org/2022/1371.pdf // -namespace yacl::crypto { - -YACL_MODULE_DECLARE("kos_ote", SecParam::C::k128, SecParam::S::k64); - void KosOtExtSend(const std::shared_ptr& ctx, const OtRecvStore& base_ot, absl::Span> send_blocks, diff --git a/yacl/crypto/primitives/ot/ot_store.cc b/yacl/crypto/primitives/ot/ot_store.cc index 0bc38040..b5bb9888 100644 --- a/yacl/crypto/primitives/ot/ot_store.cc +++ b/yacl/crypto/primitives/ot/ot_store.cc @@ -538,7 +538,7 @@ MockOtStore MockRots(uint64_t num, dynamic_bitset choices) { AlignedVector recv_blocks; AlignedVector> send_blocks; - Prg gen(RandSeed()); + Prg gen(FastRandSeed()); for (uint64_t i = 0; i < num; ++i) { send_blocks.push_back({gen(), gen()}); recv_blocks.push_back(send_blocks[i][choices[i]]); @@ -559,7 +559,7 @@ MockOtStore MockCots(uint64_t num, uint128_t delta, AlignedVector recv_blocks; AlignedVector send_blocks; - Prg gen(RandSeed()); + Prg gen(FastRandSeed()); for (uint64_t i = 0; i < num; ++i) { auto msg = gen(); send_blocks.push_back(msg); @@ -575,12 +575,12 @@ MockOtStore MockCots(uint64_t num, uint128_t delta, } MockOtStore MockCompactOts(uint64_t num) { - uint128_t delta = RandU128(); + uint128_t delta = FastRandU128(); delta |= 0x1; // make sure its last bits = 1; AlignedVector recv_blocks; AlignedVector send_blocks; - Prg gen(RandSeed()); + Prg gen(FastRandSeed()); for (uint64_t i = 0; i < num; ++i) { auto recv_msg = gen(); auto choice = recv_msg & 0x1; diff --git a/yacl/crypto/primitives/ot/ot_store_test.cc b/yacl/crypto/primitives/ot/ot_store_test.cc index 1dd339ec..5a40be8f 100644 --- a/yacl/crypto/primitives/ot/ot_store_test.cc +++ b/yacl/crypto/primitives/ot/ot_store_test.cc @@ -25,6 +25,7 @@ #include "gtest/gtest.h" #include "yacl/base/exception.h" +#include "yacl/crypto/tools/prg.h" #include "yacl/crypto/utils/rand.h" #include "yacl/link/test_util.h" @@ -64,7 +65,7 @@ RandOtSendStore(uint64_t /*num*/) { inline std::pair>> RandCompactOtSendStore(uint64_t num) { auto inputs = RandVec(num); - auto delta = RandU128(); + auto delta = FastRandU128(); std::vector> blocks; for (uint64_t i = 0; i < num; i++) { blocks.push_back({inputs[i], inputs[i] ^ delta}); @@ -268,7 +269,7 @@ TEST(MockRotTest, Works) { TEST(MockCotTest, Works) { // GIVEN const size_t ot_num = 2; - auto delta = RandU128(); + auto delta = FastRandU128(); // WHEN auto cot = MockCots(ot_num, delta); diff --git a/yacl/crypto/primitives/ot/portable_ot_interface.cc b/yacl/crypto/primitives/ot/portable_ot_interface.cc index 0c9cedc8..bdf83c2d 100644 --- a/yacl/crypto/primitives/ot/portable_ot_interface.cc +++ b/yacl/crypto/primitives/ot/portable_ot_interface.cc @@ -18,7 +18,7 @@ #include "simplest_ot_portable/ot_sender.h" #include "yacl/base/exception.h" -#include "yacl/crypto/tools/random_oracle.h" +#include "yacl/crypto/tools/ro.h" namespace yacl::crypto { diff --git a/yacl/crypto/primitives/ot/sgrr_ote.cc b/yacl/crypto/primitives/ot/sgrr_ote.cc index 197ef0aa..7e53aa3b 100644 --- a/yacl/crypto/primitives/ot/sgrr_ote.cc +++ b/yacl/crypto/primitives/ot/sgrr_ote.cc @@ -26,8 +26,10 @@ #include "yacl/base/exception.h" #include "yacl/base/int128.h" #include "yacl/crypto/base/aes/aes_opt.h" +#include "yacl/crypto/tools/crhash.h" #include "yacl/crypto/tools/prg.h" -#include "yacl/crypto/tools/random_permutation.h" +#include "yacl/crypto/tools/ro.h" +#include "yacl/crypto/tools/rp.h" #include "yacl/crypto/utils/rand.h" #include "yacl/math/gadget.h" @@ -100,7 +102,7 @@ std::vector SplitAllSeeds(absl::Span seeds) { void SgrrOtExtRecv(const std::shared_ptr& ctx, const OtRecvStore& base_ot, uint32_t n, uint32_t index, - absl::Span output) { + absl::Span output, bool mal) { uint32_t ot_num = math::Log2Ceil(n); YACL_ENFORCE_GE(n, (uint32_t)1); // range should > 1 YACL_ENFORCE_GE((uint32_t)128, base_ot.Size()); // base ot num < 128 @@ -157,11 +159,45 @@ void SgrrOtExtRecv(const std::shared_ptr& ctx, output[inserted_idx] = insert_val; } } + + // check consistency + if (mal) { + size_t size = n; + + std::vector> s; + std::array, 2> t = {}; // set zeros + + for (size_t i = 0; i < size; ++i) { + s.emplace_back(Blake3(ByteContainerView(&output[i], sizeof(uint128_t)))); + // t[0] = t[0] xor s[i] + std::transform(s[i].cbegin(), s[i].cend(), t[0].cbegin(), t[0].begin(), + std::bit_xor()); + } + // t[0] = t[0] xor s[index] + std::transform(s[index].cbegin(), s[index].cend(), t[0].cbegin(), + t[0].begin(), std::bit_xor()); + + auto buff = ctx->Recv(ctx->NextRank(), "SGRR_OTE:RECV-PROOF"); + YACL_ENFORCE(buff.size() == 64); + std::array, 2> recv_t; + memcpy(recv_t.data(), buff.data(), buff.size()); + + // s[index] = t[0] xor recv_t[index] + std::transform(recv_t[0].cbegin(), recv_t[0].cend(), t[0].cbegin(), + s[index].begin(), std::bit_xor()); + + t[1] = Blake3(ByteContainerView(s.data(), s.size() * 32)); + YACL_ENFORCE(ByteContainerView(t[1]) == ByteContainerView(recv_t[1])); + + // refresh output + ParaCrHashInplace_128(output.subspan(0, n)); + output[index] = 0; + } } void SgrrOtExtSend(const std::shared_ptr& ctx, const OtSendStore& base_ot, uint32_t n, - absl::Span output) { + absl::Span output, bool mal) { uint32_t ot_num = math::Log2Ceil(n); YACL_ENFORCE_GE(base_ot.Size(), ot_num); YACL_ENFORCE_GE(n, (uint32_t)1); @@ -200,6 +236,24 @@ void SgrrOtExtSend(const std::shared_ptr& ctx, ctx->NextRank(), ByteContainerView(send_msgs.data(), ot_num * 2 * sizeof(uint128_t)), "SGRR_OTE:SEND-CORR"); + + // prove consistency + if (mal) { + size_t size = n; + std::vector> s; + std::array, 2> t = {}; // set zeros + for (size_t i = 0; i < size; ++i) { + s.emplace_back(Blake3(ByteContainerView(&output[i], sizeof(uint128_t)))); + // t[0] = t[0] xor s[i] + std::transform(s[i].cbegin(), s[i].cend(), t[0].cbegin(), t[0].begin(), + std::bit_xor()); + } + t[1] = Blake3(ByteContainerView(s.data(), s.size() * 32)); + ctx->SendAsync(ctx->NextRank(), ByteContainerView(t.data(), 64), + "SGRR_OTE:SEND-PROOF"); + // Refresh output + ParaCrHashInplace_128(output.subspan(0, n)); + } } // Notice that: @@ -207,24 +261,24 @@ void SgrrOtExtSend(const std::shared_ptr& ctx, // > punctured index might be greater than n // So, please do NOT use "FixIndexSgrrOtExtRecv" and "FixIndexSgrrOtExtSend", // unless you are certainly sure how do these algorithms work. -void SgrrOtExtRecv_fixindex(const std::shared_ptr& ctx, - const OtRecvStore& base_ot, uint32_t n, - absl::Span output) { +void SgrrOtExtRecv_fixed_index(const std::shared_ptr& ctx, + const OtRecvStore& base_ot, uint32_t n, + absl::Span output) { uint32_t ot_num = math::Log2Ceil(n); auto recv_buf = ctx->Recv(ctx->NextRank(), "SGRR_OTE:RECV-CORR"); YACL_ENFORCE(recv_buf.size() >= static_cast(ot_num * 2 * sizeof(uint128_t))); auto recv_msgs = absl::MakeSpan( reinterpret_cast*>(recv_buf.data()), ot_num); - SgrrOtExtRecv_fixindex(base_ot, n, output, absl::MakeSpan(recv_msgs)); + SgrrOtExtRecv_fixed_index(base_ot, n, output, absl::MakeSpan(recv_msgs)); } -void SgrrOtExtSend_fixindex(const std::shared_ptr& ctx, - const OtSendStore& base_ot, uint32_t n, - absl::Span output) { +void SgrrOtExtSend_fixed_index(const std::shared_ptr& ctx, + const OtSendStore& base_ot, uint32_t n, + absl::Span output) { uint32_t ot_num = math::Log2Ceil(n); std::vector> send_msgs(ot_num); - SgrrOtExtSend_fixindex(base_ot, n, output, absl::MakeSpan(send_msgs)); + SgrrOtExtSend_fixed_index(base_ot, n, output, absl::MakeSpan(send_msgs)); ctx->SendAsync( ctx->NextRank(), @@ -232,9 +286,9 @@ void SgrrOtExtSend_fixindex(const std::shared_ptr& ctx, "SGRR_OTE:SEND-CORR"); } -void SgrrOtExtRecv_fixindex(const OtRecvStore& base_ot, uint32_t n, - absl::Span output, - absl::Span> recv_msgs) { +void SgrrOtExtRecv_fixed_index(const OtRecvStore& base_ot, uint32_t n, + absl::Span output, + absl::Span> recv_msgs) { uint32_t ot_num = math::Log2Ceil(n); YACL_ENFORCE_GE(n, (uint32_t)1); // range should > 1 YACL_ENFORCE_GE((uint32_t)128, base_ot.Size()); // base ot num < 128 @@ -277,9 +331,9 @@ void SgrrOtExtRecv_fixindex(const OtRecvStore& base_ot, uint32_t n, } } -void SgrrOtExtSend_fixindex(const OtSendStore& base_ot, uint32_t n, - absl::Span output, - absl::Span> send_msgs) { +void SgrrOtExtSend_fixed_index(const OtSendStore& base_ot, uint32_t n, + absl::Span output, + absl::Span> send_msgs) { uint32_t ot_num = math::Log2Ceil(n); YACL_ENFORCE_GE(base_ot.Size(), ot_num); YACL_ENFORCE_GE(n, (uint32_t)1); diff --git a/yacl/crypto/primitives/ot/sgrr_ote.h b/yacl/crypto/primitives/ot/sgrr_ote.h index 59839be7..b3fc4707 100644 --- a/yacl/crypto/primitives/ot/sgrr_ote.h +++ b/yacl/crypto/primitives/ot/sgrr_ote.h @@ -23,6 +23,8 @@ #include "yacl/crypto/utils/secparam.h" #include "yacl/link/link.h" +YACL_MODULE_DECLARE("sgrr_ote", SecParam::C::INF, SecParam::S::INF); + namespace yacl::crypto { // Implementation of (n-1)-out-of-n Random OT (also called oblivious punctured @@ -46,33 +48,38 @@ namespace yacl::crypto { // https://crypto.stackexchange.com/questions/38039 // https://stackoverflow.com/questions/50402168 -YACL_MODULE_DECLARE("sgrr_ote", SecParam::C::INF, SecParam::S::INF); - void SgrrOtExtRecv(const std::shared_ptr& ctx, const OtRecvStore& base_ot, uint32_t n, uint32_t index, - absl::Span output); + absl::Span output, bool mal = false); void SgrrOtExtSend(const std::shared_ptr& ctx, const OtSendStore& base_ot, uint32_t n, - absl::Span output); + absl::Span output, bool mal = false); +// +// -------------------------- +// Customized +// -------------------------- +// // Notice that: // > In such cases, punctured index would be the choice of cot // > punctured index might be greater than n -void SgrrOtExtRecv_fixindex(const std::shared_ptr& ctx, - const OtRecvStore& base_ot, uint32_t n, - absl::Span output); +void SgrrOtExtRecv_fixed_index(const std::shared_ptr& ctx, + const OtRecvStore& base_ot, uint32_t n, + absl::Span output, bool mal = false); + +void SgrrOtExtSend_fixed_index(const std::shared_ptr& ctx, + const OtSendStore& base_ot, uint32_t n, + absl::Span output, bool mal = false); -void SgrrOtExtSend_fixindex(const std::shared_ptr& ctx, - const OtSendStore& base_ot, uint32_t n, - absl::Span output); // non-interactive function, Receiver should receive "recv_msgs" from Sender -void SgrrOtExtRecv_fixindex(const OtRecvStore& base_ot, uint32_t n, - absl::Span output, - absl::Span> recv_msg); +void SgrrOtExtRecv_fixed_index(const OtRecvStore& base_ot, uint32_t n, + absl::Span output, + absl::Span> recv_msg); + // non-interactive function, Sender should send "send_msg" to Receiver -void SgrrOtExtSend_fixindex(const OtSendStore& base_ot, uint32_t n, - absl::Span output, - absl::Span> send_msg); +void SgrrOtExtSend_fixed_index(const OtSendStore& base_ot, uint32_t n, + absl::Span output, + absl::Span> send_msg); } // namespace yacl::crypto diff --git a/yacl/crypto/primitives/ot/sgrr_ote_test.cc b/yacl/crypto/primitives/ot/sgrr_ote_test.cc index 7bfed554..e6ffa20a 100644 --- a/yacl/crypto/primitives/ot/sgrr_ote_test.cc +++ b/yacl/crypto/primitives/ot/sgrr_ote_test.cc @@ -35,7 +35,7 @@ struct TestParams { class SgrrParamTest : public ::testing::TestWithParam {}; -TEST_P(SgrrParamTest, Works) { +TEST_P(SgrrParamTest, SemiHonestWorks) { size_t n = GetParam().n; auto index = RandInRange(n); @@ -47,11 +47,45 @@ TEST_P(SgrrParamTest, Works) { std::future sender = std::async([&] { SgrrOtExtRecv(lctxs[0], std::move(base_ot.recv), n, index, - absl::MakeSpan(recv_out)); + absl::MakeSpan(recv_out), false); }); std::future receiver = std::async([&] { SgrrOtExtSend(lctxs[1], std::move(base_ot.send), n, - absl::MakeSpan(send_out)); + absl::MakeSpan(send_out), false); + }); + sender.get(); + receiver.get(); + + EXPECT_EQ(send_out.size(), n); + EXPECT_EQ(recv_out.size(), n); + + for (size_t i = 0; i < n; ++i) { + if (index != i) { + EXPECT_NE(recv_out[i], 0); + EXPECT_EQ(send_out[i], recv_out[i]); + } else { + EXPECT_EQ(0, recv_out[i]); + } + } +} + +TEST_P(SgrrParamTest, MaliciousWorks) { + size_t n = GetParam().n; + + auto index = RandInRange(n); + auto lctxs = link::test::SetupWorld(2); + auto base_ot = MockRots(math::Log2Ceil(n)); // mock many base OTs + + std::vector send_out(n); + std::vector recv_out(n); + + std::future sender = std::async([&] { + SgrrOtExtRecv(lctxs[0], std::move(base_ot.recv), n, index, + absl::MakeSpan(recv_out), true); + }); + std::future receiver = std::async([&] { + SgrrOtExtSend(lctxs[1], std::move(base_ot.send), n, + absl::MakeSpan(send_out), true); }); sender.get(); receiver.get(); diff --git a/yacl/crypto/primitives/ot/softspoken_ote.cc b/yacl/crypto/primitives/ot/softspoken_ote.cc index 922290df..51aa9c4a 100644 --- a/yacl/crypto/primitives/ot/softspoken_ote.cc +++ b/yacl/crypto/primitives/ot/softspoken_ote.cc @@ -14,12 +14,20 @@ #include "yacl/crypto/primitives/ot/softspoken_ote.h" +#include + +#include #include #include "yacl/base/aligned_vector.h" #include "yacl/base/dynamic_bitset.h" +#include "yacl/base/int128.h" #include "yacl/crypto/primitives/ot/base_ot.h" +#include "yacl/crypto/tools/crhash.h" +#include "yacl/crypto/tools/prg.h" #include "yacl/crypto/utils/rand.h" +#include "yacl/math/f2k/f2k.h" +#include "yacl/utils/serialize.h" #ifndef __aarch64__ // sse @@ -40,7 +48,7 @@ #include "yacl/base/exception.h" #include "yacl/base/int128.h" #include "yacl/crypto/primitives/ot/sgrr_ote.h" -#include "yacl/crypto/tools/random_permutation.h" +#include "yacl/crypto/tools/rp.h" #include "yacl/utils/matrix_utils.h" namespace yacl::crypto { @@ -49,6 +57,46 @@ namespace { constexpr uint64_t kBatchSize = 128; constexpr uint64_t kKappa = 128; +constexpr size_t kS = 64; // statistical security parameter + +template +struct CheckMsg { + T x = 0; + std::array t{0}; + + // pack the check_msg into one byte buffer (for networking) + Buffer Pack() { + Buffer out((kKappa + 1) * sizeof(T)); + memcpy(out.data(), &x, sizeof(T)); + memcpy(out.data() + sizeof(T), t.data(), sizeof(T) * kKappa); + return out; + } + + // unpack the check_msg from byte buffer (for networking) + void Unpack(ByteContainerView buf) { + std::memcpy(&x, buf.data(), sizeof(T)); + std::memcpy(t.data(), buf.data() + sizeof(T), kKappa * sizeof(T)); + } +}; + +inline dynamic_bitset ExtendChoice( + const dynamic_bitset& choices, size_t final_size) { + // Extend choices to batch_num * kBlockNum bits + // 1st part (valid_ot_num bits): original ot choices + // 2nd part (verify_ot_num bits): rand bits used for checking + // 3rd party (the rest bits): padding 1; + dynamic_bitset choices_ext = choices; + + // 2nd part Extension + Prg gen; + for (size_t i = 0; i < kS; i++) { + choices_ext.push_back(gen()); + } + + // 3rd part Extension + choices_ext.resize(final_size); + return choices_ext; +} inline void XorBlock(absl::Span in, absl::Span out, const uint128_t block) { @@ -79,21 +127,14 @@ inline void XorReduce(absl::Span inout) { } template <> -inline void XorReduce<1>(absl::Span inout) { - const uint64_t buf_size = inout.size(); - constexpr uint64_t stride = 1; - for (uint64_t i = 0; i < buf_size; i += 2 * stride) { - inout[i] = reinterpret_cast( - _mm_xor_si128(reinterpret_cast<__m128i>(inout[i]), - reinterpret_cast<__m128i>(inout[i + stride]))); - } -} +inline void XorReduce<0>([[maybe_unused]] absl::Span inout) {} inline void XorReduce(uint64_t k, absl::Span inout) { + YACL_ENFORCE(k <= 64); const uint64_t buf_size = inout.size(); for (uint64_t depth = 1; depth <= k; ++depth) { - uint64_t stride = 1 << (depth - 1); + uint64_t stride = static_cast(1) << (depth - 1); for (uint64_t i = 0; i < buf_size; i += 2 * stride) { for (uint64_t j = 0; j < depth; ++j) { inout[i + j] ^= inout[i + j + stride]; @@ -105,30 +146,21 @@ inline void XorReduce(uint64_t k, absl::Span inout) { inline void XorReduceImpl(uint64_t k, absl::Span inout) { switch (k) { - case 1: - XorReduce<1>(inout); - break; - case 2: - XorReduce<2>(inout); - break; - case 3: - XorReduce<3>(inout); - break; - case 4: - XorReduce<4>(inout); - break; - case 5: - XorReduce<5>(inout); - break; - case 6: - XorReduce<6>(inout); - break; - case 7: - XorReduce<7>(inout); - break; - case 8: - XorReduce<8>(inout); - break; +#define SWITCH_CASE(n) \ + case n: \ + XorReduce(inout); \ + break; + + SWITCH_CASE(1); + SWITCH_CASE(2); + SWITCH_CASE(3); + SWITCH_CASE(4); + SWITCH_CASE(5); + SWITCH_CASE(6); + SWITCH_CASE(7); + SWITCH_CASE(8); + +#undef SWITCH_CASE default: XorReduce(k, inout); break; @@ -137,8 +169,9 @@ inline void XorReduceImpl(uint64_t k, absl::Span inout) { } // namespace -SoftspokenOtExtSender::SoftspokenOtExtSender(uint64_t k, uint64_t step) - : k_(k), step_(step) { +SoftspokenOtExtSender::SoftspokenOtExtSender(uint64_t k, uint64_t step, + bool mal) + : k_(k), step_(step), mal_(mal) { counter_ = 0; pprf_num_ = (kKappa + k_ - 1) / k_; pprf_range_ = static_cast(1) << k_; @@ -152,6 +185,8 @@ SoftspokenOtExtSender::SoftspokenOtExtSender(uint64_t k, uint64_t step) punctured_idx_ = AlignedVector(pprf_num_); // remove the empty entries in punctured_leaves_ compress_leaves_ = AlignedVector(total_size - pprf_num_); + // init delta + delta_ = MakeUint128(0, 0); // set default step or super batch if (step_ == 0) { @@ -165,8 +200,9 @@ SoftspokenOtExtSender::SoftspokenOtExtSender(uint64_t k, uint64_t step) } } -SoftspokenOtExtReceiver::SoftspokenOtExtReceiver(uint64_t k, uint64_t step) - : k_(k), step_(step) { +SoftspokenOtExtReceiver::SoftspokenOtExtReceiver(uint64_t k, uint64_t step, + bool mal) + : k_(k), step_(step), mal_(mal) { counter_ = 0; pprf_num_ = (kKappa + k_ - 1) / k_; pprf_range_ = static_cast(1) << k_; @@ -192,6 +228,7 @@ void SoftspokenOtExtSender::OneTimeSetup( if (inited_) { return; } + // generate base-OT auto choices = RandBits(kKappa, true); auto base_ot = BaseOtRecv(ctx, choices, kKappa); @@ -208,16 +245,7 @@ void SoftspokenOtExtSender::OneTimeSetup( // FIXME: Copy base_ot, since NextSlice is not const auto dup_base_ot = base_ot; // set delta - // delta_ = base_ot.CopyChoice().data()[0]; - delta_ = 0; - for (uint32_t i = 0; i < 128; ++i) { - delta_ |= static_cast(base_ot.GetChoice(i)) << i; - } - - std::vector> recv_msgs(kKappa); - auto recv_buf = ctx->Recv(ctx->NextRank(), "Softspoken_OneTimeSetup"); - std::memcpy(recv_msgs.data(), recv_buf.data(), recv_buf.size()); - auto recv_span = absl::MakeSpan(recv_msgs); + delta_ = base_ot.CopyChoice().data()[0]; // One-time Setup for Softspoken // k 1-out-of-2 ROT to (2^k-1)-out-of-(2^k) ROT @@ -228,17 +256,11 @@ void SoftspokenOtExtSender::OneTimeSetup( auto sub_ot = dup_base_ot.NextSlice(k_limit); // TODO: [low efficiency] It would copy dynamic_bitset. // punctured index for i-th pprf - // punctured_idx_[i] = sub_ot.CopyChoice().data()[0]; - punctured_idx_[i] = 0; - for (uint32_t j = 0; j < k_limit; ++j) { - punctured_idx_[i] |= (sub_ot.GetChoice(j)) << j; - } - + punctured_idx_[i] = sub_ot.CopyChoice().data()[0]; // punctured leaves for the i-th pprf auto leaves = absl::MakeSpan(punctured_leaves_.data() + i * pprf_range_, range_limit); - SgrrOtExtRecv_fixindex(sub_ot, range_limit, leaves, - recv_span.subspan(i * k_, k_limit)); + SgrrOtExtRecv(ctx, sub_ot, range_limit, punctured_idx_[i], leaves, mal_); // if the j-th bit of punctured index is 1, set mask as all one; // set mask as all zero otherwise. @@ -283,9 +305,6 @@ void SoftspokenOtExtReceiver::OneTimeSetup( auto dup_base_ot = base_ot; // One-time Setup for Softspoken // k 1-out-of-2 ROT to (2^k-1)-out-of-(2^k) ROT - std::vector> send_msgs(kKappa); - auto send_span = absl::MakeSpan(send_msgs); - for (uint64_t i = 0; i < pprf_num_; ++i) { const uint64_t k_limit = std::min(k_, kKappa - i * k_); const uint64_t range_limit = static_cast(1) << k_limit; @@ -294,14 +313,8 @@ void SoftspokenOtExtReceiver::OneTimeSetup( // leaves in i-th pprf auto leaves = absl::MakeSpan(all_leaves_.data() + i * pprf_range_, range_limit); - SgrrOtExtSend_fixindex(sub_ot, range_limit, leaves, - send_span.subspan(i * k_, k_limit)); + SgrrOtExtSend(ctx, sub_ot, range_limit, leaves, mal_); } - - ctx->SendAsync( - ctx->NextRank(), - ByteContainerView(send_msgs.data(), kKappa * 2 * sizeof(uint128_t)), - "Softspoken_OneTimeSetup"); inited_ = true; } @@ -410,6 +423,9 @@ OtRecvStore SoftspokenOtExtReceiver::GenCot( return out; } +// Generate Smallfield VOLE and Subspace VOLE +// Reference: https://eprint.iacr.org/2022/192.pdf Figure 7 & Figure 8 +// s.t. W = choice * delta + V OtRecvStore SoftspokenOtExtReceiver::GenCot( const std::shared_ptr& ctx, const dynamic_bitset& choices) { @@ -531,15 +547,21 @@ void SoftspokenOtExtSender::Send( const uint64_t batch_size = kBatchSize; const uint64_t super_batch_size = step * batch_size; const uint64_t numOt = send_blocks.size(); + const uint64_t expand_numOt = + (numOt + kS + kBatchSize - 1) / kBatchSize * kBatchSize; const uint64_t super_batch_num = numOt / super_batch_size; const uint64_t batch_offset = super_batch_num * super_batch_size; const uint64_t batch_num = - (numOt - batch_offset + kBatchSize - 1) / kBatchSize; + (expand_numOt - batch_offset + kBatchSize - 1) / kBatchSize; + const uint64_t all_batch_num = super_batch_num * step + batch_num; + YACL_ENFORCE(all_batch_num * kBatchSize == expand_numOt); + AlignedVector, 32> allV(all_batch_num); // OT extension // AVX need to be aligned to 32 bytes. - AlignedVector, 32> V(step); - AlignedVector, 32> V_xor_delta(step); + // Extra one array for consitency check in batch_num for-loop. + AlignedVector, 32> V(step + 1); + AlignedVector, 32> V_xor_delta(step + 1); // Hash Buffer to perform AES/PRG // Xor Buffer to perform XorReduce ( \sum x PRG(M_x) ) auto hash_buff = AlignedVector(compress_leaves_.size()); @@ -559,6 +581,10 @@ void SoftspokenOtExtSender::Send( GenSfVole(absl::MakeSpan(hash_buff), absl::MakeSpan(xor_buff), absl::MakeSpan(recv_U.data() + s * pprf_num_, pprf_num_), absl::MakeSpan(V[s])); + if (mal_) { + allV[t * step + s] = V[s]; + } + // 3. Matrix Transpose MatrixTranspose128(&V[s]); XorBlock(absl::MakeSpan(V[s]), absl::MakeSpan(V_xor_delta[s]), delta); @@ -588,20 +614,59 @@ void SoftspokenOtExtSender::Send( // 2. smallfield/subspace VOLE GenSfVole(absl::MakeSpan(hash_buff), absl::MakeSpan(xor_buff), absl::MakeSpan(recv_U), absl::MakeSpan(V[t])); + if (mal_) { + allV[super_batch_num * step + t] = V[t]; + } + // 3. Matrix Transpose - MatrixTranspose128(&V[t]); - XorBlock(absl::MakeSpan(V[t]), absl::MakeSpan(V_xor_delta[t]), delta); - // 4. perform CrHash to break the correlation if cot flag is false - if (!cot) { - ParaCrHashInplace_128(absl::MakeSpan(V[t])); - ParaCrHashInplace_128(absl::MakeSpan(V_xor_delta[t])); + if (numOt > batch_offset + t * kBatchSize) { + MatrixTranspose128(&V[t]); + XorBlock(absl::MakeSpan(V[t]), absl::MakeSpan(V_xor_delta[t]), delta); + // 4. perform CrHash to break the correlation if cot flag is false + if (!cot) { + ParaCrHashInplace_128(absl::MakeSpan(V[t])); + ParaCrHashInplace_128(absl::MakeSpan(V_xor_delta[t])); + } + + const uint64_t limit = + std::min(kBatchSize, numOt - batch_offset - t * kBatchSize); + for (uint64_t j = 0; j < limit; ++j) { + send_blocks[batch_offset + t * kBatchSize + j][0] = V[t][j]; + send_blocks[batch_offset + t * kBatchSize + j][1] = V_xor_delta[t][j]; + } + } + } + + if (mal_) { + // Sender generates a random seed and sends it to receiver. + uint128_t seed = SecureRandSeed(); + ctx->SendAsync(ctx->NextRank(), SerializeUint128(seed), + fmt::format("SSMal-Seed")); + + // Consistency check + std::vector rand_samples(all_batch_num * 2); + PrgAesCtr(seed, absl::Span(rand_samples)); + + CheckMsg check_msgs; + for (size_t i = 0; i < all_batch_num; ++i) { + for (size_t k = 0; k < kKappa; ++k) { + check_msgs.t[k] ^= ClMul64( + absl::MakeSpan(rand_samples.data() + i * 2, 2), + absl::MakeSpan(reinterpret_cast(allV[i].data() + k), 2)); + } + } + + CheckMsg msgs; + std::array check_vals; + for (size_t k = 0; k < kKappa; ++k) { + check_vals[k] = Reduce64(check_msgs.t[k]); } - const uint64_t limit = - std::min(kBatchSize, numOt - batch_offset - t * kBatchSize); - for (uint64_t j = 0; j < limit; ++j) { - send_blocks[batch_offset + t * kBatchSize + j][0] = V[t][j]; - send_blocks[batch_offset + t * kBatchSize + j][1] = V_xor_delta[t][j]; + msgs.Unpack(ctx->Recv(ctx->NextRank(), fmt::format("MAL-SS-CHECK-FINAL"))); + + for (size_t k = 0; k < kKappa; ++k) { + auto recv_check_val = msgs.t[k] ^ (p_idx_mask_[k] & msgs.x); + YACL_ENFORCE(recv_check_val == check_vals[k]); } } } @@ -614,18 +679,26 @@ void SoftspokenOtExtReceiver::Recv(const std::shared_ptr& ctx, if (!inited_) { OneTimeSetup(ctx); } + YACL_ENFORCE(choices.size() == recv_blocks.size()); const uint64_t& step = step_; const uint64_t batch_size = kBatchSize; const uint64_t super_batch_size = step * batch_size; const uint64_t numOt = recv_blocks.size(); + const uint64_t expand_numOt = + (numOt + kS + kBatchSize - 1) / kBatchSize * kBatchSize; const uint64_t super_batch_num = numOt / super_batch_size; const uint64_t batch_offset = super_batch_num * super_batch_size; const uint64_t batch_num = - (numOt - batch_offset + kBatchSize - 1) / kBatchSize; + (expand_numOt - batch_offset + kBatchSize - 1) / kBatchSize; + const uint64_t all_batch_num = super_batch_num * step + batch_num; + YACL_ENFORCE(all_batch_num * kBatchSize == expand_numOt); + AlignedVector, 32> allW(all_batch_num); + auto choice_ext = ExtendChoice(choices, expand_numOt); // AVX need to be aligned to 32 bytes. - AlignedVector, 32> W(step); + // Extra one array for consitency check in batch_num for-loop. + AlignedVector, 32> W(step + 1); // AES Buffer & Xor Buffer to perform AES/PRG and XorReduce auto xor_buff = AlignedVector(pprf_num_ * pprf_range_); AlignedVector U(pprf_num_ * step); @@ -635,15 +708,17 @@ void SoftspokenOtExtReceiver::Recv(const std::shared_ptr& ctx, // The same as IKNP OTe, see `yacl/crypto/primitive/ot/iknp_ote_cc` // 1. smallfield/subspace VOLE for (uint64_t s = 0; s < step; ++s) { - GenSfVole(choices.data()[t * step + s], absl::MakeSpan(xor_buff), + GenSfVole(choice_ext.data()[t * step + s], absl::MakeSpan(xor_buff), absl::MakeSpan(U.data() + s * pprf_num_, pprf_num_), absl::MakeSpan(W[s])); + if (mal_) { + allW[t * step + s] = W[s]; + } } // 2. send the masked choices ctx->SendAsync(ctx->NextRank(), ByteContainerView(U.data(), U.size() * sizeof(uint128_t)), "softspoken_switch_u"); - for (uint64_t s = 0; s < step; ++s) { // 3. matrix transpose MatrixTranspose128(&W[s]); @@ -661,24 +736,61 @@ void SoftspokenOtExtReceiver::Recv(const std::shared_ptr& ctx, for (uint64_t t = 0; t < batch_num; ++t) { // The same as IKNP OTe // 1. smallfield/subspace VOLE - GenSfVole(choices.data()[super_batch_num * step + t], + GenSfVole(choice_ext.data()[super_batch_num * step + t], absl::MakeSpan(xor_buff), absl::MakeSpan(U), absl::MakeSpan(W[t])); + if (mal_) { + allW[super_batch_num * step + t] = W[t]; + } // 2. send the masked choices ctx->SendAsync(ctx->NextRank(), ByteContainerView(U.data(), pprf_num_ * sizeof(uint128_t)), "softspoken_switch_u"); + // 3. matrix transpose - MatrixTranspose128(&W[t]); - const uint64_t limit = - std::min(kBatchSize, numOt - batch_offset - t * kBatchSize); - // 4. perform CrHash to break the correlation if cot flag is false - if (!cot) { - ParaCrHashInplace_128(absl::MakeSpan(W[t])); + if (numOt > batch_offset + t * kBatchSize) { + MatrixTranspose128(&W[t]); + const uint64_t limit = + std::min(kBatchSize, numOt - batch_offset - t * kBatchSize); + // 4. perform CrHash to break the correlation if cot flag is false + if (!cot) { + ParaCrHashInplace_128(absl::MakeSpan(W[t])); + } + for (uint64_t j = 0; j < limit; ++j) { + recv_blocks[batch_offset + t * kBatchSize + j] = W[t][j]; + } } - for (uint64_t j = 0; j < limit; ++j) { - recv_blocks[batch_offset + t * kBatchSize + j] = W[t][j]; + } + + if (mal_) { + // Recevies the random seed from sender + uint128_t seed = DeserializeUint128( + ctx->Recv(ctx->NextRank(), fmt::format("SSMal-Seed"))); + + // Consistency check + std::vector rand_samples(all_batch_num * 2); + PrgAesCtr(seed, absl::Span(rand_samples)); + + CheckMsg check_msgs; + auto choice_span = absl::MakeSpan( + reinterpret_cast(choice_ext.data()), all_batch_num * 2); + check_msgs.x ^= ClMul64(absl::MakeSpan(rand_samples), choice_span); + + for (size_t i = 0; i < all_batch_num; ++i) { + for (size_t k = 0; k < kKappa; ++k) { + check_msgs.t[k] ^= ClMul64( + absl::MakeSpan(rand_samples.data() + i * 2, 2), + absl::MakeSpan(reinterpret_cast(allW[i].data() + k), 2)); + } + } + + CheckMsg msgs; + msgs.x = Reduce64(check_msgs.x); + for (size_t k = 0; k < kKappa; ++k) { + msgs.t[k] = Reduce64(check_msgs.t[k]); } + auto buf = msgs.Pack(); + ctx->SendAsync(ctx->NextRank(), buf, fmt::format("MAL-SS-CHECK-FINAL")); } } diff --git a/yacl/crypto/primitives/ot/softspoken_ote.h b/yacl/crypto/primitives/ot/softspoken_ote.h index b17272c0..2d11b16f 100644 --- a/yacl/crypto/primitives/ot/softspoken_ote.h +++ b/yacl/crypto/primitives/ot/softspoken_ote.h @@ -24,9 +24,12 @@ #include "yacl/base/int128.h" #include "yacl/crypto/primitives/ot/ot_store.h" #include "yacl/crypto/utils/rand.h" +#include "yacl/crypto/utils/secparam.h" #include "yacl/link/context.h" #include "yacl/link/link.h" +YACL_MODULE_DECLARE("softspoken_ote", SecParam::C::k128, SecParam::S::INF); + namespace yacl::crypto { // SoftSpoken OT Extension Implementation @@ -51,7 +54,7 @@ namespace yacl::crypto { // // Security assumptions: // *. correlation-robust hash function, for more details about its -// implementation, see `yacl/crypto/tools/random_permutation.h` +// implementation, see `yacl/crypto/tools/rp.h` // // NOTE: // * OT Extension sender requires receiver base ot context. @@ -65,12 +68,12 @@ namespace yacl::crypto { class SoftspokenOtExtSender { public: - SoftspokenOtExtSender(uint64_t k = 2, uint64_t step = 0); + SoftspokenOtExtSender(uint64_t k = 2, uint64_t step = 0, bool mal = false); void OneTimeSetup(const std::shared_ptr& ctx); void OneTimeSetup(const std::shared_ptr& ctx, - const OtRecvStore& base_ot); + const OtRecvStore& base_ot /* rot */); // old-style interface void Send(const std::shared_ptr& ctx, @@ -120,16 +123,17 @@ class SoftspokenOtExtSender { std::array p_idx_mask_; // mask for punctured index AlignedVector compress_leaves_; // compressed pprf leaves uint64_t step_{32}; // super batch size = step_ * 128 + bool mal_{false}; // malicous }; class SoftspokenOtExtReceiver { public: - SoftspokenOtExtReceiver(uint64_t k = 2, uint64_t step = 0); + SoftspokenOtExtReceiver(uint64_t k = 2, uint64_t step = 0, bool mal = false); void OneTimeSetup(const std::shared_ptr& ctx); void OneTimeSetup(const std::shared_ptr& ctx, - const OtSendStore& base_ot); + const OtSendStore& base_ot /* rot */); // old-style interface void Recv(const std::shared_ptr& ctx, @@ -180,24 +184,27 @@ class SoftspokenOtExtReceiver { uint64_t pprf_range_; // the number of leaves for single pprf AlignedVector all_leaves_; // leaves for all pprf uint64_t step_{32}; // super batch size = step_ * 128 + bool mal_{false}; // malicous }; // Softspoken Ot Extension interface inline void SoftspokenOtExtSend( - const std::shared_ptr& ctx, const OtRecvStore& base_ot, + const std::shared_ptr& ctx, + const OtRecvStore& base_ot /* rot */, absl::Span> send_blocks, uint64_t k = 2, - bool cot = false) { - auto ssSender = SoftspokenOtExtSender(k); + bool cot = false, bool mal = false) { + auto ssSender = SoftspokenOtExtSender(k, 0, mal); ssSender.OneTimeSetup(ctx, base_ot); ssSender.Send(ctx, send_blocks, cot); } inline void SoftspokenOtExtRecv(const std::shared_ptr& ctx, - const OtSendStore& base_ot, + const OtSendStore& base_ot /* rot */, const dynamic_bitset& choices, absl::Span recv_blocks, - uint64_t k = 2, bool cot = false) { - auto ssReceiver = SoftspokenOtExtReceiver(k); + uint64_t k = 2, bool cot = false, + bool mal = false) { + auto ssReceiver = SoftspokenOtExtReceiver(k, 0, mal); ssReceiver.OneTimeSetup(ctx, base_ot); ssReceiver.Recv(ctx, choices, recv_blocks, cot); } diff --git a/yacl/crypto/primitives/ot/softspoken_ote_test.cc b/yacl/crypto/primitives/ot/softspoken_ote_test.cc index 990580a0..c6f89c13 100644 --- a/yacl/crypto/primitives/ot/softspoken_ote_test.cc +++ b/yacl/crypto/primitives/ot/softspoken_ote_test.cc @@ -30,24 +30,30 @@ namespace yacl::crypto { struct OtTestParams { unsigned num_ot; + bool mal = false; }; struct KTestParams { unsigned k; + bool mal = false; }; struct StepTestParams { unsigned step; + bool mal = false; }; class SoftspokenStepTest : public ::testing::TestWithParam {}; class SoftspokenKTest : public ::testing::TestWithParam {}; class SoftspokenOtExtTest : public ::testing::TestWithParam {}; +TEST(SecParamTest, Works) { YACL_PRINT_MODULE_SUMMARY(); } + TEST_P(SoftspokenStepTest, Works) { // GIVEN const int kWorldSize = 2; const size_t step = GetParam().step; + const bool mal = GetParam().mal; const size_t num_ot = 4096; auto lctxs = link::test::SetupWorld(kWorldSize); // setup network auto base_ot = MockRots(128); // mock option @@ -56,8 +62,10 @@ TEST_P(SoftspokenStepTest, Works) { // WHEN std::vector> send_out(num_ot); std::vector recv_out(num_ot); - auto ssSenderTask = std::async([&] { return SoftspokenOtExtSender(2); }); - auto ssReceiverTask = std::async([&] { return SoftspokenOtExtReceiver(2); }); + auto ssSenderTask = + std::async([&] { return SoftspokenOtExtSender(2, 0, mal); }); + auto ssReceiverTask = + std::async([&] { return SoftspokenOtExtReceiver(2, 0, mal); }); auto ssSender = ssSenderTask.get(); auto ssReceiver = ssReceiverTask.get(); @@ -86,6 +94,7 @@ TEST_P(SoftspokenKTest, KWorks) { // GIVEN const int kWorldSize = 2; const size_t k = GetParam().k; + const bool mal = GetParam().mal; const size_t num_ot = 4096; auto lctxs = link::test::SetupWorld(kWorldSize); // setup network auto base_ot = MockRots(128); // mock option @@ -95,11 +104,12 @@ TEST_P(SoftspokenKTest, KWorks) { std::vector> send_out(num_ot); std::vector recv_out(num_ot); std::future sender = std::async([&] { - SoftspokenOtExtSend(lctxs[0], base_ot.recv, absl::MakeSpan(send_out), k); + SoftspokenOtExtSend(lctxs[0], base_ot.recv, absl::MakeSpan(send_out), k, + false, mal); }); std::future receiver = std::async([&] { SoftspokenOtExtRecv(lctxs[1], base_ot.send, choices, - absl::MakeSpan(recv_out), k); + absl::MakeSpan(recv_out), k, false, mal); }); receiver.get(); sender.get(); @@ -117,6 +127,7 @@ TEST_P(SoftspokenKTest, ReuseWorks) { // GIVEN const int kWorldSize = 2; const size_t k = GetParam().k; + const bool mal = GetParam().mal; const size_t num_ot = 4096; auto lctxs = link::test::SetupWorld(kWorldSize); // setup network auto base_ot = MockRots(128); // mock option @@ -124,8 +135,10 @@ TEST_P(SoftspokenKTest, ReuseWorks) { // WHEN // One time setup for Softspoken - auto ssReceiverTask = std::async([&] { return SoftspokenOtExtReceiver(k); }); - auto ssSenderTask = std::async([&] { return SoftspokenOtExtSender(k); }); + auto ssReceiverTask = + std::async([&] { return SoftspokenOtExtReceiver(k, 0, mal); }); + auto ssSenderTask = + std::async([&] { return SoftspokenOtExtSender(k, 0, mal); }); auto ssReceiver = ssReceiverTask.get(); auto ssSender = ssSenderTask.get(); @@ -169,6 +182,7 @@ TEST_P(SoftspokenOtExtTest, RotExtWorks) { // GIVEN const int kWorldSize = 2; const size_t num_ot = GetParam().num_ot; + const bool mal = GetParam().mal; auto lctxs = link::test::SetupWorld(kWorldSize); // setup network auto base_ot = MockRots(128); // mock option auto choices = RandBits>(num_ot); // get input @@ -177,11 +191,12 @@ TEST_P(SoftspokenOtExtTest, RotExtWorks) { std::vector> send_out(num_ot); std::vector recv_out(num_ot); std::future sender = std::async([&] { - SoftspokenOtExtSend(lctxs[0], base_ot.recv, absl::MakeSpan(send_out), 2); + SoftspokenOtExtSend(lctxs[0], base_ot.recv, absl::MakeSpan(send_out), 2, + false, mal); }); std::future receiver = std::async([&] { SoftspokenOtExtRecv(lctxs[1], base_ot.send, choices, - absl::MakeSpan(recv_out), 2); + absl::MakeSpan(recv_out), 2, false, mal); }); receiver.get(); sender.get(); @@ -199,6 +214,7 @@ TEST_P(SoftspokenOtExtTest, CotExtWorks) { // GIVEN const int kWorldSize = 2; const size_t num_ot = GetParam().num_ot; + const bool mal = GetParam().mal; auto lctxs = link::test::SetupWorld(kWorldSize); // setup network auto base_ot = MockRots(128); // mock option auto choices = RandBits>(num_ot); // get input @@ -209,11 +225,11 @@ TEST_P(SoftspokenOtExtTest, CotExtWorks) { std::future sender = std::async([&] { SoftspokenOtExtSend(lctxs[0], base_ot.recv, absl::MakeSpan(send_out), 3, - true); + true, mal); }); std::future receiver = std::async([&] { SoftspokenOtExtRecv(lctxs[1], base_ot.send, choices, - absl::MakeSpan(recv_out), 3, true); + absl::MakeSpan(recv_out), 3, true, mal); }); receiver.get(); sender.get(); @@ -234,13 +250,16 @@ TEST_P(SoftspokenOtExtTest, RotStoreWorks) { // GIVEN const int kWorldSize = 2; const size_t num_ot = GetParam().num_ot; + const bool mal = GetParam().mal; auto lctxs = link::test::SetupWorld(kWorldSize); // setup network auto base_ot = MockRots(128); // mock option // WHEN // One time setup for Softspoken - auto ssReceiverTask = std::async([&] { return SoftspokenOtExtReceiver(2); }); - auto ssSenderTask = std::async([&] { return SoftspokenOtExtSender(2); }); + auto ssReceiverTask = + std::async([&] { return SoftspokenOtExtReceiver(2, 0, mal); }); + auto ssSenderTask = + std::async([&] { return SoftspokenOtExtSender(2, 0, mal); }); auto ssReceiver = ssReceiverTask.get(); auto ssSender = ssSenderTask.get(); @@ -277,13 +296,16 @@ TEST_P(SoftspokenOtExtTest, CotStoreWorks) { // GIVEN const int kWorldSize = 2; const size_t num_ot = GetParam().num_ot; + const bool mal = GetParam().mal; auto lctxs = link::test::SetupWorld(kWorldSize); // setup network auto base_ot = MockRots(128); // mock option // WHEN // One time setup for Softspoken - auto ssReceiverTask = std::async([&] { return SoftspokenOtExtReceiver(2); }); - auto ssSenderTask = std::async([&] { return SoftspokenOtExtSender(2); }); + auto ssReceiverTask = + std::async([&] { return SoftspokenOtExtReceiver(2, 0, mal); }); + auto ssSenderTask = + std::async([&] { return SoftspokenOtExtSender(2, 0, mal); }); auto ssReceiver = ssReceiverTask.get(); auto ssSender = ssSenderTask.get(); @@ -318,35 +340,59 @@ TEST_P(SoftspokenOtExtTest, CotStoreWorks) { } INSTANTIATE_TEST_SUITE_P(Works_Instances, SoftspokenStepTest, - testing::Values(StepTestParams{1}, // - StepTestParams{2}, // - StepTestParams{4}, // - StepTestParams{8}, // - StepTestParams{16}, // - StepTestParams{32}, // - StepTestParams{64}, // - StepTestParams{128} // - )); + testing::Values(StepTestParams{1}, // + StepTestParams{2}, // + StepTestParams{4}, // + StepTestParams{8}, // + StepTestParams{16}, // + StepTestParams{32}, // + StepTestParams{64}, // + StepTestParams{128}, // + StepTestParams{1, true}, // + StepTestParams{2, true}, // + StepTestParams{4, true}, // + StepTestParams{8, true}, // + StepTestParams{16, true}, // + StepTestParams{32, true}, // + StepTestParams{64, true}, // + StepTestParams{128, true})); INSTANTIATE_TEST_SUITE_P(Works_Instances, SoftspokenKTest, - testing::Values(KTestParams{1}, // - KTestParams{2}, // - KTestParams{3}, // - KTestParams{4}, // - KTestParams{5}, // - KTestParams{6}, // - KTestParams{7}, // - KTestParams{8}, // - KTestParams{9}, // - KTestParams{10})); + testing::Values(KTestParams{1}, // + KTestParams{2}, // + KTestParams{3}, // + KTestParams{4}, // + KTestParams{5}, // + KTestParams{6}, // + KTestParams{7}, // + KTestParams{8}, // + KTestParams{9}, // + KTestParams{10}, // + KTestParams{1, true}, // + KTestParams{2, true}, // + KTestParams{3, true}, // + KTestParams{4, true}, // + KTestParams{5, true}, // + KTestParams{6, true}, // + KTestParams{7, true}, // + KTestParams{8, true}, // + KTestParams{9, true}, // + KTestParams{10, true})); INSTANTIATE_TEST_SUITE_P(Works_Instances, SoftspokenOtExtTest, - testing::Values(OtTestParams{8}, // - OtTestParams{128}, // - OtTestParams{129}, // - OtTestParams{4095}, // - OtTestParams{4096}, // - OtTestParams{65536}, // - OtTestParams{100000})); + testing::Values(OtTestParams{8}, // + OtTestParams{128}, // + OtTestParams{129}, // + OtTestParams{4095}, // + OtTestParams{4096}, // + OtTestParams{65536}, // + OtTestParams{100000}, // + OtTestParams{8, true}, // + OtTestParams{128, true}, // + OtTestParams{129, true}, // + OtTestParams{4095, true}, // + OtTestParams{4096, true}, // + OtTestParams{65536, true}, // + OtTestParams{100000, true})); } // namespace yacl::crypto diff --git a/yacl/crypto/primitives/ot/x86_asm_ot_interface.cc b/yacl/crypto/primitives/ot/x86_asm_ot_interface.cc index ecfda685..d0ad7d11 100644 --- a/yacl/crypto/primitives/ot/x86_asm_ot_interface.cc +++ b/yacl/crypto/primitives/ot/x86_asm_ot_interface.cc @@ -23,7 +23,7 @@ #include "yacl/base/byte_container_view.h" #include "yacl/base/exception.h" -#include "yacl/crypto/tools/random_oracle.h" +#include "yacl/crypto/tools/ro.h" #include "yacl/math/gadget.h" namespace yacl::crypto { diff --git a/yacl/crypto/primitives/vole/f2k/BUILD.bazel b/yacl/crypto/primitives/vole/f2k/BUILD.bazel index d233be4f..a92ba422 100644 --- a/yacl/crypto/primitives/vole/f2k/BUILD.bazel +++ b/yacl/crypto/primitives/vole/f2k/BUILD.bazel @@ -27,6 +27,7 @@ yacl_cc_library( "//yacl/crypto/primitives/ot:ot_store", "//yacl/crypto/primitives/ot:softspoken_ote", "//yacl/crypto/utils:rand", + "//yacl/crypto/utils:secparam", "//yacl/math:gadget", "//yacl/math/f2k", "//yacl/utils:serialize", @@ -60,6 +61,7 @@ yacl_cc_library( "//yacl/crypto/primitives/ot:sgrr_ote", "//yacl/crypto/primitives/ot:softspoken_ote", "//yacl/crypto/utils:rand", + "//yacl/crypto/utils:secparam", "//yacl/math:gadget", "//yacl/math/f2k", "//yacl/utils:serialize", @@ -90,12 +92,13 @@ yacl_cc_library( "//yacl/base:aligned_vector", "//yacl/base:dynamic_bitset", "//yacl/base:int128", + "//yacl/crypto/primitives/code:code_interface", + "//yacl/crypto/primitives/code:ea_code", + "//yacl/crypto/primitives/code:silver_code", "//yacl/crypto/primitives/ot:ferret_ote", "//yacl/crypto/primitives/ot:ot_store", "//yacl/crypto/primitives/ot:softspoken_ote", - "//yacl/crypto/tools:code_interface", - "//yacl/crypto/tools:expand_accumulate_code", - "//yacl/crypto/tools:silver_code", + "//yacl/crypto/utils:secparam", "//yacl/link:context", "//yacl/math:gadget", ], diff --git a/yacl/crypto/primitives/vole/f2k/base_vole.h b/yacl/crypto/primitives/vole/f2k/base_vole.h index 2872821d..bd3f9afe 100644 --- a/yacl/crypto/primitives/vole/f2k/base_vole.h +++ b/yacl/crypto/primitives/vole/f2k/base_vole.h @@ -22,9 +22,12 @@ #include "yacl/crypto/primitives/ot/ot_store.h" #include "yacl/crypto/primitives/ot/softspoken_ote.h" #include "yacl/crypto/utils/rand.h" +#include "yacl/crypto/utils/secparam.h" #include "yacl/math/f2k/f2k.h" #include "yacl/math/gadget.h" +YACL_MODULE_DECLARE("base_vole", SecParam::C::INF, SecParam::S::INF); + namespace yacl::crypto { namespace vole::internal { @@ -124,6 +127,7 @@ void inline GilboaVoleSend(const std::shared_ptr& ctx, const size_t size = w.size(); auto sender = SoftspokenOtExtSender(2); + // setup Softspoken by base_ot sender.OneTimeSetup(ctx, base_ot); auto send_ot = sender.GenCot(ctx, size * T_bits); Ot2VoleSend(send_ot, w); @@ -138,6 +142,7 @@ void inline GilboaVoleRecv(const std::shared_ptr& ctx, YACL_ENFORCE(size == v.size()); auto receiver = SoftspokenOtExtReceiver(2); + // setup Softspoken by base_ot receiver.OneTimeSetup(ctx, base_ot); auto recv_ot = receiver.GenCot(ctx, size * T_bits); Ot2VoleRecv(recv_ot, u, v); diff --git a/yacl/crypto/primitives/vole/f2k/base_vole_test.cc b/yacl/crypto/primitives/vole/f2k/base_vole_test.cc index aae15832..63d8cd63 100644 --- a/yacl/crypto/primitives/vole/f2k/base_vole_test.cc +++ b/yacl/crypto/primitives/vole/f2k/base_vole_test.cc @@ -48,7 +48,7 @@ using GF128 = uint128_t; #define DECLARE_OT2VOLE_TEST(type0, type1) \ TEST_P(BaseVoleTest, Ot2Vole_##type0##x##type1##_Work) { \ const uint64_t vole_num = GetParam().num; \ - auto delta128 = RandU128(); \ + auto delta128 = FastRandU128(); \ auto ot_num = vole_num * sizeof(type0) * 8; \ auto cot = MockCots(ot_num, delta128); \ std::vector u(vole_num); \ diff --git a/yacl/crypto/primitives/vole/f2k/benchmark.cc b/yacl/crypto/primitives/vole/f2k/benchmark.cc index 7047da2b..fa512526 100644 --- a/yacl/crypto/primitives/vole/f2k/benchmark.cc +++ b/yacl/crypto/primitives/vole/f2k/benchmark.cc @@ -61,8 +61,8 @@ class VoleBench : public benchmark::Fixture { public: void SetUp(const ::benchmark::State&) override { if (lctxs_.empty()) { - lctxs_ = link::test::SetupBrpcWorld(2); - // lctxs_ = link::test::SetupWorld(2); + // lctxs_ = link::test::SetupBrpcWorld(2); + lctxs_ = link::test::SetupWorld(2); } } @@ -214,8 +214,8 @@ DELCARE_SILENT_SUBFIELDVOLE_BENCH(ExAcc21); DELCARE_SILENT_SUBFIELDVOLE_BENCH(ExAcc40); #define BM_REGISTER_SILVER_SILENT_VOLE(Arguments) \ - BENCHMARK_REGISTER_F(VoleBench, Silver5Vole_GF128)->Apply(Arguments); \ BENCHMARK_REGISTER_F(VoleBench, Silver5Vole_GF64)->Apply(Arguments); \ + BENCHMARK_REGISTER_F(VoleBench, Silver5Vole_GF128)->Apply(Arguments); \ BENCHMARK_REGISTER_F(VoleBench, Silver5SubfieldVole)->Apply(Arguments); \ BENCHMARK_REGISTER_F(VoleBench, Silver11Vole_GF64)->Apply(Arguments); \ BENCHMARK_REGISTER_F(VoleBench, Silver11Vole_GF128)->Apply(Arguments); \ @@ -255,10 +255,10 @@ void BM_PerfArguments(benchmark::internal::Benchmark* b) { ->Iterations(10); } -BM_REGISTER_ALL_VOLE(BM_DefaultArguments); +// BM_REGISTER_ALL_VOLE(BM_DefaultArguments); -// BM_REGISTER_GILBOA_VOLE(BM_DefaultArguments); -// BM_REGISTER_SILVER_SILENT_VOLE(BM_PerfArguments); -// BM_REGISTER_EXACC_SILENT_VOLE(BM_PerfArguments); +BM_REGISTER_GILBOA_VOLE(BM_DefaultArguments); +BM_REGISTER_SILVER_SILENT_VOLE(BM_PerfArguments); +BM_REGISTER_EXACC_SILENT_VOLE(BM_PerfArguments); } // namespace yacl::crypto diff --git a/yacl/crypto/primitives/vole/f2k/silent_vole.cc b/yacl/crypto/primitives/vole/f2k/silent_vole.cc index b3721325..50a42972 100644 --- a/yacl/crypto/primitives/vole/f2k/silent_vole.cc +++ b/yacl/crypto/primitives/vole/f2k/silent_vole.cc @@ -19,12 +19,12 @@ #include "yacl/base/aligned_vector.h" #include "yacl/base/dynamic_bitset.h" #include "yacl/base/int128.h" +#include "yacl/crypto/primitives/code/code_interface.h" +#include "yacl/crypto/primitives/code/ea_code.h" +#include "yacl/crypto/primitives/code/silver_code.h" #include "yacl/crypto/primitives/ot/ferret_ote.h" #include "yacl/crypto/primitives/vole/f2k/base_vole.h" #include "yacl/crypto/primitives/vole/f2k/sparse_vole.h" -#include "yacl/crypto/tools/code_interface.h" -#include "yacl/crypto/tools/expand_accumulate_code.h" -#include "yacl/crypto/tools/silver_code.h" #include "yacl/crypto/utils/rand.h" #include "yacl/math/gadget.h" @@ -32,6 +32,16 @@ namespace yacl::crypto { namespace { +// Linear Test, more details could be found in +// https://eprint.iacr.org/2022/1014.pdf Definition 2.5 bias( Reg_t^N ) equal or +// less than e^{-td/N} where t is the number of noise in dual-LPN problem, d is +// the minimum weight of vectors in dual-LPN matrix. Thus, we can view d/N as +// the minimum distance ratio for dual-LPN matrix. +// +// Implementation of GenRegNoiseWeight is mostly from: +// https://github.com/osu-crypto/libOTe/blob/master/libOTe/TwoChooseOne/ConfigureCode.cpp +// which would return the number of noise in MpVole +// uint64_t GenRegNoiseWeight(double min_dist_ratio, uint64_t sec) { if (min_dist_ratio > 0.5 || min_dist_ratio <= 0) { YACL_THROW("mini distance too small, rate {}", min_dist_ratio); @@ -44,7 +54,7 @@ uint64_t GenRegNoiseWeight(double min_dist_ratio, uint64_t sec) { } // Silent Vole internal parameters -template +template struct VoleParam { uint64_t vole_num_; // vole num uint64_t code_size_; // code size @@ -58,10 +68,11 @@ struct VoleParam { uint64_t mp_vole_ot_num_; // mp vole (cot/rot-based) uint64_t require_ot_num_; // total ot num - // dual-LPN encoder: SilverCode, ExAccCode, or (ExConvCode) - std::shared_ptr encoder_{nullptr}; + // Constructor + VoleParam(CodeType code, uint64_t vole_num) + : VoleParam(code, vole_num, YACL_MODULE_SECPARAM_C_UINT("silent_vole")) {} - VoleParam(CodeType code, uint64_t vole_num, uint64_t sec = 128) { + VoleParam(CodeType code, uint64_t vole_num, uint64_t sec) { // default uint64_t gap = 0; uint64_t code_scaler = 2; @@ -110,86 +121,84 @@ struct VoleParam { mp_param_.noise_num_ * sizeof(T) * 8; // base_vole (cot-based) mp_vole_ot_num_ = mp_param_.require_ot_num_; // mp_vole (cot/rot-based) require_ot_num_ = base_vole_ot_num_ + mp_vole_ot_num_; - - // initialize encoder - switch (codetype_) { - // the size of SilverCode is ( code_size_ * 2 x code_size_ ) - case CodeType::Silver5: - encoder_ = std::make_shared(code_size_, 5); - break; - case CodeType::Silver11: - encoder_ = std::make_shared(code_size_, 11); - break; - // the size of ExAccCode is ( code_size_ * 2 x vole_num_ ) - case CodeType::ExAcc7: - encoder_ = - std::make_shared>(vole_num_, mp_param_.mp_vole_size_); - break; - case CodeType::ExAcc11: - encoder_ = - std::make_shared>(vole_num_, mp_param_.mp_vole_size_); - break; - case CodeType::ExAcc21: - encoder_ = - std::make_shared>(vole_num_, mp_param_.mp_vole_size_); - break; - case CodeType::ExAcc40: - encoder_ = - std::make_shared>(vole_num_, mp_param_.mp_vole_size_); - break; - // TODO: @wenfan - // support ExConv Code - default: - break; - } } +}; - AlignedVector GetSparseNoise(absl::Span noise) { - YACL_ENFORCE(noise.size() >= mp_param_.noise_num_); - AlignedVector sparse_noise(mp_param_.mp_vole_size_, 0); - - if (mp_param_.indexes_.empty()) { - mp_param_.GenIndexes(); // generate indexes for mp vole - } - - for (uint32_t i = 0; i < mp_param_.noise_num_; ++i) { - sparse_noise[i * mp_param_.sp_vole_size_ + mp_param_.indexes_[i]] = - noise[i]; - } - return sparse_noise; +// Get Dual LPN Encoder, e.g. SilverCode, ExAccCode, (ExConvCode) +template +std::shared_ptr GetEncoder(const VoleParam& param) { + std::shared_ptr encoder{nullptr}; + + const auto codetype = param.codetype_; + const auto code_size = param.code_size_; + const auto vole_num = param.vole_num_; + const auto mp_vole_size = param.mp_param_.mp_vole_size_; + + switch (codetype) { + // the size of SilverCode is ( code_size * 2, code_size ) + case CodeType::Silver5: + encoder = std::make_shared(code_size, 5); + break; + case CodeType::Silver11: + encoder = std::make_shared(code_size, 11); + break; + // the size of ExAccCode is ( code_size * 2, vole_num ) + case CodeType::ExAcc7: + encoder = std::make_shared>(vole_num, mp_vole_size); + break; + case CodeType::ExAcc11: + encoder = std::make_shared>(vole_num, mp_vole_size); + break; + case CodeType::ExAcc21: + encoder = std::make_shared>(vole_num, mp_vole_size); + break; + case CodeType::ExAcc40: + encoder = std::make_shared>(vole_num, mp_vole_size); + break; + // TODO: @wenfan + // support ExConv Code + default: + break; } + return encoder; +} - void dualLPN(absl::Span in, absl::Span out) const { - if (std::dynamic_pointer_cast(encoder_)) { - // [Warning] code_size_ is greater than vole_num_ - // thus, "out" does not have enough space to execute "DualEncode" - std::dynamic_pointer_cast(encoder_)->DualEncodeInplace(in); - memcpy(out.data(), in.data(), vole_num_ * sizeof(K)); - } else if (std::dynamic_pointer_cast(encoder_)) { - std::dynamic_pointer_cast(encoder_)->DualEncode(in, - out); - } else { - YACL_THROW("Did not implement"); - } +template +void DualLpnEncode(const VoleParam& param, absl::Span in, + absl::Span out) { + auto encoder = GetEncoder(param); + if (std::dynamic_pointer_cast(encoder)) { + const auto vole_num = param.vole_num_; + // [Warning] code_size is greater than vole_num + // thus, "out" does not have enough space to execute "DualEncode" + std::dynamic_pointer_cast(encoder)->DualEncodeInplace(in); + memcpy(out.data(), in.data(), vole_num * sizeof(K)); + } else if (std::dynamic_pointer_cast(encoder)) { + std::dynamic_pointer_cast(encoder)->DualEncode(in, out); + } else { + YACL_THROW("Did not implement"); } +} - void dualLPN2(absl::Span in0, absl::Span out0, absl::Span in1, - absl::Span out1) const { - if (std::dynamic_pointer_cast(encoder_)) { - // [Warning] code_size_ is greater than vole_num_ - // thus, "out" does not have enough space to execute "DualEncode2" - std::dynamic_pointer_cast(encoder_)->DualEncodeInplace2(in0, - in1); - memcpy(out0.data(), in0.data(), vole_num_ * sizeof(T)); - memcpy(out1.data(), in1.data(), vole_num_ * sizeof(K)); - } else if (std::dynamic_pointer_cast(encoder_)) { - std::dynamic_pointer_cast(encoder_)->DualEncode2( - in0, out0, in1, out1); - } else { - YACL_THROW("Did not implement"); - } +template +void DualLpnEncode2(const VoleParam& param, absl::Span in0, + absl::Span out0, absl::Span in1, absl::Span out1) { + auto encoder = GetEncoder(param); + if (std::dynamic_pointer_cast(encoder)) { + const auto vole_num = param.vole_num_; + // [Warning] code_size is greater than vole_num + // thus, "out" does not have enough space to execute "DualEncode2" + std::dynamic_pointer_cast(encoder)->DualEncodeInplace2(in0, + in1); + memcpy(out0.data(), in0.data(), vole_num * sizeof(T)); + memcpy(out1.data(), in1.data(), vole_num * sizeof(K)); + } else if (std::dynamic_pointer_cast(encoder)) { + std::dynamic_pointer_cast(encoder)->DualEncode2( + in0, out0, in1, out1); + } else { + YACL_THROW("Did not implement"); } -}; +} } // namespace @@ -226,25 +235,25 @@ void SilentVoleSender::SendImpl(const std::shared_ptr& ctx, } const auto vole_num = c.size(); - auto param = VoleParam(codetype_, vole_num, 128); + auto param = VoleParam(codetype_, vole_num); + auto& mp_param = param.mp_param_; // [Warning] copy, low efficiency - auto all_cot = ss_sender_.GenCot(ctx, param.require_ot_num_); - auto mp_vole_cot = all_cot.NextSlice(param.mp_vole_ot_num_); // mp-vole + auto all_cot = ss_sender_.GenCot(ctx, param.require_ot_num_); // generate Cot + auto mp_vole_cot = all_cot.NextSlice(param.mp_vole_ot_num_); // mp-vole auto base_vole_cot = all_cot.NextSlice(param.base_vole_ot_num_); // base-vole // base vole, w = u * delta + v - AlignedVector w(param.mp_param_.noise_num_); - + AlignedVector w(mp_param.noise_num_); Ot2VoleSend(base_vole_cot, absl::MakeSpan(w)); // mp vole - AlignedVector mp_vole_output(param.mp_param_.mp_vole_size_); - MpVoleSend_fixindex(ctx, mp_vole_cot, param.mp_param_, absl::MakeSpan(w), - absl::MakeSpan(mp_vole_output)); + AlignedVector mp_vole_output(mp_param.mp_vole_size_); + MpVoleSend_fixed_index(ctx, mp_vole_cot, mp_param, absl::MakeSpan(w), + absl::MakeSpan(mp_vole_output)); // dual LPN // compressing mp_vole_output into c - param.dualLPN(absl::MakeSpan(mp_vole_output), c); + DualLpnEncode(param, absl::MakeSpan(mp_vole_output), c); } template @@ -256,46 +265,54 @@ void SilentVoleReceiver::RecvImpl(const std::shared_ptr& ctx, const auto vole_num = a.size(); YACL_ENFORCE(vole_num == b.size()); - auto param = VoleParam(codetype_, vole_num, 128); + auto param = VoleParam(codetype_, vole_num); + auto& mp_param = param.mp_param_; auto choices = RandBits>(param.require_ot_num_); // generate punctured indexes for MpVole - param.mp_param_.GenIndexes(); + mp_param.GenIndexes(); // set mp-cot choices by punctured indexes - uint64_t pos = 0; - for (size_t i = 0; i < param.mp_param_.noise_num_; ++i) { - auto this_size = (i == param.mp_param_.noise_num_ - 1) - ? math::Log2Ceil(param.mp_param_.last_sp_vole_size_) - : math::Log2Ceil(param.mp_param_.sp_vole_size_); - uint32_t bound = 1 << this_size; - for (uint32_t mask = 1; mask < bound; mask <<= 1) { - choices.set(pos, param.mp_param_.indexes_[i] & mask); - ++pos; + { + uint64_t pos = 0; + auto sp_vole_length = math::Log2Ceil(mp_param.sp_vole_size_); + auto last_length = math::Log2Ceil(mp_param.last_sp_vole_size_); + for (size_t i = 0; i < mp_param.noise_num_; ++i) { + auto this_length = + (i == mp_param.noise_num_ - 1) ? last_length : sp_vole_length; + uint32_t bound = 1 << this_length; + for (uint32_t mask = 1; mask < bound; mask <<= 1) { + choices.set(pos, mp_param.indexes_[i] & mask); + ++pos; + } } } // [Warning] copy, low efficiency - auto all_cot = ss_receiver_.GenCot(ctx, choices); + auto all_cot = ss_receiver_.GenCot(ctx, choices); // generate Cot by choices auto mp_vole_cot = all_cot.NextSlice(param.mp_vole_ot_num_); // mp vole auto base_vole_cot = all_cot.NextSlice(param.base_vole_ot_num_); // base vole // base vole, w = u * delta + v - AlignedVector u(param.mp_param_.noise_num_); - AlignedVector v(param.mp_param_.noise_num_); + AlignedVector u(mp_param.noise_num_); + AlignedVector v(mp_param.noise_num_); // VOLE or subfield VOLE Ot2VoleRecv(base_vole_cot, absl::MakeSpan(u), absl::MakeSpan(v)); // mp vole - auto sparse_e = param.GetSparseNoise(absl::MakeSpan(u)); - AlignedVector mp_vole_output(param.mp_param_.mp_vole_size_); - MpVoleRecv_fixindex(ctx, mp_vole_cot, param.mp_param_, absl::MakeSpan(v), - absl::MakeSpan(mp_vole_output)); + // construct sparse noise + auto sparse_noise = AlignedVector(mp_param.mp_vole_size_); + for (uint32_t i = 0; i < mp_param.noise_num_; ++i) { + sparse_noise[i * mp_param.sp_vole_size_ + mp_param.indexes_[i]] = u[i]; + } + AlignedVector mp_vole_output(mp_param.mp_vole_size_); + MpVoleRecv_fixed_index(ctx, mp_vole_cot, mp_param, absl::MakeSpan(v), + absl::MakeSpan(mp_vole_output)); // dual LPN - // compressing sparse_e into a, mp_vole_output into b - param.dualLPN2(absl::MakeSpan(sparse_e), a, absl::MakeSpan(mp_vole_output), - b); + // compressing sparse_noise into a, mp_vole_output into b + DualLpnEncode2(param, absl::MakeSpan(sparse_noise), a, + absl::MakeSpan(mp_vole_output), b); } } // namespace yacl::crypto diff --git a/yacl/crypto/primitives/vole/f2k/silent_vole.h b/yacl/crypto/primitives/vole/f2k/silent_vole.h index 0ce8b9f6..a855bc83 100644 --- a/yacl/crypto/primitives/vole/f2k/silent_vole.h +++ b/yacl/crypto/primitives/vole/f2k/silent_vole.h @@ -19,8 +19,11 @@ #include "yacl/base/exception.h" #include "yacl/base/int128.h" #include "yacl/crypto/primitives/ot/softspoken_ote.h" +#include "yacl/crypto/utils/secparam.h" #include "yacl/link/context.h" +YACL_MODULE_DECLARE("silent_vole", SecParam::C::k128, SecParam::S::INF); + namespace yacl::crypto { enum class CodeType { @@ -78,6 +81,7 @@ class SilentVoleSender { SilentVoleSender(CodeType code) { ss_sender_ = SoftspokenOtExtSender(2); codetype_ = code; + delta_ = MakeUint128(0, 0); // init delta_ } void OneTimeSetup(const std::shared_ptr& ctx) { diff --git a/yacl/crypto/primitives/vole/f2k/sparse_vole.cc b/yacl/crypto/primitives/vole/f2k/sparse_vole.cc index 1a87d1eb..1a07b458 100644 --- a/yacl/crypto/primitives/vole/f2k/sparse_vole.cc +++ b/yacl/crypto/primitives/vole/f2k/sparse_vole.cc @@ -14,15 +14,18 @@ #include "yacl/crypto/primitives/vole/f2k/sparse_vole.h" +#include #include #include "sparse_vole.h" #include "yacl/base/aligned_vector.h" #include "yacl/base/byte_container_view.h" +#include "yacl/base/int128.h" #include "yacl/crypto/primitives/ot/gywz_ote.h" #include "yacl/crypto/primitives/ot/sgrr_ote.h" -#include "yacl/crypto/tools/random_permutation.h" +#include "yacl/crypto/tools/crhash.h" +#include "yacl/crypto/tools/rp.h" #include "yacl/math/f2k/f2k.h" #include "yacl/math/gadget.h" #include "yacl/utils/serialize.h" @@ -63,9 +66,8 @@ void SpVoleSend(const std::shared_ptr& ctx, GywzOtExtSend(ctx, send_ot, n, output); ParaCrHashInplace_128(output.subspan(0, n)); uint128_t send_msg = w; - for (uint32_t i = 0; i < n; ++i) { - send_msg ^= output[i]; - } + send_msg = std::reduce(output.begin(), output.begin() + n, send_msg, + std::bit_xor()); ctx->SendAsync(ctx->NextRank(), SerializeUint128(send_msg), "SpVole_msg"); } @@ -77,9 +79,8 @@ void SpVoleRecv(const std::shared_ptr& ctx, output[index] = 0; auto recv_buff = ctx->Recv(ctx->NextRank(), "SpVole_msg"); auto recv_msg = DeserializeUint128(ByteContainerView(recv_buff)); - for (uint32_t i = 0; i < n; ++i) { - recv_msg ^= output[i]; - } + recv_msg = std::reduce(output.begin(), output.begin() + n, recv_msg, + std::bit_xor()); output[index] = recv_msg ^ v; } @@ -142,7 +143,7 @@ void SpVoleRecv(const std::shared_ptr& ctx, void MpVoleSend(const std::shared_ptr& ctx, const OtSendStore& /*cot*/ send_ot, const MpVoleParam& param, - absl::Span w, absl::Span output) { + absl::Span w, absl::Span output) { YACL_ENFORCE(param.assumption_ == LpnNoiseAsm::RegularNoise); YACL_ENFORCE(output.size() >= param.mp_vole_size_); YACL_ENFORCE(w.size() >= param.noise_num_); @@ -174,9 +175,8 @@ void MpVoleSend(const std::shared_ptr& ctx, for (uint32_t i = 0; i < batch_num; ++i) { auto this_size = (i == batch_num - 1) ? last_batch_size : batch_size; auto this_span = output.subspan(i * batch_size, this_size); - for (const auto element : this_span) { - send_msg[i] ^= element; - } + send_msg[i] = std::reduce(this_span.begin(), this_span.end(), send_msg[i], + std::bit_xor()); } ctx->SendAsync( @@ -187,7 +187,7 @@ void MpVoleSend(const std::shared_ptr& ctx, void MpVoleRecv(const std::shared_ptr& ctx, const OtRecvStore& /*cot*/ recv_ot, const MpVoleParam& param, - absl::Span v, absl::Span output) { + absl::Span v, absl::Span output) { YACL_ENFORCE(param.assumption_ == LpnNoiseAsm::RegularNoise); YACL_ENFORCE(output.size() >= param.mp_vole_size_); YACL_ENFORCE(v.size() >= param.noise_num_); @@ -227,17 +227,17 @@ void MpVoleRecv(const std::shared_ptr& ctx, auto this_size = (i == batch_num - 1) ? last_batch_size : batch_size; auto this_span = output.subspan(i * batch_size, this_size); this_span[indexes[i]] = 0; // set punctured value as zero - for (const auto element : this_span) { - recv_msg[i] ^= element; - } + recv_msg[i] = std::reduce(this_span.begin(), this_span.end(), recv_msg[i], + std::bit_xor()); this_span[indexes[i]] = recv_msg[i] ^ v[i]; } } -void MpVoleSend_fixindex(const std::shared_ptr& ctx, - const OtSendStore& /*cot*/ send_ot, - const MpVoleParam& param, absl::Span w, - absl::Span output) { +void MpVoleSend_fixed_index(const std::shared_ptr& ctx, + const OtSendStore& /*cot*/ send_ot, + const MpVoleParam& param, + absl::Span w, + absl::Span output) { YACL_ENFORCE(param.assumption_ == LpnNoiseAsm::RegularNoise); YACL_ENFORCE(output.size() >= param.mp_vole_size_); YACL_ENFORCE(w.size() >= param.noise_num_); @@ -249,8 +249,10 @@ void MpVoleSend_fixindex(const std::shared_ptr& ctx, const auto batch_length = math::Log2Ceil(batch_size); const auto last_batch_length = math::Log2Ceil(last_batch_size); + // Copy vector w + auto spvole_sum = AlignedVector(w.data(), w.data() + batch_num); // send message buff for GYWZ OTe - auto gywz_send_msgs = std::vector( + auto gywz_send_msgs = AlignedVector( batch_length * (kSuperBatch - 1) + last_batch_length); const auto super_batch_num = math::DivCeil(batch_num, kSuperBatch); @@ -265,21 +267,25 @@ void MpVoleSend_fixindex(const std::shared_ptr& ctx, this_size = last_batch_size; this_length = last_batch_length; } - - auto this_span = - output.subspan((s * kSuperBatch + i) * batch_size, this_size); + auto batch_idx = s * kSuperBatch + i; + auto this_span = output.subspan(batch_idx * batch_size, this_size); // TODO: @wenfan // "Slice" would force to slice original OtStore from "begin" to "end", // which might cause unexpected error. // It would be better to use "NextSlice" here, but it's not a const - auto ot_slice = - send_ot.Slice((s * kSuperBatch + i) * batch_length, - (s * kSuperBatch + i) * batch_length + this_length); + auto ot_slice = send_ot.Slice(batch_idx * batch_length, + batch_idx * batch_length + this_length); auto send_span = absl::MakeSpan(gywz_send_msgs.data() + i * batch_length, this_length); // GywzOtExt is single-point COT - GywzOtExtSend_fixindex(ot_slice, this_size, this_span, send_span); + GywzOtExtSend_fixed_index(ot_slice, this_size, this_span, send_span); + // Use CrHash to break the correlation + ParaCrHashInplace_128(this_span); + // this_span xor + spvole_sum[batch_idx] = + std::reduce(this_span.begin(), this_span.end(), spvole_sum[batch_idx], + std::bit_xor()); } auto msg_length = kSuperBatch * batch_length; @@ -292,29 +298,18 @@ void MpVoleSend_fixindex(const std::shared_ptr& ctx, "GYWZ_OTE: messages"); } - // Break the correlation - ParaCrHashInplace_128(output.subspan(0, param.mp_vole_size_)); - - auto send_msgs = AlignedVector(w.data(), w.data() + batch_num); - - for (uint32_t i = 0; i < batch_num; ++i) { - auto this_size = (i == batch_num - 1) ? last_batch_size : batch_size; - auto this_span = output.subspan(i * batch_size, this_size); - for (const auto element : this_span) { - send_msgs[i] ^= element; - } - } - + auto& send_msgs = spvole_sum; ctx->SendAsync( ctx->NextRank(), ByteContainerView(send_msgs.data(), send_msgs.size() * sizeof(uint128_t)), - "MpVole_msg"); + "MPVOLE:messages"); } -void MpVoleRecv_fixindex(const std::shared_ptr& ctx, - const OtRecvStore& /*cot*/ recv_ot, - const MpVoleParam& param, absl::Span v, - absl::Span output) { +void MpVoleRecv_fixed_index(const std::shared_ptr& ctx, + const OtRecvStore& /*cot*/ recv_ot, + const MpVoleParam& param, + absl::Span v, + absl::Span output) { YACL_ENFORCE(param.assumption_ == LpnNoiseAsm::RegularNoise); YACL_ENFORCE(output.size() >= param.mp_vole_size_); YACL_ENFORCE(v.size() >= param.noise_num_); @@ -330,6 +325,9 @@ void MpVoleRecv_fixindex(const std::shared_ptr& ctx, const auto super_batch_num = math::DivCeil(batch_num, kSuperBatch); + // Copy vector v + auto spvole_sum = AlignedVector(v.begin(), v.begin() + batch_num); + for (uint32_t s = 0; s < super_batch_num; ++s) { const uint32_t bound = std::min(kSuperBatch, batch_num - s * kSuperBatch); @@ -351,48 +349,45 @@ void MpVoleRecv_fixindex(const std::shared_ptr& ctx, this_size = last_batch_size; this_length = last_batch_length; } - - auto this_span = - output.subspan((s * kSuperBatch + i) * batch_size, this_size); + auto batch_idx = s * kSuperBatch + i; + auto this_span = output.subspan(batch_idx * batch_size, this_size); // TODO: @wenfan // "Slice" would force to slice original OtStore from "begin" to "end", // which might cause unexpected error. // It would be better to use "NextSlice" here, but it's not a const - auto ot_slice = - recv_ot.Slice((s * kSuperBatch + i) * batch_length, - (s * kSuperBatch + i) * batch_length + this_length); + auto ot_slice = recv_ot.Slice(batch_idx * batch_length, + batch_idx * batch_length + this_length); auto recv_span = absl::MakeSpan(gywz_recv_msgs.data() + i * batch_length, this_length); // GywzOtExt is single-point COT - GywzOtExtRecv_fixindex(ot_slice, this_size, this_span, recv_span); + GywzOtExtRecv_fixed_index(ot_slice, this_size, this_span, recv_span); + // Use CrHash to break the correlation + ParaCrHashInplace_128(this_span); + // this_span xor + spvole_sum[batch_idx] = + std::reduce(this_span.begin(), this_span.end(), spvole_sum[batch_idx], + std::bit_xor()); } } // Break the correlation - ParaCrHashInplace_128(output.subspan(0, param.mp_vole_size_)); - auto recv_buff = ctx->Recv(ctx->NextRank(), "MpVole_msg"); - YACL_ENFORCE(static_cast(recv_buff.size()) >= + auto recv_buff = ctx->Recv(ctx->NextRank(), "MPVOLE:messages"); + YACL_ENFORCE(static_cast(recv_buff.size()) == batch_num * sizeof(uint128_t)); - auto recv_msgs = absl::MakeSpan(reinterpret_cast(recv_buff.data()), batch_num); for (uint32_t i = 0; i < batch_num; ++i) { - auto this_size = (i == batch_num - 1) ? last_batch_size : batch_size; - auto this_span = output.subspan(i * batch_size, this_size); - this_span[indexes[i]] = 0; // set punctured value as zero - for (const auto element : this_span) { - recv_msgs[i] ^= element; - } - this_span[indexes[i]] = recv_msgs[i] ^ v[i]; + output[i * batch_size + indexes[i]] ^= recv_msgs[i] ^ spvole_sum[i]; } } -void MpVoleSend_fixindex(const std::shared_ptr& ctx, - const OtSendStore& /*cot*/ send_ot, - const MpVoleParam& param, absl::Span w, - absl::Span output) { +void MpVoleSend_fixed_index(const std::shared_ptr& ctx, + const OtSendStore& /*cot*/ send_ot, + const MpVoleParam& param, + absl::Span w, + absl::Span output) { YACL_ENFORCE(param.assumption_ == LpnNoiseAsm::RegularNoise); YACL_ENFORCE(output.size() >= param.mp_vole_size_); YACL_ENFORCE(w.size() >= param.noise_num_); @@ -404,12 +399,16 @@ void MpVoleSend_fixindex(const std::shared_ptr& ctx, const auto batch_length = math::Log2Ceil(batch_size); const auto last_batch_length = math::Log2Ceil(last_batch_size); - // send message buff for GYWZ OTe - auto gywz_send_msgs = std::vector( + // copy w + auto spvole_sum = AlignedVector(w.begin(), w.begin() + batch_num); + // GywzOtExt need uint128_t buffer + auto spvole_buff = + AlignedVector(1 << std::max(batch_length, last_batch_length)); + auto spvole_span = absl::MakeSpan(spvole_buff); + // send message buffer for GYWZ OTe + auto gywz_send_msgs = AlignedVector( batch_length * (kSuperBatch - 1) + last_batch_length); - std::vector mpvole_buff(param.mp_vole_size_); - auto mpvole_span = absl::MakeSpan(mpvole_buff); const auto super_batch_num = math::DivCeil(batch_num, kSuperBatch); for (uint32_t s = 0; s < super_batch_num; ++s) { @@ -418,24 +417,37 @@ void MpVoleSend_fixindex(const std::shared_ptr& ctx, for (uint32_t i = 0; i < bound; ++i) { auto this_size = batch_size; auto this_length = batch_length; + if (s == (super_batch_num - 1) && i == (bound - 1)) { this_size = last_batch_size; this_length = last_batch_length; } - - auto this_span = - mpvole_span.subspan((s * kSuperBatch + i) * batch_size, this_size); + // full_size = 1 << this_length, would avoid copying in GywzOtExt + auto full_size = 1 << this_length; + auto batch_idx = s * kSuperBatch + i; + auto this_span = spvole_span.subspan(0, full_size); // TODO: @wenfan // "Slice" would force to slice original OtStore from "begin" to "end", // which might cause unexpected error. // It would be better to use "NextSlice" here, but it's not a const - auto ot_slice = - send_ot.Slice((s * kSuperBatch + i) * batch_length, - (s * kSuperBatch + i) * batch_length + this_length); + auto ot_slice = send_ot.Slice(batch_idx * batch_length, + batch_idx * batch_length + this_length); auto send_span = absl::MakeSpan(gywz_send_msgs.data() + i * batch_length, this_length); - GywzOtExtSend_fixindex(ot_slice, this_size, this_span, send_span); + // GywzOtExt is single-point COT + GywzOtExtSend_fixed_index(ot_slice, full_size, this_span, send_span); + // Use CrHash to break the correlation + ParaCrHashInplace_128(this_span.subspan(0, this_size)); + // convert to uint64_t + std::transform(this_span.begin(), this_span.begin() + this_size, + output.data() + batch_idx * batch_size, + [](uint128_t t) -> uint64_t { return t; }); + // this_span xor + spvole_sum[batch_idx] = + std::reduce(output.data() + batch_idx * batch_size, + output.data() + batch_idx * batch_size + this_size, + spvole_sum[batch_idx], std::bit_xor()); } auto msg_length = kSuperBatch * batch_length; @@ -448,30 +460,18 @@ void MpVoleSend_fixindex(const std::shared_ptr& ctx, "GYWZ_OTE: messages"); } - // Break the correlation - ParaCrHashInplace_128(mpvole_span.subspan(0, param.mp_vole_size_)); - - auto send_msgs = AlignedVector(w.data(), w.data() + batch_num); - - for (uint32_t i = 0; i < batch_num; ++i) { - auto this_size = (i == batch_num - 1) ? last_batch_size : batch_size; - auto this_span = output.subspan(i * batch_size, this_size); - for (uint32_t j = 0; j < this_size; ++j) { - this_span[j] = mpvole_span[batch_size * i + j]; - send_msgs[i] ^= this_span[j]; - } - } - + auto& send_msgs = spvole_sum; ctx->SendAsync( ctx->NextRank(), ByteContainerView(send_msgs.data(), send_msgs.size() * sizeof(uint64_t)), - "MpVole_msg"); + "MPVOLE:messages"); } -void MpVoleRecv_fixindex(const std::shared_ptr& ctx, - const OtRecvStore& /*cot*/ recv_ot, - const MpVoleParam& param, absl::Span v, - absl::Span output) { +void MpVoleRecv_fixed_index(const std::shared_ptr& ctx, + const OtRecvStore& /*cot*/ recv_ot, + const MpVoleParam& param, + absl::Span v, + absl::Span output) { YACL_ENFORCE(param.assumption_ == LpnNoiseAsm::RegularNoise); YACL_ENFORCE(output.size() >= param.mp_vole_size_); YACL_ENFORCE(v.size() >= param.noise_num_); @@ -485,10 +485,15 @@ void MpVoleRecv_fixindex(const std::shared_ptr& ctx, const auto& indexes = param.indexes_; - std::vector mpvole_buff(param.mp_vole_size_); - auto mpvole_span = absl::MakeSpan(mpvole_buff); const auto super_batch_num = math::DivCeil(batch_num, kSuperBatch); + // Copy vector v + auto spvole_sum = AlignedVector(v.begin(), v.begin() + batch_num); + // GywzOtExt need uint128_t buffer + auto spvole_buff = + AlignedVector(1 << std::max(batch_length, last_batch_length)); + auto spvole_span = absl::MakeSpan(spvole_buff); + for (uint32_t s = 0; s < super_batch_num; ++s) { const uint32_t bound = std::min(kSuperBatch, batch_num - s * kSuperBatch); @@ -510,42 +515,42 @@ void MpVoleRecv_fixindex(const std::shared_ptr& ctx, this_size = last_batch_size; this_length = last_batch_length; } - - auto this_span = - mpvole_span.subspan((s * kSuperBatch + i) * batch_size, this_size); + // full_size = 1 << this_length, would avoid copying in GywzOtExt + auto full_size = 1 << this_length; + auto batch_idx = s * kSuperBatch + i; + auto this_span = spvole_span.subspan(0, full_size); // TODO: @wenfan // "Slice" would force to slice original OtStore from "begin" to "end", // which might cause unexpected error. // It would be better to use "NextSlice" here, but it's not a const - auto ot_slice = - recv_ot.Slice((s * kSuperBatch + i) * batch_length, - (s * kSuperBatch + i) * batch_length + this_length); + auto ot_slice = recv_ot.Slice(batch_idx * batch_length, + batch_idx * batch_length + this_length); auto recv_span = absl::MakeSpan(gywz_recv_msgs.data() + i * batch_length, this_length); - GywzOtExtRecv_fixindex(ot_slice, this_size, this_span, recv_span); + // GywzOtExt is single-point COT + GywzOtExtRecv_fixed_index(ot_slice, full_size, this_span, recv_span); + // Use CrHash to break the correlation + ParaCrHashInplace_128(this_span.subspan(0, this_size)); + // convert to uint64_t + std::transform(this_span.begin(), this_span.begin() + this_size, + output.data() + batch_idx * batch_size, + [](uint128_t t) -> uint64_t { return t; }); + // this_span xor + spvole_sum[batch_idx] = + std::reduce(output.data() + batch_idx * batch_size, + output.data() + batch_idx * batch_size + this_size, + spvole_sum[batch_idx], std::bit_xor()); } } - // Break the correlation - ParaCrHashInplace_128(mpvole_span.subspan(0, param.mp_vole_size_)); - - auto recv_buff = ctx->Recv(ctx->NextRank(), "MpVole_msg"); - YACL_ENFORCE(static_cast(recv_buff.size()) >= + auto recv_buff = ctx->Recv(ctx->NextRank(), "MPVOLE:messages"); + YACL_ENFORCE(static_cast(recv_buff.size()) == batch_num * sizeof(uint64_t)); - auto recv_msgs = absl::MakeSpan(reinterpret_cast(recv_buff.data()), batch_num); for (uint32_t i = 0; i < batch_num; ++i) { - auto this_size = (i == batch_num - 1) ? last_batch_size : batch_size; - auto this_span = output.subspan(i * batch_size, this_size); - // set punctured value as zero - mpvole_span[i * batch_size + indexes[i]] = 0; - for (uint32_t j = 0; j < this_size; ++j) { - this_span[j] = mpvole_span[i * batch_size + j]; - recv_msgs[i] ^= this_span[j]; - } - this_span[indexes[i]] = recv_msgs[i] ^ v[i]; + output[i * batch_size + indexes[i]] ^= recv_msgs[i] ^ spvole_sum[i]; } } diff --git a/yacl/crypto/primitives/vole/f2k/sparse_vole.h b/yacl/crypto/primitives/vole/f2k/sparse_vole.h index 24efa741..ad21ef07 100644 --- a/yacl/crypto/primitives/vole/f2k/sparse_vole.h +++ b/yacl/crypto/primitives/vole/f2k/sparse_vole.h @@ -18,8 +18,11 @@ #include "yacl/crypto/primitives/ot/ot_store.h" #include "yacl/crypto/primitives/ot/softspoken_ote.h" #include "yacl/crypto/utils/rand.h" +#include "yacl/crypto/utils/secparam.h" #include "yacl/math/gadget.h" +YACL_MODULE_DECLARE("sparse_vole", SecParam::C::INF, SecParam::S::INF); + namespace yacl::crypto { // Implementation about sparse-VOLE over GF(2^128), including base-VOLE, @@ -36,7 +39,7 @@ namespace yacl::crypto { // const OtRecvStore& /*rot*/ recv_ot, uint32_t n, uint32_t // index, uint128_t v, absl::Span output); -// Single-point f2k-Vole (by GYWZ-OTe) +// Single-point GF(2^128)-Vole (by GYWZ-OTe) // the type of ot_store must be COT void SpVoleSend(const std::shared_ptr& ctx, const OtSendStore& /*cot*/ send_ot, uint32_t n, uint128_t w, @@ -57,11 +60,12 @@ struct MpVoleParam { std::vector indexes_; LpnNoiseAsm assumption_; - MpVoleParam() {} + MpVoleParam() : MpVoleParam(1, 2) {} MpVoleParam(uint64_t noise_num, uint64_t mp_vole_size, LpnNoiseAsm assumption = LpnNoiseAsm::RegularNoise) { YACL_ENFORCE(assumption == LpnNoiseAsm::RegularNoise); + YACL_ENFORCE(noise_num > 0); noise_num_ = noise_num; mp_vole_size_ = mp_vole_size; assumption_ = assumption; @@ -90,7 +94,7 @@ struct MpVoleParam { for (uint32_t i = 0; i < noise_num_ - 1; ++i) { indexes_[i] = indexes[i] % sp_vole_size_; } - indexes_[noise_num_ - 1] = indexes[noise_num_ - 1] % last_sp_vole_size_; + indexes_[noise_num_ - 1] %= last_sp_vole_size_; } }; @@ -103,41 +107,50 @@ struct MpVoleParam { // const OtRecvStore& /*rot*/ recv_ot, const MpVoleParam& param, // absl::Span v, absl::Span output); -// Multi-point f2k-Vole with Regular Noise (GYWZ-OTe based) +// Multi-point GF(2^128)-Vole with Regular Noise (GYWZ-OTe based) void MpVoleSend(const std::shared_ptr& ctx, const OtSendStore& /*cot*/ send_ot, const MpVoleParam& param, - absl::Span w, absl::Span output); + absl::Span w, absl::Span output); void MpVoleRecv(const std::shared_ptr& ctx, const OtRecvStore& /*cot*/ recv_ot, const MpVoleParam& param, - absl::Span v, absl::Span output); + absl::Span v, absl::Span output); +// +// -------------------------- +// Customized +// -------------------------- +// // Multi-point f2k-Vole with Regular Noise (GYWZ-OTe based) // Most efficiency! Punctured indexes would be determined by the choices of -// OtStore. But "FixIndexMpVoleSend_Cot/FixIndexMpVoleRecv_Cot" would not check -// the indexes determined by OtStore and the indexes provided by MpVoleParam are -// same. - +// OtStore. But "MpVoleSend_fixed_index/MpVoleRecv_fixed_index" would not check +// whether the indexes determined by OtStore and the indexes provided by +// MpVoleParam are same.态 +// // GF(2^128) -void MpVoleSend_fixindex(const std::shared_ptr& ctx, - const OtSendStore& /*cot*/ send_ot, - const MpVoleParam& param, absl::Span w, - absl::Span output); - -void MpVoleRecv_fixindex(const std::shared_ptr& ctx, - const OtRecvStore& /*cot*/ recv_ot, - const MpVoleParam& param, absl::Span v, - absl::Span output); +void MpVoleSend_fixed_index(const std::shared_ptr& ctx, + const OtSendStore& /*cot*/ send_ot, + const MpVoleParam& param, + absl::Span w, + absl::Span output); + +void MpVoleRecv_fixed_index(const std::shared_ptr& ctx, + const OtRecvStore& /*cot*/ recv_ot, + const MpVoleParam& param, + absl::Span v, + absl::Span output); // GF(2^64) -void MpVoleSend_fixindex(const std::shared_ptr& ctx, - const OtSendStore& /*cot*/ send_ot, - const MpVoleParam& param, absl::Span w, - absl::Span output); - -void MpVoleRecv_fixindex(const std::shared_ptr& ctx, - const OtRecvStore& /*cot*/ recv_ot, - const MpVoleParam& param, absl::Span v, - absl::Span output); +void MpVoleSend_fixed_index(const std::shared_ptr& ctx, + const OtSendStore& /*cot*/ send_ot, + const MpVoleParam& param, + absl::Span w, + absl::Span output); + +void MpVoleRecv_fixed_index(const std::shared_ptr& ctx, + const OtRecvStore& /*cot*/ recv_ot, + const MpVoleParam& param, + absl::Span v, + absl::Span output); } // namespace yacl::crypto diff --git a/yacl/crypto/primitives/vole/f2k/sparse_vole_test.cc b/yacl/crypto/primitives/vole/f2k/sparse_vole_test.cc index 692c5c9f..5d0b072c 100644 --- a/yacl/crypto/primitives/vole/f2k/sparse_vole_test.cc +++ b/yacl/crypto/primitives/vole/f2k/sparse_vole_test.cc @@ -46,16 +46,16 @@ class MpVoleTest : public ::testing::TestWithParam {}; TEST_P(SpVoleTest, SpVoleWork) { auto lctxs = link::test::SetupWorld(2); // setup network const uint64_t num = GetParam().num; - auto cot = MockCots(math::Log2Ceil(num), RandU128()); + auto cot = MockCots(math::Log2Ceil(num), FastRandU128()); // auto delta = rot.recv.CopyChoice().data()[0]; std::vector v(num); std::vector w(num); - uint128_t single_v = RandU128(); - uint128_t single_w = RandU128(); - uint32_t index = RandU64() % num; + uint128_t single_v = FastRandU128(); + uint128_t single_w = FastRandU128(); + uint32_t index = FastRandU64() % num; auto sender = std::async([&] { SpVoleSend(lctxs[0], cot.send, num, single_w, absl::MakeSpan(w)); @@ -85,7 +85,7 @@ TEST_P(MpVoleTest, MpVoleWork) { MpVoleParam param(index_num, num); param.GenIndexes(); - auto cot = MockCots(param.require_ot_num_, RandU128()); + auto cot = MockCots(param.require_ot_num_, FastRandU128()); std::vector s_output(num); std::vector r_output(num); @@ -124,7 +124,7 @@ TEST_P(MpVoleTest, MpVoleWork) { } } -TEST_P(MpVoleTest, MpVole128_fixindex_Work) { +TEST_P(MpVoleTest, MpVole128_fixed_index_Work) { auto lctxs = link::test::SetupWorld(2); // setup network const uint64_t num = GetParam().num; const uint64_t index_num = GetParam().index_num; @@ -149,7 +149,7 @@ TEST_P(MpVoleTest, MpVole128_fixindex_Work) { YACL_ENFORCE(pos == param.require_ot_num_); - auto cot = MockCots(param.require_ot_num_, RandU128(), choices); + auto cot = MockCots(param.require_ot_num_, FastRandU128(), choices); std::vector s_output(num); std::vector r_output(num); @@ -158,13 +158,13 @@ TEST_P(MpVoleTest, MpVole128_fixindex_Work) { auto w = RandVec(index_num); auto sender = std::async([&] { - MpVoleSend_fixindex(lctxs[0], cot.send, param, absl::MakeSpan(w), - absl::MakeSpan(s_output)); + MpVoleSend_fixed_index(lctxs[0], cot.send, param, absl::MakeSpan(w), + absl::MakeSpan(s_output)); }); auto receiver = std::async([&] { - MpVoleRecv_fixindex(lctxs[1], cot.recv, param, absl::MakeSpan(v), - absl::MakeSpan(r_output)); + MpVoleRecv_fixed_index(lctxs[1], cot.recv, param, absl::MakeSpan(v), + absl::MakeSpan(r_output)); }); sender.get(); @@ -188,7 +188,7 @@ TEST_P(MpVoleTest, MpVole128_fixindex_Work) { } } -TEST_P(MpVoleTest, MpVole64_fixindex_Work) { +TEST_P(MpVoleTest, MpVole64_fixed_index_Work) { auto lctxs = link::test::SetupWorld(2); // setup network const uint64_t num = GetParam().num; const uint64_t index_num = GetParam().index_num; @@ -213,7 +213,7 @@ TEST_P(MpVoleTest, MpVole64_fixindex_Work) { YACL_ENFORCE(pos == param.require_ot_num_); - auto cot = MockCots(param.require_ot_num_, RandU128(), choices); + auto cot = MockCots(param.require_ot_num_, FastRandU128(), choices); std::vector s_output(num); std::vector r_output(num); @@ -222,13 +222,13 @@ TEST_P(MpVoleTest, MpVole64_fixindex_Work) { auto w = RandVec(index_num); auto sender = std::async([&] { - MpVoleSend_fixindex(lctxs[0], cot.send, param, absl::MakeSpan(w), - absl::MakeSpan(s_output)); + MpVoleSend_fixed_index(lctxs[0], cot.send, param, absl::MakeSpan(w), + absl::MakeSpan(s_output)); }); auto receiver = std::async([&] { - MpVoleRecv_fixindex(lctxs[1], cot.recv, param, absl::MakeSpan(v), - absl::MakeSpan(r_output)); + MpVoleRecv_fixed_index(lctxs[1], cot.recv, param, absl::MakeSpan(v), + absl::MakeSpan(r_output)); }); sender.get(); @@ -266,4 +266,4 @@ INSTANTIATE_TEST_SUITE_P(Works_Instances, MpVoleTest, TestParams2{1 << 10, 257}, TestParams2{1 << 20, 1024})); -} // namespace yacl::crypto \ No newline at end of file +} // namespace yacl::crypto diff --git a/yacl/crypto/primitives/vss/poly.cc b/yacl/crypto/primitives/vss/poly.cc index 77fee51e..4374a55b 100644 --- a/yacl/crypto/primitives/vss/poly.cc +++ b/yacl/crypto/primitives/vss/poly.cc @@ -2,12 +2,17 @@ namespace yacl::crypto { +void Polynomial::RandomPolynomial(size_t threshold) { + MPInt zero_value; + MPInt::RandomLtN(this->modulus_, &zero_value); + CreatePolynomial(zero_value, threshold); +} + // Generate a random polynomial with the given zero value, threshold, and // modulus_. -void Polynomial::CreatePolynomial(const math::MPInt& zero_value, - size_t threshold) { +void Polynomial::CreatePolynomial(const MPInt& zero_value, size_t threshold) { // Create a vector to hold the polynomial coefficients. - std::vector coefficients(threshold); + std::vector coefficients(threshold); // Set the constant term (coefficient[0]) of the polynomial to the given // zero_value. @@ -16,11 +21,11 @@ void Polynomial::CreatePolynomial(const math::MPInt& zero_value, // Generate random coefficients for the remaining terms of the polynomial. for (size_t i = 1; i < threshold; ++i) { // Create a variable to hold the current coefficient being generated. - math::MPInt coefficient_i; + MPInt coefficient_i; // Generate a random integer less than modulus_ and assign it to // coefficient_i. - math::MPInt::RandomLtN(this->modulus_, &coefficient_i); + MPInt::RandomLtN(this->modulus_, &coefficient_i); // Set the current coefficient to the generated random value. coefficients[i] = coefficient_i; @@ -31,75 +36,79 @@ void Polynomial::CreatePolynomial(const math::MPInt& zero_value, } // Horner's method for computing the polynomial value at a given x. -void Polynomial::EvaluatePolynomial(const math::MPInt& x, - math::MPInt& result) const { +void Polynomial::EvaluatePolynomial(const MPInt& x, MPInt* result) const { // Initialize the result to the constant term (coefficient of highest degree) // of the polynomial. - if (!coeffs_.empty()) { - result = coeffs_.back(); - } else { - // If the coefficients vector is empty, print a warning message. - std::cout << "coeffs_ is empty!!!" << std::endl; - } + YACL_ENFORCE(!coeffs_.empty(), "coeffs_ is empty!!!"); + auto tmp = coeffs_.back(); // Evaluate the polynomial using Horner's method. // Starting from the second highest degree coefficient to the constant term // (coefficient[0]). for (int i = coeffs_.size() - 2; i >= 0; --i) { // Create a duplicate of the given x to avoid modifying it. - // math::MPInt x_dup = x; + // MPInt x_dup = x; // Multiply the current result with the x value and update the result. // result = x_dup.MulMod(result, modulus_); - result = x.MulMod(result, modulus_); + tmp = x.MulMod(tmp, modulus_); // Add the next coefficient to the result. - result = result.AddMod(coeffs_[i], modulus_); + tmp = tmp.AddMod(coeffs_[i], modulus_); } + + *result = tmp; } // Lagrange Interpolation algorithm for polynomial interpolation. -void Polynomial::LagrangeInterpolation(std::vector& xs, - std::vector& ys, - math::MPInt& result) const { +void Polynomial::LagrangeInterpolation(absl::Span xs, + absl::Span ys, + MPInt* result) const { + *result = LagrangeInterpolation(xs, ys, 0_mp, modulus_); +} + +MPInt Polynomial::LagrangeInterpolation(absl::Span xs, + absl::Span ys, + const MPInt& target_x, + const MPInt& modulus) { + YACL_ENFORCE(xs.size() == ys.size()); // Initialize the accumulator to store the result of the interpolation. - math::MPInt acc(0); + auto acc = 0_mp; // Loop over each element in the input points xs and interpolate the // polynomial. - for (size_t i = 0; i < xs.size(); ++i) { - // Initialize the numerator and denominator for Lagrange interpolation. - math::MPInt num(1); - math::MPInt denum(1); - - // Compute the numerator and denominator for the current interpolation - // point. - for (size_t j = 0; j < xs.size(); ++j) { - if (j != i) { - math::MPInt xj = xs[j]; - - // Update the numerator by multiplying it with the current xj. - num = num.MulMod(xj, modulus_); - - // Compute the difference between the current xj and the current xi - // (xs[i]). - math::MPInt xj_sub_xi = xj.SubMod(xs[i], modulus_); - - // Update the denominator by multiplying it with the difference. - denum = denum.MulMod(xj_sub_xi, modulus_); - } - } + for (uint64_t i = 0; i < xs.size(); ++i) { + auto t = Polynomial::LagrangeComputeAtX(xs, i, ys[i], target_x, modulus); + acc = t.AddMod(acc, modulus); + } + return acc; +} + +MPInt Polynomial::LagrangeComputeAtX(absl::Span xs, uint64_t index, + const MPInt& y, const MPInt& target_x, + const MPInt& modulus) { + YACL_ENFORCE(index < xs.size(), "X index should be < xs.size()"); + + auto num = 1_mp; + auto denum = 1_mp; + for (uint64_t j = 0; j < xs.size(); ++j) { + if (j != index) { + MPInt xj_sub_targetx = xs[j].SubMod(target_x, modulus); - // Compute the inverse of the denominator modulo the modulus_. - math::MPInt denum_inv = denum.InvertMod(modulus_); + // Update the numerator by multiplying it with the current xj. + num = num.MulMod(xj_sub_targetx, modulus); - // Compute the current interpolated value and add it to the accumulator. - acc = ys[i] - .MulMod(num, modulus_) - .MulMod(denum_inv, modulus_) - .AddMod(acc, modulus_); + // Compute the difference between the current xj and the current xi + // (xs[i]). + MPInt xj_sub_xi = xs[j].SubMod(xs[index], modulus); + + // Update the denominator by multiplying it with the difference. + denum = denum.MulMod(xj_sub_xi, modulus); + } } + // Compute the inverse of the denominator modulo the modulus_. + MPInt denum_inv = denum.InvertMod(modulus); - // Store the final interpolated result in the 'result' variable. - result = acc; + return y.MulMod(num, modulus).MulMod(denum_inv, modulus); } + } // namespace yacl::crypto diff --git a/yacl/crypto/primitives/vss/poly.h b/yacl/crypto/primitives/vss/poly.h index 3ae74248..71ff8d48 100644 --- a/yacl/crypto/primitives/vss/poly.h +++ b/yacl/crypto/primitives/vss/poly.h @@ -4,6 +4,8 @@ namespace yacl::crypto { +using math::MPInt; + // Polynomial class for polynomial manipulation and sharing. class Polynomial { public: @@ -12,7 +14,7 @@ class Polynomial { * * @param modulus */ - Polynomial(math::MPInt modulus) : modulus_(modulus) {} + Polynomial(const MPInt& modulus) : modulus_(modulus) {} /** * @brief Destroy the Polynomial object @@ -24,11 +26,12 @@ class Polynomial { * @brief Creates a random polynomial with the given zero_value, threshold, * and modulus. * - * @param zero_value + * @param zero_value Set poly(0) to be the zero_value(secret value). * @param threshold * @param modulus */ - void CreatePolynomial(const math::MPInt& zero_value, size_t threshold); + void CreatePolynomial(const MPInt& zero_value, size_t threshold); + void RandomPolynomial(size_t threshold); /** * @brief Horner's method, also known as Horner's rule or Horner's scheme, is @@ -59,7 +62,7 @@ class Polynomial { * @param modulus * @param result */ - void EvaluatePolynomial(const math::MPInt& x, math::MPInt& result) const; + void EvaluatePolynomial(const MPInt& x, MPInt* result) const; /** * @brief Performs Lagrange interpolation to interpolate the polynomial based @@ -70,9 +73,8 @@ class Polynomial { * @param prime * @param result */ - void LagrangeInterpolation(std::vector& xs, - std::vector& ys, - math::MPInt& result) const; + void LagrangeInterpolation(absl::Span, absl::Span, + MPInt* result) const; /** * @brief Sets the coefficients of the polynomial to the provided vector of @@ -80,21 +82,29 @@ class Polynomial { * * @param coefficients */ - void SetCoeffs(const std::vector& coefficients) { + void SetCoeffs(const std::vector& coefficients) { coeffs_ = coefficients; } /** * @brief Returns the coefficients of the polynomial as a vector of MPInt. * - * @return std::vector + * @return std::vector */ - std::vector GetCoeffs() const { return coeffs_; } + std::vector GetCoeffs() const { return coeffs_; } + + static MPInt LagrangeInterpolation(absl::Span xs, + absl::Span ys, + const MPInt& target_x, + const MPInt& modulus); + static MPInt LagrangeComputeAtX(absl::Span xs, uint64_t index, + const MPInt& y, const MPInt& target_x, + const MPInt& modulus); private: // Vector to store the coefficients of the polynomial. - std::vector coeffs_; - math::MPInt modulus_; + std::vector coeffs_; + MPInt modulus_; }; } // namespace yacl::crypto diff --git a/yacl/crypto/primitives/vss/vss.cc b/yacl/crypto/primitives/vss/vss.cc index 89ea5ddf..b29cd230 100644 --- a/yacl/crypto/primitives/vss/vss.cc +++ b/yacl/crypto/primitives/vss/vss.cc @@ -5,29 +5,29 @@ namespace yacl::crypto { // Generate shares for the Verifiable Secret Sharing scheme. // Generate shares for the given secret using the provided polynomial. std::vector -VerifiableSecretSharing::CreateShare(const math::MPInt& secret, - Polynomial& poly) { +VerifiableSecretSharing::CreateShare(const MPInt& secret, + Polynomial& poly) const { // Create a polynomial with the secret as the constant term and random // coefficients. - std::vector coefficients(this->GetThreshold()); + std::vector coefficients(this->GetThreshold()); poly.CreatePolynomial(secret, this->GetThreshold()); - std::vector xs(this->GetTotal()); - std::vector ys(this->GetTotal()); + std::vector xs(total_); + std::vector ys(total_); // Vector to store the generated shares (x, y) for the Verifiable Secret // Sharing scheme. std::vector shares; // Generate shares by evaluating the polynomial at random points xs. - for (size_t i = 0; i < this->GetTotal(); i++) { - math::MPInt x_i; - math::MPInt::RandomLtN(this->GetPrime(), &x_i); + for (size_t i = 0; i < total_; i++) { + MPInt x_i; + MPInt::RandomLtN(prime_, &x_i); // EvaluatePolynomial uses Horner's method. // Evaluate the polynomial at the point x_i to compute the share's // y-coordinate (ys[i]). - poly.EvaluatePolynomial(x_i, ys[i]); + poly.EvaluatePolynomial(x_i, &ys[i]); xs[i] = x_i; shares.push_back({xs[i], ys[i]}); @@ -39,22 +39,23 @@ VerifiableSecretSharing::CreateShare(const math::MPInt& secret, // Generate shares with commitments for the Verifiable Secret Sharing scheme. VerifiableSecretSharing::ShareWithCommitsResult VerifiableSecretSharing::CreateShareWithCommits( - const math::MPInt& secret, - const std::unique_ptr& ecc_group, Polynomial& poly) { + const MPInt& secret, + const std::unique_ptr& ecc_group, + Polynomial& poly) const { // Create a polynomial with the secret as the constant term and random // coefficients. poly.CreatePolynomial(secret, this->threshold_); - std::vector xs(this->total_); - std::vector ys(this->total_); + std::vector xs(this->total_); + std::vector ys(this->total_); std::vector shares(this->total_); // Generate shares by evaluating the polynomial at random points xs. for (size_t i = 0; i < this->total_; i++) { - math::MPInt x_i; - math::MPInt::RandomLtN(this->prime_, &x_i); + MPInt x_i; + MPInt::RandomLtN(this->prime_, &x_i); - poly.EvaluatePolynomial(x_i, ys[i]); + poly.EvaluatePolynomial(x_i, &ys[i]); xs[i] = x_i; shares[i] = {xs[i], ys[i]}; } @@ -68,23 +69,23 @@ VerifiableSecretSharing::CreateShareWithCommits( } // Recover the secret from the shares using Lagrange interpolation. -math::MPInt VerifiableSecretSharing::RecoverSecret( - absl::Span shares) { - YACL_ENFORCE(shares.size() == threshold_); +MPInt VerifiableSecretSharing::RecoverSecret( + absl::Span shares) const { + YACL_ENFORCE(shares.size() >= threshold_); - math::MPInt secret(0); - std::vector xs(shares.size()); - std::vector ys(shares.size()); + MPInt secret(0); + std::vector xs(threshold_); + std::vector ys(threshold_); // Extract xs and ys from the given shares. - for (size_t i = 0; i < shares.size(); i++) { + for (size_t i = 0; i < threshold_; i++) { xs[i] = shares[i].x; ys[i] = shares[i].y; } // Use Lagrange interpolation to recover the secret from the shares. Polynomial poly(this->prime_); - poly.LagrangeInterpolation(xs, ys, secret); + poly.LagrangeInterpolation(xs, ys, &secret); return secret; } @@ -93,7 +94,7 @@ math::MPInt VerifiableSecretSharing::RecoverSecret( // curve group. std::vector CreateCommits( const std::unique_ptr& ecc_group, - const std::vector& coefficients) { + const std::vector& coefficients) { std::vector commits(coefficients.size()); for (size_t i = 0; i < coefficients.size(); i++) { // Commit each coefficient by multiplying it with the base point of the @@ -107,12 +108,12 @@ std::vector CreateCommits( bool VerifyCommits(const std::unique_ptr& ecc_group, const VerifiableSecretSharing::Share& share, const std::vector& commits, - const math::MPInt& prime) { + const MPInt& prime) { // Compute the expected commitment of the share.y by multiplying it with the // base point. yacl::crypto::EcPoint expected_gy = ecc_group->MulBase(share.y); - math::MPInt x_pow_i(1); + MPInt x_pow_i(1); yacl::crypto::EcPoint gy = commits[0]; // Evaluate the Lagrange polynomial at x = share.x to compute the share.y and @@ -123,10 +124,7 @@ bool VerifyCommits(const std::unique_ptr& ecc_group, } // Compare the computed gy with the expected_gy to verify the commitment. - if (ecc_group->PointEqual(expected_gy, gy)) { - return true; - } - return false; + return ecc_group->PointEqual(expected_gy, gy); } } // namespace yacl::crypto diff --git a/yacl/crypto/primitives/vss/vss.h b/yacl/crypto/primitives/vss/vss.h index 6b17f827..952a9654 100644 --- a/yacl/crypto/primitives/vss/vss.h +++ b/yacl/crypto/primitives/vss/vss.h @@ -62,8 +62,8 @@ class VerifiableSecretSharing { * @param threshold * @param prime */ - VerifiableSecretSharing(size_t total, size_t threshold, math::MPInt prime) - : total_(total), threshold_(threshold), prime_(std::move(prime)) { + VerifiableSecretSharing(size_t total, size_t threshold, const MPInt& prime) + : total_(total), threshold_(threshold), prime_(prime) { YACL_ENFORCE(total >= threshold); } @@ -79,8 +79,8 @@ class VerifiableSecretSharing { * */ struct Share { - math::MPInt x; // The x-coordinate of the share. - math::MPInt y; // The y-coordinate of the share. + MPInt x; // The x-coordinate of the share. + MPInt y; // The y-coordinate of the share. }; /** @@ -90,7 +90,7 @@ class VerifiableSecretSharing { * @param poly * @return std::vector */ - std::vector CreateShare(const math::MPInt& secret, Polynomial& poly); + std::vector CreateShare(const MPInt& secret, Polynomial& poly) const; /** * @brief Recover the secret from the given shares using Lagrange @@ -98,9 +98,9 @@ class VerifiableSecretSharing { * * @param shares * @param poly - * @return math::MPInt + * @return MPInt */ - math::MPInt RecoverSecret(absl::Span shares); + MPInt RecoverSecret(absl::Span shares) const; // New name for the type representing the result of GenerateShareWithCommits // function. @@ -117,9 +117,9 @@ class VerifiableSecretSharing { * @return ShareWithCommitsResult */ ShareWithCommitsResult CreateShareWithCommits( - const math::MPInt& secret, + const MPInt& secret, const std::unique_ptr& ecc_group, - Polynomial& poly); + Polynomial& poly) const; /** * @brief Get the Total object @@ -139,15 +139,15 @@ class VerifiableSecretSharing { /** * @brief Get the prime modulus used in the scheme. * - * @return math::MPInt + * @return MPInt */ - math::MPInt GetPrime() const { return prime_; } + MPInt GetPrime() const { return prime_; } private: - size_t total_; // Total number of shares in the scheme. - size_t threshold_; // Minimum number of shares required to reconstruct the - // secret. - math::MPInt prime_; // Prime modulus used in the scheme. + size_t total_; // Total number of shares in the scheme. + size_t threshold_; // Minimum number of shares required to reconstruct the + // secret. + MPInt prime_; // Prime modulus used in the scheme. }; /** @@ -160,7 +160,7 @@ class VerifiableSecretSharing { */ std::vector CreateCommits( const std::unique_ptr& ecc_group, - const std::vector& coefficients); + const std::vector& coefficients); /** * @brief Verify the commitments and shares in the Verifiable Secret Sharing @@ -176,6 +176,6 @@ std::vector CreateCommits( bool VerifyCommits(const std::unique_ptr& ecc_group, const VerifiableSecretSharing::Share& share, const std::vector& commits, - const math::MPInt& prime); + const MPInt& prime); } // namespace yacl::crypto diff --git a/yacl/crypto/primitives/vss/vss_test.cc b/yacl/crypto/primitives/vss/vss_test.cc index dcfea8c4..cc40ab05 100644 --- a/yacl/crypto/primitives/vss/vss_test.cc +++ b/yacl/crypto/primitives/vss/vss_test.cc @@ -14,10 +14,10 @@ TEST(VerifiableSecretSharingTest, TestCreateAndVerifyShares) { std::unique_ptr ec_group = EcGroupFactory::Instance().Create("sm2"); // Get the order of the elliptic curve group as the modulus - math::MPInt modulus = ec_group->GetOrder(); + MPInt modulus = ec_group->GetOrder(); // Define the secret to be shared - math::MPInt original_secret("1234567890"); + MPInt original_secret("1234567890"); // Create a VerifiableSecretSharing instance with parameters (total_shares, // required_shares, modulus) @@ -40,7 +40,7 @@ TEST(VerifiableSecretSharingTest, TestCreateAndVerifyShares) { } // Reconstruct the secret using the shares and the polynomial - math::MPInt reconstructed_secret = vss.RecoverSecret(shares); + MPInt reconstructed_secret = vss.RecoverSecret(shares); // Check if the reconstructed secret matches the original secret EXPECT_EQ(reconstructed_secret, original_secret); diff --git a/yacl/crypto/primitives/zkp/BUILD.bazel b/yacl/crypto/primitives/zkp/BUILD.bazel index 0c596085..65f7cdff 100644 --- a/yacl/crypto/primitives/zkp/BUILD.bazel +++ b/yacl/crypto/primitives/zkp/BUILD.bazel @@ -48,7 +48,7 @@ yacl_cc_library( ], deps = [ ":sigma_owh", - "//yacl/crypto/tools:random_oracle", + "//yacl/crypto/tools:ro", ], ) diff --git a/yacl/crypto/primitives/zkp/sigma.cc b/yacl/crypto/primitives/zkp/sigma.cc index bb77ecde..14958593 100644 --- a/yacl/crypto/primitives/zkp/sigma.cc +++ b/yacl/crypto/primitives/zkp/sigma.cc @@ -14,7 +14,7 @@ #include "yacl/crypto/primitives/zkp/sigma.h" -#include "yacl/crypto/tools/random_oracle.h" +#include "yacl/crypto/tools/ro.h" namespace yacl::crypto { diff --git a/yacl/crypto/provider/BUILD.bazel b/yacl/crypto/provider/BUILD.bazel new file mode 100644 index 00000000..4e9c1fdf --- /dev/null +++ b/yacl/crypto/provider/BUILD.bazel @@ -0,0 +1,92 @@ +# Copyright 2022 Ant Group Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//bazel:yacl.bzl", "yacl_cc_library", "yacl_cc_test") + +# core +cc_shared_library( + name = "prov_shared", + additional_linker_inputs = select({ + "@bazel_tools//src/conditions:darwin": [ + ":macos_exported_syms.lds", + ], + "//conditions:default": [ + ":linux_exported_syms.lds", + ], + }), + user_link_flags = select({ + "@bazel_tools//src/conditions:darwin": [ + "-Wl,-exported_symbols_list,$(location :macos_exported_syms.lds)", + ], + "//conditions:default": [ + "-Wl,--version-script,$(location :linux_exported_syms.lds)", + ], + }), + visibility = ["//visibility:public"], # public + deps = [ + ":provider", + ], +) + +# helper for loading provider +yacl_cc_library( + name = "helper", + hdrs = [ + "helper.h", + ], + visibility = ["//visibility:public"], # public + deps = [ + "//yacl/crypto/base:openssl_wrappers", # openssl here + "@com_google_absl//absl/strings", + ], +) + +# private target +yacl_cc_library( + name = "provider", + srcs = [ + "provider.cc", + "rand_impl.h", + "version.h", + ], + visibility = ["//visibility:private"], + deps = [ + "//yacl/crypto/base:openssl_wrappers", # openssl here + "//yacl/crypto/utils/entropy_source", # use yacl es + ], + alwayslink = True, # DO NOT DELETE THIS +) + +# private target +exports_files( + [ + "linux_exported_syms.lds", + "macos_exported_syms.lds", + ], + visibility = ["//visibility:private"], +) + +yacl_cc_test( + name = "provider_test", + srcs = [ + "provider_test.cc", + ], + data = [ + ":prov_shared", + ], + deps = [ + ":helper", + "//yacl/base:exception", + ], +) diff --git a/yacl/crypto/provider/helper.h b/yacl/crypto/provider/helper.h new file mode 100644 index 00000000..8232bfb2 --- /dev/null +++ b/yacl/crypto/provider/helper.h @@ -0,0 +1,83 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +#include "absl/strings/str_split.h" +#include "spdlog/spdlog.h" + +#include "yacl/base/exception.h" + +#ifdef __APPLE__ +#include +#include + +#define SO_EXT ".dylib" +#else +#define SO_EXT ".so" +#endif + +namespace yacl::crypto { + +inline std::string GetProviderPath() { + // first, get the exec path + std::filesystem::path exe_path; +#ifndef __APPLE__ + exe_path = std::filesystem::canonical("/proc/self/exe"); +#else + std::array buf; + uint32_t bufsize = PATH_MAX; + auto ret = _NSGetExecutablePath(buf.data(), &bufsize); + YACL_ENFORCE(ret == 0); + + exe_path = std::filesystem::path(buf.data()); +#endif + auto selfdir_str = exe_path.parent_path().generic_string(); + + // persumely, you are using bazel, so split the path in a bazel way + // HACK: bazel path + try { + std::string path1; + std::string path2; + std::string path3 = + fmt::format("/yacl/crypto/provider/libprov_shared{}", SO_EXT); + + // step 1: determine if target is "cc_test" or "cc_library" + if (selfdir_str.find("sandbox") != std::string::npos) { + std::vector tmp = absl::StrSplit(selfdir_str, "sandbox"); + path1 = tmp.at(0); + tmp = absl::StrSplit(selfdir_str, "execroot"); + tmp = absl::StrSplit(tmp.at(1), "bin"); + path2 = tmp.at(0); + } else { + std::vector tmp = absl::StrSplit(selfdir_str, "execroot"); + path1 = tmp.at(0); + tmp = absl::StrSplit(tmp.at(1), "bin"); + path2 = tmp.at(0); + } + + std::string filename = + fmt::format("{}execroot{}bin{}", path1, path2, path3); + return filename; + } catch (std::exception& e) { + return ""; + } +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/provider/linux_exported_syms.lds b/yacl/crypto/provider/linux_exported_syms.lds new file mode 100644 index 00000000..4b18cb5b --- /dev/null +++ b/yacl/crypto/provider/linux_exported_syms.lds @@ -0,0 +1,9 @@ +VERS_1.0 { + # Export symbols in pybind. + global: + OSSL_provider_init; + + # Hide everything else. + local: + *; +}; diff --git a/yacl/crypto/provider/macos_exported_syms.lds b/yacl/crypto/provider/macos_exported_syms.lds new file mode 100644 index 00000000..4c91f54d --- /dev/null +++ b/yacl/crypto/provider/macos_exported_syms.lds @@ -0,0 +1 @@ +_OSSL_provider_init \ No newline at end of file diff --git a/yacl/crypto/provider/provider.cc b/yacl/crypto/provider/provider.cc new file mode 100644 index 00000000..201b9489 --- /dev/null +++ b/yacl/crypto/provider/provider.cc @@ -0,0 +1,111 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/provider/rand_impl.h" +#include "yacl/crypto/provider/version.h" + +using FuncPtr = void (*)(); + +// FIXME(@shanzhu.cjm): Indirect memeory leak +// Declare the function types that yacl provider provides +static const OSSL_ALGORITHM provider_rands[] = { + {/* algorithm_names */ "Yes", /* Yacl's entropy source */ + /* property_definition */ "provider=yes", + /* implementations */ yacl_rand_prov_functions, + /* algorithm_description */ "yacl's self-defined random entropy source"}, + {nullptr, nullptr, nullptr, nullptr}}; + +/* Parameters we provide to the core */ +static const OSSL_PARAM yacl_prov_param_types[] = { + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_VERSION, OSSL_PARAM_UTF8_PTR, NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_BUILDINFO, OSSL_PARAM_UTF8_PTR, NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_STATUS, OSSL_PARAM_INTEGER, NULL, 0), + OSSL_PARAM_END}; + +// The function that returns the appropriate algorithm table per operation +static const OSSL_ALGORITHM *yacl_prov_operation(ossl_unused void *vprov, + ossl_unused int operation_id, + int *no_cache) { + *no_cache = 0; + switch (operation_id) { + case OSSL_OP_RAND: /* Yacl Provider only supports rand operation */ + return provider_rands; + } + return nullptr; +} + +// provider status function +static int yacl_prov_is_running() { return 1; } + +// tear down yacl's entropy source provider +static void yacl_prov_ctx_teardown(ossl_unused void *vprov) {} + +static const OSSL_PARAM *yacl_prov_gettable_params( + ossl_unused const OSSL_PROVIDER *prov) { + return yacl_prov_param_types; +} + +static int yacl_prov_get_params(ossl_unused const OSSL_PROVIDER *provctx, + OSSL_PARAM params[]) { + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_NAME); + if (p != nullptr && (OSSL_PARAM_set_utf8_ptr(p, YACL_STR) == 0)) { + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_VERSION); + if (p != nullptr && (OSSL_PARAM_set_utf8_ptr(p, YACL_VERSION_STR) == 0)) { + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_BUILDINFO); + if (p != nullptr && + (OSSL_PARAM_set_utf8_ptr(p, YACL_FULL_VERSION_STR) == 0)) { + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_STATUS); + if (p != nullptr && (OSSL_PARAM_set_int(p, yacl_prov_is_running()) == 0)) { + return 0; + } + return 1; +} + +// ---------------------- +// Setup OpsnSSL Provider +// ---------------------- + +// the dispatched functions that yacl's entropy source should implement +static const OSSL_DISPATCH yacl_prov_funcs[] = { + {OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, + reinterpret_cast(yacl_prov_gettable_params)}, + {OSSL_FUNC_PROVIDER_GET_PARAMS, + reinterpret_cast(yacl_prov_get_params)}, + {OSSL_FUNC_PROVIDER_TEARDOWN, + reinterpret_cast(yacl_prov_ctx_teardown)}, + {OSSL_FUNC_PROVIDER_QUERY_OPERATION, + reinterpret_cast(yacl_prov_operation)}, + {0, nullptr}}; + +// the provider entry point +int OSSL_provider_init(const OSSL_CORE_HANDLE *core, + ossl_unused const OSSL_DISPATCH *in, + const OSSL_DISPATCH **out, void **vprov) { + /* Could be anything - we don't use it */ + *vprov = (void *)core; + + // init provider functions + *out = yacl_prov_funcs; + + return 1; +} diff --git a/yacl/crypto/provider/provider_test.cc b/yacl/crypto/provider/provider_test.cc new file mode 100644 index 00000000..fd06befb --- /dev/null +++ b/yacl/crypto/provider/provider_test.cc @@ -0,0 +1,141 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "gtest/gtest.h" +#include "openssl/crypto.h" +#include "openssl/e_os2.h" +#include "openssl/err.h" +#include "openssl/params.h" +#include "openssl/proverr.h" +#include "openssl/rand.h" +#include "openssl/randerr.h" + +#include "yacl/crypto/base/openssl_wrappers.h" +#include "yacl/crypto/provider/helper.h" + +namespace yacl::crypto { + +TEST(OpensslTest, ShouldWork) { + auto libctx = openssl::UniqueLib(OSSL_LIB_CTX_new()); + + // OSSL_PROVIDER_load() loads and initializes a provider. This may simply + // initialize a provider that was previously added with + auto prov = openssl::UniqueProv( + OSSL_PROVIDER_load(libctx.get(), GetProviderPath().c_str())); + YACL_ENFORCE(prov != nullptr); + + // get provider's entropy source EVP_RAND* rand; + auto yes = EVP_RAND_fetch(libctx.get(), "Yes", + nullptr); /* yes = yacl entropy source */ + YACL_ENFORCE(yes != nullptr); + auto* yes_ctx = EVP_RAND_CTX_new(yes, nullptr); + YACL_ENFORCE(yes_ctx != nullptr); + EVP_RAND_instantiate(yes_ctx, 128, 0, nullptr, 0, nullptr); + + /* Feed seed into a DRBG */ + EVP_RAND* rand = EVP_RAND_fetch(nullptr, "CTR-DRBG", nullptr); + auto* rctx = EVP_RAND_CTX_new(rand, yes_ctx); + + /* Configure the DRBG */ + unsigned char bytes[20]; + OSSL_PARAM params[2]; + OSSL_PARAM* p = params; + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER, + (char*)"aes-256-ctr", 0); + *p = OSSL_PARAM_construct_end(); + auto ret = EVP_RAND_instantiate(rctx, 128, 0, nullptr, 0, params); + EXPECT_EQ(ret, 1); + + // EVP_RAND_generate() produces random bytes from the RAND ctx with the + // additional input addin of length addin_len. The bytes produced will meet + // the security strength. If prediction_resistance is specified, fresh + // entropy from a live source will be sought. This call operates as per + // NIST SP 800-90A and SP 800-90C. + auto ret1 = EVP_RAND_generate(rctx, bytes, sizeof(bytes), 128, 0, nullptr, 0); + EXPECT_EQ(ret1, 1); + + EVP_RAND_free(yes); /* free */ + EVP_RAND_CTX_free(yes_ctx); + EVP_RAND_free(rand); /* free */ + EVP_RAND_CTX_free(rctx); +} + +// // https://www.openssl.org/docs/man3.0/man7/EVP_RAND-SEED-SRC.html +// TEST(OpensslTest, Example1) { +// EVP_RAND* rand; +// EVP_RAND_CTX* seed; +// EVP_RAND_CTX* rctx; +// unsigned char bytes[100]; +// OSSL_PARAM params[2]; +// OSSL_PARAM* p = params; +// unsigned int strength = 128; + +// /* Create a seed source */ +// rand = EVP_RAND_fetch(nullptr, "SEED-SRC", nullptr); +// seed = EVP_RAND_CTX_new(rand, nullptr); +// EVP_RAND_instantiate(seed, 128, 0, nullptr, 0, nullptr); + +// /* Feed this into a DRBG */ +// auto* tmp = EVP_RAND_fetch(nullptr, "CTR-DRBG", nullptr); +// // EVP_RAND_CTX_new() creates a new context for the RAND implementation +// rand. +// // If not NULL, parent specifies the seed source for this implementation. +// rctx = EVP_RAND_CTX_new(tmp, seed); +// YACL_ENFORCE(rctx != nullptr); + +// /* Configure the DRBG */ +// *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER, +// (char*)"AES-256-CTR", 0); +// *p = OSSL_PARAM_construct_end(); +// EVP_RAND_instantiate(rctx, strength, 0, nullptr, 0, params); + +// int ret = +// EVP_RAND_generate(rctx, bytes, sizeof(bytes), strength, 0, nullptr, 0); +// EXPECT_EQ(ret, 1); + +// EVP_RAND_free(rand); +// EVP_RAND_free(tmp); +// EVP_RAND_CTX_free(rctx); +// EVP_RAND_CTX_free(seed); +// } + +// // https://www.openssl.org/docs/man3.0/man7/EVP_RAND-CTR-DRBG.html +// TEST(OpensslTest, Example2) { +// EVP_RAND* rand; +// EVP_RAND_CTX* rctx; +// unsigned char bytes[100]; +// OSSL_PARAM params[2]; +// OSSL_PARAM* p = params; +// unsigned int strength = 128; + +// rand = EVP_RAND_fetch(nullptr, "CTR-DRBG", nullptr); +// rctx = EVP_RAND_CTX_new(rand, nullptr); + +// *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER, +// (char*)"AES-256-CTR", 0); +// *p = OSSL_PARAM_construct_end(); +// int ret0 = EVP_RAND_instantiate(rctx, strength, 0, nullptr, 0, params); +// EXPECT_EQ(ret0, 1); + +// int ret1 = +// EVP_RAND_generate(rctx, bytes, sizeof(bytes), strength, 0, nullptr, 0); +// EXPECT_EQ(ret1, 1); + +// EVP_RAND_free(rand); +// EVP_RAND_CTX_free(rctx); +// } + +} // namespace yacl::crypto diff --git a/yacl/crypto/provider/rand_impl.h b/yacl/crypto/provider/rand_impl.h new file mode 100644 index 00000000..4bd6365d --- /dev/null +++ b/yacl/crypto/provider/rand_impl.h @@ -0,0 +1,265 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "openssl/crypto.h" +#include "openssl/e_os2.h" +#include "openssl/err.h" +#include "openssl/params.h" +#include "openssl/proverr.h" +#include "openssl/rand.h" +#include "openssl/randerr.h" +#include "spdlog/spdlog.h" + +#include "yacl/crypto/base/openssl_wrappers.h" +#include "yacl/crypto/utils/entropy_source/entropy_source.h" + +namespace yc = yacl::crypto; + +static OSSL_FUNC_rand_newctx_fn yacl_rand_ctx_new; +static OSSL_FUNC_rand_freectx_fn yacl_rand_ctx_free; +static OSSL_FUNC_rand_instantiate_fn yacl_rand_ctx_instantiate; +static OSSL_FUNC_rand_uninstantiate_fn yacl_rand_ctx_uninstantiate; +static OSSL_FUNC_rand_generate_fn yacl_rand_ctx_generate; +static OSSL_FUNC_rand_reseed_fn yacl_rand_ctx_reseed; +static OSSL_FUNC_rand_gettable_ctx_params_fn yacl_rand_ctx_gettable_ctx_params; +static OSSL_FUNC_rand_get_ctx_params_fn yacl_rand_ctx_get_ctx_params; +static OSSL_FUNC_rand_verify_zeroization_fn yacl_rand_ctx_verify_zeroization; +static OSSL_FUNC_rand_enable_locking_fn yacl_rand_ctx_enable_locking; +static OSSL_FUNC_rand_lock_fn yacl_rand_ctx_lock; +static OSSL_FUNC_rand_unlock_fn yacl_rand_ctx_unlock; +static OSSL_FUNC_rand_get_seed_fn yacl_rand_ctx_get_seed; +static OSSL_FUNC_rand_clear_seed_fn yacl_rand_ctx_clear_seed; + +const OSSL_DISPATCH yacl_rand_prov_functions[] = { + {OSSL_FUNC_RAND_NEWCTX, (void (*)(void))yacl_rand_ctx_new}, + {OSSL_FUNC_RAND_FREECTX, (void (*)(void))yacl_rand_ctx_free}, + {OSSL_FUNC_RAND_INSTANTIATE, (void (*)(void))yacl_rand_ctx_instantiate}, + {OSSL_FUNC_RAND_UNINSTANTIATE, (void (*)(void))yacl_rand_ctx_uninstantiate}, + {OSSL_FUNC_RAND_GENERATE, (void (*)(void))yacl_rand_ctx_generate}, + {OSSL_FUNC_RAND_RESEED, (void (*)(void))yacl_rand_ctx_reseed}, + {OSSL_FUNC_RAND_ENABLE_LOCKING, + (void (*)(void))yacl_rand_ctx_enable_locking}, + {OSSL_FUNC_RAND_LOCK, (void (*)(void))yacl_rand_ctx_lock}, + {OSSL_FUNC_RAND_UNLOCK, (void (*)(void))yacl_rand_ctx_unlock}, + {OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, + (void (*)(void))yacl_rand_ctx_gettable_ctx_params}, + {OSSL_FUNC_RAND_GET_CTX_PARAMS, + (void (*)(void))yacl_rand_ctx_get_ctx_params}, + {OSSL_FUNC_RAND_VERIFY_ZEROIZATION, + (void (*)(void))yacl_rand_ctx_verify_zeroization}, + {OSSL_FUNC_RAND_GET_SEED, (void (*)(void))yacl_rand_ctx_get_seed}, + {OSSL_FUNC_RAND_CLEAR_SEED, (void (*)(void))yacl_rand_ctx_clear_seed}, + /* OSSL_DISPATCH_END */ {0, nullptr}}; + +static const OSSL_PARAM yacl_rand_gettable_ctx_params[] = { + OSSL_PARAM_int(OSSL_RAND_PARAM_STATE, NULL), + OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, NULL), + OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_REQUEST, NULL), OSSL_PARAM_END}; + +// ------------------------------------------- +// OpenSSL Seed Source Function Implementation +// ------------------------------------------- + +class RandProvider { + public: + int state; +}; + +// since this is the random source, there should be no parent +static void *yacl_rand_ctx_new( + ossl_unused void *provider, void *parent, + ossl_unused const OSSL_DISPATCH *parent_dispatch) { + RandProvider *s; + + if (parent != nullptr) { + ERR_raise(ERR_LIB_PROV, PROV_R_SEED_SOURCES_MUST_NOT_HAVE_A_PARENT); + return nullptr; + } + + s = static_cast(OPENSSL_zalloc(sizeof(*s))); + + if (s == nullptr) { + return nullptr; + } + + s->state = EVP_RAND_STATE_UNINITIALISED; + return s; +} + +static void yacl_rand_ctx_free(void *vseed) { OPENSSL_free(vseed); } + +// OSSL_FUNC_rand_instantiate() is used to instantiate the DRBG ctx at a +// requested security strength. In addition, prediction_resistance can be +// requested. Additional input addin of length addin_len bytes can optionally be +// provided. The parameters specified in params configure the DRBG and these +// should be processed before instantiation. +// +// https://www.openssl.org/docs/man3.0/man7/provider-rand.html +static int yacl_rand_ctx_instantiate(void *vseed, + ossl_unused unsigned int strength, + ossl_unused int prediction_resistance, + ossl_unused const unsigned char *pstr, + ossl_unused size_t pstr_len, + ossl_unused const OSSL_PARAM params[]) { + auto *s = static_cast(vseed); + + s->state = EVP_RAND_STATE_READY; + return 1; +} + +// OSSL_FUNC_rand_uninstantiate() is used to uninstantiate the DRBG ctx. After +// being uninstantiated, a DRBG is unable to produce output until it is +// instantiated anew. +// +// https://www.openssl.org/docs/man3.0/man7/provider-rand.html +static int yacl_rand_ctx_uninstantiate(void *vseed) { + auto *s = static_cast(vseed); + + s->state = EVP_RAND_STATE_UNINITIALISED; + return 1; +} + +static int yacl_rand_ctx_generate(void *vseed, unsigned char *out, + size_t outlen, + ossl_unused unsigned int strength, + ossl_unused int prediction_resistance, + ossl_unused const unsigned char *adin, + ossl_unused size_t adin_len) { + auto *s = static_cast(vseed); + + if (s->state != EVP_RAND_STATE_READY) { + ERR_raise(ERR_LIB_PROV, s->state == EVP_RAND_STATE_ERROR + ? PROV_R_IN_ERROR_STATE + : PROV_R_NOT_INSTANTIATED); + return 0; + } + + /* core implementation */ + SPDLOG_INFO("Using Yacl's Random Entropy Source"); + auto es = yc::EntropySourceFactory::Instance().Create("auto"); + auto out_buf = es->GetEntropy(outlen); + YACL_ENFORCE((size_t)out_buf.size() == outlen); + std::memcpy(out, out_buf.data(), out_buf.size()); + + return 1; +} + +static int yacl_rand_ctx_reseed(void *vseed, + ossl_unused int prediction_resistance, + ossl_unused const unsigned char *ent, + ossl_unused size_t ent_len, + ossl_unused const unsigned char *adin, + ossl_unused size_t adin_len) { + auto *s = static_cast(vseed); + + if (s->state != EVP_RAND_STATE_READY) { + ERR_raise(ERR_LIB_PROV, s->state == EVP_RAND_STATE_ERROR + ? PROV_R_IN_ERROR_STATE + : PROV_R_NOT_INSTANTIATED); + return 0; + } + return 1; +} + +static int yacl_rand_ctx_get_ctx_params(void *vseed, OSSL_PARAM params[]) { + auto *s = static_cast(vseed); + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE); + if (p != nullptr && (OSSL_PARAM_set_int(p, s->state) == 0)) { + return 0; + } + + // copied from: + // https://github.com/openssl/openssl/blob/master/providers/implementations/rands/seed_src.c#L148 + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STRENGTH); + if (p != nullptr && (OSSL_PARAM_set_int(p, 1024) == 0)) { + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST); + if (p != nullptr && (OSSL_PARAM_set_size_t(p, 128) == 0)) { + return 0; + } + return 1; +} + +static const OSSL_PARAM *yacl_rand_ctx_gettable_ctx_params( + ossl_unused void *vseed, ossl_unused void *provider) { + return yacl_rand_gettable_ctx_params; +} + +// OSSL_FUNC_rand_verify_zeroization() is used to determine if the internal +// state of the DRBG is zero. This capability is mandated by NIST as part of the +// self tests, it is unlikely to be useful in other circumstances. +// +// https://www.openssl.org/docs/man3.0/man7/provider-rand.html +static int yacl_rand_ctx_verify_zeroization(ossl_unused void *vseed) { + return 1; +} + +// OSSL_FUNC_rand_get_seed() is used by deterministic generators to obtain their +// seeding material from their parent. The seed bytes will meet the specified +// security level of entropy bits and there will be between min_len and max_len +// inclusive bytes in total. If prediction_resistance is true, the bytes will be +// produced from a live entropy source. Additional input addin of length +// addin_len bytes can optionally be provided. A pointer to the seed material is +// returned in *buffer and this must be freed by a later call to +// OSSL_FUNC_rand_clear_seed(). +// +// https://www.openssl.org/docs/man3.0/man7/provider-rand.html +static size_t yacl_rand_ctx_get_seed(void *vseed, unsigned char **pout, + ossl_unused int entropy, size_t min_len, + ossl_unused size_t max_len, + ossl_unused int prediction_resistance, + const unsigned char *adin, + size_t adin_len) { + auto *s = static_cast(vseed); + + if (s->state != EVP_RAND_STATE_READY) { + ERR_raise(ERR_LIB_PROV, s->state == EVP_RAND_STATE_ERROR + ? PROV_R_IN_ERROR_STATE + : PROV_R_NOT_INSTANTIATED); + return 0; + } + + // allocate storatge + auto *buffer = static_cast(OPENSSL_secure_malloc(min_len)); + + // gen entropy with min_len length + // auto es = yc::EntropySourceFactory::Instance().Create("auto"); + // auto out_buf = es->GetEntropy(min_len); + // std::memcpy(buffer, out_buf.data(), out_buf.size()); + *pout = buffer; + + /* xor the additional data into the output */ + for (size_t i = 0; i < adin_len; ++i) { + (*pout)[i % min_len] ^= adin[i]; + } + + return min_len; +} + +static void yacl_rand_ctx_clear_seed(ossl_unused void *vdrbg, + unsigned char *out, size_t outlen) { + OPENSSL_secure_clear_free(out, outlen); +} + +static int yacl_rand_ctx_enable_locking(ossl_unused void *vseed) { return 1; } + +int yacl_rand_ctx_lock(ossl_unused void *vctx) { return 1; } + +void yacl_rand_ctx_unlock(ossl_unused void *vctx) {} \ No newline at end of file diff --git a/yacl/crypto/base/drbg/entropy_source_selector.h b/yacl/crypto/provider/version.h similarity index 77% rename from yacl/crypto/base/drbg/entropy_source_selector.h rename to yacl/crypto/provider/version.h index 7715f0e3..b32051a4 100644 --- a/yacl/crypto/base/drbg/entropy_source_selector.h +++ b/yacl/crypto/provider/version.h @@ -1,4 +1,4 @@ -// Copyright 2022 Ant Group Co., Ltd. +// Copyright 2023 Ant Group Co., Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,10 +14,6 @@ #pragma once -#include "yacl/crypto/base/drbg/entropy_source.h" - -namespace yacl::crypto { - -std::shared_ptr makeEntropySource(); - -} \ No newline at end of file +#define YACL_STR "Yacl" +#define YACL_VERSION_STR "0.4.2" +#define YACL_FULL_VERSION_STR "Yacl 0.4.2 build" \ No newline at end of file diff --git a/yacl/crypto/tools/BUILD.bazel b/yacl/crypto/tools/BUILD.bazel index 6c07e6a7..d5dbddfb 100644 --- a/yacl/crypto/tools/BUILD.bazel +++ b/yacl/crypto/tools/BUILD.bazel @@ -22,9 +22,8 @@ yacl_cc_library( hdrs = ["prg.h"], deps = [ "//yacl/base:dynamic_bitset", - "//yacl/crypto/base:symmetric_crypto", - "//yacl/crypto/base/drbg:nist_aes_drbg", - "//yacl/crypto/base/drbg:sm4_drbg", + "//yacl/crypto/base/block_cipher:symmetric_crypto", + "//yacl/crypto/utils:secparam", ], ) @@ -37,118 +36,58 @@ yacl_cc_test( ) yacl_cc_library( - name = "random_oracle", - hdrs = ["random_oracle.h"], + name = "ro", + hdrs = ["ro.h"], deps = [ "//yacl/crypto/base/hash:hash_utils", ], ) yacl_cc_test( - name = "random_oracle_test", - srcs = ["random_oracle_test.cc"], + name = "ro_test", + srcs = ["ro_test.cc"], deps = [ - ":random_oracle", + ":ro", "//yacl/crypto/utils:rand", ], ) yacl_cc_library( - name = "random_permutation", - srcs = ["random_permutation.cc"], - hdrs = ["random_permutation.h"], + name = "rp", + srcs = ["rp.cc"], + hdrs = ["rp.h"], deps = [ - "//yacl/crypto/base:symmetric_crypto", - "//yacl/crypto/base/aes:aes_intrinsics", + "//yacl/crypto/base/block_cipher:symmetric_crypto", ], ) yacl_cc_test( - name = "random_permutation_test", - srcs = ["random_permutation_test.cc"], + name = "rp_test", + srcs = ["rp_test.cc"], deps = [ ":prg", - ":random_permutation", - ], -) - -yacl_cc_library( - name = "code_interface", - hdrs = ["code_interface.h"], -) - -yacl_cc_library( - name = "linear_code", - hdrs = ["linear_code.h"], - deps = [ - ":code_interface", - "//yacl/crypto/tools:random_permutation", - "//yacl/math:gadget", - ] + select({ - "@platforms//cpu:aarch64": [ - "@com_github_dltcollab_sse2neon//:sse2neon", - ], - "//conditions:default": [], - }), -) - -yacl_cc_test( - name = "linear_code_test", - srcs = ["linear_code_test.cc"], - deps = [ - ":linear_code", + ":rp", "//yacl/crypto/utils:rand", ], ) yacl_cc_library( - name = "silver_code", - srcs = ["silver_code.cc"], - hdrs = ["silver_code.h"], - deps = [ - ":code_interface", - "//yacl/base:block", - "//yacl/base:exception", - "//yacl/base:int128", - ] + select({ - "@platforms//cpu:aarch64": [ - "@com_github_dltcollab_sse2neon//:sse2neon", - ], - "//conditions:default": [], - }), -) - -yacl_cc_test( - name = "silver_code_test", - srcs = ["silver_code_test.cc"], + name = "crhash", + srcs = ["crhash.cc"], + hdrs = ["crhash.h"], deps = [ - ":silver_code", + ":rp", + "//yacl/crypto/base/aes:aes_intrinsics", "//yacl/crypto/utils:rand", ], ) -yacl_cc_library( - name = "expand_accumulate_code", - hdrs = ["expand_accumulate_code.h"], - deps = [ - ":code_interface", - ":linear_code", - "//yacl/base:block", - "//yacl/base:int128", - ] + select({ - "@platforms//cpu:aarch64": [ - "@com_github_dltcollab_sse2neon//:sse2neon", - ], - "//conditions:default": [], - }), -) - yacl_cc_test( - name = "expand_accumulate_code_test", - srcs = ["expand_accumulate_code_test.cc"], + name = "crhash_test", + srcs = ["crhash_test.cc"], deps = [ - ":expand_accumulate_code", - "//yacl/crypto/utils:rand", + ":crhash", + ":prg", ], ) @@ -159,12 +98,10 @@ yacl_cc_binary( "benchmark.h", ], deps = [ - ":expand_accumulate_code", - ":linear_code", + ":crhash", ":prg", - ":random_oracle", - ":random_permutation", - ":silver_code", + ":ro", + ":rp", "//yacl/base:aligned_vector", "//yacl/crypto/utils:rand", "@com_github_google_benchmark//:benchmark_main", diff --git a/yacl/crypto/tools/benchmark.cc b/yacl/crypto/tools/benchmark.cc index 05d0275f..4a41825d 100644 --- a/yacl/crypto/tools/benchmark.cc +++ b/yacl/crypto/tools/benchmark.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "yacl/crypto/tools/benchmark.h" +#include "benchmark.h" #include @@ -26,43 +26,17 @@ void BM_DefaultArguments(benchmark::internal::Benchmark* b) { ->Arg(22437250); } -void BM_DualEncodeArguments(benchmark::internal::Benchmark* b) { - b->Unit(benchmark::kMillisecond) - ->Iterations(10) - ->Arg(100000) - ->Arg(1000000) // one million - ->Arg(10000000) // ten million - ->Arg(22437250); -} +// Register benchmarks for (Circular) CrHash +BENCHMARK_REGISTER_F(ToolBench, RP)->Apply(BM_DefaultArguments); +BENCHMARK_REGISTER_F(ToolBench, CRHASH)->Apply(BM_DefaultArguments); +BENCHMARK_REGISTER_F(ToolBench, CRHASH_INPLACE)->Apply(BM_DefaultArguments); +BENCHMARK_REGISTER_F(ToolBench, CCRHASH)->Apply(BM_DefaultArguments); +BENCHMARK_REGISTER_F(ToolBench, CCRHASH_INPLACE)->Apply(BM_DefaultArguments); +BENCHMARK_REGISTER_F(ToolBench, RO)->Apply(BM_DefaultArguments); -// Register benchmarks for local linear code -BENCHMARK_REGISTER_F(ToolBench, LLC) +BENCHMARK_REGISTER_F(ToolBench, PRG) ->Unit(benchmark::kMillisecond) - ->Iterations(10) - ->Args({10485760, 452000}); - -// Register benchmarks for dual LPN -BENCHMARK_REGISTER_F(ToolBench, Silver5)->Apply(BM_DualEncodeArguments); -BENCHMARK_REGISTER_F(ToolBench, Silver5Inplace)->Apply(BM_DualEncodeArguments); -BENCHMARK_REGISTER_F(ToolBench, Silver11)->Apply(BM_DualEncodeArguments); -BENCHMARK_REGISTER_F(ToolBench, Silver11Inplace)->Apply(BM_DualEncodeArguments); -BENCHMARK_REGISTER_F(ToolBench, ExAcc7)->Apply(BM_DualEncodeArguments); -BENCHMARK_REGISTER_F(ToolBench, ExAcc11)->Apply(BM_DualEncodeArguments); -BENCHMARK_REGISTER_F(ToolBench, ExAcc21)->Apply(BM_DualEncodeArguments); -BENCHMARK_REGISTER_F(ToolBench, ExAcc40)->Apply(BM_DualEncodeArguments); - -// BENCHMARK(BM_RP)->Apply(BM_DefaultArguments); -// BENCHMARK(BM_CrHash)->Apply(BM_DefaultArguments); -// BENCHMARK(BM_CcrHash)->Apply(BM_DefaultArguments); -// BENCHMARK(BM_RO)->Apply(BM_DefaultArguments); - -// BENCHMARK(BM_Prg) -// ->Unit(benchmark::kMillisecond) -// ->Arg(static_cast(PRG_MODE::kNistAesCtrDrbg)) -// ->Arg(static_cast(PRG_MODE::kGmSm4CtrDrbg)) -// ->Arg(static_cast(PRG_MODE::kAesEcb)) -// ->Arg(static_cast(PRG_MODE::KSm4Ecb)); - -// BENCHMARK(BM_Llc)->Unit(benchmark::kMillisecond)->Args({10485760, 452000}); + ->Arg(static_cast(PRG_MODE::kAesEcb)) + ->Arg(static_cast(PRG_MODE::kSm4Ecb)); } // namespace yacl::crypto diff --git a/yacl/crypto/tools/benchmark.h b/yacl/crypto/tools/benchmark.h index 9025d257..6f17395f 100644 --- a/yacl/crypto/tools/benchmark.h +++ b/yacl/crypto/tools/benchmark.h @@ -12,111 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. +#pragma once + #include #include #include "benchmark/benchmark.h" -#include "yacl/base/aligned_vector.h" -#include "yacl/crypto/tools/expand_accumulate_code.h" -#include "yacl/crypto/tools/linear_code.h" +#include "yacl/crypto/tools/crhash.h" #include "yacl/crypto/tools/prg.h" -#include "yacl/crypto/tools/random_oracle.h" -#include "yacl/crypto/tools/random_permutation.h" -#include "yacl/crypto/tools/silver_code.h" +#include "yacl/crypto/tools/ro.h" +#include "yacl/crypto/tools/rp.h" #include "yacl/crypto/utils/rand.h" namespace yacl::crypto { class ToolBench : public benchmark::Fixture {}; -// 1st arg = n (generor matrix) -// 2nd arg = k (generor matrix) -BENCHMARK_DEFINE_F(ToolBench, LLC)(benchmark::State& state) { - for (auto _ : state) { - state.PauseTiming(); - { - auto n = state.range(0); - auto k = state.range(1); - uint128_t seed = RandSeed(); - LocalLinearCode<10> llc(seed, n, k); - auto input = RandVec(k); - std::vector out(n); - - state.ResumeTiming(); - - llc.Encode(input, absl::MakeSpan(out)); - - state.PauseTiming(); - } - state.ResumeTiming(); - } -} - -// 1st arg = n (output size) -#define DELCARE_SLV_INPLACE_BENCH(weight) \ - BENCHMARK_DEFINE_F(ToolBench, Silver##weight##Inplace) \ - (benchmark::State & state) { \ - for (auto _ : state) { \ - state.PauseTiming(); \ - { \ - auto n = state.range(0); \ - SilverCode slv(n, weight); \ - auto input = RandVec(n * 2); \ - state.ResumeTiming(); \ - slv.DualEncodeInplace(absl::MakeSpan(input)); \ - state.PauseTiming(); \ - } \ - state.ResumeTiming(); \ - } \ - } - -// 1st arg = n (output size) -#define DELCARE_SLV_BENCH(weight) \ - BENCHMARK_DEFINE_F(ToolBench, Silver##weight)(benchmark::State & state) { \ - for (auto _ : state) { \ - state.PauseTiming(); \ - { \ - auto n = state.range(0); \ - SilverCode slv(n, weight); \ - auto input = RandVec(n * 2); \ - auto output = std::vector(n); \ - state.ResumeTiming(); \ - slv.DualEncode(absl::MakeSpan(input), absl::MakeSpan(output)); \ - state.PauseTiming(); \ - } \ - state.ResumeTiming(); \ - } \ - } - -DELCARE_SLV_BENCH(5); -DELCARE_SLV_INPLACE_BENCH(5); -DELCARE_SLV_BENCH(11); -DELCARE_SLV_INPLACE_BENCH(11); - -// 1st arg = n (output size) -#define DELCARE_EXACC_BENCH(weight) \ - BENCHMARK_DEFINE_F(ToolBench, ExAcc##weight)(benchmark::State & state) { \ - for (auto _ : state) { \ - state.PauseTiming(); \ - { \ - auto n = state.range(0); \ - ExAccCode acc(n); \ - auto input = RandVec(n * 2); \ - auto output = std::vector(n); \ - state.ResumeTiming(); \ - acc.DualEncode(absl::MakeSpan(input), absl::MakeSpan(output)); \ - state.PauseTiming(); \ - } \ - state.ResumeTiming(); \ - } \ - } - -DELCARE_EXACC_BENCH(7); -DELCARE_EXACC_BENCH(11); -DELCARE_EXACC_BENCH(21); -DELCARE_EXACC_BENCH(40); - // 1st arg = prg type BENCHMARK_DEFINE_F(ToolBench, PRG)(benchmark::State& state) { for (auto _ : state) { @@ -152,8 +64,8 @@ BENCHMARK_DEFINE_F(ToolBench, RP)(benchmark::State& state) { std::fill(input.begin(), input.end(), 0); state.ResumeTiming(); using Ctype = SymmetricCrypto::CryptoType; - const auto& RP = RandomPerm(Ctype::AES128_CTR, 0x12345678); - RP.Gen(absl::MakeSpan(input)); + const auto& rp = RP(Ctype::AES128_CTR, 0x12345678); + rp.Gen(absl::MakeSpan(input)); } } @@ -169,6 +81,17 @@ BENCHMARK_DEFINE_F(ToolBench, CRHASH)(benchmark::State& state) { } } +BENCHMARK_DEFINE_F(ToolBench, CRHASH_INPLACE)(benchmark::State& state) { + for (auto _ : state) { + state.PauseTiming(); + size_t n = state.range(0); + std::vector input(n); + std::fill(input.begin(), input.end(), 0); + state.ResumeTiming(); + ParaCrHashInplace_128(absl::MakeSpan(input)); + } +} + // 1st arg = numer of batched inputs BENCHMARK_DEFINE_F(ToolBench, CCRHASH)(benchmark::State& state) { for (auto _ : state) { @@ -181,4 +104,15 @@ BENCHMARK_DEFINE_F(ToolBench, CCRHASH)(benchmark::State& state) { } } +BENCHMARK_DEFINE_F(ToolBench, CCRHASH_INPLACE)(benchmark::State& state) { + for (auto _ : state) { + state.PauseTiming(); + size_t n = state.range(0); + std::vector input(n); + std::fill(input.begin(), input.end(), 0); + state.ResumeTiming(); + ParaCcrHashInplace_128(absl::MakeSpan(input)); + } +} + } // namespace yacl::crypto diff --git a/yacl/crypto/tools/crhash.cc b/yacl/crypto/tools/crhash.cc new file mode 100644 index 00000000..6d1ffd45 --- /dev/null +++ b/yacl/crypto/tools/crhash.cc @@ -0,0 +1,148 @@ +// Copyright 2022 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/tools/crhash.h" + +#include "yacl/crypto/tools/rp.h" + +#ifndef __aarch64__ +// sse +#include +#include +// pclmul +#include +#else +#include "sse2neon.h" +#endif + +namespace yacl::crypto { + +namespace { +constexpr uint64_t kBatchSize = 1024; + +// Circular Correlation Robust Hash function (Single Block) +// See https://eprint.iacr.org/2019/074.pdf Sec 7.3 +// CcrHash = RP(Sigma(x)) ^ Sigma(x) +// Sigma(x) = (x.left ^ x.right) || x.left +inline uint128_t Sigma(uint128_t x) { + auto _x = _mm_loadu_si128(reinterpret_cast<__m128i*>(&x)); + auto exchange = _mm_shuffle_epi32(_x, 0b01001110); + auto left = _mm_unpackhi_epi64(_x, _mm_setzero_si128()); + return reinterpret_cast(_mm_xor_si128(exchange, left)); +} + +inline std::vector Sigma(absl::Span x) { + const uint32_t num = x.size(); + + std::vector ret(num); + auto zero = _mm_setzero_si128(); + auto* dst = reinterpret_cast<__m128i*>(ret.data()); + const auto* src = reinterpret_cast(x.data()); + const auto* end = src + num; + for (; src != end; ++src, ++dst) { + auto _xi = _mm_loadu_si128(src); // _xi = x[i] + // exchange = _xi.right || _xi.left + auto exchange = _mm_shuffle_epi32(_xi, 0b01001110); + // high = _xi.left || zero + auto left = _mm_unpacklo_epi64(_xi, zero); + // _xi.left xor _xi.right || _xi.left + _mm_storeu_si128(dst, _mm_xor_si128(exchange, left)); + } + return ret; +} + +inline void SigmaInplace(absl::Span x) { + const uint32_t num = x.size(); + auto zero = _mm_setzero_si128(); + auto* ptr = reinterpret_cast<__m128i*>(x.data()); + auto* end = ptr + num; + for (; ptr != end; ++ptr) { + auto _xi = _mm_loadu_si128(ptr); // _xi = x[i] + // exchange = _xi.right || _xi.left + auto exchange = _mm_shuffle_epi32(_xi, 0b01001110); + // high = _xi.left || zero + auto left = _mm_unpacklo_epi64(_xi, zero); + // _xi.left xor _xi.right || _xi.left + _mm_storeu_si128(ptr, _mm_xor_si128(exchange, left)); + } +} + +} // namespace + +uint128_t CrHash_128(uint128_t x) { + const auto& RP = RP::GetDefault(); + return RP.Gen(x) ^ x; +} + +// FIXME: Rename to BatchCrHash_128 +std::vector ParaCrHash_128(absl::Span x) { + std::vector out(x.size()); + const auto& RP = RP::GetCrDefault(); + RP.Gen(x, absl::MakeSpan(out)); + std::transform(x.begin(), x.end(), out.begin(), out.begin(), + std::bit_xor()); + return out; +} + +// FIXME: Rename to BatchCrHashInplace_128 +void ParaCrHashInplace_128(absl::Span inout) { + const auto& RP = RP::GetCrDefault(); + // TODO: add dynamic batch size + alignas(32) std::array tmp; + auto tmp_span = absl::MakeSpan(tmp); + const uint64_t size = inout.size(); + + uint64_t offset = 0; + for (; offset + kBatchSize <= size; offset += kBatchSize) { + auto inout_span = inout.subspan(offset, kBatchSize); + RP.Gen(inout_span, tmp_span); + std::transform(tmp_span.begin(), tmp_span.begin() + kBatchSize, + inout_span.begin(), inout_span.begin(), + std::bit_xor()); + } + uint64_t remain = size - offset; + if (remain > 0) { + auto inout_span = inout.subspan(offset, remain); + RP.Gen(inout_span, tmp_span.subspan(0, remain)); + std::transform(tmp_span.begin(), tmp_span.begin() + remain, + inout_span.begin(), inout_span.begin(), + std::bit_xor()); + } +} + +uint128_t CcrHash_128(uint128_t x) { return CrHash_128(Sigma(x)); } + +// FIXME: Rename to BatchCcrHash_128 +std::vector ParaCcrHash_128(absl::Span x) { + auto tmp = Sigma(x); + ParaCrHashInplace_128(absl::MakeSpan(tmp)); + return tmp; +} + +// FIXME: Rename to BatchCcrHashInplace_128 +void ParaCcrHashInplace_128(absl::Span inout) { + const uint64_t size = inout.size(); + uint64_t offset = 0; + + auto inout_span = absl::MakeSpan(inout); + for (; offset + kBatchSize < size; offset += kBatchSize) { + SigmaInplace(inout_span.subspan(offset, kBatchSize)); + ParaCrHashInplace_128(inout_span.subspan(offset, kBatchSize)); + } + auto remain = size - offset; + SigmaInplace(inout_span.subspan(offset, remain)); + ParaCrHashInplace_128(inout_span.subspan(offset, remain)); +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/tools/crhash.h b/yacl/crypto/tools/crhash.h new file mode 100644 index 00000000..2ba6b665 --- /dev/null +++ b/yacl/crypto/tools/crhash.h @@ -0,0 +1,51 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#include "absl/types/span.h" + +#include "yacl/base/int128.h" + +namespace yacl::crypto { + +// Correlation Robust Hash function (Single Block input) +// See https://eprint.iacr.org/2019/074.pdf Sec 7.2 +// CrHash = RP(x) ^ x +uint128_t CrHash_128(uint128_t x); + +// parallel crhash for many blocks +std::vector ParaCrHash_128(absl::Span x); + +// inplace parallel crhash for many blocks +void ParaCrHashInplace_128(absl::Span inout); + +// Circular Correlation Robust Hash function (Single Block) +// See https://eprint.iacr.org/2019/074.pdf Sec 7.3 +// CcrHash = RP(Sigma(x)) ^ Sigma(x) +// Sigma(x) = (x.left ^ x.right) || x.left +uint128_t CcrHash_128(uint128_t x); + +// parallel ccrhash for many blocks +std::vector ParaCcrHash_128(absl::Span x); + +// inplace parallel ccrhash for many blocks +void ParaCcrHashInplace_128(absl::Span inout); + +// TODO(@shanzhu) Tweakable Correlation Robust Hash function (Multiple Blocks) +// See https://eprint.iacr.org/2019/074.pdf Sec 7.4 + +} // namespace yacl::crypto diff --git a/yacl/crypto/tools/random_permutation_test.cc b/yacl/crypto/tools/crhash_test.cc similarity index 74% rename from yacl/crypto/tools/random_permutation_test.cc rename to yacl/crypto/tools/crhash_test.cc index c74caee7..0571bb52 100644 --- a/yacl/crypto/tools/random_permutation_test.cc +++ b/yacl/crypto/tools/crhash_test.cc @@ -12,15 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "yacl/crypto/tools/random_permutation.h" +#include "yacl/crypto/tools/crhash.h" #include -#include #include "gtest/gtest.h" #include "yacl/base/exception.h" #include "yacl/crypto/tools/prg.h" +#include "yacl/crypto/utils/rand.h" namespace yacl::crypto { @@ -28,43 +28,23 @@ namespace { inline auto RandomBlocks(size_t length) { std::vector rand_inputs(length); Prg prg; - prg.Fill(absl::MakeSpan(rand_inputs)); + prg.Fill(absl::MakeSpan(rand_inputs)); return rand_inputs; } -inline auto RandomU128() { - Prg prg(0, PRG_MODE::kNistAesCtrDrbg); - return prg(); -} - } // namespace -TEST(RandomPermTest, U128Works) { - const auto& RP = RandomPerm::GetDefault(); - - auto input = RandomU128(); - - EXPECT_EQ(RP.Gen(input), RP.Gen(input)); -} - -TEST(RandomPermTest, BlocksWorks) { - const auto& RP = RandomPerm::GetDefault(); - - auto input = RandomBlocks(20); - - EXPECT_EQ(RP.Gen(absl::MakeSpan(input)), RP.Gen(absl::MakeSpan(input))); -} - -TEST(RandomPermTest, CrHashWorks) { - const uint128_t x = RandomU128(); - const uint128_t y = RandomU128(); +TEST(RPTest, CrHashWorks) { + uint128_t x = FastRandU128(); + uint128_t y = FastRandU128(); + EXPECT_NE(x, y); EXPECT_NE(CrHash_128(x), 0); EXPECT_EQ(CrHash_128(x), CrHash_128(x)); EXPECT_NE(CrHash_128(x), CrHash_128(y)); } -TEST(RandomPermTest, ParaCrHashWorks) { +TEST(RPTest, ParaCrHashWorks) { const auto size = 20; std::vector zeros(size, 0); @@ -76,7 +56,7 @@ TEST(RandomPermTest, ParaCrHashWorks) { EXPECT_EQ(absl::MakeSpan(output), ParaCrHash_128(absl::MakeSpan(input))); } -TEST(RandomPermTest, ParaCrHashInplaceWorks) { +TEST(RPTest, ParaCrHashInplaceWorks) { const auto size = 20; std::vector zeros(size, 0); @@ -91,16 +71,17 @@ TEST(RandomPermTest, ParaCrHashInplaceWorks) { EXPECT_EQ(absl::MakeSpan(inout), absl::MakeSpan(inout_copy)); } -TEST(RandomPermTest, CcrHashWorks) { - const uint128_t x = RandomU128(); - const uint128_t y = RandomU128(); +TEST(RPTest, CcrHashWorks) { + const uint128_t x = FastRandU128(); + const uint128_t y = FastRandU128(); + EXPECT_NE(x, y); EXPECT_NE(CcrHash_128(x), 0); EXPECT_EQ(CcrHash_128(x), CcrHash_128(x)); EXPECT_NE(CcrHash_128(x), CcrHash_128(y)); } -TEST(RandomPermTest, ParaCcrHashWorks) { +TEST(RPTest, ParaCcrHashWorks) { const auto size = 20; std::vector zeros(size, 0); @@ -112,7 +93,7 @@ TEST(RandomPermTest, ParaCcrHashWorks) { EXPECT_EQ(absl::MakeSpan(output), ParaCcrHash_128(absl::MakeSpan(input))); } -TEST(RandomPermTest, ParaCcrHashInplaceWorks) { +TEST(RPTest, ParaCcrHashInplaceWorks) { const auto size = 20; std::vector zeros(size, 0); diff --git a/yacl/crypto/tools/prg.cc b/yacl/crypto/tools/prg.cc index 9e73fb1c..ea653cf9 100644 --- a/yacl/crypto/tools/prg.cc +++ b/yacl/crypto/tools/prg.cc @@ -16,51 +16,51 @@ namespace yacl::crypto { -uint64_t FillPRandBytes(SymmetricCrypto::CryptoType crypto_type, uint128_t seed, - uint128_t iv, uint64_t count, absl::Span out) { +uint64_t FillPRand(SymmetricCrypto::CryptoType type, uint128_t seed, + uint64_t iv, uint64_t count, char* buf, size_t len) { constexpr size_t block_size = SymmetricCrypto::BlockSize(); - const size_t nbytes = out.size(); + const size_t nbytes = len; const size_t nblock = (nbytes + block_size - 1) / block_size; const size_t padding_bytes = nbytes % block_size; - bool isCTR = (crypto_type == SymmetricCrypto::CryptoType::AES128_CTR || - crypto_type == SymmetricCrypto::CryptoType::SM4_CTR); + bool isCTR = (type == SymmetricCrypto::CryptoType::AES128_CTR || + type == SymmetricCrypto::CryptoType::SM4_CTR); std::unique_ptr crypto; if (isCTR) { // CTR mode does not requires padding or manully build counter... - crypto = std::make_unique(crypto_type, seed, count); - std::memset(out.data(), 0, nbytes); - auto bv = absl::MakeSpan(reinterpret_cast(out.data()), nbytes); + crypto = std::make_unique(type, seed, count); + std::memset(buf, 0, nbytes); + auto bv = absl::MakeSpan(reinterpret_cast(buf), nbytes); crypto->Encrypt(bv, bv); } else { - crypto = std::make_unique(crypto_type, seed, iv); + crypto = std::make_unique(type, seed, iv); if (padding_bytes == 0) { // No padding, fast path - auto s = absl::MakeSpan(reinterpret_cast(out.data()), nblock); + auto s = absl::MakeSpan(reinterpret_cast(buf), nblock); internal::EcbMakeContentBlocks(count, s); crypto->Encrypt(s, s); } else { - if (crypto_type == SymmetricCrypto::CryptoType::AES128_ECB || - crypto_type == SymmetricCrypto::CryptoType::SM4_ECB) { + if (type == SymmetricCrypto::CryptoType::AES128_ECB || + type == SymmetricCrypto::CryptoType::SM4_ECB) { if (nblock > 1) { // first n-1 block - auto s = absl::MakeSpan(reinterpret_cast(out.data()), - nblock - 1); + auto s = + absl::MakeSpan(reinterpret_cast(buf), nblock - 1); internal::EcbMakeContentBlocks(count, s); crypto->Encrypt(s, s); } // last padding block uint128_t padding = count + nblock - 1; padding = crypto->Encrypt(padding); - std::memcpy(reinterpret_cast(out.data()) + (nblock - 1), - &padding, padding_bytes); + std::memcpy(reinterpret_cast(buf) + (nblock - 1), &padding, + padding_bytes); } else { std::vector cipher(nblock); auto s = absl::MakeSpan(cipher); internal::EcbMakeContentBlocks(count, s); crypto->Encrypt(s, s); - std::memcpy(out.data(), cipher.data(), nbytes); + std::memcpy(buf, cipher.data(), nbytes); } } } diff --git a/yacl/crypto/tools/prg.h b/yacl/crypto/tools/prg.h index 10295640..ee16278b 100644 --- a/yacl/crypto/tools/prg.h +++ b/yacl/crypto/tools/prg.h @@ -22,14 +22,69 @@ #include "yacl/base/dynamic_bitset.h" #include "yacl/base/int128.h" -#include "yacl/crypto/base/drbg/drbg.h" -#include "yacl/crypto/base/drbg/entropy_source.h" -#include "yacl/crypto/base/drbg/nist_aes_drbg.h" -#include "yacl/crypto/base/drbg/sm4_drbg.h" -#include "yacl/crypto/base/symmetric_crypto.h" +#include "yacl/crypto/base/block_cipher/symmetric_crypto.h" +#include "yacl/crypto/utils/secparam.h" + +YACL_MODULE_DECLARE("prg", SecParam::C::k128, SecParam::S::INF); namespace yacl::crypto { +// --------------------------- +// Fill Pseudorandom (PRand) +// --------------------------- + +// Core implementation of filling deterministic pseudorandomness, return the +// increased counter (count++, presumably). +// Note: FillPRand is different from drbg, NIST800-90A since FillPRand will +// never perform healthcheck, reseed. FillPRand is only an abstract API for the +// theoretical tool: PRG. +uint64_t FillPRand(SymmetricCrypto::CryptoType type, uint128_t seed, + uint64_t iv, uint64_t count, char* buf, size_t len); + +// Fill pseudo-randomness with template type T. +// Return the increased counter (count++, presumably). +template ::value, int> = 0> +inline uint64_t FillPRand(SymmetricCrypto::CryptoType crypto_type, + uint128_t seed, uint64_t iv, uint64_t count, + absl::Span out) { + return FillPRand(crypto_type, seed, iv, count, (char*)out.data(), + out.size() * sizeof(T)); +} + +// ----------------------------------- +// Simpler Fill Pseudorandoms (PRand) +// ----------------------------------- +// Since Prg is over-complex for simple tasks, here we provide a simple, yet +// useful way of using Prg. +template ::value, int> = 0> +inline void PrgAesCtr(const uint128_t seed, absl::Span out) { + FillPRand(SymmetricCrypto::CryptoType::AES128_CTR, seed, 0, 0, out); +} + +template ::value, int> = 0> +inline std::vector PrgAesCtr(const uint128_t seed, const size_t num) { + std::vector res(num); + FillPRand(SymmetricCrypto::CryptoType::AES128_CTR, seed, 0, 0, + absl::MakeSpan(res)); + return res; +} + +template ::value, int> = 0> +inline std::vector PrgAesCbc(const uint128_t seed, const size_t num) { + std::vector res(num); + FillPRand(SymmetricCrypto::CryptoType::AES128_CBC, seed, 0, 0, + absl::MakeSpan(res)); + return res; +} + +// --------------------------- +// PRG with cache +// --------------------------- + namespace internal { template struct cipher_data { @@ -52,61 +107,10 @@ struct cipher_data { }; } // namespace internal -/////////////////////////////////////////////////////////////////// -// Fill Pseudorandom (PRand) // -/////////////////////////////////////////////////////////////////// - -// FillPRandBytes generate pseudo random bytes and fill the `out`. -uint64_t FillPRandBytes(SymmetricCrypto::CryptoType crypto_type, uint128_t seed, - uint128_t iv, uint64_t count, absl::Span out); - -// Fill pseudo-randomness with type-T -template ::value, int> = 0> -inline uint64_t FillPRand(SymmetricCrypto::CryptoType crypto_type, - uint128_t seed, uint128_t iv, uint64_t count, - absl::Span out) { - const size_t nbytes = out.size() * sizeof(T); - auto ctr = FillPRandBytes(crypto_type, seed, iv, count, - absl::MakeSpan((uint8_t*)out.data(), nbytes)); - return ctr; -} - -// The pseudo random bytes are generated by using AES-CBC to encrypt a -// continuous buffer with incremental counters as contents. - -#define DECLARE_FILLPRand_TYPE(TYPE) \ - template ::value, int> = 0> \ - inline uint64_t FillPRand_##TYPE(uint128_t seed, uint64_t count, \ - absl::Span out) { \ - return FillPRand(SymmetricCrypto::CryptoType::TYPE, seed, 0, count, \ - out); \ - } - -DECLARE_FILLPRand_TYPE(SM4_CBC); // declare FillPRand_SM4_CBC -DECLARE_FILLPRand_TYPE(AES128_CBC); // declare FillPRand_AES128_CBC - -/////////////////////////////////////////////////////////////////// -// PRG // -/////////////////////////////////////////////////////////////////// - -// This is an implementation of the **theoretical tool**: Pseudorandom -// Generator - +// core implementation of prg enum class PRG_MODE { - // nist drbg standard - // get random seed from intel entropy source, generate pseudorandom bytes - kNistAesCtrDrbg, - // gm drbg - // get random seed from intel entropy source, generate pseudorandom bytes - kGmSm4CtrDrbg, - // aes ecb (with an internal counter) - // get seed from parameter, use ctr mode, generate pseudorandom bytes - kAesEcb, // use aes128 - // sm4 ecb (with an internal counter) - // get seed from parameter, use ctr mode, generate pseudorandom bytes - KSm4Ecb + kAesEcb, // aes-128 ecb (with an internal counter) + kSm4Ecb, // sm4-128 ecb (with an internal counter) }; template (seed); - } else if (mode_ == PRG_MODE::kGmSm4CtrDrbg) { - ctr_drbg_ = std::make_unique(seed); - } } uint128_t Seed() const { return seed_; } @@ -155,17 +154,16 @@ class Prg { std::enable_if_t, int> = 0> void Fill(absl::Span out) { switch (mode_) { - case PRG_MODE::kNistAesCtrDrbg: - case PRG_MODE::kGmSm4CtrDrbg: - ctr_drbg_->FillPRand(out); - break; case PRG_MODE::kAesEcb: - counter_ = FillPRand(SymmetricCrypto::CryptoType::AES128_ECB, seed_, - kInitVector, counter_, out); + counter_ = FillPRand( + SymmetricCrypto::CryptoType::AES128_ECB, seed_, kInitVector, + counter_, + absl::Span((uint8_t*)out.data(), sizeof(Y) * out.size())); break; - case PRG_MODE::KSm4Ecb: - counter_ = FillPRand(SymmetricCrypto::CryptoType::SM4_ECB, seed_, - kInitVector, counter_, out); + case PRG_MODE::kSm4Ecb: + counter_ = FillPRand( + SymmetricCrypto::CryptoType::SM4_ECB, seed_, kInitVector, counter_, + absl::Span((uint8_t*)out.data(), sizeof(Y) * out.size())); break; } } @@ -179,19 +177,15 @@ class Prg { size_t cipher_size = cipher_data_.size(); switch (mode_) { - case PRG_MODE::kNistAesCtrDrbg: - case PRG_MODE::kGmSm4CtrDrbg: - ctr_drbg_->FillPRandBytes(absl::MakeSpan(cipher_ptr, cipher_size)); - break; case PRG_MODE::kAesEcb: - counter_ = FillPRandBytes(SymmetricCrypto::CryptoType::AES128_ECB, - seed_, kInitVector, counter_, - absl::MakeSpan(cipher_ptr, cipher_size)); + counter_ = FillPRand(SymmetricCrypto::CryptoType::AES128_ECB, seed_, + kInitVector, counter_, + absl::MakeSpan(cipher_ptr, cipher_size)); break; - case PRG_MODE::KSm4Ecb: - counter_ = FillPRandBytes(SymmetricCrypto::CryptoType::SM4_ECB, seed_, - kInitVector, counter_, - absl::MakeSpan(cipher_ptr, cipher_size)); + case PRG_MODE::kSm4Ecb: + counter_ = + FillPRand(SymmetricCrypto::CryptoType::SM4_ECB, seed_, kInitVector, + counter_, absl::MakeSpan(cipher_ptr, cipher_size)); break; } } @@ -201,37 +195,7 @@ class Prg { internal::cipher_data cipher_data_; // budget (in bytes). size_t num_consumed_ = BATCH_SIZE; // How many ciphers are consumed. - PRG_MODE mode_; // prg mode - std::unique_ptr ctr_drbg_; // for nist aes ctr drbg + PRG_MODE mode_; // prg mode }; -/////////////////////////////////////////////////////////////////// -// PRG // -/////////////////////////////////////////////////////////////////// -// Since Prg is over-complex for simple tasks, here we provide a simple, yet -// useful way of using Prg. -template ::value, int> = 0> -inline void PrgAesCtr(const uint128_t seed, absl::Span out) { - FillPRand(SymmetricCrypto::CryptoType::AES128_CTR, seed, 0, 0, out); -} - -template ::value, int> = 0> -inline std::vector PrgAesCtr(const uint128_t seed, const size_t num) { - std::vector res(num); - FillPRand(SymmetricCrypto::CryptoType::AES128_CTR, seed, 0, 0, - absl::MakeSpan(res)); - return res; -} - -template ::value, int> = 0> -inline std::vector PrgAesCbc(const uint128_t seed, const size_t num) { - std::vector res(num); - FillPRand(SymmetricCrypto::CryptoType::AES128_CBC, seed, 0, 0, - absl::MakeSpan(res)); - return res; -} - } // namespace yacl::crypto diff --git a/yacl/crypto/tools/prg_test.cc b/yacl/crypto/tools/prg_test.cc index d383c2fe..25894eee 100644 --- a/yacl/crypto/tools/prg_test.cc +++ b/yacl/crypto/tools/prg_test.cc @@ -21,134 +21,134 @@ #include "gtest/gtest.h" namespace yacl::crypto { -namespace { - -constexpr uint128_t kKey1 = 1234; -constexpr uint128_t kKey2 = 2345; - -struct Foo { - uint64_t a; - char b; - uint8_t c; - bool operator==(const Foo& rhs) const { - return a == rhs.a && b == rhs.b && c == rhs.c; - } - bool operator!=(const Foo& rhs) const { return !(*this == rhs); } -}; - -std::ostream& operator<<(std::ostream& os, const Foo& foo) { - os << "[ a=" << foo.a << ", b=" << foo.b << ", c=" << foo.c; - return os; -} - -} // namespace - -TEST(Prg, BooleanWorks) { - // GIVEN - Prg prg(kKey1); - // WHEN - std::array counts = {0, 0}; - const int kNumCalls = 10000; - for (int i = 0; i < kNumCalls; ++i) { - bool index = prg(); - EXPECT_TRUE(index == 0 || index == 1); - counts[index]++; - } - // THEN - double ratio = counts[0] / static_cast(kNumCalls); - // Give a loose constraint `5%` - EXPECT_TRUE(std::abs(ratio - 0.5) <= 0.05) << ratio; -} - -TEST(Prg, BuiltinScalarsWorks) { - { - // GIVEN - Prg prg(kKey1); - // WHEN - int a = prg(); - int b = prg(); - // THEN - EXPECT_NE(a, b); - } - - { - // GIVEN - Prg prg(kKey1); - // WHEN - double a = prg(); - double b = prg(); - // THEN - EXPECT_NE(a, b); - } - - { - // GIVEN - Prg prg(kKey1); - // WHEN - uint64_t a = prg(); - uint64_t b = prg(); - // THEN - EXPECT_NE(a, b); - } - - { - // GIVEN - Prg prg(kKey1); - // WHEN - uint128_t a = prg(); - uint128_t b = prg(); - // THEN - EXPECT_NE(a, b); - } -} - -TEST(Prg, WorksForCustomizedStruct) { - // GIVEN - Prg prg(kKey1); - int ncalls = 3 * decltype(prg)::BatchSize() + 13; - Foo last = prg(); - for (int i = 0; i < ncalls; ++i) { - // WHEN - Foo now = prg(); - // THEN - EXPECT_NE(now, last); - } -} - -TEST(Prg, DeterministicWithSameSeed) { - Prg prg1(kKey1); - Prg prg2(kKey1); - for (int i = 0; i < 128; ++i) { - EXPECT_EQ(prg1(), prg2()); - EXPECT_EQ(prg1(), prg2()); - } -} - -TEST(Prg, DeterministicWithDifferentSeed) { - Prg prg1(kKey1); - Prg prg2(kKey2); - for (int i = 0; i < 128; ++i) { - EXPECT_NE(prg1(), prg2()); - EXPECT_NE(prg1(), prg2()); - } -} - -TEST(Prg, FillPRandomBytes) { - constexpr int kSize = 11; - std::vector output1(kSize); - std::vector output2(kSize); - auto c1 = FillPRandBytes(SymmetricCrypto::CryptoType::AES128_ECB, 0, 0, 0, - absl::MakeSpan(output1)); - auto c2 = FillPRandBytes(SymmetricCrypto::CryptoType::AES128_ECB, 0, 0, c1, - absl::MakeSpan(output2)); - const uint128_t expected = - (kSize + sizeof(uint128_t) - 1) / sizeof(uint128_t); - EXPECT_EQ(c1, expected); - EXPECT_EQ(c2, 2 * expected); - for (int i = 0; i < kSize; ++i) { - EXPECT_NE(output1[i], output2[i]); - } -} +// namespace { + +// constexpr uint128_t kKey1 = 1234; +// constexpr uint128_t kKey2 = 2345; + +// struct Foo { +// uint64_t a; +// char b; +// uint8_t c; +// bool operator==(const Foo& rhs) const { +// return a == rhs.a && b == rhs.b && c == rhs.c; +// } +// bool operator!=(const Foo& rhs) const { return !(*this == rhs); } +// }; + +// std::ostream& operator<<(std::ostream& os, const Foo& foo) { +// os << "[ a=" << foo.a << ", b=" << foo.b << ", c=" << foo.c; +// return os; +// } + +// } // namespace + +// TEST(Prg, BooleanWorks) { +// // GIVEN +// Prg prg(kKey1); +// // WHEN +// std::array counts = {0, 0}; +// const int kNumCalls = 10000; +// for (int i = 0; i < kNumCalls; ++i) { +// bool index = prg(); +// EXPECT_TRUE(index == 0 || index == 1); +// counts[index]++; +// } +// // THEN +// double ratio = counts[0] / static_cast(kNumCalls); +// // Give a loose constraint `5%` +// EXPECT_TRUE(std::abs(ratio - 0.5) <= 0.05) << ratio; +// } + +// TEST(Prg, BuiltinScalarsWorks) { +// { +// // GIVEN +// Prg prg(kKey1); +// // WHEN +// int a = prg(); +// int b = prg(); +// // THEN +// EXPECT_NE(a, b); +// } + +// { +// // GIVEN +// Prg prg(kKey1); +// // WHEN +// double a = prg(); +// double b = prg(); +// // THEN +// EXPECT_NE(a, b); +// } + +// { +// // GIVEN +// Prg prg(kKey1); +// // WHEN +// uint64_t a = prg(); +// uint64_t b = prg(); +// // THEN +// EXPECT_NE(a, b); +// } + +// { +// // GIVEN +// Prg prg(kKey1); +// // WHEN +// uint128_t a = prg(); +// uint128_t b = prg(); +// // THEN +// EXPECT_NE(a, b); +// } +// } + +// TEST(Prg, WorksForCustomizedStruct) { +// // GIVEN +// Prg prg(kKey1); +// int ncalls = 3 * decltype(prg)::BatchSize() + 13; +// Foo last = prg(); +// for (int i = 0; i < ncalls; ++i) { +// // WHEN +// Foo now = prg(); +// // THEN +// EXPECT_NE(now, last); +// } +// } + +// TEST(Prg, DeterministicWithSameSeed) { +// Prg prg1(kKey1); +// Prg prg2(kKey1); +// for (int i = 0; i < 128; ++i) { +// EXPECT_EQ(prg1(), prg2()); +// EXPECT_EQ(prg1(), prg2()); +// } +// } + +// TEST(Prg, DeterministicWithDifferentSeed) { +// Prg prg1(kKey1); +// Prg prg2(kKey2); +// for (int i = 0; i < 128; ++i) { +// EXPECT_NE(prg1(), prg2()); +// EXPECT_NE(prg1(), prg2()); +// } +// } + +// TEST(Prg, FillPRandomBytes) { +// constexpr int kSize = 11; +// std::vector output1(kSize); +// std::vector output2(kSize); +// auto c1 = FillPRand(SymmetricCrypto::CryptoType::AES128_ECB, 0, 0, 0, +// absl::MakeSpan(output1)); +// auto c2 = FillPRand(SymmetricCrypto::CryptoType::AES128_ECB, 0, 0, c1, +// absl::MakeSpan(output2)); +// const uint128_t expected = +// (kSize + sizeof(uint128_t) - 1) / sizeof(uint128_t); +// EXPECT_EQ(c1, expected); +// EXPECT_EQ(c2, 2 * expected); +// for (int i = 0; i < kSize; ++i) { +// EXPECT_NE(output1[i], output2[i]); +// } +// } TEST(Prg, FillAesRandom) { constexpr int kSize = 11; @@ -167,204 +167,204 @@ TEST(Prg, FillAesRandom) { } } -TEST(Prg, DeterministicWithSameSeedSm4) { - Prg prg1(kKey1, PRG_MODE::KSm4Ecb); - Prg prg2(kKey1, PRG_MODE::KSm4Ecb); - for (int i = 0; i < 128; ++i) { - EXPECT_EQ(prg1(), prg2()); - EXPECT_EQ(prg1(), prg2()); - } -} - -TEST(Prg, DeterministicWithDifferentSeedSm4) { - Prg prg1(kKey1, PRG_MODE::KSm4Ecb); - Prg prg2(kKey2, PRG_MODE::KSm4Ecb); - for (int i = 0; i < 128; ++i) { - EXPECT_NE(prg1(), prg2()); - EXPECT_NE(prg1(), prg2()); - } -} - -// nist ase_ctr drbg -TEST(PRandomCtrDrbg, BooleanWorks) { - // GIVEN - Prg prg(kKey1, PRG_MODE::kNistAesCtrDrbg); - // WHEN - std::array counts = {0, 0}; - const int kNumCalls = 10000; - for (int i = 0; i < kNumCalls; ++i) { - bool index = prg(); - EXPECT_TRUE(index == 0 || index == 1); - counts[index]++; - } - // THEN - double ratio = counts[0] / static_cast(kNumCalls); - // Give a loose constraint `5%` - EXPECT_TRUE(std::abs(ratio - 0.5) <= 0.05) << ratio; -} - -TEST(PRandomCtrDrbg, BuiltinScalarsWorks) { - { - // GIVEN - Prg prg(kKey1, PRG_MODE::kNistAesCtrDrbg); - // WHEN - int a = prg(); - int b = prg(); - // THEN - EXPECT_NE(a, b); - } - - { - // GIVEN - Prg prg(kKey1, PRG_MODE::kNistAesCtrDrbg); - // WHEN - double a = prg(); - double b = prg(); - // THEN - EXPECT_NE(a, b); - } - - { - // GIVEN - Prg prg(kKey1, PRG_MODE::kNistAesCtrDrbg); - // WHEN - uint64_t a = prg(); - uint64_t b = prg(); - // THEN - EXPECT_NE(a, b); - } - - { - // GIVEN - Prg prg(kKey1, PRG_MODE::kNistAesCtrDrbg); - // WHEN - uint128_t a = prg(); - uint128_t b = prg(); - // THEN - EXPECT_NE(a, b); - } -} - -TEST(PRandomCtrDrbg, WorksForCustomizedStruct) { - // GIVEN - Prg prg(kKey1, PRG_MODE::kNistAesCtrDrbg); - int ncalls = 3 * decltype(prg)::BatchSize() + 13; - Foo last = prg(); - for (int i = 0; i < ncalls; ++i) { - // WHEN - Foo now = prg(); - // THEN - EXPECT_NE(now, last); - } -} - -TEST(PRandomCtrDrbg, DeterministicWithSameSeed) { - Prg prg1(kKey1, PRG_MODE::kNistAesCtrDrbg); - Prg prg2(kKey1, PRG_MODE::kNistAesCtrDrbg); - for (int i = 0; i < 128; ++i) { - EXPECT_NE(prg1(), prg2()); - EXPECT_NE(prg1(), prg2()); - } -} - -TEST(PRandomCtrDrbg, DeterministicWithDifferentSeed) { - Prg prg1(kKey1, PRG_MODE::kNistAesCtrDrbg); - Prg prg2(kKey2, PRG_MODE::kNistAesCtrDrbg); - for (int i = 0; i < 128; ++i) { - EXPECT_NE(prg1(), prg2()); - EXPECT_NE(prg1(), prg2()); - } -} +// TEST(Prg, DeterministicWithSameSeedSm4) { +// Prg prg1(kKey1, PRG_MODE::kSm4Ecb); +// Prg prg2(kKey1, PRG_MODE::kSm4Ecb); +// for (int i = 0; i < 128; ++i) { +// EXPECT_EQ(prg1(), prg2()); +// EXPECT_EQ(prg1(), prg2()); +// } +// } + +// TEST(Prg, DeterministicWithDifferentSeedSm4) { +// Prg prg1(kKey1, PRG_MODE::kSm4Ecb); +// Prg prg2(kKey2, PRG_MODE::kSm4Ecb); +// for (int i = 0; i < 128; ++i) { +// EXPECT_NE(prg1(), prg2()); +// EXPECT_NE(prg1(), prg2()); +// } +// } + +// // nist ase_ctr drbg +// TEST(PRandomCtrDrbg, BooleanWorks) { +// // GIVEN +// Prg prg(kKey1, PRG_MODE::kAesEcb); +// // WHEN +// std::array counts = {0, 0}; +// const int kNumCalls = 10000; +// for (int i = 0; i < kNumCalls; ++i) { +// bool index = prg(); +// EXPECT_TRUE(index == 0 || index == 1); +// counts[index]++; +// } +// // THEN +// double ratio = counts[0] / static_cast(kNumCalls); +// // Give a loose constraint `5%` +// EXPECT_TRUE(std::abs(ratio - 0.5) <= 0.05) << ratio; +// } + +// TEST(PRandomCtrDrbg, BuiltinScalarsWorks) { +// { +// // GIVEN +// Prg prg(kKey1, PRG_MODE::kAesEcb); +// // WHEN +// int a = prg(); +// int b = prg(); +// // THEN +// EXPECT_NE(a, b); +// } + +// { +// // GIVEN +// Prg prg(kKey1, PRG_MODE::kAesEcb); +// // WHEN +// double a = prg(); +// double b = prg(); +// // THEN +// EXPECT_NE(a, b); +// } + +// { +// // GIVEN +// Prg prg(kKey1, PRG_MODE::kAesEcb); +// // WHEN +// uint64_t a = prg(); +// uint64_t b = prg(); +// // THEN +// EXPECT_NE(a, b); +// } + +// { +// // GIVEN +// Prg prg(kKey1, PRG_MODE::kAesEcb); +// // WHEN +// uint128_t a = prg(); +// uint128_t b = prg(); +// // THEN +// EXPECT_NE(a, b); +// } +// } + +// TEST(PRandomCtrDrbg, WorksForCustomizedStruct) { +// // GIVEN +// Prg prg(kKey1, PRG_MODE::kAesEcb); +// int ncalls = 3 * decltype(prg)::BatchSize() + 13; +// Foo last = prg(); +// for (int i = 0; i < ncalls; ++i) { +// // WHEN +// Foo now = prg(); +// // THEN +// EXPECT_NE(now, last); +// } +// } + +// // TEST(PRandomCtrDrbg, DeterministicWithSameSeed) { +// // Prg prg1(kKey1, PRG_MODE::kAesEcb); +// // Prg prg2(kKey1, PRG_MODE::kAesEcb); +// // for (int i = 0; i < 128; ++i) { +// // EXPECT_NE(prg1(), prg2()); +// // EXPECT_NE(prg1(), prg2()); +// // } +// // } + +// TEST(PRandomCtrDrbg, DeterministicWithDifferentSeed) { +// Prg prg1(kKey1, PRG_MODE::kAesEcb); +// Prg prg2(kKey2, PRG_MODE::kAesEcb); +// for (int i = 0; i < 128; ++i) { +// EXPECT_NE(prg1(), prg2()); +// EXPECT_NE(prg1(), prg2()); +// } +// } // nist gm sm4_ctr drbg -TEST(PRandomSm4Drbg, BooleanWorks) { - // GIVEN - Prg prg(kKey1, PRG_MODE::kGmSm4CtrDrbg); - // WHEN - std::array counts = {0, 0}; - const int kNumCalls = 10000; - for (int i = 0; i < kNumCalls; ++i) { - bool index = prg(); - EXPECT_TRUE(index == 0 || index == 1); - counts[index]++; - } - // THEN - double ratio = counts[0] / static_cast(kNumCalls); - // Give a loose constraint `5%` - EXPECT_TRUE(std::abs(ratio - 0.5) <= 0.05) << ratio; -} - -TEST(PRandomSm4Drbg, BuiltinScalarsWorks) { - { - // GIVEN - Prg prg(kKey1, PRG_MODE::kGmSm4CtrDrbg); - // WHEN - int a = prg(); - int b = prg(); - // THEN - EXPECT_NE(a, b); - } - - { - // GIVEN - Prg prg(kKey1, PRG_MODE::kGmSm4CtrDrbg); - // WHEN - double a = prg(); - double b = prg(); - // THEN - EXPECT_NE(a, b); - } - - { - // GIVEN - Prg prg(kKey1, PRG_MODE::kGmSm4CtrDrbg); - // WHEN - uint64_t a = prg(); - uint64_t b = prg(); - // THEN - EXPECT_NE(a, b); - } - - { - // GIVEN - Prg prg(kKey1, PRG_MODE::kGmSm4CtrDrbg); - // WHEN - uint128_t a = prg(); - uint128_t b = prg(); - // THEN - EXPECT_NE(a, b); - } -} - -TEST(PRandomSm4Drbg, WorksForCustomizedStruct) { - // GIVEN - Prg prg(kKey1, PRG_MODE::kGmSm4CtrDrbg); - int ncalls = 3 * decltype(prg)::BatchSize() + 13; - Foo last = prg(); - for (int i = 0; i < ncalls; ++i) { - // WHEN - Foo now = prg(); - // THEN - EXPECT_NE(now, last); - } -} - -TEST(PRandomSm4Drbg, DeterministicWithSameSeed) { - Prg prg1(kKey1, PRG_MODE::kGmSm4CtrDrbg); - Prg prg2(kKey1, PRG_MODE::kGmSm4CtrDrbg); - for (int i = 0; i < 128; ++i) { - EXPECT_NE(prg1(), prg2()); - EXPECT_NE(prg1(), prg2()); - } -} - -TEST(PRandomSm4Drbg, DeterministicWithDifferentSeed) { - Prg prg1(kKey1, PRG_MODE::kGmSm4CtrDrbg); - Prg prg2(kKey2, PRG_MODE::kGmSm4CtrDrbg); - for (int i = 0; i < 128; ++i) { - EXPECT_NE(prg1(), prg2()); - EXPECT_NE(prg1(), prg2()); - } -} +// TEST(PRandomSm4Drbg, BooleanWorks) { +// // GIVEN +// Prg prg(kKey1, PRG_MODE::kGmSm4CtrDrbg); +// // WHEN +// std::array counts = {0, 0}; +// const int kNumCalls = 10000; +// for (int i = 0; i < kNumCalls; ++i) { +// bool index = prg(); +// EXPECT_TRUE(index == 0 || index == 1); +// counts[index]++; +// } +// // THEN +// double ratio = counts[0] / static_cast(kNumCalls); +// // Give a loose constraint `5%` +// EXPECT_TRUE(std::abs(ratio - 0.5) <= 0.05) << ratio; +// } + +// TEST(PRandomSm4Drbg, BuiltinScalarsWorks) { +// { +// // GIVEN +// Prg prg(kKey1, PRG_MODE::kGmSm4CtrDrbg); +// // WHEN +// int a = prg(); +// int b = prg(); +// // THEN +// EXPECT_NE(a, b); +// } + +// { +// // GIVEN +// Prg prg(kKey1, PRG_MODE::kGmSm4CtrDrbg); +// // WHEN +// double a = prg(); +// double b = prg(); +// // THEN +// EXPECT_NE(a, b); +// } + +// { +// // GIVEN +// Prg prg(kKey1, PRG_MODE::kGmSm4CtrDrbg); +// // WHEN +// uint64_t a = prg(); +// uint64_t b = prg(); +// // THEN +// EXPECT_NE(a, b); +// } + +// { +// // GIVEN +// Prg prg(kKey1, PRG_MODE::kGmSm4CtrDrbg); +// // WHEN +// uint128_t a = prg(); +// uint128_t b = prg(); +// // THEN +// EXPECT_NE(a, b); +// } +// } + +// TEST(PRandomSm4Drbg, WorksForCustomizedStruct) { +// // GIVEN +// Prg prg(kKey1, PRG_MODE::kGmSm4CtrDrbg); +// int ncalls = 3 * decltype(prg)::BatchSize() + 13; +// Foo last = prg(); +// for (int i = 0; i < ncalls; ++i) { +// // WHEN +// Foo now = prg(); +// // THEN +// EXPECT_NE(now, last); +// } +// } + +// TEST(PRandomSm4Drbg, DeterministicWithSameSeed) { +// Prg prg1(kKey1, PRG_MODE::kGmSm4CtrDrbg); +// Prg prg2(kKey1, PRG_MODE::kGmSm4CtrDrbg); +// for (int i = 0; i < 128; ++i) { +// EXPECT_NE(prg1(), prg2()); +// EXPECT_NE(prg1(), prg2()); +// } +// } + +// TEST(PRandomSm4Drbg, DeterministicWithDifferentSeed) { +// Prg prg1(kKey1, PRG_MODE::kGmSm4CtrDrbg); +// Prg prg2(kKey2, PRG_MODE::kGmSm4CtrDrbg); +// for (int i = 0; i < 128; ++i) { +// EXPECT_NE(prg1(), prg2()); +// EXPECT_NE(prg1(), prg2()); +// } +// } } // namespace yacl::crypto diff --git a/yacl/crypto/tools/random_permutation.cc b/yacl/crypto/tools/random_permutation.cc deleted file mode 100644 index fb3cc9cc..00000000 --- a/yacl/crypto/tools/random_permutation.cc +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2022 Ant Group Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "yacl/crypto/tools/random_permutation.h" - -#include - -#include "yacl/base/int128.h" -#include "yacl/crypto/base/symmetric_crypto.h" - -namespace yacl::crypto { - -namespace { -using Ctype = SymmetricCrypto::CryptoType; - -// Circular Correlation Robust Hash function (Single Block) -// See https://eprint.iacr.org/2019/074.pdf Sec 7.3 -// CcrHash = RP(Sigma(x)) ^ Sigma(x) -// Sigma(x) = (x.left ^ x.right) || x.left -inline uint128_t Sigma(uint128_t x) { - // TODO: Sigma(x) = _mm_shuffle_epi32(a, 78) ^ and_si128(x, mask) - // where mask = 1^64 || 0^64 - const auto& [left, right] = DecomposeUInt128(x); - return MakeUint128(left ^ right, left); -} - -// x = SigmaInv( Sigma(x) ) -// inline uint128_t SigmaInv(uint128_t x) { -// auto [left, right] = DecomposeUInt128(x); -// return MakeUint128(right, left ^ right); -// } -} // namespace - -void RandomPerm::Gen(absl::Span x, - absl::Span out) const { - YACL_ENFORCE(x.size() == out.size()); - sym_alg_.Encrypt(x, out); -} - -std::vector RandomPerm::Gen(absl::Span x) const { - std::vector res(x.size()); - Gen(x, absl::MakeSpan(res)); - return res; -} - -void RandomPerm::GenInplace(absl::Span inout) const { - sym_alg_.Encrypt(inout, inout); -} - -uint128_t RandomPerm::Gen(uint128_t x) const { - YACL_ENFORCE(sym_alg_.GetType() != Ctype::AES128_CTR); - return sym_alg_.Encrypt(x); -} - -uint128_t CrHash_128(uint128_t x) { - const auto& RP = RandomPerm::GetDefault(); - return RP.Gen(x) ^ x; -} - -// FIXME: Rename to BatchCrHash_128 -std::vector ParaCrHash_128(absl::Span x) { - std::vector out(x.size()); - const auto& RP = RandomPerm::GetCrDefault(); - RP.Gen(x, absl::MakeSpan(out)); - for (uint64_t i = 0; i < x.size(); ++i) { - out[i] ^= x[i]; - } - return out; -} - -// FIXME: Rename to BatchCrHashInplace_128 -void ParaCrHashInplace_128(absl::Span inout) { - const auto& RP = RandomPerm::GetCrDefault(); - // TODO: add dynamic batch size - alignas(32) std::array tmp; - auto tmp_span = absl::MakeSpan(tmp); - const uint64_t size = inout.size(); - - uint64_t offset = 0; - for (; offset + 128 <= size; offset += 128) { - auto inout_span = inout.subspan(offset, 128); - RP.Gen(inout_span, tmp_span); - for (uint64_t i = 0; i < 128; ++i) { - inout_span[i] ^= tmp[i]; - } - } - uint64_t remain = size - offset; - if (remain > 0) { - auto inout_span = inout.subspan(offset, remain); - RP.Gen(inout_span, tmp_span.subspan(0, remain)); - for (uint64_t i = 0; i < remain; ++i) { - inout_span[i] ^= tmp[i]; - } - } -} - -uint128_t CcrHash_128(uint128_t x) { return CrHash_128(Sigma(x)); } - -// FIXME: Rename to BatchCcrHash_128 -std::vector ParaCcrHash_128(absl::Span x) { - std::vector tmp(x.size()); - for (uint64_t i = 0; i < x.size(); ++i) { - tmp[i] = Sigma(x[i]); - } - ParaCrHashInplace_128(absl::MakeSpan(tmp)); - return tmp; -} - -// FIXME: Rename to BatchCcrHashInplace_128 -void ParaCcrHashInplace_128(absl::Span inout) { - for (auto& e : inout) { - e = Sigma(e); - } - ParaCrHashInplace_128(inout); -} - -} // namespace yacl::crypto diff --git a/yacl/crypto/tools/random_oracle.h b/yacl/crypto/tools/ro.h similarity index 100% rename from yacl/crypto/tools/random_oracle.h rename to yacl/crypto/tools/ro.h diff --git a/yacl/crypto/tools/random_oracle_test.cc b/yacl/crypto/tools/ro_test.cc similarity index 97% rename from yacl/crypto/tools/random_oracle_test.cc rename to yacl/crypto/tools/ro_test.cc index 4f4e7450..f671b946 100644 --- a/yacl/crypto/tools/random_oracle_test.cc +++ b/yacl/crypto/tools/ro_test.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "yacl/crypto/tools/random_oracle.h" +#include "yacl/crypto/tools/ro.h" #include #include @@ -80,7 +80,7 @@ TEST_P(RandomOracleTest, TwoParamTest) { const auto& param = GetParam(); const auto& RO = RandomOracle::GetDefault(); auto input_bytes = RandBytes(param); - auto input_u64 = RandU64(); + auto input_u64 = FastRandU64(); EXPECT_EQ(RO.Gen(input_bytes, input_u64), RO.Gen(input_bytes, input_u64)); diff --git a/yacl/crypto/tools/rp.cc b/yacl/crypto/tools/rp.cc new file mode 100644 index 00000000..75966e8f --- /dev/null +++ b/yacl/crypto/tools/rp.cc @@ -0,0 +1,46 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/tools/rp.h" + +#include +#include + +#include "yacl/crypto/base/block_cipher/symmetric_crypto.h" + +namespace yacl::crypto { + +using Ctype = SymmetricCrypto::CryptoType; + +void RP::Gen(absl::Span x, absl::Span out) const { + YACL_ENFORCE(x.size() == out.size()); + sym_alg_.Encrypt(x, out); +} + +std::vector RP::Gen(absl::Span x) const { + std::vector res(x.size()); + Gen(x, absl::MakeSpan(res)); + return res; +} + +void RP::GenInplace(absl::Span inout) const { + sym_alg_.Encrypt(inout, inout); +} + +uint128_t RP::Gen(uint128_t x) const { + YACL_ENFORCE(sym_alg_.GetType() != Ctype::AES128_CTR); + return sym_alg_.Encrypt(x); +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/tools/random_permutation.h b/yacl/crypto/tools/rp.h similarity index 63% rename from yacl/crypto/tools/random_permutation.h rename to yacl/crypto/tools/rp.h index 78355e1a..ab6954c5 100644 --- a/yacl/crypto/tools/random_permutation.h +++ b/yacl/crypto/tools/rp.h @@ -21,7 +21,7 @@ #include "yacl/base/exception.h" #include "yacl/base/int128.h" #include "yacl/crypto/base/aes/aes_intrinsics.h" -#include "yacl/crypto/base/symmetric_crypto.h" +#include "yacl/crypto/base/block_cipher/symmetric_crypto.h" namespace yacl::crypto { @@ -40,12 +40,11 @@ namespace yacl::crypto { // [Security Assumption]: AES with a "fixed-and-public-known" key is a random // permutation // - -class RandomPerm { +class RP { public: using Ctype = SymmetricCrypto::CryptoType; - explicit RandomPerm(Ctype ctype, uint128_t key, uint128_t iv = 0) + explicit RP(Ctype ctype, uint128_t key, uint128_t iv = 0) : sym_alg_(ctype, key, iv) {} // generate a block x's random permutation, and outputs @@ -60,49 +59,22 @@ class RandomPerm { // generate (block vector) x's random permutation, and inplace void GenInplace(absl::Span inout) const; - // Example: const auto rp = RandomPerm::GetDefault(); - static RandomPerm& GetDefault() { + // Example: const auto rp = RP::GetDefault(); + static RP& GetDefault() { // Note: it's ok to use AES CTR blocks when you want to encrypt multiple // blocks, but when you want to encrypt a single block, please use ECB or // CBC - static RandomPerm rp(Ctype::AES128_CBC, 0x12345678); + static RP rp(Ctype::AES128_CBC, 0x12345678); return rp; } - static const RandomPerm& GetCrDefault() { - const static RandomPerm rp(Ctype::AES128_ECB, 0x12345678); + static const RP& GetCrDefault() { + const static RP rp(Ctype::AES128_ECB, 0x12345678); return rp; } private: SymmetricCrypto sym_alg_; - // AES_KEY aes_key_; }; -// Correlation Robust Hash function (Single Block input) -// See https://eprint.iacr.org/2019/074.pdf Sec 7.2 -// CrHash = RP(x) ^ x -uint128_t CrHash_128(uint128_t x); - -// parallel crhash for many blocks -std::vector ParaCrHash_128(absl::Span x); - -// inplace parallel crhash for many blocks -void ParaCrHashInplace_128(absl::Span inout); - -// Circular Correlation Robust Hash function (Single Block) -// See https://eprint.iacr.org/2019/074.pdf Sec 7.3 -// CcrHash = RP(Sigma(x)) ^ Sigma(x) -// Sigma(x) = (x.left ^ x.right) || x.left -uint128_t CcrHash_128(uint128_t x); - -// parallel ccrhash for many blocks -std::vector ParaCcrHash_128(absl::Span x); - -// inplace parallel ccrhash for many blocks -void ParaCcrHashInplace_128(absl::Span inout); - -// TODO(@shanzhu) Tweakable Correlation Robust Hash function (Multiple Blocks) -// See https://eprint.iacr.org/2019/074.pdf Sec 7.4 - } // namespace yacl::crypto diff --git a/yacl/crypto/tools/rp_test.cc b/yacl/crypto/tools/rp_test.cc new file mode 100644 index 00000000..bf2e161e --- /dev/null +++ b/yacl/crypto/tools/rp_test.cc @@ -0,0 +1,54 @@ +// Copyright 2021 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/tools/rp.h" + +#include +#include + +#include "gtest/gtest.h" + +#include "yacl/base/exception.h" +#include "yacl/crypto/tools/prg.h" +#include "yacl/crypto/utils/rand.h" + +namespace yacl::crypto { + +namespace { +inline auto RandomBlocks(size_t length) { + std::vector rand_inputs(length); + Prg prg; + prg.Fill(absl::MakeSpan(rand_inputs)); + return rand_inputs; +} + +} // namespace + +TEST(RPTest, U128Works) { + const auto& RP = RP::GetDefault(); + + auto input = FastRandU128(); + + EXPECT_EQ(RP.Gen(input), RP.Gen(input)); +} + +TEST(RPTest, BlocksWorks) { + const auto& RP = RP::GetDefault(); + + auto input = RandomBlocks(20); + + EXPECT_EQ(RP.Gen(absl::MakeSpan(input)), RP.Gen(absl::MakeSpan(input))); +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/utils/BUILD.bazel b/yacl/crypto/utils/BUILD.bazel index c1d0ea5f..cb5139be 100644 --- a/yacl/crypto/utils/BUILD.bazel +++ b/yacl/crypto/utils/BUILD.bazel @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:yacl.bzl", "yacl_cc_library", "yacl_cc_test") +load("//bazel:yacl.bzl", "yacl_cc_binary", "yacl_cc_library", "yacl_cc_test") package(default_visibility = ["//visibility:public"]) @@ -21,23 +21,31 @@ yacl_cc_library( srcs = ["rand.cc"], hdrs = ["rand.h"], deps = [ + ":secparam", "//yacl/base:dynamic_bitset", "//yacl/base:exception", "//yacl/base:int128", "//yacl/crypto/tools:prg", - "@com_github_openssl_openssl//:openssl", - "@com_google_absl//absl/types:span", + "//yacl/crypto/utils/drbg", ], ) -# TODO(@shanzhu.cjm) -# yacl_cc_test( -# name = "rand_test", -# srcs = ["rand_test.cc"], -# deps = [ -# ":rand", -# ], -# ) +yacl_cc_test( + name = "rand_test", + srcs = ["rand_test.cc"], + deps = [ + ":rand", + ], +) + +yacl_cc_binary( + name = "rand_bench", + srcs = ["rand_bench.cc"], + deps = [ + ":rand", + "@com_github_google_benchmark//:benchmark_main", + ], +) yacl_cc_library( name = "secparam", diff --git a/yacl/crypto/utils/compile_time_utils.h b/yacl/crypto/utils/compile_time_utils.h index 44093abb..2b170257 100644 --- a/yacl/crypto/utils/compile_time_utils.h +++ b/yacl/crypto/utils/compile_time_utils.h @@ -88,8 +88,10 @@ constexpr uint32_t crc32(-1)>( return 0xFFFFFFFF; } +} // namespace yacl::crypto + // helper macros -#define CT_CRC32(x) (crc32(x) ^ 0xFFFFFFFF) +#define CT_CRC32(x) (yacl::crypto::crc32(x) ^ 0xFFFFFFFF) // ---------------------------------------- // Compile-Time Utility: Customized Counter @@ -132,12 +134,10 @@ constexpr constant_index counter_crumb(id, constant_index, COUNTER_READ_CRUMB( \ TAG, 64, COUNTER_READ_CRUMB(TAG, 128, 0)))))))) -// counter ++ +// counter++ #define COUNTER_INC(TAG) \ constexpr constant_index counter_crumb( \ TAG, constant_index<(COUNTER_READ(TAG) + 1) & ~COUNTER_READ(TAG)>, \ constant_index<(COUNTER_READ(TAG) + 1) & COUNTER_READ(TAG)>) { \ return {}; \ } - -} // namespace yacl::crypto diff --git a/yacl/crypto/utils/drbg/BUILD.bazel b/yacl/crypto/utils/drbg/BUILD.bazel new file mode 100644 index 00000000..b7cc41b1 --- /dev/null +++ b/yacl/crypto/utils/drbg/BUILD.bazel @@ -0,0 +1,94 @@ +# Copyright 2022 Ant Group Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//bazel:yacl.bzl", "yacl_cc_library", "yacl_cc_test") + +# core +yacl_cc_library( + name = "drbg", + visibility = ["//visibility:public"], + deps = [ + ":ic_factory", + ":openssl_factory", # since we have only one impl + ], +) + +# private spi +yacl_cc_library( + name = "spi", + hdrs = [ + "drbg.h", + ], + visibility = ["//visibility:private"], + deps = [ + "//yacl/base:byte_container_view", + "//yacl/base:int128", + "//yacl/crypto/utils:secparam", + "//yacl/crypto/utils/entropy_source", + "//yacl/utils/spi", + ], +) + +# private openssl drbg impl +yacl_cc_library( + name = "openssl_factory", + srcs = [ + "openssl_factory.cc", + ], + hdrs = [ + "openssl_factory.h", + ], + data = [ + "//yacl/crypto/provider:prov_shared", # openssl provider shared lib + ], + visibility = ["//visibility:private"], + deps = [ + ":spi", + "//yacl/crypto/base:openssl_wrappers", + "//yacl/crypto/provider:helper", # helper + "//yacl/crypto/utils/entropy_source", + ], + alwayslink = 1, +) + +# ic factory +yacl_cc_library( + name = "ic_factory", + srcs = [ + "ic_factory.cc", + ], + hdrs = [ + "ic_factory.h", + ], + data = [ + "//yacl/crypto/provider:prov_shared", # openssl provider shared lib + ], + visibility = ["//visibility:private"], + deps = [ + ":spi", + "//yacl/crypto/base:openssl_wrappers", + "//yacl/crypto/provider:helper", # helper + "//yacl/crypto/utils/entropy_source", + "@com_github_greendow_hash_drbg//:hash_drbg", + ], + alwayslink = 1, +) + +yacl_cc_test( + name = "factory_test", + srcs = ["factory_test.cc"], + deps = [ + ":drbg", + ], +) diff --git a/yacl/crypto/utils/drbg/drbg.h b/yacl/crypto/utils/drbg/drbg.h new file mode 100644 index 00000000..66f2c670 --- /dev/null +++ b/yacl/crypto/utils/drbg/drbg.h @@ -0,0 +1,87 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +#include "yacl/base/exception.h" +#include "yacl/base/int128.h" +#include "yacl/crypto/utils/entropy_source/entropy_source.h" +#include "yacl/crypto/utils/secparam.h" +#include "yacl/utils/spi/spi_factory.h" + +namespace yacl::crypto { + +// ----------------------------------- +// Base class of DRBG (NIST SP800-90A) +// ----------------------------------- +// DRBG: Deterministic Random Bit Generator. Each subclass should implement a +// different DRBG , all implementations of DRBG should comply NIST SP800-90A, +// see: +// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90A.pdf +// +// Note that we only consider the *block-cipher based DRBG*, all DRBG in yacl +// refers to this sepcific type of DRBG (see Section NIST SP800-90Ar1 10.2.1) +// +// --------------- +// Usage: +// auto drbg = DrbgFactory::Instance().Create("ctr-drbg"); +// ---------------- +// Currently, the supported drbg types are (case insensitive): +// 1. ctr-drbg + +DEFINE_ARG_bool(UseYaclEs); // spi args, default should be true +DEFINE_ARG(SecParam::C, SecParamC); // spi args, default should >= 128 + +class Drbg { + public: + // constructor and destructor + explicit Drbg(bool use_yacl_es = true, SecParam::C c = SecParam::C::k128) + : use_yacl_es_(use_yacl_es), c_(c) {} + virtual ~Drbg() = default; + + // fill the output with generated randomness + virtual void Fill(char* buf, size_t len) = 0; + + // set the seed for this drbg + // [warning]: this feature may not be allowed by all implementations + virtual void SetSeed([[maybe_unused]] uint128_t seed) { + YACL_THROW("Set Seed is not Allowed"); + } + + // return the name of the implementation lib + virtual std::string Name() = 0; + + protected: + const bool use_yacl_es_; // whether use yacl's entropy source + const SecParam::C c_; // comp. security parameter +}; + +// by defalt we want the DRBG has at least 128 bit security strength +class DrbgFactory final : public SpiFactoryBase { + public: + static DrbgFactory& Instance() { + static DrbgFactory factory; + return factory; + } +}; + +#define REGISTER_DRBG_LIBRARY(lib_name, performance, checker, creator) \ + REGISTER_SPI_LIBRARY_HELPER(DrbgFactory, lib_name, performance, checker, \ + creator) + +} // namespace yacl::crypto diff --git a/yacl/crypto/utils/drbg/factory_test.cc b/yacl/crypto/utils/drbg/factory_test.cc new file mode 100644 index 00000000..dc9150e4 --- /dev/null +++ b/yacl/crypto/utils/drbg/factory_test.cc @@ -0,0 +1,121 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" + +#include "yacl/base/byte_container_view.h" +#include "yacl/crypto/utils/drbg/drbg.h" + +namespace yacl::crypto { + +TEST(OpensslTest, CtrDrbgWorks) { + auto drbg = DrbgFactory::Instance().Create("ctr-drbg"); + + std::vector out1(8); + std::vector out2(8); + drbg->Fill(out1.data(), 8); + drbg->Fill(out2.data(), 8); + + // should be different + EXPECT_NE(std::memcmp(out1.data(), out2.data(), 8), 0); +} + +TEST(OpensslTest, HashDrbgWorks) { + auto drbg = DrbgFactory::Instance().Create("hash-drbg"); + + std::vector out1(8); + std::vector out2(8); + drbg->Fill(out1.data(), 8); + drbg->Fill(out2.data(), 8); + + // should be different + EXPECT_NE(std::memcmp(out1.data(), out2.data(), 8), 0); +} + +TEST(OpensslTest, HmacDrbgWorks) { + auto drbg = DrbgFactory::Instance().Create("hmac-drbg"); + + std::vector out1(8); + std::vector out2(8); + drbg->Fill(out1.data(), 8); + drbg->Fill(out2.data(), 8); + + // should be different + EXPECT_NE(std::memcmp(out1.data(), out2.data(), 8), 0); +} + +// TEST(OpensslTest, IcDrbgSameSeedSameResults) { +// auto drbg1 = DrbgFactory::Instance().Create("IC-HASH-DRBG"); +// auto drbg2 = DrbgFactory::Instance().Create("IC-HASH-DRBG"); + +// std::vector out1(8); +// std::vector out2(8); + +// // set seed +// drbg1->SetSeed(123); +// drbg2->SetSeed(123); + +// drbg1->Fill(out1.data(), 8); +// drbg2->Fill(out2.data(), 8); + +// // should be same +// EXPECT_NE(std::memcmp(out1.data(), out2.data(), 8), 1); + +// drbg1->Fill(out1.data(), 8); +// drbg2->Fill(out2.data(), 8); + +// // should be same +// EXPECT_NE(std::memcmp(out1.data(), out2.data(), 8), 1); +// } + +// TEST(OpensslTest, IcDrbgDiffSeedDiffResults) { +// auto drbg1 = DrbgFactory::Instance().Create("IC-HASH-DRBG"); +// auto drbg2 = DrbgFactory::Instance().Create("IC-HASH-DRBG"); + +// std::vector out1(8); +// std::vector out2(8); + +// // set seed +// drbg1->SetSeed(123); +// drbg2->SetSeed(124); + +// drbg1->Fill(out1.data(), 8); +// drbg2->Fill(out2.data(), 8); + +// // should be different +// EXPECT_NE(std::memcmp(out1.data(), out2.data(), 8), 0); + +// drbg1->Fill(out1.data(), 8); +// drbg2->Fill(out2.data(), 8); + +// // should be different +// EXPECT_NE(std::memcmp(out1.data(), out2.data(), 8), 0); +// } + +// TEST(OpensslTest, IcDrbgDiffRoundDiffResults) { +// auto drbg = DrbgFactory::Instance().Create("IC-HASH-DRBG"); + +// std::vector out1(8); +// std::vector out2(8); + +// drbg->SetSeed(123); + +// drbg->Fill(out1.data(), 8); +// drbg->Fill(out2.data(), 8); + +// // should be different +// EXPECT_NE(std::memcmp(out1.data(), out2.data(), 8), 0); +// } + +} // namespace yacl::crypto diff --git a/yacl/crypto/utils/drbg/ic_factory.cc b/yacl/crypto/utils/drbg/ic_factory.cc new file mode 100644 index 00000000..4346ba73 --- /dev/null +++ b/yacl/crypto/utils/drbg/ic_factory.cc @@ -0,0 +1,82 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "yacl/crypto/utils/drbg/ic_factory.h" + +#include +#include + +#include "yacl/base/int128.h" + +namespace yacl::crypto { + +namespace { +constexpr std::array kIcDrbgNonce = {0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27}; + +constexpr std::array kIcDrbgPersonalStr = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, + 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, + 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76}; + +constexpr std::array kAdditionalInput = { + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, + 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, + 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, + 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96}; + +constexpr size_t kBatchSize = 1024; + +} // namespace + +IcDrbg::IcDrbg(std::string type, bool use_yacl_es, SecParam::C secparam) + : Drbg(use_yacl_es), type_(std::move(type)), secparam_(secparam) { + YACL_ENFORCE(secparam_ <= SecParam::C::k256); + uint128_t seed = 0; + + // default seeded using yacl's entropy source + auto es = EntropySourceFactory::Instance().Create("auto"); + auto out_buf = es->GetEntropy(sizeof(uint128_t)); + std::memcpy(&seed, out_buf.data(), out_buf.size()); + SetSeed(seed); +} + +void IcDrbg::SetSeed(uint128_t seed) { + seed_ = seed; + const EVP_MD *md = EVP_sha256(); + drbg_ctx_ = hash_drbg_ctx_new(); + hash_drbg_instantiate(md, reinterpret_cast(&seed_), + sizeof(uint128_t), (unsigned char *)kIcDrbgNonce.data(), + kIcDrbgNonce.size(), + (unsigned char *)kIcDrbgPersonalStr.data(), + kIcDrbgPersonalStr.size(), drbg_ctx_); +} + +void IcDrbg::Fill(char *buf, size_t len) { + YACL_ENFORCE(seed_ != 0, "Seed is not correctly configured!"); + + const auto batch_num = (len + kBatchSize - 1) / kBatchSize; + + for (uint32_t step = 0; step < batch_num; step++) { + const uint32_t limit = std::min(kBatchSize, len - step * kBatchSize); + auto *offset = buf + step * kBatchSize; + gen_rnd_bytes_with_hash_drbg( + drbg_ctx_, limit, (unsigned char *)kAdditionalInput.data(), + kAdditionalInput.size(), reinterpret_cast(offset)); + } +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/utils/drbg/ic_factory.h b/yacl/crypto/utils/drbg/ic_factory.h new file mode 100644 index 00000000..f19ba835 --- /dev/null +++ b/yacl/crypto/utils/drbg/ic_factory.h @@ -0,0 +1,80 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +#include "hash_drbg.h" // from @com_github_greendow_hash_drbg//:hash_drbg + +#include "yacl/base/int128.h" +#include "yacl/crypto/utils/drbg/drbg.h" +#include "yacl/crypto/utils/entropy_source/entropy_source.h" +#include "yacl/crypto/utils/secparam.h" +#include "yacl/utils/spi/argument/arg_set.h" + +namespace yacl::crypto { + +// NIST SP 800-90A hash-drbg, Recommendation for Random Number Generation Using +// Deterministic Random Bit Generators, see: +// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf +// +class IcDrbg : public Drbg { + public: + static constexpr std::array TypeList = { + "IC-HASH-DRBG", + }; + + explicit IcDrbg(std::string type, bool use_yacl_es = true, + SecParam::C secparam = SecParam::C::k128); + ~IcDrbg() override = default; + + // create drbg instance + static std::unique_ptr Create(const std::string &type, + const SpiArgs &config) { + YACL_ENFORCE(Check(type, config)); // make sure check passes + return std::make_unique( + absl::AsciiStrToUpper(type), config.Get(ArgUseYaclEs, true), + config.Get(ArgSecParamC, SecParam::C::k128)); + } + + // this checker would return ture only for ctr-drbg type + static bool Check(const std::string &type, + [[maybe_unused]] const SpiArgs &config) { + return find(begin(TypeList), end(TypeList), absl::AsciiStrToUpper(type)) != + end(TypeList); + } + + // fill buffer with randomness + void Fill(char *buf, size_t len) final; + + // set seed + void SetSeed(uint128_t seed) final; + + // get the lib name + std::string Name() override { return "Interconnection"; } + + private: + uint128_t seed_ = 0; + const std::string type_; + const SecParam::C secparam_; + HASH_DRBG_CTX *drbg_ctx_; +}; + +REGISTER_DRBG_LIBRARY("Interconnection", 100, IcDrbg::Check, IcDrbg::Create); + +} // namespace yacl::crypto diff --git a/yacl/crypto/utils/drbg/openssl_factory.cc b/yacl/crypto/utils/drbg/openssl_factory.cc new file mode 100644 index 00000000..c242f78a --- /dev/null +++ b/yacl/crypto/utils/drbg/openssl_factory.cc @@ -0,0 +1,113 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/utils/drbg/openssl_factory.h" + +#include +#include +#include +#include +#include +#include + +#include "openssl/objects.h" + +#include "yacl/base/exception.h" +#include "yacl/crypto/provider/helper.h" +#include "yacl/crypto/utils/secparam.h" + +namespace yacl::crypto { + +namespace { + +std::vector SelectParams(const std::string& type, SecParam::C c) { + YACL_ENFORCE(c <= SecParam::C::k256); + if (type == "CTR-DRBG") { + std::vector params(2); + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER, + (char*)SN_aes_256_ctr, 0); + params[1] = OSSL_PARAM_construct_end(); + return params; + } else if (type == "HASH-DRBG") { + std::vector params(2); + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_DIGEST, + (char*)SN_sha256, 0); + params[1] = OSSL_PARAM_construct_end(); + return params; + + } else if (type == "HMAC-DRBG") { + std::vector params(3); + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_MAC, + (char*)SN_hmac, 0); + params[1] = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_DIGEST, + (char*)SN_sha256, 0); + params[2] = OSSL_PARAM_construct_end(); + return params; + + } else { + YACL_THROW("unknown drbg type!"); + } +} + +} // namespace + +OpensslDrbg::OpensslDrbg(std::string type, bool use_yacl_es, + SecParam::C secparam) + : Drbg(use_yacl_es), type_(std::move(type)), secparam_(secparam) { + openssl::UniqueRandCtx seed = nullptr; + if (use_yacl_es) { + auto libctx = openssl::UniqueLib(OSSL_LIB_CTX_new()); + auto prov = openssl::UniqueProv( + OSSL_PROVIDER_load(libctx.get(), GetProviderPath().c_str())); + if (prov != nullptr) { + // get provider's entropy source + auto rand = + openssl::UniqueRand(EVP_RAND_fetch(libctx.get(), "Yes", nullptr)); + YACL_ENFORCE(rand != nullptr); + seed = openssl::UniqueRandCtx(EVP_RAND_CTX_new(rand.get(), nullptr)); + YACL_ENFORCE(seed != nullptr); + YACL_ENFORCE( + EVP_RAND_instantiate(seed.get(), 128, 0, nullptr, 0, nullptr) > 0); + } else { + SPDLOG_WARN( + "Yacl has been configured to use Yacl's entropy source, but unable " + "to find one. Fallback to use openssl's default entropy srouce"); + } + } + + auto rand = + openssl::UniqueRand(EVP_RAND_fetch(nullptr, type_.c_str(), nullptr)); + YACL_ENFORCE(rand != nullptr); + + ctx_ = openssl::UniqueRandCtx(EVP_RAND_CTX_new(rand.get(), seed.get())); + YACL_ENFORCE(ctx_ != nullptr); + + // setup parameters + YACL_ENFORCE(EVP_RAND_instantiate( + ctx_.get(), + static_cast(SecParam::MakeInt(secparam_)), 0, + nullptr, 0, SelectParams(type_, c_).data()) > 0); + YACL_ENFORCE(EVP_RAND_enable_locking(ctx_.get()) > 0); +} + +OpensslDrbg::~OpensslDrbg() = default; + +void OpensslDrbg::Fill(char* buf, size_t len) { + YACL_ENFORCE(EVP_RAND_get_state(ctx_.get()) == EVP_RAND_STATE_READY); + YACL_ENFORCE(EVP_RAND_generate(ctx_.get(), (unsigned char*)buf, len, + SecParam::MakeInt(secparam_), 0, nullptr, + 0) > 0); +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/utils/drbg/openssl_factory.h b/yacl/crypto/utils/drbg/openssl_factory.h new file mode 100644 index 00000000..6fb2b174 --- /dev/null +++ b/yacl/crypto/utils/drbg/openssl_factory.h @@ -0,0 +1,79 @@ +// Copyright 2020 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +#include "yacl/base/int128.h" +#include "yacl/crypto/base/openssl_wrappers.h" +#include "yacl/crypto/utils/drbg/drbg.h" +#include "yacl/crypto/utils/entropy_source/entropy_source.h" +#include "yacl/crypto/utils/secparam.h" +#include "yacl/utils/spi/argument/arg_set.h" + +namespace yacl::crypto { + +// NIST SP 800-90A ctr-drbg, Recommendation for Random Number Generation Using +// Deterministic Random Bit Generators, see: +// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf +// +// For openssl docs, see: https://www.openssl.org/docs/man3.1/man3/EVP_RAND.html +class OpensslDrbg : public Drbg { + public: + static constexpr std::array TypeList = { + "CTR-DRBG", + "HASH-DRBG", + "HMAC-DRBG", + }; + + explicit OpensslDrbg(std::string type, bool use_yacl_es = true, + SecParam::C secparam = SecParam::C::k128); + + ~OpensslDrbg() override; + + // create drbg instance + static std::unique_ptr Create(const std::string &type, + const SpiArgs &config) { + YACL_ENFORCE(Check(type, config)); // make sure check passes + return std::make_unique( + absl::AsciiStrToUpper(type), config.Get(ArgUseYaclEs, true), + config.Get(ArgSecParamC, SecParam::C::k128)); + } + + // this checker would return ture only for ctr-drbg type + static bool Check(const std::string &type, + [[maybe_unused]] const SpiArgs &config) { + return find(begin(TypeList), end(TypeList), absl::AsciiStrToUpper(type)) != + end(TypeList); + } + + // fill buffer with randomness + void Fill(char *buf, size_t len) final; + + // get the lib name + std::string Name() override { return "OpenSSL"; } + + private: + const std::string type_; + const SecParam::C secparam_; + openssl::UniqueRandCtx ctx_; +}; + +REGISTER_DRBG_LIBRARY("OpenSSL", 100, OpensslDrbg::Check, OpensslDrbg::Create); + +} // namespace yacl::crypto diff --git a/yacl/crypto/utils/entropy_source/BUILD.bazel b/yacl/crypto/utils/entropy_source/BUILD.bazel new file mode 100644 index 00000000..645674f9 --- /dev/null +++ b/yacl/crypto/utils/entropy_source/BUILD.bazel @@ -0,0 +1,85 @@ +# Copyright 2022 Ant Group Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//bazel:yacl.bzl", "yacl_cc_library", "yacl_cc_test") + +# core +yacl_cc_library( + name = "entropy_source", + visibility = ["//visibility:public"], + deps = [ + ":urandom_factory", + ] + select({ + "@platforms//cpu:x86_64": [ + ":intel_factory", + ], + "//conditions:default": [], + }), +) + +# private spi +yacl_cc_library( + name = "spi", + hdrs = [ + "entropy_source.h", + ], + visibility = ["//visibility:private"], + deps = [ + "//yacl/crypto/utils:secparam", + "//yacl/utils/spi", + ], +) + +# private urandom drbg impl +yacl_cc_library( + name = "urandom_factory", + srcs = [ + "urandom_factory.cc", + ], + hdrs = [ + "urandom_factory.h", + ], + visibility = ["//visibility:private"], + deps = [ + ":spi", + ], + alwayslink = 1, +) + +# private intel drbg impl +yacl_cc_library( + name = "intel_factory", + srcs = [ + "intel_factory.cc", + ], + hdrs = [ + "intel_factory.h", + ], + visibility = ["//visibility:private"], + deps = [ + ":spi", + "@com_github_google_cpu_features//:cpu_features", + ], + alwayslink = 1, +) + +yacl_cc_test( + name = "factory_test", + srcs = [ + "factory_test.cc", + ], + deps = [ + ":entropy_source", + ], +) diff --git a/yacl/crypto/utils/entropy_source/entropy_source.h b/yacl/crypto/utils/entropy_source/entropy_source.h new file mode 100644 index 00000000..c83dc2bf --- /dev/null +++ b/yacl/crypto/utils/entropy_source/entropy_source.h @@ -0,0 +1,66 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include "yacl/base/buffer.h" +#include "yacl/crypto/utils/secparam.h" +#include "yacl/utils/spi/spi_factory.h" + +namespace yacl::crypto { + +// Base class of Entropy Source (NIST SP800-90B) +// +// Each subclass should implement a different random entropy source, all +// implementations of entropy source should comply NIST SP800-90B, see: +// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90B.pdf +// +class EntropySource { + public: + // Constructor and desctructor + EntropySource() = default; + virtual ~EntropySource() = default; + + virtual std::string Name() = 0; + + // Get entropy with given amount of bytes + virtual Buffer GetEntropy(uint32_t num_bytes) = 0; + + // You may also provide this api (not mandatory): + // virtual Buffer GetNoise() = 0; + + // You may also provide this api (note mandatory): + // virtual bool HealthTest(Buffer buf); +}; + +// by defalt we want the entropy source random has at least 128 bit security +// strength +// SpiArgKey SecLevel("sec_level"); +class EntropySourceFactory final : public SpiFactoryBase { + public: + static EntropySourceFactory &Instance() { + static EntropySourceFactory factory; + return factory; + } +}; + +#define REGISTER_ENTROPY_SOURCE_LIBRARY(lib_name, performance, checker, \ + creator) \ + REGISTER_SPI_LIBRARY_HELPER(EntropySourceFactory, lib_name, performance, \ + checker, creator) + +} // namespace yacl::crypto diff --git a/yacl/crypto/utils/entropy_source/factory_test.cc b/yacl/crypto/utils/entropy_source/factory_test.cc new file mode 100644 index 00000000..33bdfe6c --- /dev/null +++ b/yacl/crypto/utils/entropy_source/factory_test.cc @@ -0,0 +1,59 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" + +#include "yacl/crypto/utils/entropy_source/entropy_source.h" + +namespace yacl::crypto { + +namespace { +constexpr size_t kTestSize = 10; +} + +#ifdef __x86_64 + +TEST(OpensslTest, HardwareESWorks) { + auto es = EntropySourceFactory::Instance().Create("hardware"); + auto x = es->GetEntropy(kTestSize); + auto y = es->GetEntropy(kTestSize); + + // SPDLOG_INFO(es->Name()); + + EXPECT_NE(std::memcmp(x.data(), y.data(), kTestSize), 0); +} + +#endif + +TEST(OpensslTest, SoftwareESWorks) { + auto es = EntropySourceFactory::Instance().Create("software"); + auto x = es->GetEntropy(kTestSize); + auto y = es->GetEntropy(kTestSize); + + // SPDLOG_INFO(es->Name()); + + EXPECT_NE(std::memcmp(x.data(), y.data(), kTestSize), 0); +} + +TEST(OpensslTest, AutoESWorks) { + auto es = EntropySourceFactory::Instance().Create("auto"); + auto x = es->GetEntropy(kTestSize); + auto y = es->GetEntropy(kTestSize); + + SPDLOG_INFO(es->Name()); + + EXPECT_NE(std::memcmp(x.data(), y.data(), kTestSize), 0); +} + +} // namespace yacl::crypto diff --git a/yacl/crypto/utils/entropy_source/intel_factory.cc b/yacl/crypto/utils/entropy_source/intel_factory.cc new file mode 100644 index 00000000..1bb88d58 --- /dev/null +++ b/yacl/crypto/utils/entropy_source/intel_factory.cc @@ -0,0 +1,72 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/utils/entropy_source/intel_factory.h" + +#include + +#ifdef __x86_64 + +namespace yacl::crypto { + +namespace { + +// Example from Code Example 9, +// https://www.intel.com/content/www/us/en/developer/articles/guide/ +// intel-digital-random-number-generator-drng-software-implementation-guide.html +int rdseed64_step(uint64_t *out) { + unsigned char ok = 0; + asm volatile("rdseed %0; setc %1" : "=r"(*out), "=qm"(ok)); + return static_cast(ok); +} + +// Or maybe just use the buit-in function: +// ---------------------------------------- +// #include +// int _rdseed64_step(uint64_t*); +// ---------------------------------------- + +} // namespace + +Buffer IntelEntropySource::GetEntropy(uint32_t num_bytes) { + YACL_ENFORCE(num_bytes != 0); + + Buffer out(num_bytes); + + // Batched Random Entropy Generation + size_t batch_size = sizeof(uint64_t); + size_t batch_num = (num_bytes + batch_size - 1) / batch_size; + for (size_t idx = 0; idx < batch_num; idx++) { + uint64_t temp_rand = 0; + size_t current_pos = idx * batch_size; + size_t current_batch_size = std::min(num_bytes - current_pos, batch_size); + + // if failed, retry geneartion, we adopt strategy in section 5.3.1.1 + while (rdseed64_step(&temp_rand) == 0) { + // [retry forever ... ] Maybe add loops / pauses in the future + } + + std::memcpy(static_cast(out.data()) + current_pos, &temp_rand, + current_batch_size); + } + + return out; +} + +REGISTER_ENTROPY_SOURCE_LIBRARY("Intel", 100, IntelEntropySource::Check, + IntelEntropySource::Create); + +} // namespace yacl::crypto + +#endif diff --git a/yacl/crypto/utils/entropy_source/intel_factory.h b/yacl/crypto/utils/entropy_source/intel_factory.h new file mode 100644 index 00000000..dc23a474 --- /dev/null +++ b/yacl/crypto/utils/entropy_source/intel_factory.h @@ -0,0 +1,56 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +#include "yacl/crypto/utils/entropy_source/entropy_source.h" + +#ifdef __x86_64 +#include + +#include "cpu_features/cpuinfo_x86.h" + +namespace yacl::crypto { + +class IntelEntropySource : public EntropySource { + public: + static std::unique_ptr Create( + const std::string &type, [[maybe_unused]] const SpiArgs &config) { + // this entropy source should be used only if the CPU has rdseed support + YACL_ENFORCE(cpu_features::GetX86Info().features.rdseed); + YACL_ENFORCE(absl::AsciiStrToLower(type) == "hardware" || + absl::AsciiStrToLower(type) == "auto"); + return std::make_unique(); + } + + // this checker would always return ture + static bool Check(const std::string &type, + [[maybe_unused]] const SpiArgs &config) { + return cpu_features::GetX86Info().features.rdseed && + (absl::AsciiStrToLower(type) == "hardware" || + absl::AsciiStrToLower(type) == "auto"); + } + + Buffer GetEntropy(uint32_t num_bytes) override; + + std::string Name() override { return "intel rdseed entropy source"; } +}; + +} // namespace yacl::crypto + +#endif diff --git a/yacl/crypto/utils/entropy_source/urandom_factory.cc b/yacl/crypto/utils/entropy_source/urandom_factory.cc new file mode 100644 index 00000000..2cc95d19 --- /dev/null +++ b/yacl/crypto/utils/entropy_source/urandom_factory.cc @@ -0,0 +1,50 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/utils/entropy_source/urandom_factory.h" + +#include +#include +#include +#include + +namespace yacl::crypto { + +Buffer UrandomEntropySource::GetEntropy(uint32_t num_bytes) { + YACL_ENFORCE(num_bytes != 0); + + Buffer out(num_bytes); + std::random_device rd("/dev/urandom"); + + // Batched Random Entropy Generation + size_t batch_size = sizeof(uint32_t); + size_t batch_num = (num_bytes + batch_size - 1) / batch_size; + for (size_t idx = 0; idx < batch_num; idx++) { + uint64_t temp_rand = 0; + size_t current_pos = idx * batch_size; + size_t current_batch_size = std::min(num_bytes - current_pos, batch_size); + + temp_rand = static_cast(rd()); + + std::memcpy(static_cast(out.data()) + current_pos, &temp_rand, + current_batch_size); + } + + return out; +} + +REGISTER_ENTROPY_SOURCE_LIBRARY("urandom", 100, UrandomEntropySource::Check, + UrandomEntropySource::Create); + +} // namespace yacl::crypto diff --git a/yacl/crypto/utils/entropy_source/urandom_factory.h b/yacl/crypto/utils/entropy_source/urandom_factory.h new file mode 100644 index 00000000..e493c8b8 --- /dev/null +++ b/yacl/crypto/utils/entropy_source/urandom_factory.h @@ -0,0 +1,47 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +#include "yacl/crypto/utils/entropy_source/entropy_source.h" + +namespace yacl::crypto { + +class UrandomEntropySource : public EntropySource { + public: + static std::unique_ptr Create( + const std::string &type, [[maybe_unused]] const SpiArgs &config) { + // this entropy source should be used only if the CPU has rdseed support + YACL_ENFORCE(absl::AsciiStrToLower(type) == "software" || + absl::AsciiStrToLower(type) == "auto"); + return std::make_unique(); + } + + // this checker would always return ture + static bool Check(const std::string &type, + [[maybe_unused]] const SpiArgs &config) { + return absl::AsciiStrToLower(type) == "software" || + absl::AsciiStrToLower(type) == "auto"; + } + + Buffer GetEntropy(uint32_t num_bytes) override; + + std::string Name() override { return "urandom entropy source"; } +}; + +} // namespace yacl::crypto diff --git a/yacl/crypto/utils/rand.cc b/yacl/crypto/utils/rand.cc index 0e7a5d62..cd75f94a 100644 --- a/yacl/crypto/utils/rand.cc +++ b/yacl/crypto/utils/rand.cc @@ -14,143 +14,91 @@ #include "yacl/crypto/utils/rand.h" -#include -#include -#include +#include +#include +#include "openssl/rand.h" + +#include "yacl/base/byte_container_view.h" #include "yacl/base/dynamic_bitset.h" +#include "yacl/crypto/provider/helper.h" +#include "yacl/crypto/utils/entropy_source/entropy_source.h" namespace yacl::crypto { -namespace { - -std::once_flag seed_flag; - -void OpensslSeedOnce() { - // NistAesCtrDrbg seed with intel rdseed - std::call_once(seed_flag, []() { - Prg prg(0, PRG_MODE::kNistAesCtrDrbg); - std::array rand_bytes; - prg.Fill(absl::MakeSpan(rand_bytes)); // get 256 bits seed - - RAND_seed(rand_bytes.data(), rand_bytes.size()); // reseed - }); +// -------------------- +// Core Implementations +// -------------------- +RandCtx::RandCtx(SecParam::C c, bool use_yacl_es) : c_(c) { + ctr_drbg_ = DrbgFactory::Instance().Create( + "ctr-drbg", ArgUseYaclEs = use_yacl_es, ArgSecParamC = c_); + hash_drbg_ = DrbgFactory::Instance().Create( + "hash-drbg", ArgUseYaclEs = use_yacl_es, ArgSecParamC = c_); } -} // namespace - -// RAND_priv_bytes() and RAND_bytes() Generates num random bytes using a -// cryptographically secure pseudo random generator (CSPRNG) and stores them -// in out (with 256 security strength). For details, see: -// https://www.openssl.org/docs/man1.1.1/man3/RAND_bytes.html -// -// By default, the OpenSSL CSPRNG supports a security level of 256 bits, -// provided it was able to seed itself from a trusted entropy source. -// On all major platforms supported by OpenSSL (including the Unix-like -// platforms and Windows), OpenSSL is configured to automatically seed -// the CSPRNG on first use using the operating systems's random generator. -// -// OpenSSL comes with a default implementation of the RAND API which -// is based on the deterministic random bit generator (DRBG) model -// as described in [NIST SP 800-90A Rev. 1]. -// It seeds and reseeds itself automatically using trusted random -// sources provided by the operating system. -// -// Reference: -// https://www.openssl.org/docs/man3.0/man7/RAND.html -// https://www.openssl.org/docs/man3.0/man3/RAND_seed.html -// https://www.openssl.org/docs/manmaster/man3/RAND_bytes.html - -uint64_t RandU64(bool use_secure_rand) { - uint64_t rand64; - if (use_secure_rand) { - OpensslSeedOnce(); // reseed openssl internal CSPRNG - // RAND_priv_bytes() has the same semantics as RAND_bytes(). It uses a - // separate "private" PRNG instance so that a compromise of the "public" - // PRNG instance will not affect the secrecy of these private values - // - // RAND_priv_bytes() is thread-safe with OpenSSL >= 1.1.0 - YACL_ENFORCE(RAND_priv_bytes(reinterpret_cast(&rand64), - sizeof(rand64)) == 1); +void RandCtx::Fill(char *buf, size_t len, bool use_fast_mode) const { + YACL_ENFORCE(len <= std::numeric_limits::max()); + if (use_fast_mode) { + hash_drbg_->Fill(buf, len); } else { - YACL_ENFORCE(RAND_bytes(reinterpret_cast(&rand64), - sizeof(uint64_t)) == 1); + ctr_drbg_->Fill(buf, len); } - return rand64; } -uint128_t RandU128(bool use_secure_rand) { - uint128_t rand128; - if (use_secure_rand) { - OpensslSeedOnce(); // reseed openssl internal CSPRNG - // RAND_priv_bytes() has the same semantics as RAND_bytes(). It uses a - // separate "private" PRNG instance so that a compromise of the "public" - // PRNG instance will not affect the secrecy of these private values - // - // RAND_priv_bytes() is thread-safe with OpenSSL >= 1.1.0 - YACL_ENFORCE(RAND_priv_bytes(reinterpret_cast(&rand128), - sizeof(rand128)) == 1); +// --------------------- +// Other Implementations +// --------------------- +uint64_t RandU64(const RandCtx &ctx, bool use_fast_mode) { + uint64_t rand64 = 0; + FillRand(ctx, reinterpret_cast(&rand64), sizeof(uint64_t), + use_fast_mode); + return rand64; +} - } else { - YACL_ENFORCE(RAND_bytes(reinterpret_cast(&rand128), - sizeof(rand128)) == 1); - } +uint128_t RandU128(const RandCtx &ctx, bool use_fast_mode) { + uint128_t rand128 = 0; + FillRand(ctx, reinterpret_cast(&rand128), sizeof(uint128_t), + use_fast_mode); return rand128; } template <> std::vector RandBits>(uint64_t len, - bool use_secure_rand) { + bool use_fast_mode) { std::vector out(len, false); const unsigned stride = sizeof(unsigned) * 8; - if (use_secure_rand) { // drbg is more secure - Prg prg(RandU128(true), PRG_MODE::kNistAesCtrDrbg); - for (uint64_t i = 0; i < len; i += stride) { - unsigned rand = prg(); - unsigned size = std::min(stride, static_cast(len - i)); - for (unsigned j = 0; j < size; ++j) { - out[i + j] = (rand & (1 << j)) != 0; - } - } - } else { // fast path - Prg prg(RandU128(false), PRG_MODE::kAesEcb); - for (uint64_t i = 0; i < len; i += stride) { - unsigned rand = prg(); - unsigned size = std::min(stride, static_cast(len - i)); - for (unsigned j = 0; j < size; ++j) { - out[i + j] = (rand & (1 << j)) != 0; - } + + // generate randomness + auto rand_buf = RandVec(len, use_fast_mode); + + // for each byte + for (uint64_t i = 0; i < len; i += stride) { + unsigned size = std::min(stride, static_cast(len - i)); + for (unsigned j = 0; j < size; ++j) { + out[i + j] = (rand_buf[i] & (1 << j)) != 0; } } return out; } -#define IMPL_RANDBIT_DYNAMIC_BIT_TYPE(TYPE) \ - template <> \ - dynamic_bitset RandBits>(uint64_t len, \ - bool use_secure_rand) { \ - dynamic_bitset out(len); \ - const unsigned stride = sizeof(unsigned) * 8; \ - if (use_secure_rand) { \ - Prg prg(RandU128(true), PRG_MODE::kNistAesCtrDrbg); \ - for (uint64_t i = 0; i < len; i += stride) { \ - unsigned rand = prg(); \ - unsigned size = std::min(stride, static_cast(len - i)); \ - for (unsigned j = 0; j < size; ++j) { \ - out[i + j] = (rand & (1 << j)) != 0; \ - } \ - } \ - } else { \ - Prg prg(RandU128(false), PRG_MODE::kAesEcb); \ - for (uint64_t i = 0; i < len; i += stride) { \ - unsigned rand = prg(); \ - unsigned size = std::min(stride, static_cast(len - i)); \ - for (unsigned j = 0; j < size; ++j) { \ - out[i + j] = (rand & (1 << j)) != 0; \ - } \ - } \ - } \ - return out; \ +#define IMPL_RANDBIT_DYNAMIC_BIT_TYPE(T) \ + template <> \ + dynamic_bitset RandBits>(uint64_t len, \ + bool use_fast_mode) { \ + dynamic_bitset out(len); \ + const unsigned stride = sizeof(unsigned) * 8; \ + \ + /* generate randomness */ \ + auto rand_buf = RandBytes(len, use_fast_mode); \ + \ + /* for each byte */ \ + for (uint64_t i = 0; i < len; i += stride) { \ + unsigned size = std::min(stride, static_cast(len - i)); \ + for (unsigned j = 0; j < size; ++j) { \ + out[i + j] = (rand_buf[i] & (1 << j)) != 0; \ + } \ + } \ + return out; \ } IMPL_RANDBIT_DYNAMIC_BIT_TYPE(uint128_t); diff --git a/yacl/crypto/utils/rand.h b/yacl/crypto/utils/rand.h index 093f58db..a07cc1ce 100644 --- a/yacl/crypto/utils/rand.h +++ b/yacl/crypto/utils/rand.h @@ -14,116 +14,155 @@ #pragma once -#include - #include +#include #include +#include #include #include #include -#include "absl/types/span.h" - #include "yacl/base/dynamic_bitset.h" -#include "yacl/base/exception.h" #include "yacl/base/int128.h" -#include "yacl/crypto/base/symmetric_crypto.h" -#include "yacl/crypto/tools/prg.h" +#include "yacl/crypto/base/openssl_wrappers.h" +#include "yacl/crypto/utils/drbg/drbg.h" +#include "yacl/crypto/utils/secparam.h" -// Utility for randomness (not pseudo-randomness) -// -// We recommend applicaitons to set "use_secure_rand = true", which internally -// use DRBG to generate randomness. To generate seeded pseudorandomness, -// please use yacl/crypto-tools/prg.h. For more details of how DRBG works, see -// yacl/crypto/drbg/nist_aes_drbg.h -// -// * security strength = 128 bit (openssl=256, our drbg=128) +YACL_MODULE_DECLARE("rand", SecParam::C::k256, SecParam::S::INF); namespace yacl::crypto { +// ------------------------- +// Yacl's Randomness Context +// ------------------------- + +// A thread-safe random context class +class RandCtx { + public: + explicit RandCtx(SecParam::C c, // we do not recommend to set c <= 256 + bool use_yacl_es); + + // get a static default context + static RandCtx &GetDefault() { + static auto ctx = RandCtx(SecParam::C::k256, false); + return ctx; + } + + // fill random to buf with len (warning: does not check boundaries) + void Fill(char *buf, size_t len, bool use_fast_mode = false) const; + + private: + const SecParam::C c_; /* comp. security param */ + std::unique_ptr ctr_drbg_; + + // https://crypto.stackexchange.com/a/1395/61581 + std::unique_ptr hash_drbg_; // faster +}; + +// fil randomness to buf with len within RandCtx +inline void FillRand(const RandCtx &ctx, char *buf, size_t len, + bool use_fast_mode = false) { + ctx.Fill(buf, len, use_fast_mode); +} + +// fil randomness to buf with len within the default RandCtx +inline void FillRand(char *buf, size_t len, bool use_fast_mode = false) { + RandCtx::GetDefault().Fill(buf, len, use_fast_mode); +} + +// -------------------------------- +// Random Support for Generic Types +// -------------------------------- + // Generate uint64_t random value -// secure mode: reseed (with drbg mode kNistAesCtrDrbg), and gen (with openssl) -// insecure mode: gen (with openssl rand_bytes) -uint64_t RandU64(bool use_secure_rand = false); +uint64_t RandU64(const RandCtx &ctxctx, bool use_fast_mode = false); -inline uint64_t SecureRandU64() { return RandU64(true); } +// Generate uint64_t random value, in a faster but less secure way +inline uint64_t FastRandU64() { return RandU64(RandCtx::GetDefault(), true); } -// Generate uint128_t random value -// secure mode: reseed (with drbg mode kNistAesCtrDrbg), and gen (with openssl) -// insecure mode: gen (with openssl rand_bytes) -uint128_t RandU128(bool use_secure_rand = false); +// Generate uint64_t random value, in a slower but more secure way +// (randomness comes directly from an random entropy source) +inline uint64_t SecureRandU64() { + return RandU64(RandCtx::GetDefault(), false); +} -inline uint128_t SecureRandU128() { return RandU128(true); } +// Generate uint128_t random value +uint128_t RandU128(const RandCtx &ctxctx, bool use_fast_mode = false); -// Generate uint128_t random seed (internally calls RandU128()) -inline uint128_t RandSeed(bool use_secure_rand = false) { - return RandU128(use_secure_rand); +// Generate uint128_t random value, in a faster but less secure way +inline uint128_t FastRandU128() { + return RandU128(RandCtx::GetDefault(), true); } -inline uint128_t SecureRandSeed() { return RandSeed(true); } +// Generate uint128_t random value, in a slower but more secure way +// (randomness comes directly from an random entropy source) +inline uint128_t SecureRandU128() { + return RandU128(RandCtx::GetDefault(), false); +} -// Generate rand bits for -// - vector -// - dynamic_bitset, where T = {uint128_t, uint64_t, uint32_t, uint16_t} -// secure mode: prg.gen (with drbg mode kNistAesCtrDrbg) -// insecure mode: prg.gen (with drbg mode kAesEcb) +// Function alias +inline uint128_t RandSeed(const RandCtx &ctx, bool use_fast_mode = false) { + return RandU128(ctx, use_fast_mode); +} +inline uint128_t FastRandSeed() { return FastRandU128(); } +inline uint128_t SecureRandSeed() { return SecureRandU128(); } + +// ----------------------------- +// Random Support for Yacl Types +// ----------------------------- +// Generate rand bits for either vector or dynamic_bitset +// where T = {uint128_t, uint64_t, uint32_t, uint16_t} template -struct is_supported_bit_vector_type +struct IsSupportedBitVectorType : public std::disjunction, T>, is_dynamic_bitset_type> {}; template , - std::enable_if_t::value, bool> = true> -T RandBits(uint64_t len, bool use_secure_rand = false); + std::enable_if_t::value, bool> = true> +T RandBits(uint64_t len, bool use_fast_mode = false); template , - std::enable_if_t::value, bool> = true> -inline T SecureRandBits(uint64_t len) { + std::enable_if_t::value, bool> = true> +inline T FastRandBits(uint64_t len) { return RandBits(len, true); } -// Fill random type-T -// secure mode: RAND_priv_bytes (from openssl) -// insecure mode: RAND_bytes (from openssl) -template ::value, int> = 0> -inline void FillRand(absl::Span out, bool use_secure_rand = false) { - const uint64_t nbytes = out.size() * sizeof(T); - if (use_secure_rand) { - YACL_ENFORCE( - RAND_priv_bytes(reinterpret_cast(out.data()), nbytes) == 1); - } else { - YACL_ENFORCE(RAND_bytes(reinterpret_cast(out.data()), nbytes) == - 1); - } +// Generate rand bits in a secure but slow way +template , + std::enable_if_t::value, bool> = true> +inline T SecureRandBits(uint64_t len) { + return RandBits(len, false); } // Generate random T-type vectors -// Note: The output is `sizeof(T)` bytes aligned. template , int> = 0> -inline std::vector RandVec(uint64_t len, bool use_secure_rand = false) { +inline std::vector RandVec(uint64_t len, bool use_fast_mode = false) { std::vector out(len); - FillRand(absl::MakeSpan(out), use_secure_rand); + FillRand((char *)out.data(), sizeof(T) * len, use_fast_mode); return out; } // Generate random number of bytes inline std::vector RandBytes(uint64_t len, - bool use_secure_rand = false) { - return RandVec(len, use_secure_rand); + bool use_fast_mode = false) { + std::vector out(len); + FillRand(reinterpret_cast(out.data()), len, use_fast_mode); + return out; } -inline std::vector SecureRandBytes(uint64_t len) { +inline std::vector FastRandBytes(uint64_t len) { return RandBytes(len, true); } +inline std::vector SecureRandBytes(uint64_t len) { + return RandBytes(len, false); +} + // wanring: the output may not be strictly uniformly random +// FIXME(@shanzhu.cjm) Improve performance inline uint32_t RandInRange(uint32_t n) { - Prg gen(RandSeed()); - return gen() % n; + uint32_t tmp = FastRandU64(); + return tmp % n; } -// TODO(shanzhu) RFC: add more generic random interface, e.g. -// void FillRand(RandContext* ctx, char* buf, uint64_t len); - } // namespace yacl::crypto diff --git a/yacl/crypto/utils/rand_bench.cc b/yacl/crypto/utils/rand_bench.cc index 32eeb470..4aff8af0 100644 --- a/yacl/crypto/utils/rand_bench.cc +++ b/yacl/crypto/utils/rand_bench.cc @@ -1,4 +1,3 @@ - // Copyright 2022 Ant Group Co., Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,103 +12,100 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include #include "benchmark/benchmark.h" -#include "yacl/base/dynamic_bitset.h" #include "yacl/crypto/utils/rand.h" +#include "yacl/crypto/utils/secparam.h" namespace yacl::crypto { -static void BM_RandU64InSecure(benchmark::State& state) { +static void BM_SecureRand(benchmark::State& state) { for (auto _ : state) { state.PauseTiming(); - size_t n = state.range(0); - state.ResumeTiming(); - for (size_t i = 0; i < n; i++) { - RandU64(false); - } - } -} + { + // setup input + size_t n = state.range(0); + std::vector out(n); + auto& ctx = RandCtx::GetDefault(); -static void BM_RandU64Secure(benchmark::State& state) { - for (auto _ : state) { - state.PauseTiming(); - size_t n = state.range(0); - state.ResumeTiming(); - for (size_t i = 0; i < n; i++) { - SecureRandU64(); + // benchmark + state.ResumeTiming(); + FillRand(ctx, out.data(), out.size(), false); + state.PauseTiming(); } - } -} - -static void BM_RandU128InSecure(benchmark::State& state) { - for (auto _ : state) { - state.PauseTiming(); - size_t n = state.range(0); state.ResumeTiming(); - for (size_t i = 0; i < n; i++) { - RandU128(false); - } } } -static void BM_RandU128Secure(benchmark::State& state) { +static void BM_FastRand(benchmark::State& state) { for (auto _ : state) { state.PauseTiming(); - size_t n = state.range(0); - state.ResumeTiming(); - for (size_t i = 0; i < n; i++) { - SecureRandU128(); - } - } -} + { + // setup input + size_t n = state.range(0); + std::vector out(n); + auto& ctx = RandCtx::GetDefault(); -static void BM_RandBytesInSecure(benchmark::State& state) { - for (auto _ : state) { - state.PauseTiming(); - size_t n = state.range(0); + // benchmark + state.ResumeTiming(); + FillRand(ctx, out.data(), out.size(), true); + state.PauseTiming(); + } state.ResumeTiming(); - RandBytes(n, false); } } -static void BM_RandBytesSecure(benchmark::State& state) { +static void BM_IcDrbg(benchmark::State& state) { for (auto _ : state) { state.PauseTiming(); - size_t n = state.range(0); - state.ResumeTiming(); - SecureRandBytes(n); - } -} + { + // setup input + size_t n = state.range(0); + std::vector out(n); -static void BM_RandBitsInSecure(benchmark::State& state) { - for (auto _ : state) { - state.PauseTiming(); - size_t n = state.range(0); - state.ResumeTiming(); - SecureRandBits>(n); - } -} + auto drbg = DrbgFactory::Instance().Create("ic-hash-drbg"); + drbg->SetSeed(1234); -static void BM_RandBitsSecure(benchmark::State& state) { - for (auto _ : state) { - state.PauseTiming(); - size_t n = state.range(0); + // benchmark + state.ResumeTiming(); + drbg->Fill(out.data(), out.size()); + state.PauseTiming(); + } state.ResumeTiming(); - SecureRandBits>(n); } } -BENCHMARK(BM_RandU64InSecure)->Unit(benchmark::kMillisecond)->Arg(1 << 15); -BENCHMARK(BM_RandU64Secure)->Unit(benchmark::kMillisecond)->Arg(1 << 15); -BENCHMARK(BM_RandU128InSecure)->Unit(benchmark::kMillisecond)->Arg(1 << 15); -BENCHMARK(BM_RandU128Secure)->Unit(benchmark::kMillisecond)->Arg(1 << 15); -BENCHMARK(BM_RandBytesInSecure)->Unit(benchmark::kMillisecond)->Arg(1 << 15); -BENCHMARK(BM_RandBytesSecure)->Unit(benchmark::kMillisecond)->Arg(1 << 15); -BENCHMARK(BM_RandBitsInSecure)->Unit(benchmark::kMillisecond)->Arg(1 << 15); -BENCHMARK(BM_RandBitsSecure)->Unit(benchmark::kMillisecond)->Arg(1 << 15); +BENCHMARK(BM_SecureRand) + ->Unit(benchmark::kMillisecond) + ->Arg(1024) + ->Arg(5120) + ->Arg(10240) + ->Arg(20480) + ->Arg(40960) + ->Arg(81920) + ->Arg(1 << 24); + +BENCHMARK(BM_FastRand) + ->Unit(benchmark::kMillisecond) + ->Arg(1024) + ->Arg(5120) + ->Arg(10240) + ->Arg(20480) + ->Arg(40960) + ->Arg(81920) + ->Arg(1 << 24); +BENCHMARK(BM_IcDrbg) + ->Unit(benchmark::kMillisecond) + ->Arg(1024) + ->Arg(5120) + ->Arg(10240) + ->Arg(20480) + ->Arg(40960) + ->Arg(81920) + ->Arg(1 << 24); } // namespace yacl::crypto diff --git a/yacl/crypto/utils/rand_test.cc b/yacl/crypto/utils/rand_test.cc new file mode 100644 index 00000000..57782bf4 --- /dev/null +++ b/yacl/crypto/utils/rand_test.cc @@ -0,0 +1,44 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/crypto/utils/rand.h" + +#include "gtest/gtest.h" + +namespace yacl::crypto { + +#define TEST_GENERIC_TYPE_RAND_FUNC(FUNC, ...) \ + TEST(GenericRandTest, Fast##FUNC##Test) { \ + auto tmp1 = Fast##FUNC(__VA_ARGS__); \ + auto tmp2 = Fast##FUNC(__VA_ARGS__); \ + \ + /* should be different*/ \ + EXPECT_TRUE(tmp1 != tmp2); \ + } \ + \ + TEST(GenericRandTest, Secure##FUNC##Test) { \ + auto tmp1 = Secure##FUNC(__VA_ARGS__); \ + auto tmp2 = Secure##FUNC(__VA_ARGS__); \ + \ + /* should be different*/ \ + EXPECT_TRUE(tmp1 != tmp2); \ + } + +TEST_GENERIC_TYPE_RAND_FUNC(RandU64); +TEST_GENERIC_TYPE_RAND_FUNC(RandU128); +TEST_GENERIC_TYPE_RAND_FUNC(RandSeed); +TEST_GENERIC_TYPE_RAND_FUNC(RandBytes, 10); +TEST_GENERIC_TYPE_RAND_FUNC(RandBits, 10); + +} // namespace yacl::crypto diff --git a/yacl/crypto/utils/secparam.h b/yacl/crypto/utils/secparam.h index cb51b770..e90e279a 100644 --- a/yacl/crypto/utils/secparam.h +++ b/yacl/crypto/utils/secparam.h @@ -16,6 +16,7 @@ #include #include +#include #include "fmt/color.h" @@ -24,7 +25,9 @@ namespace yacl::crypto { +// ------------------ // Security parameter +// ------------------ class SecParam { public: // Computational Security Parameter: A number associated with the amount of @@ -72,22 +75,7 @@ class SecParam { }; // convert to int - static constexpr uint32_t MakeInt(const C c) { - switch (c) { - case C::k112: - return 112; - case C::k128: - return 128; - case C::k192: - return 192; - case C::k256: - return 256; - case C::INF: - return UINT32_MAX; - default: - return 0; // this should never be called - } - } + static constexpr uint32_t MakeInt(C c); // Statistical Security Parameter: (from wikipedia) A measure of the // probability with which an adversary can break the scheme. Statistial @@ -102,27 +90,76 @@ class SecParam { INF // the adversary can not statistically guess out anything (as // contrary to "almost anything") }; - // convert s to int - static constexpr uint32_t MakeInt(const S s) { - switch (s) { - case S::k30: - return 30; - case S::k40: - return 40; - case S::k64: - return 64; - case S::INF: - return UINT32_MAX; - default: - return 0; // this should never be called - } - } + static constexpr uint32_t MakeInt(S s); static C glob_c; // global computational security paramter static S glob_s; // global statistical security paramter }; +// ----------------------- +// Function implementaions +// ----------------------- +constexpr uint32_t SecParam::MakeInt(SecParam::C c) { + switch (c) { + case SecParam::C::k112: + return 112; + case SecParam::C::k128: + return 128; + case SecParam::C::k192: + return 192; + case SecParam::C::k256: + return 256; + case SecParam::C::INF: + return UINT32_MAX; + default: + return 0; // this should never be called + } +} + +constexpr uint32_t SecParam::MakeInt(SecParam::S s) { + switch (s) { + case SecParam::S::k30: + return 30; + case SecParam::S::k40: + return 40; + case SecParam::S::k64: + return 64; + case SecParam::S::INF: + return UINT32_MAX; + default: + return 0; // this should never be called + } +} + +// -------------------------------- +// LPN Parameter (security related) +// -------------------------------- + +enum class LpnNoiseAsm { RegularNoise, UniformNoise }; + +// For more parameter choices, see results in +// https://eprint.iacr.org/2019/273.pdf Page 20, Table 1. +class LpnParam { + public: + uint64_t n = 10485760; // primal lpn, security param = 128 + uint64_t k = 452000; // primal lpn, security param = 128 + uint64_t t = 1280; // primal lpn, security param = 128 + LpnNoiseAsm noise_asm = LpnNoiseAsm::RegularNoise; + + LpnParam(uint64_t n, uint64_t k, uint64_t t, LpnNoiseAsm noise_asm) + : n(n), k(k), t(t), noise_asm(noise_asm) {} + + static LpnParam GetDefault() { + return {10485760, 452000, 1280, LpnNoiseAsm::RegularNoise}; + } +}; +} // namespace yacl::crypto + +// ------------------ +// Yacl module +// ------------------ + // Yacl module's security parameter setup // // What is the boundary of Yacl's module? Note that each module's declaration @@ -134,7 +171,7 @@ class SecParam { // +----------+. +------------+ // dec: <128, 30> // | [APPLICATION] -// ************************************************************************ +// ======================================================================== // | [YACL] // V <128, 40> // +----------+ depends on +----------+ @@ -144,6 +181,7 @@ class SecParam { // template struct YaclModule { + using SecParam = yacl::crypto::SecParam; [[maybe_unused]] static constexpr std::string_view name = "unknown"; [[maybe_unused]] static const SecParam::C c = SecParam::C::UNKNOWN; [[maybe_unused]] static const SecParam::S s = SecParam::S::UNKNOWN; @@ -152,9 +190,7 @@ struct YaclModule { // Yacl global registry (which is a compile-time map) // this map only stores the unique module name hash (supposedly), and a // compile-time interal counter which counts the number of registerd modules -namespace internal { struct YaclModuleCtr {}; // compile-time counter initialization (start at 0) -} // namespace internal template struct YaclRegistry { @@ -164,6 +200,8 @@ struct YaclRegistry { // Yacl module handler, which helps to print all registed module infos class YaclModuleHandler { public: + using SecParam = yacl::crypto::SecParam; + template static void PrintAll() { fmt::print(fg(fmt::color::green), "{:-^50}\n", "module summary"); @@ -182,11 +220,18 @@ class YaclModuleHandler { private: template - static void iterator(bool print = false) { + static void iterator(bool print) { using Module = YaclModule::hash>; if (print) { - fmt::print("{0:<10}\t{1:<5}\t{2:<5}\n", Module::name, - SecParam::MakeInt(Module::c), SecParam::MakeInt(Module::s)); + std::string c_str = fmt::format("{}", SecParam::MakeInt(Module::c)); + std::string s_str = fmt::format("{}", SecParam::MakeInt(Module::s)); + if (SecParam::MakeInt(Module::c) == UINT32_MAX) { + c_str = "-"; + } + if (SecParam::MakeInt(Module::s) == UINT32_MAX) { + s_str = "-"; + } + fmt::print("{0:<10}\t{1:<5}\t{2:<5}\n", Module::name, c_str, s_str); } SecParam::glob_c = SecParam::glob_c > Module::c ? Module::c : SecParam::glob_c; @@ -197,7 +242,7 @@ class YaclModuleHandler { template static void interate_helper( [[maybe_unused]] std::integer_sequence int_seq, - bool print = false) { + [[maybe_unused]] bool print = false) { ((iterator(print)), ...); } }; @@ -215,47 +260,46 @@ class YaclModuleHandler { // ---------------- // YACL_MODULE_DECLARE_SECPARAM("iknp_ote", SecParam::C::k128, SecParam::S::INF) // -#define YACL_MODULE_DECLARE(NAME, COMP, STAT) \ - template <> \ - struct YaclModule { \ - static constexpr std::string_view name = NAME; \ - static constexpr SecParam::C c = (COMP); \ - static constexpr SecParam::S s = (STAT); \ - }; \ - \ - template <> \ - struct YaclRegistry { \ - static constexpr uint32_t hash = CT_CRC32(NAME); \ - }; \ - COUNTER_INC(internal::YaclModuleCtr); +#define YACL_MODULE_DECLARE(NAME, COMP, STAT) \ + template <> \ + struct YaclModule { \ + using SecParam = yacl::crypto::SecParam; \ + static constexpr std::string_view name = NAME; \ + static constexpr SecParam::C c = (COMP); \ + static constexpr SecParam::S s = (STAT); \ + }; \ + \ + template <> \ + struct YaclRegistry { \ + static constexpr uint32_t hash = CT_CRC32(NAME); \ + }; \ + COUNTER_INC(YaclModuleCtr); // Get module's security parameter #define YACL_MODULE_SECPARAM_C(NAME) YaclModule::c #define YACL_MODULE_SECPARAM_S(NAME) YaclModule::s #define YACL_MODULE_SECPARAM_C_UINT(NAME) \ - SecParam::MakeInt(YaclModule::c) + SecParam::MakeInt(YACL_MODULE_SECPARAM_C(NAME)) #define YACL_MODULE_SECPARAM_S_UINT(NAME) \ - SecParam::MakeInt(YaclModule::s) + SecParam::MakeInt(YACL_MODULE_SECPARAM_S(NAME)) + +// Get yacl's global security parameter +#define YACL_GLOB_SECPARAM_C \ + YaclModuleHandler::GetGlob().first +#define YACL_GLOB_SECPARAM_S \ + YaclModuleHandler::GetGlob().second +#define YACL_GLOB_SECPARAM_C_UINT SecParam::MakeInt(YACL_GLOB_SECPARAM_C) +#define YACL_GLOB_SECPARAM_S_UINT SecParam::MakeInt(YACL_GLOB_SECPARAM_S) // Print all module summary #define YACL_PRINT_MODULE_SUMMARY() \ - YaclModuleHandler::PrintAll(); + YaclModuleHandler::PrintAll(); // Enforce Yacl security level, fails when condition not met -#define YACL_ENFORCE_SECPARAM(COMP, STAT) \ - YACL_ENFORCE( \ - YaclModuleHandler::GetGlob() \ - .first >= COMP && \ - YaclModuleHandler::GetGlob() \ - .second >= STAT, \ - "Enforce SecurityParameter failed, expected c>{}, s>{}, but yacl got " \ - "global (c, s) = ({}, {})", \ - SecParam::MakeInt(COMP), SecParam::MakeInt(STAT), \ - SecParam::MakeInt( \ - YaclModuleHandler::GetGlob() \ - .first), \ - SecParam::MakeInt( \ - YaclModuleHandler::GetGlob() \ - .second)); - -} // namespace yacl::crypto +#define YACL_ENFORCE_SECPARAM(COMP, STAT) \ + YACL_ENFORCE( \ + YACL_GLOB_SECPARAM_C >= (COMP) && YACL_GLOB_SECPARAM_S >= (STAT), \ + "Enforce SecurityParameter failed, expected c>{}, s>{}, but yacl got " \ + "global (c, s) = ({}, {})", \ + SecParam::MakeInt(COMP), SecParam::MakeInt(STAT), \ + YACL_GLOB_SECPARAM_C_UINT, YACL_GLOB_SECPARAM_S_UINT); diff --git a/yacl/crypto/utils/secparam_test.cc b/yacl/crypto/utils/secparam_test.cc index 0bd01a91..deeb9898 100644 --- a/yacl/crypto/utils/secparam_test.cc +++ b/yacl/crypto/utils/secparam_test.cc @@ -16,13 +16,13 @@ #include "gtest/gtest.h" -namespace yacl::crypto { - // inheader YACL_MODULE_DECLARE("iknp_ote", SecParam::C::k128, SecParam::S::k40); YACL_MODULE_DECLARE("aes", SecParam::C::k128, SecParam::S::INF); YACL_MODULE_DECLARE("hash", SecParam::C::k192, SecParam::S::INF); +namespace yacl::crypto { + TEST(DeclareTest, Test) { EXPECT_EQ(YACL_MODULE_SECPARAM_C("iknp_ote"), SecParam::C::k128); EXPECT_EQ(YACL_MODULE_SECPARAM_S("iknp_ote"), SecParam::S::k40); @@ -38,5 +38,4 @@ TEST(DeclareTest, Test) { YACL_PRINT_MODULE_SUMMARY(); } - } // namespace yacl::crypto diff --git a/yacl/io/msgpack/BUILD.bazel b/yacl/io/msgpack/BUILD.bazel index 0d74d013..db995f51 100644 --- a/yacl/io/msgpack/BUILD.bazel +++ b/yacl/io/msgpack/BUILD.bazel @@ -26,6 +26,7 @@ yacl_cc_library( yacl_cc_library( name = "spec_traits", + srcs = ["spec_traits.cc"], hdrs = ["spec_traits.h"], ) diff --git a/yacl/io/msgpack/spec_traits.cc b/yacl/io/msgpack/spec_traits.cc new file mode 100644 index 00000000..78960544 --- /dev/null +++ b/yacl/io/msgpack/spec_traits.cc @@ -0,0 +1,78 @@ +// Copyright 2023 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/io/msgpack/spec_traits.h" + +namespace yacl::io::msgpack_traits { + +size_t HeadSizeOfStr(size_t str_len) { + // Str format family stores a byte array in 1, 2, 3, or 5 bytes of extra bytes + // in addition to the size of the byte array. + if (str_len < 32) { + // fixstr stores a byte array whose length is upto 31 bytes: + // +--------+========+ + // |101XXXXX| data | + // +--------+========+ + return 1; + + } else if (str_len < 256) { + // str 8 stores a byte array whose length is upto (2^8)-1 bytes: + // +--------+--------+========+ + // | 0xd9 |YYYYYYYY| data | + // +--------+--------+========+ + return 2; + + } else if (str_len < 65536) { + // str 16 stores a byte array whose length is upto (2^16)-1 bytes: + // +--------+--------+--------+========+ + // | 0xda |ZZZZZZZZ|ZZZZZZZZ| data | + // +--------+--------+--------+========+ + return 3; + + } else { + // str 32 stores a byte array whose length is upto (2^32)-1 bytes: + // +--------+--------+--------+--------+--------+========+ + // | 0xdb |AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA| data | + // +--------+--------+--------+--------+--------+========+ + return 5; + } +} + +size_t HeadSizeOfArray(size_t array_len) { + // Array format family stores a sequence of elements in 1, 3, or 5 bytes of + // extra bytes in addition to the elements. + if (array_len < 16) { + // fixarray stores an array whose length is upto 15 elements: + // +--------+~~~~~~~~~~~~~~~~~+ + // |1001XXXX| N objects | + // +--------+~~~~~~~~~~~~~~~~~+ + return 1; + + } else if (array_len < 65536) { + // array 16 stores an array whose length is upto (2^16)-1 elements: + // +--------+--------+--------+~~~~~~~~~~~~~~~~~+ + // | 0xdc |YYYYYYYY|YYYYYYYY| N objects | + // +--------+--------+--------+~~~~~~~~~~~~~~~~~+ + return 3; + + } else { + // array 32 stores an array whose length is upto (2^32)-1 elements: + // +--------+--------+--------+--------+--------+~~~~~~~~~~~~~~~~~+ + // | 0xdd |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ| N objects | + // +--------+--------+--------+--------+--------+~~~~~~~~~~~~~~~~~+ + return 5; + } +} + +} // namespace yacl::io::msgpack_traits diff --git a/yacl/io/msgpack/spec_traits.h b/yacl/io/msgpack/spec_traits.h index 44b3ce0f..6bb640f5 100644 --- a/yacl/io/msgpack/spec_traits.h +++ b/yacl/io/msgpack/spec_traits.h @@ -21,63 +21,10 @@ namespace yacl::io::msgpack_traits { // The msgpack spec: // https://github.com/msgpack/msgpack/blob/master/spec.md -size_t HeadSizeOfStr(size_t str_len) { - // Str format family stores a byte array in 1, 2, 3, or 5 bytes of extra bytes - // in addition to the size of the byte array. - if (str_len < 32) { - // fixstr stores a byte array whose length is upto 31 bytes: - // +--------+========+ - // |101XXXXX| data | - // +--------+========+ - return 1; +// get the head size of str according to msgpack spec +size_t HeadSizeOfStr(size_t str_len); - } else if (str_len < 256) { - // str 8 stores a byte array whose length is upto (2^8)-1 bytes: - // +--------+--------+========+ - // | 0xd9 |YYYYYYYY| data | - // +--------+--------+========+ - return 2; - - } else if (str_len < 65536) { - // str 16 stores a byte array whose length is upto (2^16)-1 bytes: - // +--------+--------+--------+========+ - // | 0xda |ZZZZZZZZ|ZZZZZZZZ| data | - // +--------+--------+--------+========+ - return 3; - - } else { - // str 32 stores a byte array whose length is upto (2^32)-1 bytes: - // +--------+--------+--------+--------+--------+========+ - // | 0xdb |AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA| data | - // +--------+--------+--------+--------+--------+========+ - return 5; - } -} - -size_t HeadSizeOfArray(size_t array_len) { - // Array format family stores a sequence of elements in 1, 3, or 5 bytes of - // extra bytes in addition to the elements. - if (array_len < 16) { - // fixarray stores an array whose length is upto 15 elements: - // +--------+~~~~~~~~~~~~~~~~~+ - // |1001XXXX| N objects | - // +--------+~~~~~~~~~~~~~~~~~+ - return 1; - - } else if (array_len < 65536) { - // array 16 stores an array whose length is upto (2^16)-1 elements: - // +--------+--------+--------+~~~~~~~~~~~~~~~~~+ - // | 0xdc |YYYYYYYY|YYYYYYYY| N objects | - // +--------+--------+--------+~~~~~~~~~~~~~~~~~+ - return 3; - - } else { - // array 32 stores an array whose length is upto (2^32)-1 elements: - // +--------+--------+--------+--------+--------+~~~~~~~~~~~~~~~~~+ - // | 0xdd |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ| N objects | - // +--------+--------+--------+--------+--------+~~~~~~~~~~~~~~~~~+ - return 5; - } -} +// get the head size of array according to msgpack spec +size_t HeadSizeOfArray(size_t array_len); } // namespace yacl::io::msgpack_traits diff --git a/yacl/link/BUILD.bazel b/yacl/link/BUILD.bazel index 6c9f924a..0a89f6dc 100644 --- a/yacl/link/BUILD.bazel +++ b/yacl/link/BUILD.bazel @@ -66,7 +66,7 @@ yacl_cc_library( ":trace", "//yacl/base:byte_container_view", "//yacl/link/transport:channel", - "//yacl/utils:hash", + "//yacl/utils:hash_combine", ], ) diff --git a/yacl/link/context.h b/yacl/link/context.h index 8f4626dc..b291ae05 100644 --- a/yacl/link/context.h +++ b/yacl/link/context.h @@ -27,7 +27,7 @@ #include "yacl/link/retry_options.h" #include "yacl/link/ssl_options.h" #include "yacl/link/transport/channel.h" -#include "yacl/utils/hash.h" +#include "yacl/utils/hash_combine.h" #include "yacl/link/link.pb.h" @@ -140,6 +140,8 @@ struct ContextDesc { RetryOptions retry_opts; + bool disable_msg_seq_id = false; + bool operator==(const ContextDesc& other) const { return (id == other.id) && (parties == other.parties); } diff --git a/yacl/link/factory_brpc.cc b/yacl/link/factory_brpc.cc index b44e08f8..4b61109d 100644 --- a/yacl/link/factory_brpc.cc +++ b/yacl/link/factory_brpc.cc @@ -66,6 +66,7 @@ std::shared_ptr FactoryBrpc::CreateContext(const ContextDesc& desc, delegate, desc.recv_timeout_ms, desc.exit_if_async_error, desc.retry_opts); channel->SetThrottleWindowSize(desc.throttle_window_size); + channel->SetDisableMsgSeqId(desc.disable_msg_seq_id); msg_loop->AddListener(rank, channel); channels[rank] = std::move(channel); } diff --git a/yacl/link/test_util.h b/yacl/link/test_util.h index b8a0529d..ee34f6c8 100644 --- a/yacl/link/test_util.h +++ b/yacl/link/test_util.h @@ -40,7 +40,12 @@ inline std::vector> SetupBrpcWorld( contexts[rank] = FactoryBrpc().CreateContext(ctx_desc, rank); } - auto proc = [&](size_t rank) { contexts[rank]->ConnectToMesh(); }; + auto proc = [&](size_t rank) { + contexts[rank]->ConnectToMesh(); + // If throttle_window_size is not zero, "SendAsync" will block until + // messages are processed + contexts[rank]->SetThrottleWindowSize(0); + }; std::vector> jobs(world_size); for (size_t rank = 0; rank < world_size; rank++) { jobs[rank] = std::async(proc, rank); diff --git a/yacl/link/transport/BUILD.bazel b/yacl/link/transport/BUILD.bazel index 9f898f83..7daa46fb 100644 --- a/yacl/link/transport/BUILD.bazel +++ b/yacl/link/transport/BUILD.bazel @@ -51,6 +51,14 @@ yacl_cc_library( ], ) +yacl_cc_test( + name = "channel_mem_test", + srcs = ["channel_mem_test.cc"], + deps = [ + ":channel_mem", + ], +) + cc_proto_library( name = "ic_transport_proto", deps = ["@org_interconnection//interconnection/link"], diff --git a/yacl/link/transport/blackbox_interconnect/mock_transport.h b/yacl/link/transport/blackbox_interconnect/mock_transport.h index 2ef5573e..260a200f 100644 --- a/yacl/link/transport/blackbox_interconnect/mock_transport.h +++ b/yacl/link/transport/blackbox_interconnect/mock_transport.h @@ -106,6 +106,7 @@ class MockTransport { YACL_THROW_IO_ERROR("brpc server failed to add msg service"); } brpc::ServerOptions server_opt; + server_opt.has_builtin_services = false; if (server_.Start(local_transport_url.c_str(), &server_opt) != 0) { YACL_THROW_IO_ERROR("brpc server failed start at {}", local_transport_url); diff --git a/yacl/link/transport/brpc_link.cc b/yacl/link/transport/brpc_link.cc index 2697fa98..65b819c5 100644 --- a/yacl/link/transport/brpc_link.cc +++ b/yacl/link/transport/brpc_link.cc @@ -86,6 +86,7 @@ std::string ReceiverLoopBrpc::Start(const std::string& host, // Start the server. brpc::ServerOptions options; + options.has_builtin_services = false; if (ssl_opts != nullptr) { options.mutable_ssl_options()->default_cert.certificate = ssl_opts->cert.certificate_path; diff --git a/yacl/link/transport/channel.cc b/yacl/link/transport/channel.cc index 708cfee2..52b38388 100644 --- a/yacl/link/transport/channel.cc +++ b/yacl/link/transport/channel.cc @@ -26,6 +26,8 @@ namespace yacl::link::transport { +#define YACL_UNLIKELY(x) __builtin_expect(!!(x), 0) + namespace { // use acsii control code inside ack/fin msg key. // avoid conflict to normal msg key. @@ -53,11 +55,15 @@ std::string BuildChannelKey(std::string_view msg_key, size_t seq_id) { } std::pair SplitChannelKey(std::string_view key) { - auto pos = key.find(kSeqKey); - std::pair ret; - ret.first = key.substr(0, pos); - ret.second = ViewToSizeT(key.substr(pos + kSeqKey.size())); + auto pos = key.find(kSeqKey); + if (YACL_UNLIKELY(pos == std::string_view::npos)) { + ret.first = key; + ret.second = 0; + } else { + ret.first = key.substr(0, pos); + ret.second = ViewToSizeT(key.substr(pos + kSeqKey.size())); + } return ret; } @@ -556,12 +562,23 @@ void Channel::SendAsync(const std::string& msg_key, Buffer&& value) { YACL_ENFORCE(!waiting_finish_.load(), "SendAsync is not allowed when channel is closing"); NormalMessageKeyEnforce(msg_key); - size_t seq_id = msg_seq_id_.fetch_add(1) + 1; - auto key = BuildChannelKey(msg_key, seq_id); + + size_t seq_id = 0; + std::string key; + if (YACL_UNLIKELY(disable_msg_seq_id_)) { + key = msg_key; + } else { + seq_id = msg_seq_id_.fetch_add(1) + 1; + key = BuildChannelKey(msg_key, seq_id); + } send_msgs_.Push(Message(seq_id, std::move(key), std::move(value))); } void Channel::Send(const std::string& msg_key, ByteContainerView value) { + if (YACL_UNLIKELY(disable_msg_seq_id_)) { + YACL_THROW("Send is not allowed when msg_seq_id is disabled"); + } + YACL_ENFORCE(!waiting_finish_.load(), "Send is not allowed when channel is closing"); NormalMessageKeyEnforce(msg_key); @@ -577,6 +594,10 @@ void Channel::SendAsyncThrottled(const std::string& msg_key, } void Channel::SendAsyncThrottled(const std::string& msg_key, Buffer&& value) { + if (YACL_UNLIKELY(disable_msg_seq_id_)) { + return SendAsync(msg_key, value); + } + YACL_ENFORCE(!waiting_finish_.load(), "SendAsync is not allowed when channel is closing"); NormalMessageKeyEnforce(msg_key); @@ -723,4 +744,6 @@ void Channel::OnRequest(const ::google::protobuf::Message& request, } } +#undef YACL_UNLIKELY + } // namespace yacl::link::transport diff --git a/yacl/link/transport/channel.h b/yacl/link/transport/channel.h index 0df5e0a7..9d386ee9 100644 --- a/yacl/link/transport/channel.h +++ b/yacl/link/transport/channel.h @@ -217,6 +217,10 @@ class Channel : public IChannel, public std::enable_shared_from_this { chunk_parallel_send_size_ = size; } + void SetDisableMsgSeqId(bool disable_msg_seq_id) { + disable_msg_seq_id_ = disable_msg_seq_id; + } + void SendRequestWithRetry( const ::google::protobuf::Message& request, uint32_t timeout_override_ms, spdlog::level::level_enum log_level = spdlog::level::info) const; @@ -356,6 +360,8 @@ class Channel : public IChannel, public std::enable_shared_from_this { std::shared_ptr link_; RetryOptions retry_options_; + + bool disable_msg_seq_id_ = false; }; // A receiver loop is a thread loop which receives messages from the world. diff --git a/yacl/link/transport/channel_mem.cc b/yacl/link/transport/channel_mem.cc index 630538df..f711c911 100644 --- a/yacl/link/transport/channel_mem.cc +++ b/yacl/link/transport/channel_mem.cc @@ -24,6 +24,7 @@ ChannelMem::ChannelMem(size_t /*self_rank*/, size_t /*peer_rank*/, void ChannelMem::SetPeer(const std::shared_ptr& peer_task) { peer_channel_ = peer_task; + finished_ = false; } void ChannelMem::SendImpl(const std::string& key, ByteContainerView value) { @@ -65,4 +66,16 @@ void ChannelMem::OnMessage(const std::string& msg_key, msg_db_cond_.notify_all(); } +void ChannelMem::WaitLinkTaskFinish() { + bool expect = false; + if (!finished_.compare_exchange_strong(expect, true)) { + return; + } + + SendImpl(kFinKey, ""); + auto recv = Recv(kFinKey); + recv.reset(); + finished_ = true; +} + } // namespace yacl::link::transport diff --git a/yacl/link/transport/channel_mem.h b/yacl/link/transport/channel_mem.h index 23716243..54b241f3 100644 --- a/yacl/link/transport/channel_mem.h +++ b/yacl/link/transport/channel_mem.h @@ -14,10 +14,12 @@ #pragma once +#include #include #include #include #include +#include #include #include "yacl/link/transport/channel.h" @@ -34,7 +36,12 @@ class ReceiverLoopMem final : public IReceiverLoop { class ChannelMem final : public IChannel { public: - ~ChannelMem() override = default; + ~ChannelMem() override { + if (!finished_) { + // WaitLinkTaskFinish should be called if you want to keep sync with + // peers. + } + } ChannelMem(size_t self_rank, size_t peer_rank, size_t timeout_ms = 20000U); @@ -71,8 +78,9 @@ class ChannelMem final : public IChannel { uint64_t GetRecvTimeout() const final { return recv_timeout_ms_.count(); } + void WaitLinkTaskFinish() final; + // do nothing - void WaitLinkTaskFinish() final {} void SetThrottleWindowSize(size_t) final {} void TestSend(uint32_t /*timeout*/) final {} void TestRecv() final {} @@ -90,6 +98,9 @@ class ChannelMem final : public IChannel { std::chrono::milliseconds recv_timeout_ms_ = 3UL * 60 * std::chrono::milliseconds(1000); + + std::atomic finished_{true}; + inline static const std::string kFinKey = "_fin_"; }; } // namespace yacl::link::transport diff --git a/yacl/link/transport/channel_mem_test.cc b/yacl/link/transport/channel_mem_test.cc new file mode 100644 index 00000000..ec94237a --- /dev/null +++ b/yacl/link/transport/channel_mem_test.cc @@ -0,0 +1,98 @@ +// Copyright 2019 Ant Group Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yacl/link/transport/channel_mem.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fmt/format.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include "yacl/base/byte_container_view.h" +#include "yacl/base/exception.h" + +// disable detect leaks for brpc's "acceptable mem leak" +// https://github.com/apache/incubator-brpc/blob/0.9.6/src/brpc/server.cpp#L1138 +extern "C" const char* __asan_default_options() { return "detect_leaks=0"; } + +namespace yacl::link::transport::test { + +class ChannelMemTest : public ::testing::Test { + protected: + void SetUp() override { + size_t send_rank = 0; + size_t recv_rank = 1; + sender_ = std::make_shared(send_rank, recv_rank); + receiver_ = std::make_shared(recv_rank, send_rank); + sender_->SetPeer(receiver_); + receiver_->SetPeer(sender_); + } + + void TearDown() override {} + + std::shared_ptr sender_; + std::shared_ptr receiver_; +}; + +TEST_F(ChannelMemTest, Normal) { + const std::string key = "key"; + const std::string sent = "test"; + sender_->SendAsync(key, ByteContainerView{sent}); + auto received = receiver_->Recv(key); + + EXPECT_EQ(sent, std::string_view(received)); + + auto wait = [](std::shared_ptr& l) { + if (l) { + l->WaitLinkTaskFinish(); + } + }; + auto f_s = std::async(wait, std::ref(sender_)); + auto f_r = std::async(wait, std::ref(receiver_)); + f_s.get(); + f_r.get(); +} + +TEST_F(ChannelMemTest, WaitFinishSync) { + const std::string key = "key"; + const std::string sent = "test"; + sender_->SendAsync(key, ByteContainerView{sent}); + auto received = receiver_->Recv(key); + + EXPECT_EQ(sent, std::string_view(received)); + + auto f_s = std::async( + [](std::shared_ptr& channel) { + channel->WaitLinkTaskFinish(); + }, + std::ref(sender_)); + auto f_r = std::async( + [](std::shared_ptr& channel) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + channel->WaitLinkTaskFinish(); + }, + std::ref(receiver_)); + f_s.get(); + f_r.get(); +} + +} // namespace yacl::link::transport::test diff --git a/yacl/math/galois_field/BUILD.bazel b/yacl/math/galois_field/BUILD.bazel index 2d9a3393..e0c8e508 100644 --- a/yacl/math/galois_field/BUILD.bazel +++ b/yacl/math/galois_field/BUILD.bazel @@ -44,6 +44,7 @@ yacl_cc_library( "gf_spi.cc", ], hdrs = [ + "gf_configs.h", "gf_spi.h", ], deps = [ diff --git a/yacl/math/galois_field/mpint_field/configs.h b/yacl/math/galois_field/gf_configs.h similarity index 63% rename from yacl/math/galois_field/mpint_field/configs.h rename to yacl/math/galois_field/gf_configs.h index 796b6d19..6ed4a32e 100644 --- a/yacl/math/galois_field/mpint_field/configs.h +++ b/yacl/math/galois_field/gf_configs.h @@ -17,25 +17,37 @@ #include "yacl/math/mpint/mp_int.h" #include "yacl/utils/spi/argument/argument.h" +namespace yacl::math { + +//== Field names ==// + +inline const std::string kPrimeField = "GF_p"; +inline const std::string kExtensionField = "GF_p^k"; +inline const std::string kBinaryField = "GF_2^k"; + +//== Field options... ==// + +// configs for kPrimeField, kExtensionField +DECLARE_ARG(MPInt, Mod); // the value of p in GF_p + +// configs for kExtensionField, kBinaryField +DECLARE_ARG(uint64_t, degree); + +//== Supported lib list... ==// + +// Example: // How to use mpint field? // // > #include "yacl/math/galois_field/gf_spi.h" -// > #include "yacl/math/galois_field/mpint_field/configs.h" // > // > void foo() { // > auto gf = GaloisFieldFactory::Instance().Create("Zn", ArgMod = 13_mp); // > auto sum = gf->Add(10_mp, 5_mp); // output 2 // > } // -// Note 1: Do not include 'mpint_field.h', include 'configs.h' instead. +// Note 1: Do not include any field in mpint_field dir. // Note 2: Get mpint field instance by `GaloisFieldFactory::Instance().Create()` -namespace yacl::math::mpf { - -inline const std::string kFieldName = "Zp"; -inline const std::string kLibName = "mpint"; - -// Prd-defined options... -DECLARE_ARG(MPInt, Mod); +inline const std::string kMPIntLib = "mpint"; -} // namespace yacl::math::mpf +} // namespace yacl::math diff --git a/yacl/math/galois_field/gf_scalar.h b/yacl/math/galois_field/gf_scalar.h index f966cb98..e829e065 100644 --- a/yacl/math/galois_field/gf_scalar.h +++ b/yacl/math/galois_field/gf_scalar.h @@ -284,12 +284,12 @@ class GFScalarSketch : public GaloisField { auto xsp = x->AsSpan(); yacl::parallel_for(0, xsp.length(), [&](int64_t beg, int64_t end) { for (int64_t i = beg; i < end; ++i) { - Pow(&xsp[i], y); + PowInplace(&xsp[i], y); } }); return; } else { - Pow(x->As(), y); + PowInplace(x->As(), y); return; } } diff --git a/yacl/math/galois_field/gf_spi.cc b/yacl/math/galois_field/gf_spi.cc index 1b2ae6fc..75c2d77c 100644 --- a/yacl/math/galois_field/gf_spi.cc +++ b/yacl/math/galois_field/gf_spi.cc @@ -14,8 +14,12 @@ #include "yacl/math/galois_field/gf_spi.h" +#include "yacl/math/galois_field/gf_configs.h" + namespace yacl::math { +DEFINE_ARG(MPInt, Mod); + GaloisFieldFactory& GaloisFieldFactory::Instance() { static GaloisFieldFactory factory; return factory; diff --git a/yacl/math/galois_field/mpint_field/BUILD.bazel b/yacl/math/galois_field/mpint_field/BUILD.bazel index 5798dc84..8ab366b7 100644 --- a/yacl/math/galois_field/mpint_field/BUILD.bazel +++ b/yacl/math/galois_field/mpint_field/BUILD.bazel @@ -16,21 +16,11 @@ load("//bazel:yacl.bzl", "yacl_cc_binary", "yacl_cc_library", "yacl_cc_test") package(default_visibility = ["//visibility:public"]) -yacl_cc_library( - name = "configs", - hdrs = ["configs.h"], - deps = [ - "//yacl/math/mpint", - "//yacl/utils/spi/argument", - ], -) - yacl_cc_library( name = "mpint_field", srcs = ["mpint_field.cc"], hdrs = ["mpint_field.h"], deps = [ - ":configs", "//yacl/math/galois_field:sketch", ], alwayslink = 1, @@ -48,7 +38,6 @@ yacl_cc_binary( name = "bench", srcs = ["mpint_field_bench.cc"], deps = [ - ":configs", "//yacl/math/galois_field", "@com_github_google_benchmark//:benchmark", ], diff --git a/yacl/math/galois_field/mpint_field/mpint_field.cc b/yacl/math/galois_field/mpint_field/mpint_field.cc index 9e5f9b80..f86c4a8e 100644 --- a/yacl/math/galois_field/mpint_field/mpint_field.cc +++ b/yacl/math/galois_field/mpint_field/mpint_field.cc @@ -14,29 +14,27 @@ #include "yacl/math/galois_field/mpint_field/mpint_field.h" -#include "yacl/math/galois_field/mpint_field/configs.h" +#include "yacl/math/galois_field/gf_configs.h" namespace yacl::math::mpf { -DEFINE_ARG(MPInt, Mod); - -REGISTER_GF_LIBRARY(kLibName, 100, MPIntField::Check, MPIntField::Create); +REGISTER_GF_LIBRARY(kMPIntLib, 100, MPIntField::Check, MPIntField::Create); std::unique_ptr MPIntField::Create(const std::string &field_name, const SpiArgs &args) { - YACL_ENFORCE(field_name == kFieldName); + YACL_ENFORCE(field_name == kPrimeField); auto mod = args.GetRequired(ArgMod); YACL_ENFORCE(mod.IsPrime(), "ArgMod must be a prime"); return std::unique_ptr(new MPIntField(std::move(mod))); } bool MPIntField::Check(const std::string &field_name, const SpiArgs &) { - return field_name == kFieldName; + return field_name == kPrimeField; } -std::string MPIntField::GetLibraryName() const { return kLibName; } +std::string MPIntField::GetLibraryName() const { return kMPIntLib; } -std::string MPIntField::GetFieldName() const { return kFieldName; } +std::string MPIntField::GetFieldName() const { return kPrimeField; } MPInt MPIntField::GetOrder() const { return mod_; } diff --git a/yacl/math/galois_field/mpint_field/mpint_field_bench.cc b/yacl/math/galois_field/mpint_field/mpint_field_bench.cc index 6b7818f3..55b6b729 100644 --- a/yacl/math/galois_field/mpint_field/mpint_field_bench.cc +++ b/yacl/math/galois_field/mpint_field/mpint_field_bench.cc @@ -14,8 +14,8 @@ #include "benchmark/benchmark.h" +#include "yacl/math/galois_field/gf_configs.h" #include "yacl/math/galois_field/gf_spi.h" -#include "yacl/math/galois_field/mpint_field/configs.h" #include "yacl/math/mpint/mp_int.h" using yacl::math::MPInt; @@ -39,7 +39,8 @@ static void BM_MpfAdd(benchmark::State& state) { MPInt::RandomExactBits(state.range(0) - 1, &mod); auto spi = yacl::math::GaloisFieldFactory::Instance().Create( - "Zp", yacl::ArgLib = "mpint", yacl::math::mpf::ArgMod = mod); + yacl::math::kPrimeField, yacl::ArgLib = yacl::math::kMPIntLib, + yacl::math::ArgMod = mod); for (auto _ : state) { benchmark::DoNotOptimize(spi->Add(m1, m2)); diff --git a/yacl/math/galois_field/mpint_field/mpint_field_test.cc b/yacl/math/galois_field/mpint_field/mpint_field_test.cc index bd0f8544..f088ad5d 100644 --- a/yacl/math/galois_field/mpint_field/mpint_field_test.cc +++ b/yacl/math/galois_field/mpint_field/mpint_field_test.cc @@ -14,19 +14,19 @@ #include "gtest/gtest.h" +#include "yacl/math/galois_field/gf_configs.h" #include "yacl/math/galois_field/gf_spi.h" -#include "yacl/math/galois_field/mpint_field/configs.h" namespace yacl::math::mpf::test { class MPIntFieldTest : public testing::Test {}; TEST_F(MPIntFieldTest, AddWorks) { - auto gf = GaloisFieldFactory::Instance().Create(kFieldName, ArgLib = kLibName, - ArgMod = 13_mp); + auto gf = GaloisFieldFactory::Instance().Create( + kPrimeField, ArgLib = kMPIntLib, ArgMod = 13_mp); - EXPECT_EQ(gf->GetLibraryName(), kLibName); - EXPECT_EQ(gf->GetFieldName(), kFieldName); + EXPECT_EQ(gf->GetLibraryName(), kMPIntLib); + EXPECT_EQ(gf->GetFieldName(), kPrimeField); EXPECT_EQ(gf->GetOrder(), 13_mp); EXPECT_TRUE(gf->GetExtensionDegree().IsOne()); @@ -37,8 +37,8 @@ TEST_F(MPIntFieldTest, AddWorks) { } TEST_F(MPIntFieldTest, ScalarWorks) { - auto gf = GaloisFieldFactory::Instance().Create(kFieldName, ArgLib = kLibName, - ArgMod = 13_mp); + auto gf = GaloisFieldFactory::Instance().Create( + kPrimeField, ArgLib = kMPIntLib, ArgMod = 13_mp); EXPECT_TRUE((bool)gf->IsIdentityZero(0_mp)); EXPECT_FALSE((bool)gf->IsIdentityZero(1_mp)); @@ -125,8 +125,8 @@ TEST_F(MPIntFieldTest, ScalarWorks) { } TEST_F(MPIntFieldTest, VectorWorks) { - auto gf = GaloisFieldFactory::Instance().Create(kFieldName, ArgLib = kLibName, - ArgMod = 13_mp); + auto gf = GaloisFieldFactory::Instance().Create( + kPrimeField, ArgLib = kMPIntLib, ArgMod = 13_mp); // test item format std::vector a = {1_mp, 2_mp, 3_mp}; @@ -208,15 +208,15 @@ TEST_F(MPIntFieldTest, VectorWorks) { TEST_F(MPIntFieldTest, VectorIoWorks) { MPInt mod; MPInt::RandPrimeOver(1024, &mod, PrimeType::Normal); - auto gf = GaloisFieldFactory::Instance().Create(kFieldName, ArgLib = kLibName, - ArgMod = mod); + auto gf = GaloisFieldFactory::Instance().Create( + kPrimeField, ArgLib = kMPIntLib, ArgMod = mod); // subspan auto item1 = Item::Take({0_mp, 1_mp, 2_mp, 3_mp}); auto item2 = item1.SubSpan(0, 1); ASSERT_TRUE(item2.IsView()); ASSERT_FALSE(item2.IsReadOnly()); - ASSERT_TRUE(item2.IsHoldType>()); + ASSERT_TRUE(item2.WrappedTypeIs>()); ASSERT_TRUE(gf->Equal(item2, Item::Take({0_mp}))); // deepcopy @@ -249,4 +249,67 @@ TEST_F(MPIntFieldTest, VectorIoWorks) { EXPECT_EQ(gf->Deserialize(buf), vt); } +TEST_F(MPIntFieldTest, ScalarInplaceWorks) { + auto gf = GaloisFieldFactory::Instance().Create( + kPrimeField, ArgLib = kMPIntLib, ArgMod = 13_mp); + + // operands // + Item a = 0_mp; + gf->NegInplace(&a); + ASSERT_EQ(a, 0_mp); + + gf->AddInplace(&a, 1_mp); // a = 1 + ASSERT_EQ(a, 1_mp); + + gf->NegInplace(&a); + ASSERT_EQ(a, 12_mp); + + gf->SubInplace(&a, 5_mp); + ASSERT_EQ(a, 7_mp); + + gf->InvInplace(&a); + ASSERT_EQ(a, 2_mp); + + gf->InvInplace(&a); + ASSERT_EQ(a, 7_mp); + + gf->MulInplace(&a, 4_mp); + ASSERT_EQ(a, 2_mp); + + gf->DivInplace(&a, 2_mp); + ASSERT_EQ(a, 1_mp); + + gf->PowInplace(&a, 123456_mp); + ASSERT_EQ(a, 1_mp); +} + +TEST_F(MPIntFieldTest, VectorInplaceWorks) { + auto gf = GaloisFieldFactory::Instance().Create( + kPrimeField, ArgLib = kMPIntLib, ArgMod = 13_mp); + + std::vector va = {1_mp, 2_mp, 3_mp}; + Item a = Item::Ref(va); + + gf->AddInplace(&a, Item::Take({11_mp, 12_mp, 13_mp})); + ASSERT_EQ(a.AsSpan(), std::vector({12_mp, 1_mp, 3_mp})); + + gf->NegInplace(&a); + ASSERT_EQ(a.AsSpan(), std::vector({1_mp, 12_mp, 10_mp})); + + gf->SubInplace(&a, Item::Take({0_mp, 5_mp, 1_mp})); + ASSERT_EQ(a.AsSpan(), std::vector({1_mp, 7_mp, 9_mp})); + + gf->InvInplace(&a); + ASSERT_EQ(a.AsSpan(), std::vector({1_mp, 2_mp, 3_mp})); + + gf->MulInplace(&a, Item::Take({7_mp, 7_mp, 7_mp})); + ASSERT_EQ(a.AsSpan(), std::vector({7_mp, 1_mp, 8_mp})); + + gf->DivInplace(&a, Item::Take({1_mp, 2_mp, 4_mp})); + ASSERT_EQ(a.AsSpan(), std::vector({7_mp, 7_mp, 2_mp})); + + gf->PowInplace(&a, 2_mp); + ASSERT_EQ(a.AsSpan(), std::vector({10_mp, 10_mp, 4_mp})); +} + } // namespace yacl::math::mpf::test diff --git a/yacl/math/mpint/mp_int.cc b/yacl/math/mpint/mp_int.cc index 6adf7903..31d149d2 100644 --- a/yacl/math/mpint/mp_int.cc +++ b/yacl/math/mpint/mp_int.cc @@ -503,13 +503,22 @@ void MPInt::MulMod(const MPInt &a, const MPInt &b, const MPInt &mod, MPInt *d) { } void MPInt::Pow(const MPInt &a, uint32_t b, MPInt *c) { + if (b == 0) { + *c = MPInt::_1_; + return; + } + mpx_reserve(&c->n_, MP_BITS_TO_DIGITS(mpx_count_bits_fast(a.n_) * b)); MPINT_ENFORCE_OK(mp_expt_n(&a.n_, b, &c->n_)); } MPInt MPInt::Pow(uint32_t b) const { + if (b == 0) { + return MPInt::_1_; + } + MPInt res; - mpx_reserve(&res.n_, mpx_count_bits_fast(n_) * b); + mpx_reserve(&res.n_, MP_BITS_TO_DIGITS(mpx_count_bits_fast(n_) * b)); MPINT_ENFORCE_OK(mp_expt_n(&n_, b, &res.n_)); return res; } diff --git a/yacl/math/mpint/mp_int_test.cc b/yacl/math/mpint/mp_int_test.cc index eb540bfd..1eb20b93 100644 --- a/yacl/math/mpint/mp_int_test.cc +++ b/yacl/math/mpint/mp_int_test.cc @@ -124,6 +124,8 @@ TEST_F(MPIntTest, PowWorks) { MPInt out; MPInt::Pow(MPInt::_2_, 1111, &out); EXPECT_EQ(out, 1_mp << 1111); + MPInt::Pow(MPInt::_2_, 0, &out); + EXPECT_EQ(out, 1_mp); out.Set(123); out.PowInplace(3); diff --git a/yacl/math/mpint/tommath_ext_types.cc b/yacl/math/mpint/tommath_ext_types.cc index 0d4a33cd..def7bb16 100644 --- a/yacl/math/mpint/tommath_ext_types.cc +++ b/yacl/math/mpint/tommath_ext_types.cc @@ -42,7 +42,7 @@ void mpx_reserve(mp_int *a, size_t n_digits) { return; } - MPINT_ENFORCE_OK(mp_grow(a, 1)); + MPINT_ENFORCE_OK(mp_grow(a, n_digits)); } #define MPX_INIT_INT(name, set, type) \ diff --git a/yacl/utils/BUILD.bazel b/yacl/utils/BUILD.bazel index ebe4e1a9..3dd05fa3 100644 --- a/yacl/utils/BUILD.bazel +++ b/yacl/utils/BUILD.bazel @@ -114,8 +114,8 @@ yacl_cc_test( ) yacl_cc_library( - name = "hash", - hdrs = ["hash.h"], + name = "hash_combine", + hdrs = ["hash_combine.h"], ) yacl_cc_library( diff --git a/yacl/utils/cuckoo_index_test.cc b/yacl/utils/cuckoo_index_test.cc index bcb1e5ae..da633ecc 100644 --- a/yacl/utils/cuckoo_index_test.cc +++ b/yacl/utils/cuckoo_index_test.cc @@ -18,7 +18,6 @@ #include "gtest/gtest.h" -#include "yacl/crypto/base/symmetric_crypto.h" #include "yacl/crypto/utils/rand.h" namespace yacl { diff --git a/yacl/utils/hash.h b/yacl/utils/hash_combine.h similarity index 100% rename from yacl/utils/hash.h rename to yacl/utils/hash_combine.h diff --git a/yacl/utils/spi/item.cc b/yacl/utils/spi/item.cc index 50811e0f..b888c8bd 100644 --- a/yacl/utils/spi/item.cc +++ b/yacl/utils/spi/item.cc @@ -85,12 +85,12 @@ bool Item::IsAll(const bool &element) const { std::string Item::ToString() const { if (IsArray()) { - return fmt::format("{} Item, element_type={}, RO={}, Content={}", + return fmt::format("{} Item, element_type={}, {}, Content={}", IsView() ? "Span" : "Vector", v_.type().name(), - IsReadOnly(), TryRead(v_)); + IsReadOnly() ? "RO" : "RW", TryRead(v_)); } else { - return fmt::format("Scalar item, type={}, RO={}, Content={}", - v_.type().name(), IsReadOnly(), TryRead(v_)); + return fmt::format("Scalar item, type={}, {}, Content={}", v_.type().name(), + IsReadOnly() ? "RO" : "RW", TryRead(v_)); } } diff --git a/yacl/utils/spi/item.h b/yacl/utils/spi/item.h index f3c30b14..5f63dff7 100644 --- a/yacl/utils/spi/item.h +++ b/yacl/utils/spi/item.h @@ -113,7 +113,7 @@ class Item { try { return std::any_cast(v_); } catch (const std::bad_any_cast& e) { - YACL_THROW( + YACL_THROW_WITH_STACK( "{}, Item as lvalue: cannot cast from {} to {}, please use 'c++filt " "-t ' tool to see a human-readable name.", ToString(), v_.type().name(), typeid(T&).name()); @@ -125,7 +125,7 @@ class Item { try { return std::any_cast(std::move(v_)); } catch (const std::bad_any_cast& e) { - YACL_THROW( + YACL_THROW_WITH_STACK( "{}, Item as rvalue: cannot cast from {} to {}, please use 'c++filt " "-t ' tool to see a human-readable name", ToString(), v_.type().name(), typeid(T&&).name()); @@ -137,7 +137,7 @@ class Item { try { return std::any_cast(v_); } catch (const std::bad_any_cast& e) { - YACL_THROW( + YACL_THROW_WITH_STACK( "{}, Item as a const ref: cannot cast from {} to {}, please use " "'c++filt -t ' tool to see a human-readable name. ", ToString(), v_.type().name(), typeid(const T&).name()); @@ -149,7 +149,7 @@ class Item { try { return std::any_cast>(&v_); } catch (const std::bad_any_cast& e) { - YACL_THROW( + YACL_THROW_WITH_STACK( "{}, Item as a pointer: cannot cast from {} to {}, please use " "'c++filt -t ' tool to see a human-readable name", ToString(), v_.type().name(), @@ -221,11 +221,24 @@ class Item { bool HasValue() const noexcept { return v_.has_value(); } + // Check the type that directly stored, which is, container type + data type template - bool IsHoldType() const noexcept { + bool WrappedTypeIs() const noexcept { return v_.type() == typeid(T); } + // Check the underlying date type regardless of the wrapping container type + template + bool DataTypeIs() const noexcept { + if (IsArray()) { + return WrappedTypeIs>() || + WrappedTypeIs>() || + WrappedTypeIs>(); + } else { + return WrappedTypeIs(); + } + } + bool IsArray() const { return (meta_ & 1) != 0; } bool IsView() const { return (meta_ & 2) != 0; } bool IsReadOnly() const { return (meta_ & (1 << 2)) != 0; } @@ -235,7 +248,7 @@ class Item { static_assert(!std::is_same_v, "Cannot compare to another Item, since the Type info is " "discarded at runtime"); - return HasValue() && IsHoldType() && As() == other; + return HasValue() && WrappedTypeIs() && As() == other; } template diff --git a/yacl/utils/spi/spi_factory.h b/yacl/utils/spi/spi_factory.h index ff148c57..57d8c93f 100644 --- a/yacl/utils/spi/spi_factory.h +++ b/yacl/utils/spi/spi_factory.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "absl/strings/ascii.h" #include "spdlog/spdlog.h" diff --git a/yacl/utils/spi/spi_factory_test.cc b/yacl/utils/spi/spi_factory_test.cc index 0d020ebc..553708bb 100644 --- a/yacl/utils/spi/spi_factory_test.cc +++ b/yacl/utils/spi/spi_factory_test.cc @@ -26,7 +26,7 @@ namespace yacl::test { class MockPheSpi { public: virtual std::string ToString() = 0; - virtual ~MockPheSpi(){}; + virtual ~MockPheSpi() = default; }; DEFINE_ARG_int(KeySize);