From 076a3b0212bc3facd47bdc0818ca266268c9faf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Tue, 29 Sep 2026 23:50:33 +0200 Subject: [PATCH] build(deps): bump go-micro to v4.11.4-0.20260929213538-cd412c159a26 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Point the go-micro.dev/v4 replace at the latest main-v4 maintenance branch commit in butonic/go-micro (cd412c15) instead of the v4.11.3 tag. The new base is upstream v4.11.1 plus the registry cache node-TTL fixes (upstream #2715, #2736, #2740), the concurrent map access fix (upstream #2794), plus further dependency updates and test fixes on the maintenance branch. The branch also modernizes go-micro's own go.mod (go 1.26, lego, dario.cat/mergo v1, x/deque v2, ...), and MVS pulls the aligned versions into this module: lego v4.35.2 -> lego/v5 v5.5.2, go-jose/go-jose/v4 -> v4.1.5, gofrs/flock -> v0.13.1, mattn/go-isatty -> v0.0.24, go.uber.org/zap -> v1.28.0, x/net -> 0.59.0, miekg/dns -> 1.1.73, moby api/client, ProtonMail/go-crypto -> 1.5.2, klauspost/compress -> 1.20.1, gorilla/handlers -> 1.5.2, gobwas/ws -> 1.4.0, nxadm/tail -> 1.4.11, ... Signed-off-by: Jörn Friedrich Dreyer --- go.mod | 75 +- go.sum | 462 +- .../Azure/go-ansiterm/csi_entry_state.go | 6 +- .../Azure/go-ansiterm/csi_param_state.go | 5 +- .../go-ansiterm/escape_intermediate_state.go | 2 +- .../Azure/go-ansiterm/escape_state.go | 2 +- vendor/github.com/Azure/go-ansiterm/parser.go | 13 +- .../go-ansiterm/parser_action_helpers.go | 14 +- .../Azure/go-ansiterm/parser_actions.go | 16 +- vendor/github.com/Azure/go-ansiterm/states.go | 2 - .../github.com/Azure/go-ansiterm/utilities.go | 10 - .../Azure/go-ansiterm/winterm/ansi.go | 99 +- .../go-crypto/openpgp/aes/keywrap/keywrap.go | 2 +- .../go-crypto/openpgp/armor/armor.go | 2 + .../ProtonMail/go-crypto/openpgp/ecdh/ecdh.go | 12 +- .../go-crypto/openpgp/elgamal/elgamal.go | 3 + .../go-crypto/openpgp/errors/errors.go | 10 + .../openpgp/internal/algorithm/aead.go | 13 +- .../openpgp/internal/ecc/curve25519.go | 10 +- .../go-crypto/openpgp/internal/ecc/curves.go | 2 + .../go-crypto/openpgp/internal/ecc/generic.go | 14 +- .../go-crypto/openpgp/key_generation.go | 86 +- .../ProtonMail/go-crypto/openpgp/keys.go | 17 +- .../openpgp/mldsa_eddsa/mldsa_eddsa.go | 119 + .../openpgp/mlkem_ecdh/mlkem_ecdh.go | 258 + .../go-crypto/openpgp/packet/aead_config.go | 6 +- .../openpgp/packet/aead_encrypted.go | 13 +- .../go-crypto/openpgp/packet/compressed.go | 31 + .../go-crypto/openpgp/packet/config.go | 40 + .../go-crypto/openpgp/packet/encrypted_key.go | 101 +- .../go-crypto/openpgp/packet/packet.go | 33 +- .../go-crypto/openpgp/packet/private_key.go | 181 +- .../go-crypto/openpgp/packet/public_key.go | 326 +- .../go-crypto/openpgp/packet/signature.go | 132 +- .../openpgp/packet/symmetric_key_encrypted.go | 13 +- .../packet/symmetrically_encrypted_aead.go | 22 +- .../ProtonMail/go-crypto/openpgp/read.go | 11 +- .../go-crypto/openpgp/read_write_test_data.go | 17 + .../go-crypto/openpgp/slhdsa/slhdsa.go | 66 + .../ProtonMail/go-crypto/openpgp/write.go | 138 +- .../go-crypto/openpgp/x25519/x25519.go | 28 +- .../ProtonMail/go-crypto/openpgp/x448/x448.go | 28 +- .../bitly/go-simplejson/.travis.yml | 10 - .../github.com/bitly/go-simplejson/README.md | 7 +- .../bitly/go-simplejson/simplejson.go | 58 +- .../bitly/go-simplejson/simplejson_go10.go | 75 - ...implejson_go11.go => simplejson_reader.go} | 2 - .../cloudflare/circl/ecc/goldilocks/curve.go | 6 + .../cloudflare/circl/ecc/goldilocks/point.go | 12 +- vendor/github.com/cloudflare/circl/kem/kem.go | 121 + .../circl/kem/mlkem/mlkem1024/kyber.go | 407 + .../circl/kem/mlkem/mlkem768/kyber.go | 407 + .../cloudflare/circl/math/mlsbset/mlsbset.go | 47 +- .../circl/pke/kyber/internal/common/amd64.go | 302 + .../circl/pke/kyber/internal/common/amd64.s | 2354 +++++ .../circl/pke/kyber/internal/common/arm64.go | 83 + .../circl/pke/kyber/internal/common/arm64.s | 53 + .../circl/pke/kyber/internal/common/field.go | 74 + .../pke/kyber/internal/common/generic.go | 77 + .../circl/pke/kyber/internal/common/ntt.go | 193 + .../circl/pke/kyber/internal/common/params.go | 22 + .../kyber/internal/common/params/params.go | 21 + .../circl/pke/kyber/internal/common/poly.go | 332 + .../circl/pke/kyber/internal/common/sample.go | 236 + .../pke/kyber/internal/common/stubs_amd64.go | 32 + .../pke/kyber/kyber1024/internal/cpapke.go | 192 + .../circl/pke/kyber/kyber1024/internal/mat.go | 85 + .../pke/kyber/kyber1024/internal/params.go | 21 + .../circl/pke/kyber/kyber1024/internal/vec.go | 125 + .../circl/pke/kyber/kyber1024/kyber.go | 175 + .../pke/kyber/kyber768/internal/cpapke.go | 192 + .../circl/pke/kyber/kyber768/internal/mat.go | 85 + .../pke/kyber/kyber768/internal/params.go | 21 + .../circl/pke/kyber/kyber768/internal/vec.go | 125 + .../circl/pke/kyber/kyber768/kyber.go | 175 + .../cloudflare/circl/sign/ed25519/ed25519.go | 9 +- .../cloudflare/circl/sign/ed25519/signapi.go | 6 +- .../cloudflare/circl/sign/ed448/ed448.go | 6 + .../cloudflare/circl/sign/ed448/signapi.go | 6 +- .../circl/sign/internal/dilithium/amd64.go | 162 + .../circl/sign/internal/dilithium/amd64.s | 8407 +++++++++++++++++ .../circl/sign/internal/dilithium/arm64.go | 106 + .../circl/sign/internal/dilithium/arm64.s | 126 + .../circl/sign/internal/dilithium/field.go | 52 + .../circl/sign/internal/dilithium/generic.go | 89 + .../circl/sign/internal/dilithium/ntt.go | 217 + .../circl/sign/internal/dilithium/pack.go | 160 + .../circl/sign/internal/dilithium/params.go | 18 + .../sign/internal/dilithium/params/params.go | 25 + .../circl/sign/internal/dilithium/poly.go | 101 + .../sign/internal/dilithium/stubs_amd64.go | 35 + .../circl/sign/mldsa/mldsa65/dilithium.go | 366 + .../sign/mldsa/mldsa65/internal/dilithium.go | 509 + .../circl/sign/mldsa/mldsa65/internal/mat.go | 59 + .../circl/sign/mldsa/mldsa65/internal/pack.go | 270 + .../sign/mldsa/mldsa65/internal/params.go | 18 + .../sign/mldsa/mldsa65/internal/rounding.go | 142 + .../sign/mldsa/mldsa65/internal/sample.go | 339 + .../circl/sign/mldsa/mldsa65/internal/vec.go | 281 + .../circl/sign/mldsa/mldsa87/dilithium.go | 366 + .../sign/mldsa/mldsa87/internal/dilithium.go | 509 + .../circl/sign/mldsa/mldsa87/internal/mat.go | 59 + .../circl/sign/mldsa/mldsa87/internal/pack.go | 270 + .../sign/mldsa/mldsa87/internal/params.go | 18 + .../sign/mldsa/mldsa87/internal/rounding.go | 142 + .../sign/mldsa/mldsa87/internal/sample.go | 339 + .../circl/sign/mldsa/mldsa87/internal/vec.go | 281 + .../cloudflare/circl/sign/slhdsa/address.go | 92 + .../cloudflare/circl/sign/slhdsa/fors.go | 173 + .../cloudflare/circl/sign/slhdsa/hypertree.go | 68 + .../cloudflare/circl/sign/slhdsa/internal.go | 135 + .../cloudflare/circl/sign/slhdsa/keys.go | 137 + .../cloudflare/circl/sign/slhdsa/message.go | 119 + .../cloudflare/circl/sign/slhdsa/params.go | 182 + .../cloudflare/circl/sign/slhdsa/scheme.go | 114 + .../cloudflare/circl/sign/slhdsa/slhdsa.go | 131 + .../cloudflare/circl/sign/slhdsa/state.go | 357 + .../cloudflare/circl/sign/slhdsa/wotsp.go | 142 + .../cloudflare/circl/sign/slhdsa/xmss.go | 111 + .../circl/simd/keccakf1600/f1600x.go | 163 + .../circl/simd/keccakf1600/f1600x2_arm64.go | 13 + .../circl/simd/keccakf1600/f1600x2_arm64.s | 136 + .../circl/simd/keccakf1600/f1600x4_amd64.go | 10 + .../circl/simd/keccakf1600/f1600x4_amd64.s | 899 ++ .../simd/keccakf1600/f1600x4stubs_amd64.go | 8 + .../circl/simd/keccakf1600/fallback.go | 8 + .../cloudflare/circl/xof/k12/k12.go | 400 + vendor/github.com/cloudflare/circl/xof/xof.go | 85 + .../github.com/containerd/log/.gitattributes | 1 + .../github.com/containerd/log/.golangci.yml | 50 +- vendor/github.com/containerd/log/context.go | 70 +- vendor/github.com/containerd/log/slog.go | 66 + .../github.com/coreos/go-oidc/v3/oidc/jwks.go | 14 + .../cyphar/filepath-securejoin/CHANGELOG.md | 11 + .../cyphar/filepath-securejoin/VERSION | 2 +- .../json-patch/v5/internal/json/decode.go | 1385 +++ .../json-patch/v5/internal/json/encode.go | 1486 +++ .../json-patch/v5/internal/json/fold.go | 141 + .../json-patch/v5/internal/json/fuzz.go | 42 + .../json-patch/v5/internal/json/indent.go | 143 + .../json-patch/v5/internal/json/scanner.go | 610 ++ .../json-patch/v5/internal/json/stream.go | 495 + .../json-patch/v5/internal/json/tables.go | 218 + .../json-patch/v5/internal/json/tags.go | 38 + .../github.com/evanphx/json-patch/v5/merge.go | 132 +- .../github.com/evanphx/json-patch/v5/patch.go | 586 +- .../github.com/go-acme/lego/v4/acme/errors.go | 58 - .../go-acme/lego/{v4 => v5}/LICENSE | 1 + .../go-acme/lego/{v4 => v5}/acme/commons.go | 165 +- .../github.com/go-acme/lego/v5/acme/errors.go | 196 + .../lego/{v4 => v5}/challenge/challenges.go | 14 +- .../go-acme/lego/v5/challenge/network.go | 20 + .../lego/{v4 => v5}/challenge/provider.go | 16 +- .../go-jose/go-jose/v4/asymmetric.go | 26 +- .../go-jose/go-jose/v4/cipher/cbc_hmac.go | 6 +- .../github.com/go-jose/go-jose/v4/crypter.go | 90 +- .../go-jose/go-jose/v4/json/scanner.go | 19 +- vendor/github.com/go-jose/go-jose/v4/jwe.go | 8 + vendor/github.com/go-jose/go-jose/v4/jwk.go | 213 +- vendor/github.com/go-jose/go-jose/v4/jws.go | 15 +- .../github.com/go-jose/go-jose/v4/opaque.go | 5 + .../github.com/go-jose/go-jose/v4/shared.go | 6 + .../github.com/go-jose/go-jose/v4/signing.go | 111 +- .../go-jose/go-jose/v4/symmetric.go | 10 +- vendor/github.com/go-sql-driver/mysql/AUTHORS | 1 + .../go-sql-driver/mysql/CHANGELOG.md | 10 + .../github.com/go-sql-driver/mysql/README.md | 5 +- .../go-sql-driver/mysql/connection.go | 4 +- vendor/github.com/go-sql-driver/mysql/dsn.go | 18 +- vendor/github.com/gobwas/ws/Makefile | 2 +- vendor/github.com/gobwas/ws/cipher.go | 18 +- vendor/github.com/gobwas/ws/dialer.go | 9 +- vendor/github.com/gobwas/ws/hijack_go119.go | 18 + vendor/github.com/gobwas/ws/hijack_go120.go | 19 + vendor/github.com/gobwas/ws/http.go | 6 +- vendor/github.com/gobwas/ws/server.go | 7 +- vendor/github.com/gobwas/ws/wsutil/reader.go | 96 +- vendor/github.com/gofrs/flock/.golangci.yml | 4 +- vendor/github.com/gofrs/flock/flock.go | 4 +- vendor/github.com/gofrs/flock/flock_others.go | 2 +- vendor/github.com/gofrs/flock/flock_unix.go | 2 +- .../gofrs/flock/flock_unix_fcntl.go | 2 +- .../github.com/gofrs/flock/flock_windows.go | 2 +- vendor/github.com/gofrs/flock/zizmor.yml | 3 + .../google/go-querystring/query/encode.go | 73 +- .../github.com/gorilla/handlers/.editorconfig | 20 + vendor/github.com/gorilla/handlers/.gitignore | 2 + vendor/github.com/gorilla/handlers/LICENSE | 39 +- vendor/github.com/gorilla/handlers/Makefile | 34 + vendor/github.com/gorilla/handlers/README.md | 10 +- .../github.com/gorilla/handlers/canonical.go | 9 +- .../github.com/gorilla/handlers/compress.go | 8 +- vendor/github.com/gorilla/handlers/cors.go | 41 +- .../github.com/gorilla/handlers/handlers.go | 15 +- vendor/github.com/gorilla/handlers/logging.go | 32 +- .../gorilla/handlers/proxy_headers.go | 16 +- .../github.com/gorilla/handlers/recovery.go | 22 +- vendor/github.com/imdario/mergo/README.md | 20 +- .../json-iterator/go/reflect_map.go | 21 +- .../json-iterator/go/stream_float.go | 16 + .../kevinburke/ssh_config/.gitattributes | 1 - .../kevinburke/ssh_config/.gitignore | 1 + .../kevinburke/ssh_config/AUTHORS.txt | 4 + .../kevinburke/ssh_config/CHANGELOG.md | 48 +- .../github.com/kevinburke/ssh_config/Makefile | 17 +- .../kevinburke/ssh_config/README.md | 10 +- .../kevinburke/ssh_config/SECURITY.md | 63 + .../kevinburke/ssh_config/config.go | 127 +- .../kevinburke/ssh_config/parser.go | 86 +- .../klauspost/compress/flate/deflate.go | 35 +- .../compress/flate/huffman_bit_writer.go | 222 +- .../klauspost/compress/flate/huffman_code.go | 138 +- .../compress/flate/huffman_sortByFreq.go | 159 - .../compress/flate/huffman_sortByLiteral.go | 201 - .../klauspost/compress/flate/inflate_gen.go | 30 +- .../compress/flate/matchlen_generic.go | 13 +- .../klauspost/compress/flate/token.go | 18 +- .../klauspost/compress/huff0/bitreader.go | 63 + .../compress/huff0/decompress_amd64.go | 95 +- .../compress/huff0/decompress_amd64.s | 4102 ++++++-- .../compress/huff0/decompress_arm64.go | 43 +- .../compress/huff0/decompress_arm64.s | 2399 +++-- .../compress/huff0/decompress_asm.go | 98 +- .../github.com/klauspost/compress/s2/index.go | 4 +- .../klauspost/compress/s2/writer.go | 2 +- .../klauspost/compress/zstd/blockdec.go | 3 + .../klauspost/compress/zstd/decoder.go | 125 +- .../klauspost/compress/zstd/framedec.go | 11 +- .../compress/zstd/fse_decoder_arm64.s | 10 +- .../klauspost/compress/zstd/seqdec.go | 23 + .../klauspost/compress/zstd/seqdec_amd64.s | 1669 ++-- .../klauspost/compress/zstd/seqdec_arm64.s | 1125 +-- .../klauspost/compress/zstd/seqdec_asm.go | 7 +- .../klauspost/cpuid/v2/.goreleaser.yml | 2 +- .../github.com/klauspost/cpuid/v2/README.md | 70 +- vendor/github.com/klauspost/cpuid/v2/cpuid.go | 213 +- .../klauspost/cpuid/v2/detect_arm64.go | 9 +- .../klauspost/cpuid/v2/detect_ref.go | 3 +- .../klauspost/cpuid/v2/detect_ref_arm64.go | 19 + .../klauspost/cpuid/v2/detect_riscv64.go | 16 + .../klauspost/cpuid/v2/detect_x86.go | 1 - .../klauspost/cpuid/v2/featureid_string.go | 514 +- .../klauspost/cpuid/v2/os_darwin_arm64.go | 13 + .../klauspost/cpuid/v2/os_linux_arm64.go | 88 +- .../klauspost/cpuid/v2/os_linux_riscv64.go | 225 + .../klauspost/cpuid/v2/os_other_arm64.go | 1 - .../klauspost/cpuid/v2/os_other_riscv64.go | 14 + .../klauspost/cpuid/v2/os_safe_linux_arm64.go | 1 - .../cpuid/v2/os_unsafe_linux_arm64.go | 1 - .../klauspost/cpuid/v2/riscv_isa.go | 93 + .../mattn/go-isatty/isatty_others.go | 4 +- ...{isatty_tcgets.go => isatty_tiocgwinsz.go} | 6 +- vendor/github.com/miekg/dns/README.md | 310 +- vendor/github.com/miekg/dns/client.go | 10 +- vendor/github.com/miekg/dns/dnssec.go | 52 +- vendor/github.com/miekg/dns/edns.go | 131 +- vendor/github.com/miekg/dns/msg.go | 4 +- vendor/github.com/miekg/dns/scan.go | 10 +- vendor/github.com/miekg/dns/server.go | 4 +- vendor/github.com/miekg/dns/tools.go | 10 - vendor/github.com/miekg/dns/version.go | 2 +- vendor/github.com/miekg/dns/zmsg.go | 2 +- .../github.com/moby/go-archive/.golangci.yml | 12 + vendor/github.com/moby/go-archive/archive.go | 561 +- .../moby/go-archive/archive_linux.go | 137 +- .../moby/go-archive/archive_other.go | 8 + .../moby/go-archive/archive_unix.go | 100 +- .../moby/go-archive/archive_windows.go | 15 +- vendor/github.com/moby/go-archive/changes.go | 18 +- .../moby/go-archive/changes_linux.go | 2 +- .../moby/go-archive/changes_other.go | 2 +- .../github.com/moby/go-archive/chmod_linux.go | 46 + .../moby/go-archive/chmod_unix_nolinux.go | 27 + .../go-archive/compression/compression.go | 4 +- vendor/github.com/moby/go-archive/copy.go | 64 +- .../github.com/moby/go-archive/dev_darwin.go | 21 + .../github.com/moby/go-archive/dev_freebsd.go | 17 +- vendor/github.com/moby/go-archive/dev_unix.go | 21 +- vendor/github.com/moby/go-archive/diff.go | 141 +- .../internal/archiveoptions/options.go | 12 + vendor/github.com/moby/go-archive/rootpath.go | 142 + .../moby/go-archive/sequential_other.go | 6 + .../go-archive/sequential_windows_go126.go | 9 + .../go-archive/sequential_windows_pre126.go | 6 + .../moby/go-archive/tarheader/tarheader.go | 2 +- .../go-archive/tarheader/tarheader_unix.go | 9 +- vendor/github.com/moby/go-archive/time.go | 4 + .../moby/go-archive/time_nonwindows.go | 61 +- .../moby/go-archive/time_windows.go | 111 +- .../moby/go-archive/xattr_supported.go | 20 +- .../moby/api/types/container/hostconfig.go | 1 + .../moby/api/types/image/image_inspect.go | 6 +- .../moby/api/types/plugin/plugin_responses.go | 17 +- vendor/github.com/moby/moby/client/README.md | 1 - .../moby/moby/client/checkpoint_create.go | 6 +- vendor/github.com/moby/moby/client/client.go | 2 +- .../moby/moby/client/config_create.go | 2 +- .../moby/moby/client/config_update.go | 2 +- .../moby/moby/client/container_commit.go | 21 +- .../moby/moby/client/container_copy.go | 2 +- .../moby/moby/client/container_create.go | 67 +- .../moby/moby/client/container_exec.go | 11 +- .../moby/moby/client/container_restart.go | 3 +- .../moby/moby/client/container_stop.go | 3 +- .../moby/moby/client/container_update.go | 13 +- vendor/github.com/moby/moby/client/hijack.go | 2 +- .../moby/moby/client/image_build.go | 2 +- .../moby/moby/client/image_import.go | 2 +- .../github.com/moby/moby/client/image_load.go | 5 +- .../github.com/moby/moby/client/image_pull.go | 2 +- .../github.com/moby/moby/client/image_push.go | 2 +- .../moby/moby/client/internal/mod/mod.go | 14 +- vendor/github.com/moby/moby/client/login.go | 2 +- .../moby/moby/client/network_connect.go | 2 +- .../moby/moby/client/network_create.go | 2 +- .../moby/moby/client/network_disconnect.go | 5 +- .../moby/moby/client/node_update.go | 2 +- .../client/pkg/jsonmessage/jsonmessage.go | 42 +- .../moby/moby/client/plugin_create.go | 2 +- .../moby/moby/client/plugin_install.go | 11 +- .../moby/moby/client/plugin_push.go | 5 +- .../github.com/moby/moby/client/plugin_set.go | 2 +- .../moby/moby/client/plugin_upgrade.go | 7 +- vendor/github.com/moby/moby/client/request.go | 28 +- .../moby/moby/client/secret_create.go | 2 +- .../moby/moby/client/secret_update.go | 2 +- .../moby/moby/client/service_create.go | 26 +- .../moby/moby/client/service_inspect.go | 5 +- .../moby/moby/client/service_update.go | 2 +- .../github.com/moby/moby/client/swarm_init.go | 6 +- .../github.com/moby/moby/client/swarm_join.go | 6 +- .../moby/moby/client/swarm_unlock.go | 5 +- .../moby/moby/client/swarm_update.go | 2 +- vendor/github.com/moby/moby/client/utils.go | 8 + .../moby/moby/client/volume_create.go | 5 +- .../moby/moby/client/volume_update.go | 2 +- .../github.com/moby/sys/user/lookup_unix.go | 1 - vendor/github.com/moby/sys/user/user.go | 229 +- .../github.com/moby/sys/user/user_fuzzer.go | 1 - vendor/github.com/moby/sys/user/user_utils.go | 64 + .../moby/sys/userns/userns_linux.go | 48 + vendor/github.com/nxadm/tail/.cirrus.yml | 8 + vendor/github.com/nxadm/tail/.gitignore | 3 +- vendor/github.com/nxadm/tail/CHANGES.md | 10 +- vendor/github.com/nxadm/tail/CONTRIBUTING.md | 5 + vendor/github.com/nxadm/tail/README.md | 13 +- vendor/github.com/nxadm/tail/tail.go | 36 +- .../http/services/appprovider/appprovider.go | 6 + .../v2/pkg/appauth/manager/jsoncs3/jsoncs3.go | 80 +- .../reva/v2/pkg/metadatacache/store.go | 28 +- .../storage/pkg/decomposedfs/decomposedfs.go | 568 +- .../pkg/storage/pkg/decomposedfs/metadata.go | 25 +- .../storage/pkg/decomposedfs/node/locks.go | 20 + .../utils/decomposedfs/decomposedfs.go | 504 +- .../sirupsen/logrus/hooks/slog/handler.go | 201 + .../sirupsen/logrus/hooks/slog/level.go | 119 + .../sirupsen/logrus/hooks/slog/slog.go | 126 + vendor/github.com/skeema/knownhosts/NOTICE | 2 +- vendor/github.com/skeema/knownhosts/README.md | 3 +- .../skeema/knownhosts/knownhosts.go | 33 +- vendor/github.com/xrash/smetrics/jaro.go | 2 +- vendor/go-micro.dev/v4/api/handler/rpc/rpc.go | 2 +- .../v4/api/server/acme/options.go | 2 +- vendor/go-micro.dev/v4/client/rpc_client.go | 22 +- vendor/go-micro.dev/v4/client/rpc_codec.go | 12 +- vendor/go-micro.dev/v4/config/default.go | 10 +- .../v4/config/reader/json/json.go | 2 +- vendor/go-micro.dev/v4/events/memory.go | 2 + .../go-micro.dev/v4/registry/cache/cache.go | 12 +- vendor/go-micro.dev/v4/runtime/service.go | 2 +- vendor/go-micro.dev/v4/store/memory.go | 34 +- .../go-micro.dev/v4/transport/http_client.go | 4 +- vendor/go-micro.dev/v4/util/mdns/client.go | 9 +- vendor/go-micro.dev/v4/util/mdns/server.go | 4 +- vendor/go.uber.org/zap/CHANGELOG.md | 4 + vendor/go.uber.org/zap/zapcore/entry.go | 32 +- vendor/golang.org/x/crypto/blake2s/blake2s.go | 254 + .../x/crypto/blake2s/blake2s_386.go | 32 + .../golang.org/x/crypto/blake2s/blake2s_386.s | 429 + .../x/crypto/blake2s/blake2s_amd64.go | 37 + .../x/crypto/blake2s/blake2s_amd64.s | 2173 +++++ .../x/crypto/blake2s/blake2s_generic.go | 178 + .../x/crypto/blake2s/blake2s_ref.go | 17 + vendor/golang.org/x/crypto/blake2s/blake2x.go | 178 + vendor/golang.org/x/net/html/escape.go | 5 +- vendor/golang.org/x/net/http2/ascii.go | 14 +- vendor/golang.org/x/net/http2/databuffer.go | 5 +- vendor/golang.org/x/net/http2/h2c/h2c.go | 5 + .../golang.org/x/net/http2/server_common.go | 47 + vendor/golang.org/x/net/http2/transport.go | 2 + .../x/net/http2/transport_common.go | 79 +- .../golang.org/x/net/http2/transport_wrap.go | 2 + .../x/net/internal/httpcommon/README.md | 7 + .../x/net/internal/httpcommon/request.go | 34 +- vendor/golang.org/x/net/trace/histogram.go | 5 +- vendor/modules.txt | 148 +- 396 files changed, 46182 insertions(+), 7104 deletions(-) create mode 100644 vendor/github.com/ProtonMail/go-crypto/openpgp/mldsa_eddsa/mldsa_eddsa.go create mode 100644 vendor/github.com/ProtonMail/go-crypto/openpgp/mlkem_ecdh/mlkem_ecdh.go create mode 100644 vendor/github.com/ProtonMail/go-crypto/openpgp/slhdsa/slhdsa.go delete mode 100644 vendor/github.com/bitly/go-simplejson/.travis.yml delete mode 100644 vendor/github.com/bitly/go-simplejson/simplejson_go10.go rename vendor/github.com/bitly/go-simplejson/{simplejson_go11.go => simplejson_reader.go} (99%) create mode 100644 vendor/github.com/cloudflare/circl/kem/kem.go create mode 100644 vendor/github.com/cloudflare/circl/kem/mlkem/mlkem1024/kyber.go create mode 100644 vendor/github.com/cloudflare/circl/kem/mlkem/mlkem768/kyber.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/internal/common/amd64.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/internal/common/amd64.s create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/internal/common/arm64.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/internal/common/arm64.s create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/internal/common/field.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/internal/common/generic.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/internal/common/ntt.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/internal/common/params.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/internal/common/params/params.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/internal/common/poly.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/internal/common/sample.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/internal/common/stubs_amd64.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/cpapke.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/mat.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/params.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/vec.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/kyber.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/cpapke.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/mat.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/params.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/vec.go create mode 100644 vendor/github.com/cloudflare/circl/pke/kyber/kyber768/kyber.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/amd64.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/amd64.s create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/arm64.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/arm64.s create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/field.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/generic.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/ntt.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/pack.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/params.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/params/params.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/poly.go create mode 100644 vendor/github.com/cloudflare/circl/sign/internal/dilithium/stubs_amd64.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/mat.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/pack.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/params.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/rounding.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/sample.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/vec.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/dilithium.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/mat.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/pack.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/params.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/rounding.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/sample.go create mode 100644 vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/vec.go create mode 100644 vendor/github.com/cloudflare/circl/sign/slhdsa/address.go create mode 100644 vendor/github.com/cloudflare/circl/sign/slhdsa/fors.go create mode 100644 vendor/github.com/cloudflare/circl/sign/slhdsa/hypertree.go create mode 100644 vendor/github.com/cloudflare/circl/sign/slhdsa/internal.go create mode 100644 vendor/github.com/cloudflare/circl/sign/slhdsa/keys.go create mode 100644 vendor/github.com/cloudflare/circl/sign/slhdsa/message.go create mode 100644 vendor/github.com/cloudflare/circl/sign/slhdsa/params.go create mode 100644 vendor/github.com/cloudflare/circl/sign/slhdsa/scheme.go create mode 100644 vendor/github.com/cloudflare/circl/sign/slhdsa/slhdsa.go create mode 100644 vendor/github.com/cloudflare/circl/sign/slhdsa/state.go create mode 100644 vendor/github.com/cloudflare/circl/sign/slhdsa/wotsp.go create mode 100644 vendor/github.com/cloudflare/circl/sign/slhdsa/xmss.go create mode 100644 vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x.go create mode 100644 vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.go create mode 100644 vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.s create mode 100644 vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.go create mode 100644 vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.s create mode 100644 vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4stubs_amd64.go create mode 100644 vendor/github.com/cloudflare/circl/simd/keccakf1600/fallback.go create mode 100644 vendor/github.com/cloudflare/circl/xof/k12/k12.go create mode 100644 vendor/github.com/cloudflare/circl/xof/xof.go create mode 100644 vendor/github.com/containerd/log/.gitattributes create mode 100644 vendor/github.com/containerd/log/slog.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/decode.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/encode.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/fold.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/fuzz.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/indent.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/scanner.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/stream.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/tables.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/tags.go delete mode 100644 vendor/github.com/go-acme/lego/v4/acme/errors.go rename vendor/github.com/go-acme/lego/{v4 => v5}/LICENSE (96%) rename vendor/github.com/go-acme/lego/{v4 => v5}/acme/commons.go (66%) create mode 100644 vendor/github.com/go-acme/lego/v5/acme/errors.go rename vendor/github.com/go-acme/lego/{v4 => v5}/challenge/challenges.go (57%) create mode 100644 vendor/github.com/go-acme/lego/v5/challenge/network.go rename vendor/github.com/go-acme/lego/{v4 => v5}/challenge/provider.go (66%) create mode 100644 vendor/github.com/gobwas/ws/hijack_go119.go create mode 100644 vendor/github.com/gobwas/ws/hijack_go120.go create mode 100644 vendor/github.com/gofrs/flock/zizmor.yml create mode 100644 vendor/github.com/gorilla/handlers/.editorconfig create mode 100644 vendor/github.com/gorilla/handlers/.gitignore create mode 100644 vendor/github.com/gorilla/handlers/Makefile delete mode 100644 vendor/github.com/kevinburke/ssh_config/.gitattributes create mode 100644 vendor/github.com/kevinburke/ssh_config/SECURITY.md delete mode 100644 vendor/github.com/klauspost/compress/flate/huffman_sortByFreq.go delete mode 100644 vendor/github.com/klauspost/compress/flate/huffman_sortByLiteral.go create mode 100644 vendor/github.com/klauspost/cpuid/v2/detect_ref_arm64.go create mode 100644 vendor/github.com/klauspost/cpuid/v2/detect_riscv64.go create mode 100644 vendor/github.com/klauspost/cpuid/v2/os_linux_riscv64.go create mode 100644 vendor/github.com/klauspost/cpuid/v2/os_other_riscv64.go create mode 100644 vendor/github.com/klauspost/cpuid/v2/riscv_isa.go rename vendor/github.com/mattn/go-isatty/{isatty_tcgets.go => isatty_tiocgwinsz.go} (62%) delete mode 100644 vendor/github.com/miekg/dns/tools.go create mode 100644 vendor/github.com/moby/go-archive/chmod_linux.go create mode 100644 vendor/github.com/moby/go-archive/chmod_unix_nolinux.go create mode 100644 vendor/github.com/moby/go-archive/dev_darwin.go create mode 100644 vendor/github.com/moby/go-archive/internal/archiveoptions/options.go create mode 100644 vendor/github.com/moby/go-archive/rootpath.go create mode 100644 vendor/github.com/moby/go-archive/sequential_other.go create mode 100644 vendor/github.com/moby/go-archive/sequential_windows_go126.go create mode 100644 vendor/github.com/moby/go-archive/sequential_windows_pre126.go create mode 100644 vendor/github.com/moby/sys/user/user_utils.go create mode 100644 vendor/github.com/nxadm/tail/.cirrus.yml create mode 100644 vendor/github.com/nxadm/tail/CONTRIBUTING.md create mode 100644 vendor/github.com/sirupsen/logrus/hooks/slog/handler.go create mode 100644 vendor/github.com/sirupsen/logrus/hooks/slog/level.go create mode 100644 vendor/github.com/sirupsen/logrus/hooks/slog/slog.go create mode 100644 vendor/golang.org/x/crypto/blake2s/blake2s.go create mode 100644 vendor/golang.org/x/crypto/blake2s/blake2s_386.go create mode 100644 vendor/golang.org/x/crypto/blake2s/blake2s_386.s create mode 100644 vendor/golang.org/x/crypto/blake2s/blake2s_amd64.go create mode 100644 vendor/golang.org/x/crypto/blake2s/blake2s_amd64.s create mode 100644 vendor/golang.org/x/crypto/blake2s/blake2s_generic.go create mode 100644 vendor/golang.org/x/crypto/blake2s/blake2s_ref.go create mode 100644 vendor/golang.org/x/crypto/blake2s/blake2x.go create mode 100644 vendor/golang.org/x/net/internal/httpcommon/README.md diff --git a/go.mod b/go.mod index 2311f11c14..562478e8e5 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/beevik/etree v1.8.0 github.com/blevesearch/bleve/v2 v2.6.1 github.com/cenkalti/backoff v2.2.1+incompatible - github.com/coreos/go-oidc/v3 v3.20.0 + github.com/coreos/go-oidc/v3 v3.21.0 github.com/cs3org/go-cs3apis v0.0.0-20260424072047-8d9ef7076ae9 github.com/davidbyttow/govips/v2 v2.18.0 github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8 @@ -64,7 +64,7 @@ require ( github.com/open-policy-agent/opa v1.19.1 github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260902170011-45af3945a067 - github.com/opencloud-eu/reva/v2 v2.50.1-0.20260924091259-7fa82c610dba + github.com/opencloud-eu/reva/v2 v2.50.1-0.20261001091108-11d87fb6b985 github.com/opensearch-project/opensearch-go/v4 v4.7.3 github.com/orcaman/concurrent-map v1.0.0 github.com/pkg/errors v0.9.1 @@ -106,12 +106,12 @@ require ( golang.org/x/crypto v0.57.0 golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f golang.org/x/image v0.46.0 - golang.org/x/net v0.58.0 + golang.org/x/net v0.59.0 golang.org/x/oauth2 v0.37.0 golang.org/x/sync v0.23.0 golang.org/x/term v0.46.0 golang.org/x/text v0.42.0 - google.golang.org/genproto/googleapis/api v0.0.0-20260819154853-08b0e4226688 + google.golang.org/genproto/googleapis/api v0.0.0-20260928230214-8a89bd6388cc google.golang.org/grpc v1.84.0 google.golang.org/protobuf v1.36.12 gopkg.in/yaml.v2 v2.4.0 @@ -123,14 +123,14 @@ require ( require ( contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect filippo.io/edwards25519 v1.2.0 // indirect - github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect + github.com/Azure/go-ansiterm v0.0.0-20260917205352-e937bb47801a // indirect github.com/Azure/go-ntlmssp v0.1.1 // indirect github.com/BurntSushi/toml v1.6.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.5.0 // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/ProtonMail/go-crypto v1.1.6 // indirect + github.com/ProtonMail/go-crypto v1.5.2 // indirect github.com/RoaringBitmap/roaring/v2 v2.14.5 // indirect github.com/agnivade/levenshtein v1.2.1 // indirect github.com/ajg/form v1.5.1 // indirect @@ -140,7 +140,7 @@ require ( github.com/armon/go-radix v1.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bitly/go-simplejson v0.5.0 // indirect + github.com/bitly/go-simplejson v0.5.1 // indirect github.com/bits-and-blooms/bitset v1.24.2 // indirect github.com/blevesearch/bleve_index_api v1.4.1 // indirect github.com/blevesearch/geo v0.2.6 // indirect @@ -168,10 +168,10 @@ require ( github.com/cevaris/ordered_map v0.0.0-20190319150403-3adeae072e73 // indirect github.com/clipperhouse/displaywidth v0.11.0 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect - github.com/cloudflare/circl v1.6.3 // indirect + github.com/cloudflare/circl v1.6.5 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect - github.com/containerd/log v0.1.0 // indirect + github.com/containerd/log v0.2.0 // indirect github.com/containerd/platforms v1.0.0-rc.2 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.7.0 // indirect @@ -180,7 +180,7 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/crewjam/httperr v0.2.0 // indirect github.com/crewjam/saml v0.4.14 // indirect - github.com/cyphar/filepath-securejoin v0.6.1 // indirect + github.com/cyphar/filepath-securejoin v0.7.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/deckarep/golang-set v1.8.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 // indirect @@ -195,18 +195,18 @@ require ( github.com/egirna/icap v0.0.0-20181108071049-d5ee18bd70bc // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/emvi/iso-639-1 v1.1.1 // indirect - github.com/evanphx/json-patch/v5 v5.5.0 // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fatih/color v1.19.0 // indirect github.com/felixge/httpsnoop v1.1.0 // indirect github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/gdexlab/go-render v1.0.1 // indirect - github.com/go-acme/lego/v4 v4.4.0 // indirect + github.com/go-acme/lego/v5 v5.5.2 // indirect github.com/go-asn1-ber/asn1-ber v1.5.8 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.9.0 // indirect + github.com/go-git/go-billy/v5 v5.9.1 // indirect github.com/go-git/go-git/v5 v5.19.2 // indirect github.com/go-jose/go-jose/v3 v3.0.5 // indirect - github.com/go-jose/go-jose/v4 v4.1.4 // indirect + github.com/go-jose/go-jose/v4 v4.1.5 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/go-logr/logr v1.4.4 // indirect @@ -218,26 +218,26 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.2 // indirect github.com/go-redis/redis/v8 v8.11.5 // indirect - github.com/go-sql-driver/mysql v1.10.0 // indirect + github.com/go-sql-driver/mysql v1.10.1 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/go-test/deep v1.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect - github.com/gobwas/ws v1.2.1 // indirect + github.com/gobwas/ws v1.4.0 // indirect github.com/goccy/go-json v0.10.6 // indirect github.com/goccy/go-yaml v1.19.2 // indirect - github.com/gofrs/flock v0.13.0 // indirect + github.com/gofrs/flock v0.13.1 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/snappy v1.0.0 // indirect - github.com/google/go-querystring v1.1.0 // indirect + github.com/google/go-querystring v1.2.0 // indirect github.com/google/go-tpm v0.9.8 // indirect github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 // indirect github.com/google/renameio/v2 v2.0.2 // indirect github.com/gookit/goutil v0.8.0 // indirect - github.com/gorilla/handlers v1.5.1 // indirect + github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/schema v1.4.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect @@ -246,15 +246,15 @@ require ( github.com/hashicorp/yamux v0.1.2 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect - github.com/imdario/mergo v0.3.15 // indirect + github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jonboulle/clockwork v0.5.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect + github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect github.com/juliangruber/go-intersect v1.1.0 // indirect - github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/compress v1.20.0 // indirect - github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/kevinburke/ssh_config v1.6.0 // indirect + github.com/klauspost/compress v1.20.1 // indirect + github.com/klauspost/cpuid/v2 v2.4.0 // indirect github.com/klauspost/crc32 v1.3.0 // indirect github.com/kovidgoyal/go-parallel v1.1.1 // indirect github.com/kovidgoyal/go-shm v1.0.0 // indirect @@ -273,11 +273,11 @@ require ( github.com/magiconair/properties v1.8.10 // indirect github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect github.com/mattn/go-colorable v0.1.15 // indirect - github.com/mattn/go-isatty v0.0.22 // indirect + github.com/mattn/go-isatty v0.0.24 // indirect github.com/mattn/go-runewidth v0.0.24 // indirect github.com/mattn/go-sqlite3 v1.14.49 // indirect github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 // indirect - github.com/miekg/dns v1.1.68 // indirect + github.com/miekg/dns v1.1.73 // indirect github.com/mileusna/useragent v1.3.5 // indirect github.com/minio/crc64nvme v1.1.1 // indirect github.com/minio/highwayhash v1.0.4 // indirect @@ -286,13 +286,13 @@ require ( github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect - github.com/moby/go-archive v0.2.0 // indirect - github.com/moby/moby/api v1.55.0 // indirect - github.com/moby/moby/client v0.5.0 // indirect + github.com/moby/go-archive v0.3.3 // indirect + github.com/moby/moby/api v1.56.0 // indirect + github.com/moby/moby/client v0.6.0 // indirect github.com/moby/patternmatcher v0.6.1 // indirect github.com/moby/sys/sequential v0.7.0 // indirect - github.com/moby/sys/user v0.4.0 // indirect - github.com/moby/sys/userns v0.1.0 // indirect + github.com/moby/sys/user v0.4.1 // indirect + github.com/moby/sys/userns v0.2.1 // indirect github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect @@ -301,7 +301,7 @@ require ( github.com/nats-io/jwt/v2 v2.8.2 // indirect github.com/nats-io/nkeys v0.4.16 // indirect github.com/nats-io/nuid v1.0.1 // indirect - github.com/nxadm/tail v1.4.8 // indirect + github.com/nxadm/tail v1.4.11 // indirect github.com/oklog/run v1.2.0 // indirect github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect github.com/olekukonko/ll v0.1.6 // indirect @@ -339,7 +339,7 @@ require ( github.com/sethvargo/go-diceware v0.6.0 // indirect github.com/sethvargo/go-password v0.4.0 // indirect github.com/shirou/gopsutil/v4 v4.26.6 // indirect - github.com/skeema/knownhosts v1.3.1 // indirect + github.com/skeema/knownhosts v1.3.3 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 // indirect github.com/spf13/cast v1.10.0 // indirect @@ -362,7 +362,7 @@ require ( github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect + github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect github.com/yashtewari/glob-intersection v0.2.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zeebo/xxh3 v1.1.0 // indirect @@ -375,7 +375,7 @@ require ( go.opentelemetry.io/otel/metric v1.46.0 // indirect go.opentelemetry.io/proto/otlp v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.1 // indirect + go.uber.org/zap v1.28.0 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.5 // indirect golang.org/x/mod v0.41.0 // indirect @@ -383,7 +383,7 @@ require ( golang.org/x/time v0.16.0 // indirect golang.org/x/tools v0.49.0 // indirect google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260928230214-8a89bd6388cc // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect gopkg.in/ini.v1 v1.67.3 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect @@ -395,7 +395,8 @@ replace github.com/studio-b12/gowebdav => github.com/kobergj/gowebdav v0.0.0-202 replace github.com/unrolled/secure => github.com/opencloud-eu/secure v0.0.0-20260312082735-b6f5cb2244e4 -replace go-micro.dev/v4 => github.com/butonic/go-micro/v4 v4.11.1-0.20241115112658-b5d4de5ed9b3 +// TODO we could bump go-micro.dev/v4 to v6 and drop this fork as our v4 changes got merged upstream +replace go-micro.dev/v4 => github.com/butonic/go-micro/v4 v4.11.4-0.20260929213538-cd412c159a26 // exclude the v2 line of go-sqlite3 which was released accidentally and prevents pulling in newer versions of go-sqlite3 // see https://github.com/mattn/go-sqlite3/issues/965 for more details diff --git a/go.sum b/go.sum index 78a0e15e6d..3dabebd265 100644 --- a/go.sum +++ b/go.sum @@ -23,7 +23,6 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -33,7 +32,6 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg= contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= @@ -45,23 +43,8 @@ github.com/Acconut/go-httptest-recorder v1.0.0 h1:TAv2dfnqp/l+SUvIaMAUK4GeN4+wqb github.com/Acconut/go-httptest-recorder v1.0.0/go.mod h1:CwQyhTH1kq/gLyWiRieo7c0uokpu3PXeyF/nZjUNtmM= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= -github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= -github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/azure/auth v0.1.0/go.mod h1:Gf7/i2FUpyb/sGBLIFxTBzrNzBo7aPXXE3ZVeDRwdpM= -github.com/Azure/go-autorest/autorest/azure/cli v0.1.0/go.mod h1:Dk8CUAt/b/PzkfeRsWzVG9Yj3ps8mS8ECztu43rdU8U= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= -github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-ansiterm v0.0.0-20260917205352-e937bb47801a h1:4hxax9ktNjSDoFn1tZSeL6gXMTRMpO0FzjdKfT01jgY= +github.com/Azure/go-ansiterm v0.0.0-20260917205352-e937bb47801a/go.mod h1:3EWSSOZ50kb+arhww0qIaEXHToib/3FjBj9Jj5lcP5g= github.com/Azure/go-ntlmssp v0.1.1 h1:l+FM/EEMb0U9QZE7mKNEDw5Mu3mFiaa2GKOoTSsNDPw= github.com/Azure/go-ntlmssp v0.1.1/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -87,19 +70,14 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Nerzal/gocloak/v13 v13.9.0 h1:YWsJsdM5b0yhM2Ba3MLydiOlujkBry4TtdzfIzSVZhw= github.com/Nerzal/gocloak/v13 v13.9.0/go.mod h1:YYuDcXZ7K2zKECyVP7pPqjKxx2AzYSpKDj8d6GuyM10= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks= -github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= -github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/ProtonMail/go-crypto v1.5.2 h1:cucYnvqcY7UOXVD//mSyjeaPY0SSN3v5cDkYPxumINk= +github.com/ProtonMail/go-crypto v1.5.2/go.mod h1:/RaSu30DaKO4RY+XdV/ACcCcZkGr7AhUIduq5sjzzCo= github.com/RoaringBitmap/roaring/v2 v2.14.5 h1:ckd0o545JqDPeVJDgeFoaM21eBixUnlWfYgjE5VnyWw= github.com/RoaringBitmap/roaring/v2 v2.14.5/go.mod h1:eq4wdNXxtJIS/oikeCzdX1rBzek7ANzbth041hrU8Q4= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM= github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.0/go.mod h1:kX6YddBkXqqywAe8c9LyvgTCyFuZCTMF4cRPQhc3Fy8= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -110,26 +88,20 @@ github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e h1:4dAU9FXIyQktp github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/alexedwards/argon2id v1.0.0 h1:wJzDx66hqWX7siL/SRUmgz3F8YMrd/nfX/xHHcQQP0w= github.com/alexedwards/argon2id v1.0.0/go.mod h1:tYKkqIjzXvZdzPvADMWOEZ+l6+BD6CtBXMj5fnJppiw= -github.com/aliyun/alibaba-cloud-sdk-go v1.61.976/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA= github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964 h1:I9YN9WMo3SUh7p/4wKeNvD/IQla3U3SUa61U7ul+xM4= github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964/go.mod h1:eFiR01PwTcpbzXtdMces7zxg6utvFM5puiWHpWB8D/k= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/antithesishq/antithesis-sdk-go v0.8.0-default-no-op h1:1BOWQJweNyvZMlpAHXGLiZQn9S+QXGcz3xh94lC0w6E= github.com/antithesishq/antithesis-sdk-go v0.8.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.37.27/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bbalet/stopwords v1.0.0 h1:0TnGycCtY0zZi4ltKoOGRFIlZHv0WqpoIGUsObjztfo= github.com/bbalet/stopwords v1.0.0/go.mod h1:sAWrQoDMfqARGIn4s6dp7OW7ISrshUD8IP2q3KoqPjc= github.com/beevik/etree v1.8.0 h1:TOfpQtMZ3ZuG9f2ZnLvsbOOVxrjTvE0qbYb5D0p44j0= @@ -140,12 +112,10 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= -github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bitly/go-simplejson v0.5.1 h1:xgwPbetQScXt1gh9BmoJ6j9JMr3TElvuIyjR8pgdoow= +github.com/bitly/go-simplejson v0.5.1/go.mod h1:YOPVLzCfwK14b4Sff3oP1AmGhI9T9Vsg84etUnlyp+Q= github.com/bits-and-blooms/bitset v1.24.2 h1:M7/NzVbsytmtfHbumG+K2bremQPMJuqv1JD3vOaFxp0= github.com/bits-and-blooms/bitset v1.24.2/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blevesearch/bleve/v2 v2.6.1 h1:47vLskRTqxvQEtxVPYHjf5KpOgzD2msslXFjvUQCgWQ= github.com/blevesearch/bleve/v2 v2.6.1/go.mod h1:Dvvx6ZoEBTOj6RSzfk0lEz0wce/qhe2yOUubXeuzd2c= github.com/blevesearch/bleve_index_api v1.4.1 h1:CYIyecFlI+/RYjzUm+NmDjYbSvk870Bb7f+Vl4b12q8= @@ -190,22 +160,17 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4Yn github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bombsimon/logrusr/v3 v3.1.0 h1:zORbLM943D+hDMGgyjMhSAz/iDz86ZV72qaak/CA0zQ= github.com/bombsimon/logrusr/v3 v3.1.0/go.mod h1:PksPPgSFEL2I52pla2glgCyyd2OqOHAnFF5E+g8Ixco= -github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= -github.com/butonic/go-micro/v4 v4.11.1-0.20241115112658-b5d4de5ed9b3 h1:h8Z0hBv5tg/uZMKu8V47+DKWYVQg0lYP8lXDQq7uRpE= -github.com/butonic/go-micro/v4 v4.11.1-0.20241115112658-b5d4de5ed9b3/go.mod h1:eE/tD53n3KbVrzrWxKLxdkGw45Fg1qaNLWjpJMvIUF4= -github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw= +github.com/butonic/go-micro/v4 v4.11.4-0.20260929213538-cd412c159a26 h1:DtJ8z75PCgVcghoDE0KoTVWc0xp1mN9xyvDebMPB688= +github.com/butonic/go-micro/v4 v4.11.4-0.20260929213538-cd412c159a26/go.mod h1:Pxkj/TW2+3WWT0h0JVdMi+DUjvLWAF+tR/vymiXea2Q= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= -github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -220,36 +185,27 @@ github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSE github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= -github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8= -github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= -github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= +github.com/cloudflare/circl v1.6.5 h1:O64F26HEqNhznd/hrC5KZXVKYuKM2rx4deZDTc4ihQA= +github.com/cloudflare/circl v1.6.5/go.mod h1:h5LNyxAc5nTue9DS5jT+48en2PSDYt3zdGnz5OstK6c= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= -github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= -github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/log v0.2.0 h1:BewD/umNgVnoczglOpX8eRMyEy5t5iPlu5AIpnWDONc= +github.com/containerd/log v0.2.0/go.mod h1:/M7L7CXKcPTfNC74XzaK+5H5KbO5+4lJVpuVI6vRLoM= github.com/containerd/platforms v1.0.0-rc.2 h1:0SPgaNZPVWGEi4grZdV8VRYQn78y+nm6acgLGv/QzE4= github.com/containerd/platforms v1.0.0-rc.2/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-oidc/v3 v3.20.0 h1:EtE0WIBHk03N+DqGkY4+UONzzZHk7amKt6IyNd7OsZE= -github.com/coreos/go-oidc/v3 v3.20.0/go.mod h1:DYCf24+ncYi+XkIH97GY1+dqoRlbaSI26KVTCI9SrY4= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-oidc/v3 v3.21.0 h1:wZo4Q9Pum8dYEj0eMUPrqR+kvuGkeUplbLpNCkBqoWM= +github.com/coreos/go-oidc/v3 v3.21.0/go.mod h1:DYCf24+ncYi+XkIH97GY1+dqoRlbaSI26KVTCI9SrY4= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA= github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cornelk/hashmap v1.0.8 h1:nv0AWgw02n+iDcawr5It4CjQIAcdMMKRrs10HOJYlrc= github.com/cornelk/hashmap v1.0.8/go.mod h1:RfZb7JO3RviW/rT6emczVuC/oxpdz4UsSB2LJSclR1k= -github.com/cpu/goacmedns v0.1.1/go.mod h1:MuaouqEhPAHxsbqjgnck5zeghuwBP1dLnPoobeGqugQ= github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -261,9 +217,8 @@ github.com/crewjam/saml v0.4.14 h1:g9FBNx62osKusnFzs3QTN5L9CVA/Egfgm+stJShzw/c= github.com/crewjam/saml v0.4.14/go.mod h1:UVSZCf18jJkk6GpWNVqcyQJMD5HsRugBPf4I1nl2mME= github.com/cs3org/go-cs3apis v0.0.0-20260424072047-8d9ef7076ae9 h1:8WtMb7TKKx1AJM3j+uR+H25y4v+b8o8GIQg/2ooCyRo= github.com/cs3org/go-cs3apis v0.0.0-20260424072047-8d9ef7076ae9/go.mod h1:DedpcqXl193qF/08Y04IO0PpxyyMu8+GrkD6kWK2MEQ= -github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= -github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE= -github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= +github.com/cyphar/filepath-securejoin v0.7.0 h1:s0Y3ITPy6sQn5xt54DuYvTF8hu134ooYLUb58DX/HjE= +github.com/cyphar/filepath-securejoin v0.7.0/go.mod h1:ymLGms/u3BYaviIiuKFnUx8EkQEZeK6cInNoAPJA3o4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -274,28 +229,22 @@ github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsP github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 h1:5RVFMOWjMyRy8cARdy79nAmgYw3hK/4HUq48LQ6Wwqo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= -github.com/deepmap/oapi-codegen v1.3.11/go.mod h1:suMvK7+rKlx3+tpa8ByptmvoXbAV70wERKTOGH3hLp0= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/dgraph-io/badger/v4 v4.9.4 h1:bcw+waCpzRZ2nmcSPbnPvDVhiEsn98TKmvnAhK7r7LM= github.com/dgraph-io/badger/v4 v4.9.4/go.mod h1:nJjaJTUOSsQEBhsq209FmwCvMJzEA3e74RjZw6V2pQI= github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7cNTs5R6Hk4V2lcmLz2NsG2VnInyNo= github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8 h1:OtSeLS5y0Uy01jaKK4mA/WVIYtpzVm63vLVAPzJXigg= github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8/go.mod h1:apkPC/CR3s48O2D7Y++n1XWEpgPNNCjXYga3PPbJe2E= -github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8= github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/dnsimple/dnsimple-go v0.63.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg= github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c= github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -304,9 +253,6 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e h1:rcHHSQqzCgvlwP0I/fQ8rQMn/MpHE5gWSLdtpxtP6KQ= github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e/go.mod h1:Byz7q8MSzSPkouskHJhX0er2mZY/m0Vj5bMeMCkkyY4= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/ebitengine/purego v0.10.1 h1:dewVBCBT2GaMu1SrNTYxQhgQBethzfhiwvZiLGP/qyY= github.com/ebitengine/purego v0.10.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/egirna/icap v0.0.0-20181108071049-d5ee18bd70bc h1:6IxmRbXV8WXVkcYcTzkU219A3UZeNMX/e6X2sve1wXA= @@ -321,15 +267,11 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch/v5 v5.5.0 h1:bAmFiUJ+o0o2B4OiTFeE3MqCOtyo+jjPP9iZ0VRxYUc= -github.com/evanphx/json-patch/v5 v5.5.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/exoscale/egoscale v0.46.0/go.mod h1:mpEXBpROAa/2i5GC0r33rfxG+TxSEka11g1PIXt9+zc= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc= github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -340,16 +282,15 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= github.com/gabriel-vasile/mimetype v1.4.15 h1:05iP/CYtZ/w455R/KZM6rZ5ieAdh99UPtd+d3YzLmaI= github.com/gabriel-vasile/mimetype v1.4.15/go.mod h1:azpTcoLcDZRNgFou5j+APrqQx9HqVPWa6ijYQIIVswQ= github.com/gdexlab/go-render v1.0.1 h1:rxqB3vo5s4n1kF0ySmoNeSPRYkEsyHgln4jFIQY7v0U= github.com/gdexlab/go-render v1.0.1/go.mod h1:wRi5nW2qfjiGj4mPukH4UV0IknS1cHD4VgFTmJX5JzM= -github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= github.com/ggwhite/go-masker v1.1.0 h1:kN/KIvktu2U+hd3KWrSlLj7xBGD1iBfc9/xdbVgFbRc= github.com/ggwhite/go-masker v1.1.0/go.mod h1:xnTRHwrIU9FtBADwEjUC5Dy/BVedvoTxyOE7/d3CNwY= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= @@ -358,23 +299,20 @@ github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01 github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= -github.com/go-acme/lego/v4 v4.4.0 h1:uHhU5LpOYQOdp3aDU+XY2bajseu8fuExphTL1Ss6/Fc= -github.com/go-acme/lego/v4 v4.4.0/go.mod h1:l3+tFUFZb590dWcqhWZegynUthtaHJbG2fevUpoOOE0= +github.com/go-acme/lego/v5 v5.5.2 h1:SJ5cMZDoyg5hB6tYpZoFcwgzkJVJI1yu5f0N8gAEeVs= +github.com/go-acme/lego/v5 v5.5.2/go.mod h1:d6S2VCJAVcPBSGAy+diFoCZbvfWo80tt0ZPSXDiq6PM= github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-asn1-ber/asn1-ber v1.4.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-asn1-ber/asn1-ber v1.5.8 h1:H9AZkK22UOmfX8J84ubyaZxKJZ3FMHVwn8swoMML7iQ= github.com/go-asn1-ber/asn1-ber v1.5.8/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi/v5 v5.3.2 h1:5YQkICvTCSZ25hoRsyJazN0scjzKGiu4VAUc7H1o1nY= github.com/go-chi/chi/v5 v5.3.2/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto= github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= -github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.9.0 h1:jItGXszUDRtR/AlferWPTMN4j38BQ88XnXKbilmmBPA= -github.com/go-git/go-billy/v5 v5.9.0/go.mod h1:jCnQMLj9eUgGU7+ludSTYoZL/GGmii14RxKFj7ROgHw= +github.com/go-git/go-billy/v5 v5.9.1 h1:8U73XiOTfINdItHVa6z4Gv7ToObcZ6grkqQbLryLCdA= +github.com/go-git/go-billy/v5 v5.9.1/go.mod h1:ExsU+jcGwXTBOnyilvAnEM1wug1IxHr4yP2ZXsNRtV0= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.19.2 h1:wkfn7vOlUBu8ivAWKBWisTiwJK4jYHzTF8Ndv1LyGqY= @@ -385,8 +323,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-jose/go-jose/v3 v3.0.5 h1:BLLJWbC4nMZOfuPVxoZIxeYsn6Nl2r1fITaJ78UQlVQ= github.com/go-jose/go-jose/v3 v3.0.5/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= -github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= -github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-jose/go-jose/v4 v4.1.5 h1:RjgjO2LOtWOJKUC5wpwY9LR3B3vwVAz6JS2YHfYU6eA= +github.com/go-jose/go-jose/v4 v4.1.5/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -443,11 +381,10 @@ github.com/go-playground/validator/v10 v10.30.3 h1:4MU6YkEwx7GbcPJOZxrtbu+QfF3pJ github.com/go-playground/validator/v10 v10.30.3/go.mod h1:4Axh7oCNGcoGkqLoE4YWt6n20mcEIsPRlB7vPk3lpyc= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= -github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8= github.com/go-resty/resty/v2 v2.17.2 h1:FQW5oHYcIlkCNrMD2lloGScxcHJ0gkjshV3qcQAyHQk= github.com/go-resty/resty/v2 v2.17.2/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA= -github.com/go-sql-driver/mysql v1.10.0 h1:Q+1LV8DkHJvSYAdR83XzuhDaTykuDx0l6fkXxoWCWfw= -github.com/go-sql-driver/mysql v1.10.0/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk= +github.com/go-sql-driver/mysql v1.10.1 h1:arlSnNLq6a5yxGxV7qg9lF4j0C+KwD6NbQyKr9QL6ME= +github.com/go-sql-driver/mysql v1.10.1/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= @@ -458,33 +395,27 @@ github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk= -github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= +github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs= +github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc= github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= -github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/flock v0.13.1 h1:jjREztyBeSKBZYAC+mgc1laB+xsgy4kYMf3FbKF2UBo= +github.com/gofrs/flock v0.13.1/go.mod h1:sf4BFiHwnvgxa25DlQoDqXQnwRMEOwqxRq37P6MzzmE= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -519,10 +450,8 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= @@ -534,18 +463,16 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0= +github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU= github.com/google/go-tika v0.3.1 h1:l+jr10hDhZjcgxFRfcQChRLo1bPXQeLFluMyvDhXTTA= github.com/google/go-tika v0.3.1/go.mod h1:DJh5N8qxXIl85QkqmXknd+PeeRkUOTbvwyYf7ieDz6c= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= @@ -565,7 +492,6 @@ github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmI github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio/v2 v2.0.2 h1:qKZs+tfn+arruZZhQ7TKC/ergJunuJicWS6gLDt/dGw= github.com/google/renameio/v2 v2.0.2/go.mod h1:OX+G6WHHpHq3NVj7cAOleLOwJfcQ1s3uUJQCrr78SWo= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -577,60 +503,26 @@ github.com/gookit/goutil v0.8.0 h1:efZWxfesXw8+5tQfTfRMSIC6A0ax527/H+A/aIiaSrw= github.com/gookit/goutil v0.8.0/go.mod h1:vJS9HXctYTCLtCsZot5L5xF+O1oR17cDYO9R0HxBmnU= github.com/gookit/ini/v2 v2.3.2 h1:W6tzOGE6zOLQelH2xhcH8BIBZPtnEpJgQ+J6SsAKBSw= github.com/gookit/ini/v2 v2.3.2/go.mod h1:StKSqY5niArRwYBS8Z71+iWUt5ow47qt359sS9YQLYY= -github.com/gophercloud/gophercloud v0.15.1-0.20210202035223-633d73521055/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4= -github.com/gophercloud/gophercloud v0.16.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4= -github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae/go.mod h1:wx8HMD8oQD0Ryhz6+6ykq75PJ79iPyEqYHfwZ4l7OsA= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= -github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= +github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E= github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 h1:/Tnpcb2E0Pz/tN9s3bfEY2Q8ePCEX9iuS+cneUwncnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0/go.mod h1:zOBXOsUaBSjKgmH4OGzV1esUpR3oUSCPYVd2cUBjKYY= -github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-plugin v1.8.0 h1:ie8S6RRY8RvB2usYZv+AAZ/wBvx2AU5p5QeP5j/FORs= github.com/hashicorp/go-plugin v1.8.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= -github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -639,16 +531,12 @@ github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4= -github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= -github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/infobloxopen/infoblox-go-client v1.1.1/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI= github.com/invopop/validation v0.8.0 h1:e5hXHGnONHImgJdonIpNbctg1hlWy1ncaHoVIQ0JWuw= github.com/invopop/validation v0.8.0/go.mod h1:nLLeXYPGwUNfdCdJo7/q3yaHO62LSx/3ri7JvgKR9vg= -github.com/jarcoal/httpmock v1.0.6/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= @@ -667,54 +555,43 @@ github.com/jellydator/ttlcache/v2 v2.11.1 h1:AZGME43Eh2Vv3giG6GeqeLeFXxwxn1/qHIt github.com/jellydator/ttlcache/v2 v2.11.1/go.mod h1:RtE5Snf0/57e+2cLWFYWCCsLas2Hy3c5Z4n14XmSvTI= github.com/jellydator/ttlcache/v3 v3.4.1 h1:bOdXmXiycyK6E6Qjyuj5vl+/vU3SCOoDs8a86NbHjAQ= github.com/jellydator/ttlcache/v3 v3.4.1/go.mod h1:j7LO12PNghFg5+0v9budMAT4rDK4JY969jb9vOdOBBk= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 h1:9Nu54bhS/H/Kgo2/7xNSUuC5G28VR8ljfrLKU2G4IjU= +github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12/go.mod h1:TBzl5BIHNXfS9+C35ZyJaklL7mLDbgUkcgXzSLa8Tk0= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juliangruber/go-intersect v1.1.0 h1:sc+y5dCjMMx0pAdYk/N6KBm00tD/f3tq+Iox7dYDUrY= github.com/juliangruber/go-intersect v1.1.0/go.mod h1:WMau+1kAmnlQnKiikekNJbtGtfmILU/mMU6H7AgKbWQ= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo= github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA= -github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= -github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= -github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kevinburke/ssh_config v1.6.0 h1:J1FBfmuVosPHf5GRdltRLhPJtJpTlMdKTBjRgTaQBFY= +github.com/kevinburke/ssh_config v1.6.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.20.0 h1:a3C1ke2ohxFymNlb2HWAHjDeKCI90scRskErZkR0ezA= -github.com/klauspost/compress v1.20.0/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI= +github.com/klauspost/compress v1.20.1 h1:T7kKElXUMXrUJ2E9QhQhxFtcK5rPyLdsGZvdbLMPdiQ= +github.com/klauspost/compress v1.20.1/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= -github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/cpuid/v2 v2.4.0 h1:S6Hrbc7+ywsr0r+RLapfGBHfyefhCTwEh3A0tV913Dw= +github.com/klauspost/cpuid/v2 v2.4.0/go.mod h1:19jmZ9mjzoF//ddRSUsv0zfBTJWh3QJh9FNxZTMrGxU= github.com/klauspost/crc32 v1.3.0 h1:sSmTt3gUt81RP655XGZPElI0PelVTZ6YwCRnPSupoFM= github.com/klauspost/crc32 v1.3.0/go.mod h1:D7kQaZhnkX/Y0tstFGf8VUzv2UofNGqCjnC3zdHB0Hw= github.com/kobergj/gowebdav v0.0.0-20250102091030-aa65266db202 h1:A1xJ2NKgiYFiaHiLl9B5yw/gUBACSs9crDykTS3GuQI= github.com/kobergj/gowebdav v0.0.0-20250102091030-aa65266db202/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= -github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kovidgoyal/go-parallel v1.1.1 h1:1OzpNjtrUkBPq3UaqrnvOoB2F9RttSt811uiUXyI7ok= github.com/kovidgoyal/go-parallel v1.1.1/go.mod h1:BJNIbe6+hxyFWv7n6oEDPj3PA5qSw5OCtf0hcVxWJiw= @@ -722,7 +599,6 @@ github.com/kovidgoyal/go-shm v1.0.0 h1:HJEel9D1F9YhULvClEHJLawoRSj/1u/EDV7MJbBPg github.com/kovidgoyal/go-shm v1.0.0/go.mod h1:Yzb80Xf9L3kaoB2RGok9hHwMIt7Oif61kT6t3+VnZds= github.com/kovidgoyal/imaging v1.8.23 h1:4WsboyQ/E8tic2kX49P93Rvscg33SPsCwTBG5EZZF54= github.com/kovidgoyal/imaging v1.8.23/go.mod h1:k3Iot3H0v2rSWXIxQISfT3e9wIryqzAHLHCuhG7z9lM= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -734,10 +610,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA= -github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w= -github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= -github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/leonelquinteros/gotext v1.7.3-0.20260422134830-b012b4ccae69 h1:ZLo0bXX17iUZpb/Sp7N+1uK4Jb7dl0fm5x5ETfzYSvY= @@ -762,61 +634,37 @@ github.com/libregraph/lico v0.67.0 h1:qsVjDVHyEGZxrKU9PEsdim7aKnEz5CVtG3VAbZ77hF github.com/libregraph/lico v0.67.0/go.mod h1:kvfaHXyIlualEubTKszOizY65oGasC1oHmFpfQt4ugQ= github.com/libregraph/oidc-go v1.1.0 h1:RyudjL3UyQblqeBQI06W53PniWobqODeeyAy6v/HumA= github.com/libregraph/oidc-go v1.1.0/go.mod h1:qW9ubcXvZrfbbWZBaLMuk7bt5qAUMYyt9/NtXQt07Cw= -github.com/linode/linodego v0.25.3/go.mod h1:GSBKPpjoQfxEfryoCRcgkuUOCuVtGHWhzI8OMdycNTE= -github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs= -github.com/liquidweb/go-lwApi v0.0.5/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs= -github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ= -github.com/liquidweb/liquidweb-go v1.6.3/go.mod h1:SuXXp+thr28LnjEw18AYtWwIbWMHSUiajPQs8T9c/Rc= github.com/longsleep/go-metrics v1.0.0 h1:o2A6Dbu4MhLpZuL444WFoZzM7X7igewrj2MouwTlmVM= github.com/longsleep/go-metrics v1.0.0/go.mod h1:w6QO1LBkVla70FZrrF6XcB0YN+jTEYugjkn3+6RYTSM= github.com/longsleep/rndm v1.2.0 h1:wPl+kIMyIUTUFW5+2b327DmM1Rlj+gmexsiyOTB7rzM= github.com/longsleep/rndm v1.2.0/go.mod h1:5qyvM6CXNteKgz6djqqwZOP4+KcPsewrfKyLWd1dCFY= github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e h1:Q6MvJtQK/iRcRtzAscm/zF23XxJlbECiGPyRicsX+Ak= github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= -github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU= github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= -github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= +github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU= github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mattn/go-sqlite3 v1.14.49 h1:B8jBHC3xhxZgxztrgruTuLucebnULQnx4W7cF7SAE9w= github.com/mattn/go-sqlite3 v1.14.49/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w= -github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= -github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 h1:Z/i1e+gTZrmcGeZyWckaLfucYG6KYOXLWo4co8pZYNY= github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103/go.mod h1:o9YPB5aGP8ob35Vy6+vyq3P3bWe7NQWzf+JLiXCiMaE= github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA= -github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= +github.com/miekg/dns v1.1.73 h1:uhT8nJxmTrPJYClxVxTCX+CVn6qnzSiybRk72Z6DgrE= +github.com/miekg/dns v1.1.73/go.mod h1:RW2Obtfd5NZHvOFe3zYG0W8koWOQtAzyHaLo8vASBuQ= github.com/mileusna/useragent v1.3.5 h1:SJM5NzBmh/hO+4LGeATKpaEX9+b4vcGg2qXGLiNGDws= github.com/mileusna/useragent v1.3.5/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc= github.com/minio/crc64nvme v1.1.1 h1:8dwx/Pz49suywbO+auHCBpCtlW1OfpcLN7wYgVR6wAI= @@ -827,38 +675,32 @@ github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v7 v7.2.1 h1:PfBfwvKB/MmqyN8Vb1G9voWisaM9OrLv+WwOvMwS9Dw= github.com/minio/minio-go/v7 v7.2.1/go.mod h1:EU9hENAStx/xXduNdrGO5e4X5vk19NtgB+RIPjZO8o0= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mna/pigeon v1.3.0 h1:/3fzVrl1C2RK3x04tyL+ribn+3S3VSEFFbCFLmRPAoc= github.com/mna/pigeon v1.3.0/go.mod h1:SKQNHonx2q9U2QSSoPtMigExj+vQ1mOpL7UVFQF/IA0= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8= -github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU= -github.com/moby/moby/api v1.55.0 h1:2/sexvQyqIWS8pRSCFddBfpW2qE7vR7FCL+vN8pxwMc= -github.com/moby/moby/api v1.55.0/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs= -github.com/moby/moby/client v0.5.0 h1:5XhyPk2fuOWf6RlSFa3MkIIgDZkF25xToXW8Q/BH7cc= -github.com/moby/moby/client v0.5.0/go.mod h1:rcVpF8ncl9vo5gaIBdol6CnbEtSj1uxMvEV/UrykF/s= +github.com/moby/go-archive v0.3.3 h1:OxxR9paxsluYi+zDUEXTTaIxtkK3viymW+Ka7vRhhME= +github.com/moby/go-archive v0.3.3/go.mod h1:Npdv43fFqlhZW7Xo8fbm3ZMYFvAGNviUPqX21VERbcE= +github.com/moby/moby/api v1.56.0 h1:GQzua3NA599ASSIICx0iFgiJeO9YkdDARvQsm23ZZuQ= +github.com/moby/moby/api v1.56.0/go.mod h1:sZ+THbVWkjOmBPPfbnzdD/G1LuIexWhqlSHHPTDQ1Uk= +github.com/moby/moby/client v0.6.0 h1:AJjEB21QPbXSXjDsZorFBoDZPhMrfbpaPLgSMAW9Bgs= +github.com/moby/moby/client v0.6.0/go.mod h1:OCo00wNRyA3m4lmJ228W3JbyCN4ZNNYjpOXiJydBdcQ= github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U= github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/mount v0.3.5 h1:eS3fsZTjHaBihwjp4/+5Z3jxqLXYsbwxqpVSfFv3M00= +github.com/moby/sys/mount v0.3.5/go.mod h1:WUQDO+/uCiCIkIztx8SrwIDVn2dtMFRBebRhpDFT71M= +github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= +github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/moby/sys/sequential v0.7.0 h1:ASQNGNROJSuOO6LL6bPHbKvuZu6NU8P4ldPWk31zj/8= github.com/moby/sys/sequential v0.7.0/go.mod h1:NfSTAp6V3fw4tmkD62PEcOKeZKquXT8VKCkf7aVR79o= -github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= -github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= -github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= -github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/moby/sys/user v0.4.1 h1:RgjRlaDKi/Xmyrz4t8lyzXT6v2ooFeO/7xtchmhVWE0= +github.com/moby/sys/user v0.4.1/go.mod h1:E9QsW5WRe1kUAf7kW8hXKwu1uhsZEAdPLYHYSDudF4Y= +github.com/moby/sys/userns v0.2.1 h1:4OvdM7BcPkASbuouHsbW3aeMJSFlYDldBRnXVZhaRk8= +github.com/moby/sys/userns v0.2.1/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -877,7 +719,6 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8= github.com/nats-io/jwt/v2 v2.8.2 h1:XXRgB60MSTnqsRwejQurVDs/hcv2dkt+86GjI+I/bMc= github.com/nats-io/jwt/v2 v2.8.2/go.mod h1:Ag/56sq9OblL4JgdYufDd16Egb17Kr/8WwwuO/forVc= github.com/nats-io/nats-server/v2 v2.15.0 h1:M99yf0y05rTr46/qc/Is6ZAowI58Ryp2SjufLCUeVJc= @@ -888,36 +729,26 @@ github.com/nats-io/nkeys v0.4.16 h1:rd5oAuLOb8mnAycB0xleuEBNS1pVVnN0fv/FF34Eypg= github.com/nats-io/nkeys v0.4.16/go.mod h1:llLgWoI0o4z/Q57q2R1kHfmocyhGV6VG/U18Glg1Afs= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= -github.com/nrdcg/auroradns v1.0.1/go.mod h1:y4pc0i9QXYlFCWrhWrUSIETnZgrf4KuwjDIWmmXo3JI= -github.com/nrdcg/desec v0.5.0/go.mod h1:2ejvMazkav1VdDbv2HeQO7w+Ta1CGHqzQr27ZBYTuEQ= -github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ= -github.com/nrdcg/goinwx v0.8.1/go.mod h1:tILVc10gieBp/5PMvbcYeXM6pVQ+c9jxDZnpaR1UW7c= -github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw= -github.com/nrdcg/porkbun v0.1.1/go.mod h1:JWl/WKnguWos4mjfp4YizvvToigk9qpQwrodOk+CPoA= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E= github.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= github.com/olekukonko/errors v1.3.0 h1:teJvgLGUEqMzBUms+Dj3/3szNqCG/Jdw9iDbum8fR6U= github.com/olekukonko/errors v1.3.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= github.com/olekukonko/ll v0.1.6 h1:lGVTHO+Qc4Qm+fce/2h2m5y9LvqaW+DCN7xW9hsU3uA= github.com/olekukonko/ll v0.1.6/go.mod h1:NVUmjBb/aCtUpjKk75BhWrOlARz3dqsM+OtszpY4o88= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I= github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.32.1 h1:6tlvcDm/3sE8lGJbZ4+d4mO3RLy24/tQWOFzVSQNIfw= github.com/onsi/ginkgo/v2 v2.32.1/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.43.1 h1:vGIPFuYrIO6/0Z09s0I0QQQgFchiX4+tb1re3MScJYo= @@ -930,8 +761,8 @@ github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 h1:W1ms+l github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89/go.mod h1:vigJkNss1N2QEceCuNw/ullDehncuJNFB6mEnzfq9UI= github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260902170011-45af3945a067 h1:UkNMKauyJAzY6RE6mmthz9bQZLYkbvBuApm7ZDCparE= github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260902170011-45af3945a067/go.mod h1:lTM8JeGblNpoMySTW7Lui2+c5TTLI95mwxtdUIHHrhU= -github.com/opencloud-eu/reva/v2 v2.50.1-0.20260924091259-7fa82c610dba h1:EmOM04qHWNsoT3F49bVfb3jQglHHSIbBvkol3eMV8Uo= -github.com/opencloud-eu/reva/v2 v2.50.1-0.20260924091259-7fa82c610dba/go.mod h1:UnhCBGqcuhLkOhrmvbEsiBaDiD5uDGzaylnoc+QzJNs= +github.com/opencloud-eu/reva/v2 v2.50.1-0.20261001091108-11d87fb6b985 h1:9NpeJKVzjzMKhiTaBPz6SqtRiv6k67E5wKPPc0zg/8M= +github.com/opencloud-eu/reva/v2 v2.50.1-0.20261001091108-11d87fb6b985/go.mod h1:ngLsDakKnt8zCFCeULhuSZFESGy5NIuSq5/JGeOhPdU= github.com/opencloud-eu/secure v0.0.0-20260312082735-b6f5cb2244e4 h1:l2oB/RctH+t8r7QBj5p8thfEHCM/jF35aAY3WQ3hADI= github.com/opencloud-eu/secure v0.0.0-20260312082735-b6f5cb2244e4/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -943,29 +774,22 @@ github.com/opensearch-project/opensearch-go/v4 v4.7.3/go.mod h1:+iikkyLrVC8ZvyfK github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= github.com/orcaman/concurrent-map v1.0.0 h1:I/2A2XPCb4IuQWcQhBhSwGfiuybl/J0ev9HDbW65HOY= github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI= -github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= github.com/pablodz/inotifywaitgo v0.0.12 h1:DVJJTFMDlSAdO46yisPF2vzozs/r+4k6ih8MVghq78M= github.com/pablodz/inotifywaitgo v0.0.12/go.mod h1:JWyDC6H+5oZRdUJUgKuaye+8Ph5hEs6HVzVoPKzWSGI= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc= github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4/v4 v4.1.26 h1:GrpZw1gZttORinvzBdXPUXATeqlJjqUG/D87TKMnhjY= github.com/pierrec/lz4/v4 v4.1.26/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4= github.com/pjbgf/sha1cd v0.6.0 h1:3WJ8Wz8gvDz29quX1OcEmkAlUg9diU4GxJHqs0/XiwU= @@ -974,25 +798,18 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= github.com/pkg/xattr v0.4.12 h1:rRTkSyFNTRElv6pkA3zpjHpQ90p/OdHQC1GmGh1aTjM= github.com/pkg/xattr v0.4.12/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/pquerna/cachecontrol v0.2.0 h1:vBXSNuE5MYP9IJ5kjsdo8uq+w41jSPgvba2DEnkRx9k= github.com/pquerna/cachecontrol v0.2.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= -github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= @@ -1002,18 +819,13 @@ github.com/prometheus/client_golang v1.24.1 h1:JnJkREXzWxUdCuPFpIWZiPispT9xVV59u github.com/prometheus/client_golang v1.24.1/go.mod h1:F+oSRECHg4sse5ucfYpYDeIv/hu68Zo0uoHKetWnzcE= github.com/prometheus/client_model v0.0.0-20170216185247-6f3806018612/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.3 h1:O0jaTVAYNxTHYInEPFJt5I3+sN8zqBtVMPTB1qyxiEo= github.com/prometheus/client_model v0.6.3/go.mod h1:gpN5P9S7Rr6Yr92PiQ+Ixvhf6JZEkF1dnxsYL2aPBEM= github.com/prometheus/common v0.0.0-20170706130215-fb369f752a7f/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= @@ -1023,10 +835,7 @@ github.com/prometheus/common v0.70.1 h1:1HvjP4D5oL3t8RsPlwxA9onvvStjtIHYE5XuuwOi github.com/prometheus/common v0.70.1/go.mod h1:VdFUQDMZK3VLkurFUVhia6uys/0suUp86TJz5qbJRhc= github.com/prometheus/procfs v0.0.0-20170703101242-e645f4e5aaa8/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= @@ -1036,16 +845,12 @@ github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIj github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= github.com/prometheus/statsd_exporter v0.22.8 h1:Qo2D9ZzaQG+id9i5NYNGmbf1aa/KxKbB9aKfMS+Yib0= github.com/prometheus/statsd_exporter v0.22.8/go.mod h1:/DzwbTEaFTE0Ojz5PqcSk6+PFHOPWGxdXVr6yC8eFOM= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0= github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I= -github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/riandyrn/otelchi v0.12.3 h1:KW9gA+97d6mExk8vbh0FRwb2biUvpyYlc8YuxP1Oap0= github.com/riandyrn/otelchi v0.12.3/go.mod h1:weZZeUJURvtCcbWsdb7Y6F8KFZGedJlSrgUjq9VirV8= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.16.0 h1:O9DK+vNMDVGLr2BeZqmpLeMjiMNkuXfcqntWbZV6S5g= github.com/rogpeppe/go-internal v1.16.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs= @@ -1057,13 +862,10 @@ github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI= github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= github.com/russellhaering/goxmldsig v1.6.0 h1:8fdWXEPh2k/NZNQBPFNoVfS3JmzS4ZprY/sAOpKQLks= github.com/russellhaering/goxmldsig v1.6.0/go.mod h1:TrnaquDcYxWXfJrOjeMBTX4mLBeYAqaHEyUeWPxZlBM= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/samber/lo v1.53.0 h1:t975lj2py4kJPQ6haz1QMgtId2gtmfktACxIXArw3HM= @@ -1072,8 +874,6 @@ github.com/samber/slog-common v0.21.0 h1:Wo2hTly1Br5RjYqX/BTWJJeDnTE85oWk/7vqlpZ github.com/samber/slog-common v0.21.0/go.mod h1:d/6OaSlzdkl9PFpfRLgn8FwY1OW6EFmPtBpsHX4MrU0= github.com/samber/slog-zerolog/v2 v2.9.2 h1:DIFzfzDTxHeRyGlfg/D7b2by7VVzcsBTybRPrzjWF4c= github.com/samber/slog-zerolog/v2 v2.9.2/go.mod h1:2q6cYK2OcN6YfQE/WyCnUtigc+yYf3ozqGsGmRwZR6I= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/kafka-go v0.4.51 h1:JgDPPG75tC1rWIS2Me6MwcvXJ6f49UQ4HjAOef71Hno= @@ -1094,53 +894,31 @@ github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKl github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v4 v4.26.6 h1:Mzr/npDtQC/xpeEuQKHZt8Zo9CmPvhTj8nkR8w5TLDs= github.com/shirou/gopsutil/v4 v4.26.6/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.10.2 h1:G2SED73/qrAu6YwbdxOD6peLkCBI3z7L+ykJFTXJBBo= github.com/sirupsen/logrus v1.10.2/go.mod h1:SLEg8TqYulVKKfIGHldVp2K2aYz2DKSVBq4g/H5bR7Q= -github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= -github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= -github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= -github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/gunit v1.0.4/go.mod h1:EH5qMBab2UclzXUcpR8b93eHsIlp9u+pDQIRp5DZNzQ= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/skeema/knownhosts v1.3.3 h1:tiFvsjIW+xqP5cqVsod7atn/xm57OY6v9KwxB1xWUyA= +github.com/skeema/knownhosts v1.3.3/go.mod h1:2y0ntYxeqSNxOw5pfqSVDcRyBt2FqfxhzNDPoKz/ifQ= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 h1:0jjO3HdJfOn6gYHD/ZNZh0LLMxEAqkYX7xoDPQReEgs= github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784/go.mod h1:ff/5myEGgtsAwf26goQCO905GrEm5ugEZSd6OWTsrhM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= @@ -1161,7 +939,6 @@ github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhgwZDDc= @@ -1194,32 +971,22 @@ github.com/tklauser/go-sysconf v0.4.0 h1:7H0uAN+7RkwWRaxhYXDLqa5V3LPrJeV8wmD9dRU github.com/tklauser/go-sysconf v0.4.0/go.mod h1:8mTNWyog7H+MpKijp4VmKJAd2bbYQ2zuUwkYRbUArPI= github.com/tklauser/numcpus v0.12.0 h1:NR85qdvHA9pFse3x3weVZ0r0ST8R6l5RHbZrlRaqob4= github.com/tklauser/numcpus v0.12.0/go.mod h1:ABHeXzJnr/qqwguhClkZKT1/8VABcYrsyUiUGobwWJg= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 h1:PM5hJF7HVfNWmCjMdEfbuOBNXSVF2cMFGgQTPdKCbwM= github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns= -github.com/transip/gotransip/v6 v6.2.0/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g= github.com/trustelem/zxcvbn v1.0.1 h1:mp4JFtzdDYGj9WYSD3KQSkwwUumWNFzXaAjckaTYpsc= github.com/trustelem/zxcvbn v1.0.1/go.mod h1:zonUyKeh7sw6psPf/e3DtRqkRyZvAbOfjNz/aO7YQ5s= github.com/tus/tusd/v2 v2.10.0 h1:2yOGmkrDl9RQmRIt/00DR2WvYWOoiEu3CoygILb+WRw= github.com/tus/tusd/v2 v2.10.0/go.mod h1:T/OuJHIAC2NHpkEUyQyyaoWyDNRDcQVpJzWl8tX5GY4= -github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= -github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADTh4= github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE= -github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/vektah/gqlparser/v2 v2.5.36 h1:CN9mKVHgMkc+XftdOWIhb4HEL8wKSYkFAqhf8booa7s= github.com/vektah/gqlparser/v2 v2.5.36/go.mod h1:cAJ9qwVgPaUkWv6Gn8vn0mqOE0Ui5Pn56wNy5396XWo= -github.com/vinyldns/go-vinyldns v0.0.0-20200917153823-148a5f6b8f14/go.mod h1:RWc47jtnVuQv6+lY3c768WtXCas/Xi+U5UFc5xULmYg= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/vultr/govultr/v2 v2.0.0/go.mod h1:2PsEeg+gs3p/Fo5Pw8F9mv+DUBEOlrNZ8GmCTGmhOhs= github.com/wI2L/jsondiff v0.7.1 h1:Fg9+yj+1/x3UtPBJhR91TKEzRkrEEWcAcLbg9dzEaNM= github.com/wI2L/jsondiff v0.7.1/go.mod h1:yAt2W7U6Jd4HK0RA8DGSGk0zDtfEtOUUJVnH/xICpjo= github.com/wk8/go-ordered-map v1.0.0 h1:BV7z+2PaK8LTSd/mWgY12HyMAo5CEgkHqbkVq2thqr8= @@ -1232,17 +999,14 @@ github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xhit/go-simple-mail/v2 v2.16.0 h1:ouGy/Ww4kuaqu2E2UrDw7SvLaziWTB60ICLkIkNVccA= github.com/xhit/go-simple-mail/v2 v2.16.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg= +github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yashtewari/glob-intersection v0.2.0 h1:8iuHdN88yYuCzCdjt0gDe+6bAhUwBeEWqThExu54RFg= github.com/yashtewari/glob-intersection v0.2.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1256,7 +1020,6 @@ github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.5.0 h1:S7GAl7Fxv12yohbwFfIbQCGDWbQbtDGPET4P/bD4lxU= go.etcd.io/bbolt v1.5.0/go.mod h1:mkltfYE5aUHQxUct9N9V+Kp7aSjFqjgrhcXIS70Lrdk= go.etcd.io/etcd/api/v3 v3.7.1 h1:KJG0/DcWGfe3Y1otDf/fsBf0TSSgpxZ5RO/L8SFt73E= @@ -1265,8 +1028,6 @@ go.etcd.io/etcd/client/pkg/v3 v3.7.1 h1:rKYsj3pRkR0eK3yjT3XOgrhqfmIfj9pzNgxjh7mf go.etcd.io/etcd/client/pkg/v3 v3.7.1/go.mod h1:cnzZGIUzSfjEwLC6UBVsSXlEK1eepS/JUD7wE6PLRT0= go.etcd.io/etcd/client/v3 v3.7.1 h1:0PEMMC0KuZmVIN+RAbdqfkZ45pYTgKVtmBEbRCvZFUg= go.etcd.io/etcd/client/v3 v3.7.1/go.mod h1:ffNqALa8tRCYhYo1F9oR489y23K39Gz+BSR3ApAGYq0= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -1301,40 +1062,27 @@ go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu6 go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI= go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk= go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= -go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= +go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= -golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= @@ -1384,12 +1132,8 @@ golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1400,8 +1144,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1420,7 +1162,6 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -1431,8 +1172,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= -golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= +golang.org/x/net v0.59.0 h1:5zfYln+w5XCxwrnMMJPufRgNoXEaGxl0wo5GqPXyues= +golang.org/x/net v0.59.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1458,19 +1199,12 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= -golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1478,16 +1212,11 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1508,10 +1237,7 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201110211018-35f3e6cf4a65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1519,18 +1245,19 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1541,7 +1268,6 @@ golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -1556,7 +1282,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -1568,20 +1293,14 @@ golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.16.0 h1:vMb6ptszcQMkcwiRTAuNNU50gom6++Q/6gY2hDM6VDE= golang.org/x/time v0.16.0/go.mod h1:rVKOqvZeKvrDKTQiAHJ7wmwP0RzleSphoEA9RcdLA0s= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1592,13 +1311,11 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1633,7 +1350,6 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1688,13 +1404,11 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 h1:XzmzkmB14QhVhgnawEVsOn6OFsnpyxNPRY9QV01dNB0= google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:L43LFes82YgSonw6iTXTxXUX1OlULt4AQtkik4ULL/I= -google.golang.org/genproto/googleapis/api v0.0.0-20260819154853-08b0e4226688 h1:ax2KzoSRIZU/M0cIxri3pKxy99vniH1PVxWC6si/eZI= -google.golang.org/genproto/googleapis/api v0.0.0-20260819154853-08b0e4226688/go.mod h1:1RJ9BQGyNdZwkGc1eTqkErfRZ6RJyYPHZo73BZ1vQqI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5 h1:1VUiZAXyC+zmiFYi+WLtBzr68Cj8wOofHjjrA/kkizc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5/go.mod h1:DjtHYE8FKJLivXcBEjGwndXfIC23G0VpXiXKqG179uA= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/genproto/googleapis/api v0.0.0-20260928230214-8a89bd6388cc h1:rZHRz0ogq4Pid1IKtA/ivHi8XONVF5tqUQXA2TtgpkE= +google.golang.org/genproto/googleapis/api v0.0.0-20260928230214-8a89bd6388cc/go.mod h1:K/n0XLazCJHjD73YuMyNJsN38BPPy1kfFnKxUXaThFU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260928230214-8a89bd6388cc h1:4bNTbnb44EqGVy9HaQxSY2jnafSUdgV3qHtedvNpDKg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260928230214-8a89bd6388cc/go.mod h1:OaIUM3+LpYcK2GXM4FTmhWoIq371Owdr+Cc7/BsYHHc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -1737,25 +1451,14 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= -gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.3 h1:iM9Lhz5MRSGhHVGGwCuzG9KO8PoirCXj/m/qTmOJJQw= gopkg.in/ini.v1 v1.67.3/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss= -gopkg.in/ns1/ns1-go.v2 v2.4.4/go.mod h1:GMnKY+ZuoJ+lVLL+78uSTjwTz2jMazq6AfGKQOYhsPk= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1770,7 +1473,6 @@ gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go index bcbe00d0c5..01c9519c3d 100644 --- a/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go +++ b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go @@ -26,7 +26,7 @@ func (csiState csiEntryState) Handle(b byte) (s state, e error) { func (csiState csiEntryState) Transition(s state) error { csiState.parser.logf("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name()) - csiState.baseState.Transition(s) + _ = csiState.baseState.Transition(s) switch s { case csiState.parser.ground: @@ -34,9 +34,9 @@ func (csiState csiEntryState) Transition(s state) error { case csiState.parser.csiParam: switch { case sliceContains(csiParams, csiState.parser.context.currentChar): - csiState.parser.collectParam() + _ = csiState.parser.collectParam() case sliceContains(intermeds, csiState.parser.context.currentChar): - csiState.parser.collectInter() + _ = csiState.parser.collectInter() } } diff --git a/vendor/github.com/Azure/go-ansiterm/csi_param_state.go b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go index 7ed5e01c34..88146e6fe5 100644 --- a/vendor/github.com/Azure/go-ansiterm/csi_param_state.go +++ b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go @@ -16,8 +16,7 @@ func (csiState csiParamState) Handle(b byte) (s state, e error) { case sliceContains(alphabetics, b): return csiState.parser.ground, nil case sliceContains(csiCollectables, b): - csiState.parser.collectParam() - return csiState, nil + return csiState, csiState.parser.collectParam() case sliceContains(executors, b): return csiState, csiState.parser.execute() } @@ -27,7 +26,7 @@ func (csiState csiParamState) Handle(b byte) (s state, e error) { func (csiState csiParamState) Transition(s state) error { csiState.parser.logf("CsiParam::Transition %s --> %s", csiState.Name(), s.Name()) - csiState.baseState.Transition(s) + _ = csiState.baseState.Transition(s) switch s { case csiState.parser.ground: diff --git a/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go index 1c719db9e4..88429690f9 100644 --- a/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go +++ b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go @@ -25,7 +25,7 @@ func (escState escapeIntermediateState) Handle(b byte) (s state, e error) { func (escState escapeIntermediateState) Transition(s state) error { escState.parser.logf("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name()) - escState.baseState.Transition(s) + _ = escState.baseState.Transition(s) switch s { case escState.parser.ground: diff --git a/vendor/github.com/Azure/go-ansiterm/escape_state.go b/vendor/github.com/Azure/go-ansiterm/escape_state.go index 6390abd231..854e3812a9 100644 --- a/vendor/github.com/Azure/go-ansiterm/escape_state.go +++ b/vendor/github.com/Azure/go-ansiterm/escape_state.go @@ -29,7 +29,7 @@ func (escState escapeState) Handle(b byte) (s state, e error) { func (escState escapeState) Transition(s state) error { escState.parser.logf("Escape::Transition %s --> %s", escState.Name(), s.Name()) - escState.baseState.Transition(s) + _ = escState.baseState.Transition(s) switch s { case escState.parser.ground: diff --git a/vendor/github.com/Azure/go-ansiterm/parser.go b/vendor/github.com/Azure/go-ansiterm/parser.go index 03cec7ada6..2e8ef80fb7 100644 --- a/vendor/github.com/Azure/go-ansiterm/parser.go +++ b/vendor/github.com/Azure/go-ansiterm/parser.go @@ -113,16 +113,13 @@ func (ap *AnsiParser) handle(b byte) error { if newState == nil { ap.logf("WARNING: newState is nil") - return errors.New("New state of 'nil' is invalid.") + return errors.New("new state of 'nil' is invalid") } - if newState != ap.currState { - if err := ap.changeState(newState); err != nil { - return err - } + if newState == ap.currState { + return nil } - - return nil + return ap.changeState(newState) } func (ap *AnsiParser) changeState(newState state) error { @@ -136,7 +133,7 @@ func (ap *AnsiParser) changeState(newState state) error { // Perform transition action if err := ap.currState.Transition(newState); err != nil { - ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err) + ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name(), err) return err } diff --git a/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go index de0a1f9cde..dc001532a6 100644 --- a/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go +++ b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go @@ -4,9 +4,9 @@ import ( "strconv" ) -func parseParams(bytes []byte) ([]string, error) { - paramBuff := make([]byte, 0, 0) - params := []string{} +func parseParams(bytes []byte) []string { + var paramBuff []byte + var params []string for _, v := range bytes { if v == ';' { @@ -14,7 +14,7 @@ func parseParams(bytes []byte) ([]string, error) { // Completed parameter, append it to the list s := string(paramBuff) params = append(params, s) - paramBuff = make([]byte, 0, 0) + paramBuff = paramBuff[:0] } } else { paramBuff = append(paramBuff, v) @@ -27,11 +27,7 @@ func parseParams(bytes []byte) ([]string, error) { params = append(params, s) } - return params, nil -} - -func parseCmd(context ansiContext) (string, error) { - return string(context.currentChar), nil + return params } func getInt(params []string, dflt int) int { diff --git a/vendor/github.com/Azure/go-ansiterm/parser_actions.go b/vendor/github.com/Azure/go-ansiterm/parser_actions.go index 0bb5e51e9a..2aee10159a 100644 --- a/vendor/github.com/Azure/go-ansiterm/parser_actions.go +++ b/vendor/github.com/Azure/go-ansiterm/parser_actions.go @@ -15,10 +15,9 @@ func (ap *AnsiParser) collectInter() error { } func (ap *AnsiParser) escDispatch() error { - cmd, _ := parseCmd(*ap.context) - intermeds := ap.context.interBuffer + cmd := string(ap.context.currentChar) ap.logf("escDispatch currentChar: %#x", ap.context.currentChar) - ap.logf("escDispatch: %v(%v)", cmd, intermeds) + ap.logf("escDispatch: %s(%q)", cmd, string(ap.context.interBuffer)) switch cmd { case "D": // IND @@ -31,14 +30,14 @@ func (ap *AnsiParser) escDispatch() error { return err case "M": // RI return ap.eventHandler.RI() + default: + return nil } - - return nil } func (ap *AnsiParser) csiDispatch() error { - cmd, _ := parseCmd(*ap.context) - params, _ := parseParams(ap.context.paramBuffer) + cmd := string(ap.context.currentChar) + params := parseParams(ap.context.paramBuffer) ap.logf("Parsed params: %v with length: %d", params, len(params)) ap.logf("csiDispatch: %v(%v)", cmd, params) @@ -109,9 +108,8 @@ func (ap *AnsiParser) print() error { return ap.eventHandler.Print(ap.context.currentChar) } -func (ap *AnsiParser) clear() error { +func (ap *AnsiParser) clear() { ap.context = &ansiContext{} - return nil } func (ap *AnsiParser) execute() error { diff --git a/vendor/github.com/Azure/go-ansiterm/states.go b/vendor/github.com/Azure/go-ansiterm/states.go index f2ea1fcd12..cf72692261 100644 --- a/vendor/github.com/Azure/go-ansiterm/states.go +++ b/vendor/github.com/Azure/go-ansiterm/states.go @@ -1,7 +1,5 @@ package ansiterm -type stateID int - type state interface { Enter() error Exit() error diff --git a/vendor/github.com/Azure/go-ansiterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/utilities.go index 392114493a..d94dd3a347 100644 --- a/vendor/github.com/Azure/go-ansiterm/utilities.go +++ b/vendor/github.com/Azure/go-ansiterm/utilities.go @@ -1,9 +1,5 @@ package ansiterm -import ( - "strconv" -) - func sliceContains(bytes []byte, b byte) bool { for _, v := range bytes { if v == b { @@ -13,9 +9,3 @@ func sliceContains(bytes []byte, b byte) bool { return false } - -func convertBytesToInteger(bytes []byte) int { - s := string(bytes) - i, _ := strconv.Atoi(s) - return i -} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go index 5599082ae9..c6cc027a78 100644 --- a/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go +++ b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go @@ -5,12 +5,9 @@ package winterm import ( "fmt" "os" - "strconv" - "strings" "syscall" - "github.com/Azure/go-ansiterm" - windows "golang.org/x/sys/windows" + "golang.org/x/sys/windows" ) // Windows keyboard constants @@ -55,100 +52,6 @@ const ( ENHANCED_KEY = 0x0100 ) -type ansiCommand struct { - CommandBytes []byte - Command string - Parameters []string - IsSpecial bool -} - -func newAnsiCommand(command []byte) *ansiCommand { - - if isCharacterSelectionCmdChar(command[1]) { - // Is Character Set Selection commands - return &ansiCommand{ - CommandBytes: command, - Command: string(command), - IsSpecial: true, - } - } - - // last char is command character - lastCharIndex := len(command) - 1 - - ac := &ansiCommand{ - CommandBytes: command, - Command: string(command[lastCharIndex]), - IsSpecial: false, - } - - // more than a single escape - if lastCharIndex != 0 { - start := 1 - // skip if double char escape sequence - if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY { - start++ - } - // convert this to GetNextParam method - ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP) - } - - return ac -} - -func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 { - if index < 0 || index >= len(ac.Parameters) { - return defaultValue - } - - param, err := strconv.ParseInt(ac.Parameters[index], 10, 16) - if err != nil { - return defaultValue - } - - return int16(param) -} - -func (ac *ansiCommand) String() string { - return fmt.Sprintf("0x%v \"%v\" (\"%v\")", - bytesToHex(ac.CommandBytes), - ac.Command, - strings.Join(ac.Parameters, "\",\"")) -} - -// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands. -// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html. -func isAnsiCommandChar(b byte) bool { - switch { - case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY: - return true - case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM: - // non-CSI escape sequence terminator - return true - case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL: - // String escape sequence terminator - return true - } - return false -} - -func isXtermOscSequence(command []byte, current byte) bool { - return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL) -} - -func isCharacterSelectionCmdChar(b byte) bool { - return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3) -} - -// bytesToHex converts a slice of bytes to a human-readable string. -func bytesToHex(b []byte) string { - hex := make([]string, len(b)) - for i, ch := range b { - hex[i] = fmt.Sprintf("%X", ch) - } - return strings.Join(hex, "") -} - // ensureInRange adjusts the passed value, if necessary, to ensure it is within // the passed min / max range. func ensureInRange(n int16, min int16, max int16) int16 { diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/aes/keywrap/keywrap.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/aes/keywrap/keywrap.go index 3c6251d1ce..6e09679c30 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/aes/keywrap/keywrap.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/aes/keywrap/keywrap.go @@ -101,7 +101,7 @@ func Wrap(key, plainText []byte) ([]byte, error) { // Unwrap a key using the RFC 3394 AES Key Wrap Algorithm. func Unwrap(key, cipherText []byte) ([]byte, error) { - if len(cipherText)%8 != 0 { + if len(cipherText) < 16 || len(cipherText)%8 != 0 { return nil, ErrUnwrapCiphertext } diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/armor/armor.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/armor/armor.go index e0a677f284..39c9b12231 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/armor/armor.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/armor/armor.go @@ -69,6 +69,8 @@ func (l *lineReader) Read(p []byte) (n int, err error) { if isPrefix { return 0, ArmorCorrupt } + // Trim the line to remove any whitespace + line = bytes.TrimSpace(line) if bytes.HasPrefix(line, armorEnd) { l.eof = true diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/ecdh.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/ecdh.go index db8fb163b6..cb452c5d83 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/ecdh.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/ecdh.go @@ -145,7 +145,14 @@ func Decrypt(priv *PrivateKey, vsG, c, curveOID, fingerprint []byte) (msg []byte // RFC6637 §8: "m = symm_alg_ID || session key || checksum || pkcs5_padding" // The last byte should be the length of the padding, as per PKCS5; strip it off. - return m[:len(m)-int(m[len(m)-1])], nil + if len(m) == 0 { + return nil, errors.New("ecdh: invalid padding") + } + padLen := int(m[len(m)-1]) + if padLen > len(m) { + return nil, errors.New("ecdh: invalid padding") + } + return m[:len(m)-padLen], nil } func buildKey(pub *PublicKey, zb []byte, curveOID, fingerprint []byte, stripLeading, stripTrailing bool) ([]byte, error) { @@ -196,6 +203,9 @@ func buildKey(pub *PublicKey, zb []byte, curveOID, fingerprint []byte, stripLead return nil, err } mb := h.Sum(nil) + if len(mb) < pub.KDF.Cipher.KeySize() { + return nil, errors.New("ecdh: KDF hash output is shorter than the KDF cipher key size") + } return mb[:pub.KDF.Cipher.KeySize()], nil // return oBits leftmost bits of MB. diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/elgamal/elgamal.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/elgamal/elgamal.go index bad2774344..cfe9fe130f 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/elgamal/elgamal.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/elgamal/elgamal.go @@ -82,6 +82,9 @@ func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) { s.Mul(s, c2) s.Mod(s, priv.P) em := s.Bytes() + if len(em) == 0 { + return nil, errors.New("elgamal: decryption error") + } firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2) diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/errors/errors.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/errors/errors.go index e44b45734d..2e341507a7 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/errors/errors.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/errors/errors.go @@ -180,6 +180,16 @@ func (dke ErrMalformedMessage) Error() string { return "openpgp: malformed message " + string(dke) } +type messageTooLargeError int + +func (e messageTooLargeError) Error() string { + return "openpgp: decompressed message size exceeds provided limit" +} + +// ErrMessageTooLarge is returned if the read data from +// a compressed packet exceeds the provided limit. +var ErrMessageTooLarge error = messageTooLargeError(0) + // ErrEncryptionKeySelection is returned if encryption key selection fails (v2 API). type ErrEncryptionKeySelection struct { PrimaryKeyId string diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/aead.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/aead.go index d067065186..323a4aaf58 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/aead.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/aead.go @@ -4,8 +4,11 @@ package algorithm import ( "crypto/cipher" + "strconv" + "github.com/ProtonMail/go-crypto/eax" "github.com/ProtonMail/go-crypto/ocb" + "github.com/ProtonMail/go-crypto/openpgp/errors" ) // AEADMode defines the Authenticated Encryption with Associated Data mode of @@ -48,8 +51,7 @@ func (mode AEADMode) NonceLength() int { } // New returns a fresh instance of the given mode -func (mode AEADMode) New(block cipher.Block) (alg cipher.AEAD) { - var err error +func (mode AEADMode) New(block cipher.Block) (alg cipher.AEAD, err error) { switch mode { case AEADModeEAX: alg, err = eax.NewEAX(block) @@ -57,9 +59,8 @@ func (mode AEADMode) New(block cipher.Block) (alg cipher.AEAD) { alg, err = ocb.NewOCB(block) case AEADModeGCM: alg, err = cipher.NewGCM(block) + default: + err = errors.UnsupportedError("unknown aead mode: " + strconv.Itoa(int(mode))) } - if err != nil { - panic(err.Error()) - } - return alg + return alg, err } diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve25519.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve25519.go index 888767c4e4..e047b3b3bd 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve25519.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve25519.go @@ -125,7 +125,10 @@ func (c *curve25519) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecr // "VB = convert point V to the octet string" // sharedPoint corresponds to `VB`. var sharedPoint x25519lib.Key - x25519lib.Shared(&sharedPoint, &ephemeralPrivate, &pubKey) + ok := x25519lib.Shared(&sharedPoint, &ephemeralPrivate, &pubKey) + if !ok { + return nil, nil, errors.KeyInvalidError("ecc: the public key is a low order point") + } return ephemeralPublic[:], sharedPoint[:], nil } @@ -146,7 +149,10 @@ func (c *curve25519) Decaps(vsG, secret []byte) (sharedSecret []byte, err error) // RFC6637 §8: "Note that the recipient obtains the shared secret by calculating // S = rV = rvG, where (r,R) is the recipient's key pair." // sharedPoint corresponds to `S`. - x25519lib.Shared(&sharedPoint, &decodedPrivate, &ephemeralPublic) + ok := x25519lib.Shared(&sharedPoint, &decodedPrivate, &ephemeralPublic) + if !ok { + return nil, errors.KeyInvalidError("ecc: the public key is a low order point") + } return sharedPoint[:], nil } diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curves.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curves.go index 5ed9c93b3d..34c4ad8603 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curves.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curves.go @@ -16,6 +16,8 @@ type ECDSACurve interface { UnmarshalIntegerPoint([]byte) (x, y *big.Int) MarshalIntegerSecret(d *big.Int) []byte UnmarshalIntegerSecret(d []byte) *big.Int + MarshalFieldInteger(d *big.Int) []byte + UnmarshalFieldInteger(d []byte) *big.Int GenerateECDSA(rand io.Reader) (x, y, secret *big.Int, err error) Sign(rand io.Reader, x, y, d *big.Int, hash []byte) (r, s *big.Int, err error) Verify(x, y *big.Int, hash []byte, r, s *big.Int) bool diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/generic.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/generic.go index e28d7c7106..2b997c6afb 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/generic.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/generic.go @@ -56,6 +56,15 @@ func (c *genericCurve) UnmarshalIntegerSecret(d []byte) *big.Int { return new(big.Int).SetBytes(d) } +func (c *genericCurve) MarshalFieldInteger(i *big.Int) (b []byte) { + b = make([]byte, (c.Curve.Params().BitSize+7)/8) + return i.FillBytes(b) +} + +func (c *genericCurve) UnmarshalFieldInteger(d []byte) *big.Int { + return new(big.Int).SetBytes(d) +} + func (c *genericCurve) GenerateECDH(rand io.Reader) (point, secret []byte, err error) { secret, x, y, err := elliptic.GenerateKey(c.Curve, rand) if err != nil { @@ -78,7 +87,7 @@ func (c *genericCurve) GenerateECDSA(rand io.Reader) (x, y, secret *big.Int, err func (c *genericCurve) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) { xP, yP := elliptic.Unmarshal(c.Curve, point) if xP == nil { - panic("invalid point") + return nil, nil, errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", c.Curve.Params().Name)) } d, x, y, err := elliptic.GenerateKey(c.Curve, rand) @@ -99,6 +108,9 @@ func (c *genericCurve) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSe func (c *genericCurve) Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) { x, y := elliptic.Unmarshal(c.Curve, ephemeral) + if x == nil { + return nil, errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", c.Curve.Params().Name)) + } zbBig, _ := c.Curve.ScalarMult(x, y, secret) byteLen := (c.Curve.Params().BitSize + 7) >> 3 zb := make([]byte, byteLen) diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go index 77213f66be..5d0214a348 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go @@ -21,7 +21,10 @@ import ( "github.com/ProtonMail/go-crypto/openpgp/errors" "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" "github.com/ProtonMail/go-crypto/openpgp/internal/ecc" + "github.com/ProtonMail/go-crypto/openpgp/mldsa_eddsa" + "github.com/ProtonMail/go-crypto/openpgp/mlkem_ecdh" "github.com/ProtonMail/go-crypto/openpgp/packet" + "github.com/ProtonMail/go-crypto/openpgp/slhdsa" "github.com/ProtonMail/go-crypto/openpgp/x25519" "github.com/ProtonMail/go-crypto/openpgp/x448" ) @@ -279,7 +282,7 @@ func newSigner(config *packet.Config) (signer interface{}, err error) { config.RSAPrimes = config.RSAPrimes[2:] return generateRSAKeyWithPrimes(config.Random(), 2, bits, primes) } - return rsa.GenerateKey(config.Random(), bits) + return generateRSAKey(config.Random(), bits) case packet.PubKeyAlgoEdDSA: if config.V6() { // Implementations MUST NOT accept or generate v6 key material @@ -319,6 +322,32 @@ func newSigner(config *packet.Config) (signer interface{}, err error) { return nil, err } return priv, nil + case packet.PubKeyAlgoMldsa65Ed25519, packet.PubKeyAlgoMldsa87Ed448: + if !config.V6() { + return nil, goerrors.New("openpgp: cannot create a non-v6 mldsa_eddsa key") + } + + c, err := packet.GetEdDSACurveFromAlgID(config.PublicKeyAlgorithm()) + if err != nil { + return nil, err + } + d, err := packet.GetMldsaFromAlgID(config.PublicKeyAlgorithm()) + if err != nil { + return nil, err + } + + return mldsa_eddsa.GenerateKey(config.Random(), uint8(config.PublicKeyAlgorithm()), c, d) + case packet.PubKeyAlgoSlhdsaShake128s, packet.PubKeyAlgoSlhdsaShake128f, packet.PubKeyAlgoSlhdsaShake256s: + if !config.V6() { + return nil, goerrors.New("openpgp: cannot create a non-v6 SLH-DSH key") + } + + scheme, err := packet.GetSlhdsaSchemeFromAlgID(config.PublicKeyAlgorithm()) + if err != nil { + return nil, err + } + + return slhdsa.GenerateKey(config.Random(), uint8(config.PublicKeyAlgorithm()), scheme) default: return nil, errors.InvalidArgumentError("unsupported public key algorithm") } @@ -326,7 +355,8 @@ func newSigner(config *packet.Config) (signer interface{}, err error) { // Generates an encryption/decryption key func newDecrypter(config *packet.Config) (decrypter interface{}, err error) { - switch config.PublicKeyAlgorithm() { + pubKeyAlgo := config.PublicKeyAlgorithm() + switch pubKeyAlgo { case packet.PubKeyAlgoRSA: bits := config.RSAModulusBits() if bits < 1024 { @@ -337,7 +367,7 @@ func newDecrypter(config *packet.Config) (decrypter interface{}, err error) { config.RSAPrimes = config.RSAPrimes[2:] return generateRSAKeyWithPrimes(config.Random(), 2, bits, primes) } - return rsa.GenerateKey(config.Random(), bits) + return generateRSAKey(config.Random(), bits) case packet.PubKeyAlgoEdDSA, packet.PubKeyAlgoECDSA: fallthrough // When passing EdDSA or ECDSA, we generate an ECDH subkey case packet.PubKeyAlgoECDH: @@ -361,6 +391,27 @@ func newDecrypter(config *packet.Config) (decrypter interface{}, err error) { return x25519.GenerateKey(config.Random()) case packet.PubKeyAlgoEd448, packet.PubKeyAlgoX448: // When passing Ed448, we generate an x448 subkey return x448.GenerateKey(config.Random()) + case packet.PubKeyAlgoMldsa65Ed25519, packet.PubKeyAlgoMldsa87Ed448, + packet.PubKeyAlgoSlhdsaShake128s, packet.PubKeyAlgoSlhdsaShake128f, packet.PubKeyAlgoSlhdsaShake256s: + if pubKeyAlgo, err = packet.GetMatchingMlkem(config.PublicKeyAlgorithm()); err != nil { + return nil, err + } + fallthrough // When passing ML-DSA + EdDSA or ECDSA, we generate a ML-KEM + ECDH subkey + case packet.PubKeyAlgoMlkem768X25519, packet.PubKeyAlgoMlkem1024X448: + if !config.V6() && pubKeyAlgo == packet.PubKeyAlgoMlkem1024X448 { + return nil, goerrors.New("openpgp: cannot create a non-v6 mlkem1024_x448 key") + } + + c, err := packet.GetECDHCurveFromAlgID(pubKeyAlgo) + if err != nil { + return nil, err + } + k, err := packet.GetMlkemFromAlgID(pubKeyAlgo) + if err != nil { + return nil, err + } + + return mlkem_ecdh.GenerateKey(config.Random(), uint8(pubKeyAlgo), c, k) default: return nil, errors.InvalidArgumentError("unsupported public key algorithm") } @@ -368,6 +419,29 @@ func newDecrypter(config *packet.Config) (decrypter interface{}, err error) { var bigOne = big.NewInt(1) +// generateRSAKey generates an RSA keypair and ensures that p < q as required by RFC 9580. +func generateRSAKey(random io.Reader, bits int) (*rsa.PrivateKey, error) { + key, err := rsa.GenerateKey(random, bits) + if err != nil { + return nil, err + } + enforceRSAPrimeOrder(key) + return key, nil +} + +// enforceRSAPrimeOrder ensures p < q, as required by RFC 9580 section 5.5.5.1 +// for RSA keys. The OpenPGP serialization writes Primes[1] as p and Primes[0] +// as q (so that Go's Qinv is u = p^-1 mod q), hence we need +// Primes[1] < Primes[0]. The Go standard library does not guarantee this, so we +// swap if needed and recompute the precomputed values. +func enforceRSAPrimeOrder(key *rsa.PrivateKey) { + if len(key.Primes) == 2 && key.Primes[0].Cmp(key.Primes[1]) < 0 { + key.Primes[0], key.Primes[1] = key.Primes[1], key.Primes[0] + key.Precomputed = rsa.PrecomputedValues{} + key.Precompute() + } +} + // generateRSAKeyWithPrimes generates a multi-prime RSA keypair of the // given bit size, using the given random source and pre-populated primes. func generateRSAKeyWithPrimes(random io.Reader, nprimes int, bits int, prepopulatedPrimes []*big.Int) (*rsa.PrivateKey, error) { @@ -451,6 +525,12 @@ NextSetOfPrimes: } } + // RFC 9580 section 5.5.5.1 requires p < q for RSA keys. + // Primes[1] is serialized as p and Primes[0] as q. + if len(priv.Primes) == 2 && priv.Primes[0].Cmp(priv.Primes[1]) < 0 { + priv.Primes[0], priv.Primes[1] = priv.Primes[1], priv.Primes[0] + } + priv.Precompute() return priv, nil } diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go index a071353e2e..d9d3927ec5 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go @@ -106,6 +106,10 @@ func shouldPreferIdentity(existingId, potentialNewId *Identity) bool { return true } + if potentialNewId.SelfSignature == nil { + return false + } + if existingId.SelfSignature.IsPrimaryId != nil && *existingId.SelfSignature.IsPrimaryId && !(potentialNewId.SelfSignature.IsPrimaryId != nil && *potentialNewId.SelfSignature.IsPrimaryId) { return false @@ -142,7 +146,9 @@ func (e *Entity) EncryptionKey(now time.Time) (Key, bool) { !subkey.PublicKey.KeyExpired(subkey.Sig, now) && !subkey.Sig.SigExpired(now) && !subkey.Revoked(now) && - (maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) { + (maxTime.IsZero() || + subkey.Sig.CreationTime.After(maxTime) || + (subkey.Sig.CreationTime.Equal(maxTime) && subkey.IsPQ())) { candidateSubkey = i maxTime = subkey.Sig.CreationTime } @@ -209,7 +215,9 @@ func (e *Entity) signingKeyByIdUsage(now time.Time, id uint64, flags int) (Key, !subkey.PublicKey.KeyExpired(subkey.Sig, now) && !subkey.Sig.SigExpired(now) && !subkey.Revoked(now) && - (maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) && + (maxTime.IsZero() || + subkey.Sig.CreationTime.After(maxTime) || + (subkey.Sig.CreationTime.Equal(maxTime) && subkey.IsPQ())) && (id == 0 || subkey.PublicKey.KeyId == id) { candidateSubkey = idx maxTime = subkey.Sig.CreationTime @@ -305,6 +313,11 @@ func (s *Subkey) Revoked(now time.Time) bool { return revoked(s.Revocations, now) } +// IsPQ returns true if the algorithm is Post-Quantum safe. +func (s *Subkey) IsPQ() bool { + return s.PublicKey.IsPQ() +} + // Revoked returns whether the key or subkey has been revoked by a self-signature. // Note that third-party revocation signatures are not supported. // Note also that Identity revocation should be checked separately. diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/mldsa_eddsa/mldsa_eddsa.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/mldsa_eddsa/mldsa_eddsa.go new file mode 100644 index 0000000000..9ff4bbe036 --- /dev/null +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/mldsa_eddsa/mldsa_eddsa.go @@ -0,0 +1,119 @@ +// Package mldsa_eddsa implements hybrid ML-DSA + EdDSA encryption for OpenPGP, +// according to https://www.rfc-editor.org/rfc/rfc9980.html#name-composite-signature-schemes. +package mldsa_eddsa + +import ( + goerrors "errors" + "io" + + "github.com/ProtonMail/go-crypto/openpgp/errors" + "github.com/ProtonMail/go-crypto/openpgp/internal/ecc" + "github.com/cloudflare/circl/sign" + "github.com/cloudflare/circl/sign/mldsa/mldsa65" + "github.com/cloudflare/circl/sign/mldsa/mldsa87" +) + +const ( + MlDsaSeedLen = 32 +) + +type PublicKey struct { + AlgId uint8 + Curve ecc.EdDSACurve + Mldsa sign.Scheme + PublicPoint []byte + PublicMldsa sign.PublicKey +} + +type PrivateKey struct { + PublicKey + SecretEc []byte + SecretMldsa sign.PrivateKey + SecretMldsaSeed []byte +} + +// GenerateKey generates a ML-DSA + EdDSA composite key as specified in +// https://www.rfc-editor.org/rfc/rfc9980.html#name-key-generation-procedure-2 +func GenerateKey(rand io.Reader, algId uint8, c ecc.EdDSACurve, d sign.Scheme) (priv *PrivateKey, err error) { + priv = new(PrivateKey) + + priv.PublicKey.AlgId = algId + priv.PublicKey.Curve = c + priv.PublicKey.Mldsa = d + + priv.PublicKey.PublicPoint, priv.SecretEc, err = c.GenerateEdDSA(rand) + if err != nil { + return nil, err + } + + keySeed := make([]byte, d.SeedSize()) + if _, err = rand.Read(keySeed); err != nil { + return nil, err + } + + if err := priv.DeriveMlDsaKeys(keySeed, true); err != nil { + return nil, err + } + return priv, nil +} + +// DeriveMlDsaKeys derives the ML-DSA keys from the provided seed and stores them inside priv. +func (priv *PrivateKey) DeriveMlDsaKeys(seed []byte, overridePublicKey bool) (err error) { + if len(seed) != MlDsaSeedLen { + return goerrors.New("mldsa_eddsa: ml-dsa secret seed has the wrong length") + } + priv.SecretMldsaSeed = seed + publicKey, privateKey := priv.PublicKey.Mldsa.DeriveKey(priv.SecretMldsaSeed) + if overridePublicKey { + priv.PublicKey.PublicMldsa = publicKey + } + priv.SecretMldsa = privateKey + return nil +} + +// Sign generates a ML-DSA + EdDSA composite signature as specified in +// https://www.rfc-editor.org/rfc/rfc9980.html#name-signature-generation +func Sign(priv *PrivateKey, message []byte) (mldsaSig, ecSig []byte, err error) { + ecSig, err = priv.PublicKey.Curve.Sign(priv.PublicKey.PublicPoint, priv.SecretEc, message) + if err != nil { + return nil, nil, err + } + + // The default signer interface does not use the hedged variant. + // Thus, we need to use the low level api + switch key := priv.SecretMldsa.(type) { + case *mldsa65.PrivateKey: + mldsaSig = make([]byte, mldsa65.SignatureSize) + err = mldsa65.SignTo(key, message, nil, true, mldsaSig) + case *mldsa87.PrivateKey: + mldsaSig = make([]byte, mldsa87.SignatureSize) + err = mldsa87.SignTo(key, message, nil, true, mldsaSig) + default: + err = goerrors.New("mldsa_eddsa: unsupported ML-DSA private key type") + } + + if err != nil { + return nil, nil, err + } + + return mldsaSig, ecSig, nil +} + +// Verify verifies a ML-DSA + EdDSA composite signature as specified in +// https://www.rfc-editor.org/rfc/rfc9980.html#name-signature-verification +func Verify(pub *PublicKey, message, dSig, ecSig []byte) bool { + return pub.Curve.Verify(pub.PublicPoint, message, ecSig) && pub.Mldsa.Verify(pub.PublicMldsa, message, dSig, nil) +} + +// Validate checks that the public key corresponds to the private key +func Validate(priv *PrivateKey) (err error) { + if err = priv.PublicKey.Curve.ValidateEdDSA(priv.PublicKey.PublicPoint, priv.SecretEc); err != nil { + return err + } + + if !priv.PublicMldsa.Equal(priv.SecretMldsa.Public()) { + return errors.KeyInvalidError("mldsa_eddsa: invalid public key") + } + + return nil +} diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/mlkem_ecdh/mlkem_ecdh.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/mlkem_ecdh/mlkem_ecdh.go new file mode 100644 index 0000000000..e47d7314ea --- /dev/null +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/mlkem_ecdh/mlkem_ecdh.go @@ -0,0 +1,258 @@ +// Package mlkem_ecdh implements hybrid ML-KEM + ECDH encryption, suitable for OpenPGP, experimental. +// It follows the spec https://www.rfc-editor.org/rfc/rfc9980.html#name-composite-kem-schemes +package mlkem_ecdh + +import ( + goerrors "errors" + "fmt" + "io" + + "golang.org/x/crypto/sha3" + + "github.com/ProtonMail/go-crypto/openpgp/aes/keywrap" + "github.com/ProtonMail/go-crypto/openpgp/errors" + "github.com/ProtonMail/go-crypto/openpgp/internal/ecc" + "github.com/cloudflare/circl/kem" +) + +const ( + maxSessionKeyLength = 64 + MlKemSeedLen = 64 + domSep = "OpenPGPCompositeKDFv1" +) + +type PublicKey struct { + AlgId uint8 + Curve ecc.ECDHCurve + Mlkem kem.Scheme + PublicMlkem kem.PublicKey + PublicPoint []byte +} + +type PrivateKey struct { + PublicKey + SecretEc []byte + SecretMlkem kem.PrivateKey + SecretMlkemSeed []byte +} + +// GenerateKey implements ML-KEM + ECC key generation as specified in +// https://www.rfc-editor.org/rfc/rfc9980.html#name-key-generation-procedure +func GenerateKey(rand io.Reader, algId uint8, c ecc.ECDHCurve, k kem.Scheme) (priv *PrivateKey, err error) { + priv = new(PrivateKey) + + priv.PublicKey.AlgId = algId + priv.PublicKey.Curve = c + priv.PublicKey.Mlkem = k + + priv.PublicKey.PublicPoint, priv.SecretEc, err = c.GenerateECDH(rand) + if err != nil { + return nil, err + } + + seed, err := generateRandomSeed(rand, MlKemSeedLen) + if err != nil { + return nil, err + } + + if err := priv.DeriveMlKemKeys(seed, true); err != nil { + return nil, err + } + return priv, nil +} + +// DeriveMlKemKeys derives the ML-KEM keys from the provided seed and stores them inside priv. +func (priv *PrivateKey) DeriveMlKemKeys(seed []byte, overridePublicKey bool) (err error) { + if len(seed) != MlKemSeedLen { + return goerrors.New("mlkem_ecdh: ml-kem secret seed has the wrong length") + } + priv.SecretMlkemSeed = seed + publicKey, privateKey := priv.PublicKey.Mlkem.DeriveKeyPair(priv.SecretMlkemSeed) + if overridePublicKey { + priv.PublicKey.PublicMlkem = publicKey + } + priv.SecretMlkem = privateKey + return nil +} + +// Encrypt implements ML-KEM + ECC encryption as specified in +// https://www.rfc-editor.org/rfc/rfc9980.html#name-encryption-procedure +func Encrypt(rand io.Reader, pub *PublicKey, msg []byte) (kEphemeral, ecEphemeral, ciphertext []byte, err error) { + if len(msg) > maxSessionKeyLength { + return nil, nil, nil, goerrors.New("mlkem_ecdh: session key too long") + } + + if len(msg)%8 != 0 { + return nil, nil, nil, goerrors.New("mlkem_ecdh: session key not a multiple of 8") + } + + // EC shared secret derivation + ecEphemeral, ecSS, err := pub.Curve.Encaps(rand, pub.PublicPoint) + if err != nil { + return nil, nil, nil, err + } + + // ML-KEM shared secret derivation + kyberSeed, err := generateRandomSeed(rand, pub.Mlkem.EncapsulationSeedSize()) + if err != nil { + return nil, nil, nil, err + } + + kEphemeral, kSS, err := pub.Mlkem.EncapsulateDeterministically(pub.PublicMlkem, kyberSeed) + if err != nil { + return nil, nil, nil, err + } + + keyEncryptionKey, err := buildKey(pub, ecSS, ecEphemeral, pub.PublicPoint, kSS) + if err != nil { + return nil, nil, nil, err + } + + if ciphertext, err = keywrap.Wrap(keyEncryptionKey, msg); err != nil { + return nil, nil, nil, err + } + + return kEphemeral, ecEphemeral, ciphertext, nil +} + +// Decrypt implements ML-KEM + ECC decryption as specified in +// https://www.rfc-editor.org/rfc/rfc9980.html#name-decryption-procedure +func Decrypt(priv *PrivateKey, kEphemeral, ecEphemeral, ciphertext []byte) (msg []byte, err error) { + // EC shared secret derivation + ecSS, err := priv.PublicKey.Curve.Decaps(ecEphemeral, priv.SecretEc) + if err != nil { + return nil, err + } + + // ML-KEM shared secret derivation + kSS, err := priv.PublicKey.Mlkem.Decapsulate(priv.SecretMlkem, kEphemeral) + if err != nil { + return nil, err + } + + kek, err := buildKey(&priv.PublicKey, ecSS, ecEphemeral, priv.PublicPoint, kSS) + if err != nil { + return nil, err + } + + return keywrap.Unwrap(kek, ciphertext) +} + +// buildKey implements the composite KDF from +// https://www.rfc-editor.org/rfc/rfc9980.html#name-key-combiner +func buildKey(pub *PublicKey, eccSecretPoint, eccCipherText, eccPublicKey, mlkemKeyShare []byte) ([]byte, error) { + /// Set the output `ecdhKeyShare` to `eccSecretPoint` + eccKeyShare := eccSecretPoint + + // mlkemKeyShare - the ML-KEM key share encoded as an octet string + // algId - the OpenPGP algorithm ID of the public-key encryption algorithm + // eccKeyShare - the ECDH key share encoded as an octet string + // eccCipherText - the ECDH ciphertext encoded as an octet string + // eccPublicKey - The ECDH public key of the recipient as an octet string + + // SHA3-256(mlkemKeyShare || eccKeyShare || eccCipherText || eccPublicKey || + // algId || "OpenPGPCompositeKDFv1" || len("OpenPGPCompositeKDFv1")) + h := sha3.New256() + _, _ = h.Write(mlkemKeyShare) + _, _ = h.Write(eccKeyShare) + _, _ = h.Write(eccCipherText) + _, _ = h.Write(eccPublicKey) + _, _ = h.Write([]byte{pub.AlgId}) + _, _ = h.Write([]byte(domSep)) + _, _ = h.Write([]byte{byte(len(domSep))}) + return h.Sum(nil), nil +} + +// Validate checks that the public key corresponds to the private key +func Validate(priv *PrivateKey) (err error) { + if err = priv.PublicKey.Curve.ValidateECDH(priv.PublicKey.PublicPoint, priv.SecretEc); err != nil { + return err + } + + if !priv.PublicKey.PublicMlkem.Equal(priv.SecretMlkem.Public()) { + return errors.KeyInvalidError("mlkem_ecdh: invalid public key") + } + + return +} + +// EncodeFields encodes an ML-KEM + ECDH session key encryption fields as +// ephemeral ECDH public key | ML-KEM ciphertext | follow byte length | cipherFunction (v3 only) | encryptedSessionKey +// and writes it to writer. +func EncodeFields(w io.Writer, ec, ml, encryptedSessionKey []byte, cipherFunction byte, v6 bool) (err error) { + if _, err = w.Write(ec); err != nil { + return err + } + + if _, err = w.Write(ml); err != nil { + return err + } + + lenAlgorithm := 0 + if !v6 { + lenAlgorithm = 1 + } + + if _, err = w.Write([]byte{byte(len(encryptedSessionKey) + lenAlgorithm)}); err != nil { + return err + } + + if !v6 { + if _, err = w.Write([]byte{cipherFunction}); err != nil { + return err + } + } + + if _, err = w.Write(encryptedSessionKey); err != nil { + return err + } + + return nil +} + +// DecodeFields decodes an ML-KEM + ECDH session key encryption fields as +// ephemeral ECDH public key | ML-KEM ciphertext | follow byte length | cipherFunction (v3 only) | encryptedSessionKey. +func DecodeFields(r io.Reader, lenEcc, lenMlkem int, v6 bool) (ephemeralPublicEcc, ephemeralPublicMlKem, encryptedSessionKey []byte, cipherFunction byte, err error) { + var buf [1]byte + + ephemeralPublicEcc = make([]byte, lenEcc) + if _, err = io.ReadFull(r, ephemeralPublicEcc); err != nil { + return + } + + ephemeralPublicMlKem = make([]byte, lenMlkem) + if _, err = io.ReadFull(r, ephemeralPublicMlKem); err != nil { + return + } + + // A one-octet size of the following fields. + if _, err = io.ReadFull(r, buf[:]); err != nil { + return + } + + followingLen := buf[0] + // The one-octet algorithm identifier, if it was passed (in the case of a v3 PKESK packet). + if !v6 { + if _, err = io.ReadFull(r, buf[:]); err != nil { + return + } + cipherFunction = buf[0] + followingLen -= 1 + } + + // The encrypted session key. + encryptedSessionKey = make([]byte, followingLen) + if _, err = io.ReadFull(r, encryptedSessionKey); err != nil { + return + } + + return +} + +func generateRandomSeed(rand io.Reader, size int) ([]byte, error) { + randomBytes := make([]byte, size) + if _, err := rand.Read(randomBytes); err != nil { + return nil, fmt.Errorf("failed to generate random bytes: %w", err) + } + return randomBytes, nil +} diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_config.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_config.go index fec41a0e73..ef100d372b 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_config.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_config.go @@ -37,7 +37,7 @@ func (conf *AEADConfig) Mode() AEADMode { // ChunkSizeByte returns the byte indicating the chunk size. The effective // chunk size is computed with the formula uint64(1) << (chunkSizeByte + 6) -// limit to 16 = 4 MiB +// limit chunkSizeByte to 16 which equals to 2^22 = 4 MiB // https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-5.13.2 func (conf *AEADConfig) ChunkSizeByte() byte { if conf == nil || conf.ChunkSize == 0 { @@ -49,8 +49,8 @@ func (conf *AEADConfig) ChunkSizeByte() byte { switch { case exponent < 6: exponent = 6 - case exponent > 16: - exponent = 16 + case exponent > 22: + exponent = 22 } return byte(exponent - 6) diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_encrypted.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_encrypted.go index 583765d87c..b11798bc58 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_encrypted.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_encrypted.go @@ -4,6 +4,7 @@ package packet import ( "io" + "strconv" "github.com/ProtonMail/go-crypto/openpgp/errors" "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" @@ -50,6 +51,9 @@ func (ae *AEADEncrypted) parse(buf io.Reader) error { ae.cipher = CipherFunction(c) ae.mode = mode ae.chunkSizeByte = headerData[3] + if ae.chunkSizeByte > 16 { + return errors.UnsupportedError("invalid aead chunk size byte: " + strconv.Itoa(int(ae.chunkSizeByte))) + } return nil } @@ -62,8 +66,15 @@ func (ae *AEADEncrypted) Decrypt(ciph CipherFunction, key []byte) (io.ReadCloser // decrypt prepares an aeadCrypter and returns a ReadCloser from which // decrypted bytes can be read (see aeadDecrypter.Read()). func (ae *AEADEncrypted) decrypt(key []byte) (io.ReadCloser, error) { + if ae.cipher.KeySize() != len(key) { + return nil, errors.StructuralError("invalid session key length for cipher: got " + strconv.Itoa(len(key)) + " bytes, but expected " + strconv.Itoa(ae.cipher.KeySize()) + " bytes") + } blockCipher := ae.cipher.new(key) - aead := ae.mode.new(blockCipher) + aead, err := ae.mode.new(blockCipher) + if err != nil { + return nil, err + } + // Carry the first tagLen bytes chunkSize := decodeAEADChunkSize(ae.chunkSizeByte) tagLen := ae.mode.TagLength() diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go index 0bcb38caca..931f55a4e8 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go @@ -98,6 +98,16 @@ func (c *Compressed) parse(r io.Reader) error { return err } +// LimitedBodyReader wraps the provided body reader with a limiter that restricts +// the number of bytes read to the specified limit. +// If limit is nil, the reader is unbounded. +func (c *Compressed) LimitedBodyReader(limit *int64) io.Reader { + if limit == nil { + return c.Body + } + return &LimitReader{R: c.Body, N: *limit} +} + // compressedWriterCloser represents the serialized compression stream // header and the compressor. Its Close() method ensures that both the // compressor and serialized stream header are closed. Its Write() @@ -159,3 +169,24 @@ func SerializeCompressed(w io.WriteCloser, algo CompressionAlgo, cc *Compression return } + +// LimitReader is an io.Reader that fails with MessageToLarge if read bytes exceed N. +type LimitReader struct { + R io.Reader // underlying reader + N int64 // max bytes allowed +} + +func (l *LimitReader) Read(p []byte) (int, error) { + if l.N <= 0 { + return 0, errors.ErrMessageTooLarge + } + + n, err := l.R.Read(p) + l.N -= int64(n) + + if err == nil && l.N <= 0 { + err = errors.ErrMessageTooLarge + } + + return n, err +} diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go index 257398d9dd..c063753762 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go @@ -47,6 +47,8 @@ var V5Disabled = false type Config struct { // Rand provides the source of entropy. // If nil, the crypto/rand Reader is used. + // Since Go 1.26, standard library calls (e.g., key generation) ignore Rand + // unless GODEBUG=cryptocustomrand=1 is set. Rand io.Reader // DefaultHash is the default hash function to be used. // If zero, SHA-256 is used. @@ -178,6 +180,23 @@ type Config struct { // When set to true, a key without flags is treated as if all flags are enabled. // This behavior is consistent with GPG. InsecureAllowAllKeyFlagsWhenMissing bool + // InsecureGenerateNonCriticalKeyFlags causes the "Key Flags" signature subpacket + // to be non-critical in newly generated signatures. + // This may be needed for keys to be accepted by older clients who do not recognize + // the subpacket. + // For example, rpm 4.14.3-150400.59.3.1 in OpenSUSE Leap 15.4 does not recognize it. + InsecureGenerateNonCriticalKeyFlags bool + // InsecureGenerateNonCriticalSignatureCreationTime causes the "Signature Creation Time" signature subpacket + // to be non-critical in newly generated signatures. + // This may be needed for keys to be accepted by older clients who do not recognize + // the subpacket. + // For example, yum 3.4.3-168 in CentOS 7 and yum 3.4.3-158 in Amazon Linux 2 do not recognize it. + InsecureGenerateNonCriticalSignatureCreationTime bool + + // MaxDecompressedMessageSize specifies the maximum number of bytes that can be + // read from a compressed packet. This serves as an upper limit to prevent + // excessively large decompressed messages. + MaxDecompressedMessageSize *int64 } func (c *Config) Random() io.Reader { @@ -415,6 +434,27 @@ func (c *Config) AllowAllKeyFlagsWhenMissing() bool { return c.InsecureAllowAllKeyFlagsWhenMissing } +func (c *Config) GenerateNonCriticalKeyFlags() bool { + if c == nil { + return false + } + return c.InsecureGenerateNonCriticalKeyFlags +} + +func (c *Config) GenerateNonCriticalSignatureCreationTime() bool { + if c == nil { + return false + } + return c.InsecureGenerateNonCriticalSignatureCreationTime +} + +func (c *Config) DecompressedMessageSizeLimit() *int64 { + if c == nil { + return nil + } + return c.MaxDecompressedMessageSize +} + // BoolPointer is a helper function to set a boolean pointer in the Config. // e.g., config.CheckPacketSequence = BoolPointer(true) func BoolPointer(value bool) *bool { diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go index b90bb28911..a98711fb2a 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go @@ -18,6 +18,7 @@ import ( "github.com/ProtonMail/go-crypto/openpgp/elgamal" "github.com/ProtonMail/go-crypto/openpgp/errors" "github.com/ProtonMail/go-crypto/openpgp/internal/encoding" + "github.com/ProtonMail/go-crypto/openpgp/mlkem_ecdh" "github.com/ProtonMail/go-crypto/openpgp/x25519" "github.com/ProtonMail/go-crypto/openpgp/x448" ) @@ -33,10 +34,11 @@ type EncryptedKey struct { CipherFunc CipherFunction // only valid after a successful Decrypt for a v3 packet Key []byte // only valid after a successful Decrypt - encryptedMPI1, encryptedMPI2 encoding.Field - ephemeralPublicX25519 *x25519.PublicKey // used for x25519 - ephemeralPublicX448 *x448.PublicKey // used for x448 - encryptedSession []byte // used for x25519 and x448 + encryptedMPI1 encoding.Field // used for RSA, Elgamal and ECDH + encryptedMPI2 encoding.Field // used for Elgamal and ECDH + ephemeralPublicEcc []byte // used for X25519, X448 and ML-KEM + ephemeralPublicMlKem []byte // used for ML-KEM + encryptedSession []byte // used for X25519, X448 and ML-KEM } func (e *EncryptedKey) parse(r io.Reader) (err error) { @@ -124,21 +126,29 @@ func (e *EncryptedKey) parse(r io.Reader) (err error) { return } case PubKeyAlgoX25519: - e.ephemeralPublicX25519, e.encryptedSession, cipherFunction, err = x25519.DecodeFields(r, e.Version == 6) + e.ephemeralPublicEcc, e.encryptedSession, cipherFunction, err = x25519.DecodeFields(r, e.Version == 6) if err != nil { return } case PubKeyAlgoX448: - e.ephemeralPublicX448, e.encryptedSession, cipherFunction, err = x448.DecodeFields(r, e.Version == 6) + e.ephemeralPublicEcc, e.encryptedSession, cipherFunction, err = x448.DecodeFields(r, e.Version == 6) if err != nil { return } + case PubKeyAlgoMlkem768X25519: + if e.ephemeralPublicEcc, e.ephemeralPublicMlKem, e.encryptedSession, cipherFunction, err = mlkem_ecdh.DecodeFields(r, 32, 1088, e.Version == 6); err != nil { + return err + } + case PubKeyAlgoMlkem1024X448: + if e.ephemeralPublicEcc, e.ephemeralPublicMlKem, e.encryptedSession, cipherFunction, err = mlkem_ecdh.DecodeFields(r, 56, 1568, e.Version == 6); err != nil { + return err + } } if e.Version < 6 { switch e.Algo { - case PubKeyAlgoX25519, PubKeyAlgoX448: + case PubKeyAlgoX25519, PubKeyAlgoX448, PubKeyAlgoMlkem768X25519, PubKeyAlgoMlkem1024X448: e.CipherFunc = CipherFunction(cipherFunction) - // Check for validiy is in the Decrypt method + // Check for validity is in the Decrypt method } } @@ -188,9 +198,11 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { } b, err = ecdh.Decrypt(priv.PrivateKey.(*ecdh.PrivateKey), vsG, m, oid, fp) case PubKeyAlgoX25519: - b, err = x25519.Decrypt(priv.PrivateKey.(*x25519.PrivateKey), e.ephemeralPublicX25519, e.encryptedSession) + b, err = x25519.Decrypt(priv.PrivateKey.(*x25519.PrivateKey), e.ephemeralPublicEcc, e.encryptedSession) case PubKeyAlgoX448: - b, err = x448.Decrypt(priv.PrivateKey.(*x448.PrivateKey), e.ephemeralPublicX448, e.encryptedSession) + b, err = x448.Decrypt(priv.PrivateKey.(*x448.PrivateKey), e.ephemeralPublicEcc, e.encryptedSession) + case PubKeyAlgoMlkem768X25519, PubKeyAlgoMlkem1024X448: + b, err = mlkem_ecdh.Decrypt(priv.PrivateKey.(*mlkem_ecdh.PrivateKey), e.ephemeralPublicMlKem, e.ephemeralPublicEcc, e.encryptedSession) default: err = errors.InvalidArgumentError("cannot decrypt encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo))) } @@ -203,6 +215,9 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH: keyOffset := 0 if e.Version < 6 { + if len(b) == 0 { + return errors.StructuralError("truncated session key") + } e.CipherFunc = CipherFunction(b[0]) keyOffset = 1 if !e.CipherFunc.IsSupported() { @@ -210,22 +225,22 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { } } key, err = decodeChecksumKey(b[keyOffset:]) - if err != nil { - return err - } - case PubKeyAlgoX25519, PubKeyAlgoX448: + case PubKeyAlgoX25519, PubKeyAlgoX448, PubKeyAlgoMlkem768X25519, PubKeyAlgoMlkem1024X448: if e.Version < 6 { switch e.CipherFunc { case CipherAES128, CipherAES192, CipherAES256: break default: - return errors.StructuralError("v3 PKESK mandates AES as cipher function for x25519 and x448") + return errors.StructuralError("v3 PKESK mandates AES as cipher function for x25519, x448, and PQC") } } key = b[:] default: return errors.UnsupportedError("unsupported algorithm for decryption") } + if err != nil { + return err + } e.Key = key return nil } @@ -244,6 +259,11 @@ func (e *EncryptedKey) Serialize(w io.Writer) error { encodedLength = x25519.EncodedFieldsLength(e.encryptedSession, e.Version == 6) case PubKeyAlgoX448: encodedLength = x448.EncodedFieldsLength(e.encryptedSession, e.Version == 6) + case PubKeyAlgoMlkem768X25519, PubKeyAlgoMlkem1024X448: + encodedLength = len(e.ephemeralPublicEcc) + len(e.ephemeralPublicMlKem) + len(e.encryptedSession) + 1 + if e.Version < 6 { + encodedLength += 1 + } default: return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo))) } @@ -309,10 +329,13 @@ func (e *EncryptedKey) Serialize(w io.Writer) error { _, err := w.Write(e.encryptedMPI2.EncodedBytes()) return err case PubKeyAlgoX25519: - err := x25519.EncodeFields(w, e.ephemeralPublicX25519, e.encryptedSession, byte(e.CipherFunc), e.Version == 6) + err := x25519.EncodeFields(w, e.ephemeralPublicEcc, e.encryptedSession, byte(e.CipherFunc), e.Version == 6) return err case PubKeyAlgoX448: - err := x448.EncodeFields(w, e.ephemeralPublicX448, e.encryptedSession, byte(e.CipherFunc), e.Version == 6) + err := x448.EncodeFields(w, e.ephemeralPublicEcc, e.encryptedSession, byte(e.CipherFunc), e.Version == 6) + return err + case PubKeyAlgoMlkem768X25519, PubKeyAlgoMlkem1024X448: + err := mlkem_ecdh.EncodeFields(w, e.ephemeralPublicEcc, e.ephemeralPublicMlKem, e.encryptedSession, byte(e.CipherFunc), e.Version == 6) return err default: panic("internal error") @@ -346,13 +369,13 @@ func SerializeEncryptedKeyAEADwithHiddenOption(w io.Writer, pub *PublicKey, ciph if version == 6 && pub.PubKeyAlgo == PubKeyAlgoElGamal { return errors.InvalidArgumentError("ElGamal v6 PKESK are not allowed") } - // In v3 PKESKs, for x25519 and x448, mandate using AES - if version == 3 && (pub.PubKeyAlgo == PubKeyAlgoX25519 || pub.PubKeyAlgo == PubKeyAlgoX448) { - switch cipherFunc { - case CipherAES128, CipherAES192, CipherAES256: - break + // In v3 PKESKs, for X25519 and X448, mandate using AES + if version == 3 && cipherFunc != CipherAES128 && cipherFunc != CipherAES192 && cipherFunc != CipherAES256 { + switch pub.PubKeyAlgo { + case PubKeyAlgoX25519, PubKeyAlgoX448, PubKeyAlgoMlkem768X25519, PubKeyAlgoMlkem1024X448: + return errors.InvalidArgumentError("v3 PKESK mandates AES for x25519, x448, and PQC") default: - return errors.InvalidArgumentError("v3 PKESK mandates AES for x25519 and x448") + break } } @@ -401,7 +424,7 @@ func SerializeEncryptedKeyAEADwithHiddenOption(w io.Writer, pub *PublicKey, ciph keyOffset = 1 } encodeChecksumKey(keyBlock[keyOffset:], key) - case PubKeyAlgoX25519, PubKeyAlgoX448: + case PubKeyAlgoX25519, PubKeyAlgoX448, PubKeyAlgoMlkem768X25519, PubKeyAlgoMlkem1024X448: // algorithm is added in plaintext below keyBlock = key } @@ -417,6 +440,8 @@ func SerializeEncryptedKeyAEADwithHiddenOption(w io.Writer, pub *PublicKey, ciph return serializeEncryptedKeyX25519(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*x25519.PublicKey), keyBlock, byte(cipherFunc), version) case PubKeyAlgoX448: return serializeEncryptedKeyX448(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*x448.PublicKey), keyBlock, byte(cipherFunc), version) + case PubKeyAlgoMlkem768X25519, PubKeyAlgoMlkem1024X448: + return serializeEncryptedKeyMlkem(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*mlkem_ecdh.PublicKey), keyBlock, byte(cipherFunc), version) case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly: return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) } @@ -567,6 +592,9 @@ func checksumKeyMaterial(key []byte) uint16 { } func decodeChecksumKey(msg []byte) (key []byte, err error) { + if len(msg) < 2 { + return nil, errors.StructuralError("truncated session key") + } key = msg[:len(msg)-2] expectedChecksum := uint16(msg[len(msg)-2])<<8 | uint16(msg[len(msg)-1]) checksum := checksumKeyMaterial(key) @@ -582,3 +610,28 @@ func encodeChecksumKey(buffer []byte, key []byte) { buffer[len(key)] = byte(checksum >> 8) buffer[len(key)+1] = byte(checksum) } + +func serializeEncryptedKeyMlkem(w io.Writer, rand io.Reader, header []byte, pub *mlkem_ecdh.PublicKey, keyBlock []byte, cipherFunc byte, version int) error { + mlE, ecE, c, err := mlkem_ecdh.Encrypt(rand, pub, keyBlock) + if err != nil { + return errors.InvalidArgumentError("ML-KEM + ECDH encryption failed: " + err.Error()) + } + + packetLen := len(header) /* header length */ + packetLen += len(ecE) + len(mlE) + len(c) + 1 + if version < 6 { + packetLen += 1 + } + + err = serializeHeader(w, packetTypeEncryptedKey, packetLen) + if err != nil { + return err + } + + _, err = w.Write(header) + if err != nil { + return err + } + + return mlkem_ecdh.EncodeFields(w, ecE, mlE, c, cipherFunc, version == 6) +} diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet.go index 1e92e22c97..e4856b728d 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet.go @@ -26,6 +26,18 @@ func readFull(r io.Reader, buf []byte) (n int, err error) { return } +// readN reads exactly n bytes from r. +func readN(r io.Reader, n uint32) ([]byte, error) { + var buf bytes.Buffer + if _, err := io.CopyN(&buf, r, int64(n)); err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + return nil, err + } + return buf.Bytes(), nil +} + // readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2. func readLength(r io.Reader) (length int64, isPartial bool, err error) { var buf [4]byte @@ -509,13 +521,25 @@ const ( // Deprecated in RFC 4880, Section 13.5. Use key flags instead. PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 + + // PQC DSA algorithms + PubKeyAlgoMldsa65Ed25519 = 30 + PubKeyAlgoMldsa87Ed448 = 31 + PubKeyAlgoSlhdsaShake128s = 32 + PubKeyAlgoSlhdsaShake128f = 33 + PubKeyAlgoSlhdsaShake256s = 34 + + // PQC KEM algorithms + PubKeyAlgoMlkem768X25519 = 35 + PubKeyAlgoMlkem1024X448 = 36 ) // CanEncrypt returns true if it's possible to encrypt a message to a public // key of the given type. func (pka PublicKeyAlgorithm) CanEncrypt() bool { switch pka { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH, PubKeyAlgoX25519, PubKeyAlgoX448: + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH, PubKeyAlgoX25519, PubKeyAlgoX448, + PubKeyAlgoMlkem768X25519, PubKeyAlgoMlkem1024X448: return true } return false @@ -525,7 +549,10 @@ func (pka PublicKeyAlgorithm) CanEncrypt() bool { // sign a message. func (pka PublicKeyAlgorithm) CanSign() bool { switch pka { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA, PubKeyAlgoEd25519, PubKeyAlgoEd448: + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA, + PubKeyAlgoEd25519, PubKeyAlgoEd448, + PubKeyAlgoMldsa65Ed25519, PubKeyAlgoMldsa87Ed448, + PubKeyAlgoSlhdsaShake128s, PubKeyAlgoSlhdsaShake128f, PubKeyAlgoSlhdsaShake256s: return true } return false @@ -611,7 +638,7 @@ func (mode AEADMode) IsSupported() bool { } // new returns a fresh instance of the given mode. -func (mode AEADMode) new(block cipher.Block) cipher.AEAD { +func (mode AEADMode) new(block cipher.Block) (cipher.AEAD, error) { return algorithm.AEADMode(mode).New(block) } diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go index f04e6c6b87..580fe0d3bf 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go @@ -13,6 +13,7 @@ import ( "crypto/sha1" "crypto/sha256" "crypto/subtle" + goerrors "errors" "fmt" "io" "math/big" @@ -27,7 +28,10 @@ import ( "github.com/ProtonMail/go-crypto/openpgp/elgamal" "github.com/ProtonMail/go-crypto/openpgp/errors" "github.com/ProtonMail/go-crypto/openpgp/internal/encoding" + "github.com/ProtonMail/go-crypto/openpgp/mldsa_eddsa" + "github.com/ProtonMail/go-crypto/openpgp/mlkem_ecdh" "github.com/ProtonMail/go-crypto/openpgp/s2k" + "github.com/ProtonMail/go-crypto/openpgp/slhdsa" "github.com/ProtonMail/go-crypto/openpgp/x25519" "github.com/ProtonMail/go-crypto/openpgp/x448" "golang.org/x/crypto/hkdf" @@ -166,6 +170,10 @@ func NewSignerPrivateKey(creationTime time.Time, signer interface{}) *PrivateKey pk.PublicKey = *NewEd448PublicKey(creationTime, &pubkey.PublicKey) case ed448.PrivateKey: pk.PublicKey = *NewEd448PublicKey(creationTime, &pubkey.PublicKey) + case *mldsa_eddsa.PrivateKey: + pk.PublicKey = *NewMldsaEddsaPublicKey(creationTime, &pubkey.PublicKey) + case *slhdsa.PrivateKey: + pk.PublicKey = *NewSlhdsaPublicKey(creationTime, &pubkey.PublicKey) default: panic("openpgp: unknown signer type in NewSignerPrivateKey") } @@ -173,7 +181,7 @@ func NewSignerPrivateKey(creationTime time.Time, signer interface{}) *PrivateKey return pk } -// NewDecrypterPrivateKey creates a PrivateKey from a *{rsa|elgamal|ecdh|x25519|x448}.PrivateKey. +// NewDecrypterPrivateKey creates a PrivateKey from a *{rsa|elgamal|ecdh|x25519|x448|mlkem_ecdh}.PrivateKey. func NewDecrypterPrivateKey(creationTime time.Time, decrypter interface{}) *PrivateKey { pk := new(PrivateKey) switch priv := decrypter.(type) { @@ -187,6 +195,8 @@ func NewDecrypterPrivateKey(creationTime time.Time, decrypter interface{}) *Priv pk.PublicKey = *NewX25519PublicKey(creationTime, &priv.PublicKey) case *x448.PrivateKey: pk.PublicKey = *NewX448PublicKey(creationTime, &priv.PublicKey) + case *mlkem_ecdh.PrivateKey: + pk.PublicKey = *NewMlkemEcdhPublicKey(creationTime, &priv.PublicKey) default: panic("openpgp: unknown decrypter type in NewDecrypterPrivateKey") } @@ -265,6 +275,9 @@ func (pk *PrivateKey) parse(r io.Reader) (err error) { if pk.s2kParams.Dummy() { return } + if !pk.cipher.IsSupported() { + return errors.UnsupportedError("unsupported cipher function in private key") + } if pk.s2kParams.Mode() == s2k.Argon2S2K && pk.s2kType != S2KAEAD { return errors.StructuralError("using Argon2 S2K without AEAD is not allowed") } @@ -300,6 +313,9 @@ func (pk *PrivateKey) parse(r io.Reader) (err error) { return } if v5 && pk.s2kType == S2KAEAD { + if pk.aead.IvLength() > len(pk.iv) { + return errors.StructuralError("invalid aead IV length for v5 private key") + } pk.iv = pk.iv[:pk.aead.IvLength()] } } @@ -530,6 +546,40 @@ func serializeEd448PrivateKey(w io.Writer, priv *ed448.PrivateKey) error { return err } +// serializeMlkemPrivateKey serializes a ML-KEM + ECC private key according to +// https://www.rfc-editor.org/rfc/rfc9980.html#name-key-material-packets +func serializeMlkemPrivateKey(w io.Writer, priv *mlkem_ecdh.PrivateKey) (err error) { + if _, err = w.Write(priv.SecretEc); err != nil { + return err + } + _, err = w.Write(priv.SecretMlkemSeed) + return err +} + +// serializeMldsaEddsaPrivateKey serializes a ML-DSA + EdDSA private key according to +// https://www.rfc-editor.org/rfc/rfc9980.html#name-key-material-packets-2 +func serializeMldsaEddsaPrivateKey(w io.Writer, priv *mldsa_eddsa.PrivateKey) error { + if _, err := w.Write(priv.SecretEc); err != nil { + return err + } + if _, err := w.Write(priv.SecretMldsaSeed); err != nil { + return err + } + return nil +} + +// serializeSlhDsaPrivateKey serializes a SLH-DSA private key. +func serializeSlhDsaPrivateKey(w io.Writer, priv *slhdsa.PrivateKey) error { + marshalledKey, err := priv.SecretSlhdsa.MarshalBinary() + if err != nil { + return err + } + if _, err := w.Write(marshalledKey); err != nil { + return err + } + return nil +} + // decrypt decrypts an encrypted private key using a decryption key. func (pk *PrivateKey) decrypt(decryptionKey []byte) error { if pk.Dummy() { @@ -542,7 +592,10 @@ func (pk *PrivateKey) decrypt(decryptionKey []byte) error { var data []byte switch pk.s2kType { case S2KAEAD: - aead := pk.aead.new(block) + aead, err := pk.aead.new(block) + if err != nil { + return err + } additionalData, err := pk.additionalData() if err != nil { return err @@ -694,7 +747,10 @@ func (pk *PrivateKey) encrypt(key []byte, params *s2k.Params, s2kType S2KType, c if pk.aead == 0 { return errors.StructuralError("aead mode is not set on key") } - aead := pk.aead.new(block) + aead, err := pk.aead.new(block) + if err != nil { + return err + } additionalData, err := pk.additionalData() if err != nil { return err @@ -830,6 +886,12 @@ func (pk *PrivateKey) serializePrivateKey(w io.Writer) (err error) { err = serializeEd25519PrivateKey(w, priv) case *ed448.PrivateKey: err = serializeEd448PrivateKey(w, priv) + case *mlkem_ecdh.PrivateKey: + err = serializeMlkemPrivateKey(w, priv) + case *mldsa_eddsa.PrivateKey: + err = serializeMldsaEddsaPrivateKey(w, priv) + case *slhdsa.PrivateKey: + err = serializeSlhDsaPrivateKey(w, priv) default: err = errors.InvalidArgumentError("unknown private key type") } @@ -858,6 +920,31 @@ func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) { return pk.parseEd25519PrivateKey(data) case PubKeyAlgoEd448: return pk.parseEd448PrivateKey(data) + case PubKeyAlgoMlkem768X25519: + if !(pk.Version == 4 || pk.Version >= 6) { + return goerrors.New("openpgp: ML-KEM-768+X25519 may only be used with v4 or v6+") + } + return pk.parseMlkemEcdhPrivateKey(data, 32, mlkem_ecdh.MlKemSeedLen) + case PubKeyAlgoMlkem1024X448: + if pk.Version < 6 { + return goerrors.New("openpgp: ML-KEM-1024+X448 may only be used with v6+") + } + return pk.parseMlkemEcdhPrivateKey(data, 56, mlkem_ecdh.MlKemSeedLen) + case PubKeyAlgoMldsa65Ed25519: + if pk.Version < 6 { + return goerrors.New("openpgp: ML-DSA-65+Ed25519 may only be used with v6+") + } + return pk.parseMldsaEddsaPrivateKey(data, 32, mldsa_eddsa.MlDsaSeedLen) + case PubKeyAlgoMldsa87Ed448: + if pk.Version < 6 { + return goerrors.New("openpgp: ML-DSA-87+Ed448 may only be used with v6+") + } + return pk.parseMldsaEddsaPrivateKey(data, 57, mldsa_eddsa.MlDsaSeedLen) + case PubKeyAlgoSlhdsaShake128s, PubKeyAlgoSlhdsaShake128f, PubKeyAlgoSlhdsaShake256s: + if pk.Version < 6 { + return goerrors.New("openpgp: SLH-DSA may only be used with v6+") + } + return pk.parseSlhdsaPrivateKey(data) default: err = errors.StructuralError("unknown private key type") return @@ -887,8 +974,10 @@ func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) { rsaPriv.D = new(big.Int).SetBytes(d.Bytes()) rsaPriv.Primes = make([]*big.Int, 2) - rsaPriv.Primes[0] = new(big.Int).SetBytes(p.Bytes()) - rsaPriv.Primes[1] = new(big.Int).SetBytes(q.Bytes()) + // Mirror serializeRSAPrivateKey: Primes[1] is p and Primes[0] is q, so that + // Go's Qinv matches u = p^-1 mod q. + rsaPriv.Primes[0] = new(big.Int).SetBytes(q.Bytes()) + rsaPriv.Primes[1] = new(big.Int).SetBytes(p.Bytes()) if err := rsaPriv.Validate(); err != nil { return errors.KeyInvalidError(err.Error()) } @@ -1121,6 +1210,88 @@ func (pk *PrivateKey) applyHKDF(inputKey []byte) []byte { return encryptionKey } +// parseMldsaEddsaPrivateKey parses a ML-DSA + EdDSA private key as specified in +// https://www.rfc-editor.org/rfc/rfc9980.html#name-key-material-packets-2 +func (pk *PrivateKey) parseMldsaEddsaPrivateKey(data []byte, ecLen, seedLen int) (err error) { + if pk.Version != 6 { + return goerrors.New("openpgp: cannot parse non-v6 ML-DSA + EdDSA key") + } + pub := pk.PublicKey.PublicKey.(*mldsa_eddsa.PublicKey) + priv := new(mldsa_eddsa.PrivateKey) + priv.PublicKey = *pub + + if len(data) != ecLen + seedLen { + return errors.StructuralError("wrong ML-DSA+EdDSA key size") + } + + ecKey := make([]byte, ecLen) + copy(ecKey, data[:ecLen]) + priv.SecretEc = ecKey + + seed := make([]byte, seedLen) + copy(seed, data[ecLen:ecLen+seedLen]) + if err = priv.DeriveMlDsaKeys(seed, false); err != nil { + return err + } + + if err := mldsa_eddsa.Validate(priv); err != nil { + return err + } + pk.PrivateKey = priv + + return nil +} + +// parseMlkemEcdhPrivateKey parses a ML-KEM + ECC private key as specified in +// https://www.rfc-editor.org/rfc/rfc9980.html#name-key-material-packets +func (pk *PrivateKey) parseMlkemEcdhPrivateKey(data []byte, ecLen, seedLen int) (err error) { + pub := pk.PublicKey.PublicKey.(*mlkem_ecdh.PublicKey) + priv := new(mlkem_ecdh.PrivateKey) + priv.PublicKey = *pub + + if len(data) != ecLen + seedLen { + return errors.StructuralError("wrong ML-KEM+ECDH key size") + } + + ecKey := make([]byte, ecLen) + copy(ecKey, data[:ecLen]) + priv.SecretEc = ecKey + + seed := make([]byte, seedLen) + copy(seed, data[ecLen:ecLen+seedLen]) + if err = priv.DeriveMlKemKeys(seed, false); err != nil { + return err + } + + if err := mlkem_ecdh.Validate(priv); err != nil { + return err + } + pk.PrivateKey = priv + + return nil +} + +// parseSlhdsaPrivateKey parses a SLH-DSA private key. +func (pk *PrivateKey) parseSlhdsaPrivateKey(data []byte) (err error) { + if pk.Version != 6 { + return goerrors.New("openpgp: cannot parse non-v6 SLH-DSA key") + } + parsedPublicKey := pk.PublicKey.PublicKey.(*slhdsa.PublicKey) + parsedPrivateKey := new(slhdsa.PrivateKey) + parsedPrivateKey.PublicKey = *parsedPublicKey + parsedPrivateKey.SecretSlhdsa, err = parsedPrivateKey.Slhdsa.UnmarshalBinaryPrivateKey(data) + if err != nil { + return goerrors.New("openpgp: failed to unmarshal SLH-DSA key") + } + + if err := slhdsa.Validate(parsedPrivateKey); err != nil { + return err + } + pk.PrivateKey = parsedPrivateKey + + return nil +} + func validateDSAParameters(priv *dsa.PrivateKey) error { p := priv.P // group prime q := priv.Q // subgroup order diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go index e2813396e3..ba73822735 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go @@ -11,6 +11,7 @@ import ( "crypto/sha256" _ "crypto/sha512" "encoding/binary" + goerrors "errors" "fmt" "hash" "io" @@ -28,8 +29,18 @@ import ( "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" "github.com/ProtonMail/go-crypto/openpgp/internal/ecc" "github.com/ProtonMail/go-crypto/openpgp/internal/encoding" + "github.com/ProtonMail/go-crypto/openpgp/mldsa_eddsa" + "github.com/ProtonMail/go-crypto/openpgp/mlkem_ecdh" + "github.com/ProtonMail/go-crypto/openpgp/slhdsa" "github.com/ProtonMail/go-crypto/openpgp/x25519" "github.com/ProtonMail/go-crypto/openpgp/x448" + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/kem/mlkem/mlkem1024" + "github.com/cloudflare/circl/kem/mlkem/mlkem768" + "github.com/cloudflare/circl/sign" + "github.com/cloudflare/circl/sign/mldsa/mldsa65" + "github.com/cloudflare/circl/sign/mldsa/mldsa87" + slhdsaCircl "github.com/cloudflare/circl/sign/slhdsa" ) // PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2. @@ -37,7 +48,7 @@ type PublicKey struct { Version int CreationTime time.Time PubKeyAlgo PublicKeyAlgorithm - PublicKey interface{} // *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey or *eddsa.PublicKey, *x25519.PublicKey, *x448.PublicKey, *ed25519.PublicKey, *ed448.PublicKey + PublicKey interface{} // *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey or *eddsa.PublicKey, *x25519.PublicKey, *x448.PublicKey, *ed25519.PublicKey, *ed448.PublicKey, or *mlkem_ecdh.PublicKey Fingerprint []byte KeyId uint64 IsSubkey bool @@ -230,6 +241,42 @@ func NewEd448PublicKey(creationTime time.Time, pub *ed448.PublicKey) *PublicKey return pk } +func NewMlkemEcdhPublicKey(creationTime time.Time, pub *mlkem_ecdh.PublicKey) *PublicKey { + pk := &PublicKey{ + Version: 4, + CreationTime: creationTime, + PubKeyAlgo: PublicKeyAlgorithm(pub.AlgId), + PublicKey: pub, + } + + pk.setFingerprintAndKeyId() + return pk +} + +func NewMldsaEddsaPublicKey(creationTime time.Time, pub *mldsa_eddsa.PublicKey) *PublicKey { + pk := &PublicKey{ + Version: 6, + CreationTime: creationTime, + PubKeyAlgo: PublicKeyAlgorithm(pub.AlgId), + PublicKey: pub, + } + + pk.setFingerprintAndKeyId() + return pk +} + +func NewSlhdsaPublicKey(creationTime time.Time, pub *slhdsa.PublicKey) *PublicKey { + pk := &PublicKey{ + Version: 6, + CreationTime: creationTime, + PubKeyAlgo: PublicKeyAlgorithm(pub.AlgId), + PublicKey: pub, + } + + pk.setFingerprintAndKeyId() + return pk +} + func (pk *PublicKey) parse(r io.Reader) (err error) { // RFC 4880, section 5.5.2 var buf [6]byte @@ -258,7 +305,7 @@ func (pk *PublicKey) parse(r io.Reader) (err error) { } pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0) pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5]) - // Ignore four-ocet length + // Ignore four-octet length switch pk.PubKeyAlgo { case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: err = pk.parseRSA(r) @@ -280,6 +327,31 @@ func (pk *PublicKey) parse(r io.Reader) (err error) { err = pk.parseEd25519(r) case PubKeyAlgoEd448: err = pk.parseEd448(r) + case PubKeyAlgoMlkem768X25519: + if !(pk.Version == 4 || pk.Version >= 6) { + return goerrors.New("openpgp: ML-KEM-768+X25519 may only be used with v4 or v6+") + } + err = pk.parseMlkemEcdh(r, 32, mlkem768.PublicKeySize) + case PubKeyAlgoMlkem1024X448: + if pk.Version < 6 { + return goerrors.New("openpgp: ML-KEM-1024+X448 may only be used with v6+") + } + err = pk.parseMlkemEcdh(r, 56, mlkem1024.PublicKeySize) + case PubKeyAlgoMldsa65Ed25519: + if pk.Version < 6 { + return goerrors.New("openpgp: ML-DSA-65+Ed25519 may only be used with v6+") + } + err = pk.parseMldsaEddsa(r, 32, mldsa65.PublicKeySize) + case PubKeyAlgoMldsa87Ed448: + if pk.Version < 6 { + return goerrors.New("openpgp: ML-DSA-87+Ed448 may only be used with v6+") + } + err = pk.parseMldsaEddsa(r, 57, mldsa87.PublicKeySize) + case PubKeyAlgoSlhdsaShake128s, PubKeyAlgoSlhdsaShake128f, PubKeyAlgoSlhdsaShake256s: + if pk.Version < 6 { + return goerrors.New("openpgp: SLH-DSA may only be used with v6+") + } + err = pk.parseSlhDsa(r) default: err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo))) } @@ -488,6 +560,10 @@ func (pk *PublicKey) parseECDH(r io.Reader) (err error) { if !ok { return errors.UnsupportedError("unsupported ECDH KDF cipher: " + strconv.Itoa(int(pk.kdf.Bytes()[2]))) } + // RFC 6637, section 7: the KDF hash must be at least as long as the KEK. + if kdfHash.HashFunc().Size() < kdfCipher.KeySize() { + return errors.StructuralError("ECDH KDF hash output is shorter than the KDF cipher key size") + } ecdhKey := ecdh.NewPublicKey(c, kdfHash, kdfCipher) err = ecdhKey.UnmarshalPoint(pk.p.Bytes()) @@ -594,6 +670,98 @@ func (pk *PublicKey) parseEd448(r io.Reader) (err error) { return } +// parseMlkemEcdh parses a ML-KEM + ECC public key as specified in +// https://www.rfc-editor.org/rfc/rfc9980.html#name-key-material-packets +func (pk *PublicKey) parseMlkemEcdh(r io.Reader, ecLen, kLen int) (err error) { + ecKey := make([]byte, ecLen) + if _, err = io.ReadFull(r, ecKey); err != nil { + return + } + + mlkemKey := make([]byte, kLen) + if _, err = io.ReadFull(r, mlkemKey); err != nil { + return + } + + pub := &mlkem_ecdh.PublicKey{ + AlgId: uint8(pk.PubKeyAlgo), + PublicPoint: ecKey, + } + + if pub.Curve, err = GetECDHCurveFromAlgID(pk.PubKeyAlgo); err != nil { + return err + } + + if pub.Mlkem, err = GetMlkemFromAlgID(pk.PubKeyAlgo); err != nil { + return err + } + + if pub.PublicMlkem, err = pub.Mlkem.UnmarshalBinaryPublicKey(mlkemKey); err != nil { + return err + } + + pk.PublicKey = pub + + return +} + +// parseMldsaEddsa parses a ML-DSA + EdDSA public key as specified in +// https://www.rfc-editor.org/rfc/rfc9980.html#name-key-material-packets-2 +func (pk *PublicKey) parseMldsaEddsa(r io.Reader, ecLen, dLen int) (err error) { + ecKey := make([]byte, ecLen) + if _, err = io.ReadFull(r, ecKey); err != nil { + return + } + + mldsaKey := make([]byte, dLen) + if _, err = io.ReadFull(r, mldsaKey); err != nil { + return + } + + pub := &mldsa_eddsa.PublicKey{ + AlgId: uint8(pk.PubKeyAlgo), + PublicPoint: ecKey, + } + + if pub.Curve, err = GetEdDSACurveFromAlgID(pk.PubKeyAlgo); err != nil { + return err + } + + if pub.Mldsa, err = GetMldsaFromAlgID(pk.PubKeyAlgo); err != nil { + return err + } + + if pub.PublicMldsa, err = pub.Mldsa.UnmarshalBinaryPublicKey(mldsaKey); err != nil { + return err + } + + pk.PublicKey = pub + return +} + +func (pk *PublicKey) parseSlhDsa(r io.Reader) (err error) { + parsedPublicKey := &slhdsa.PublicKey{ + AlgId: uint8(pk.PubKeyAlgo), + } + + if parsedPublicKey.Slhdsa, err = GetSlhdsaSchemeFromAlgID(pk.PubKeyAlgo); err != nil { + return err + } + + keyLen := parsedPublicKey.Slhdsa.PublicKeySize() + key := make([]byte, keyLen) + if _, err = io.ReadFull(r, key); err != nil { + return err + } + + if parsedPublicKey.PublicSlhdsa, err = parsedPublicKey.Slhdsa.UnmarshalBinaryPublicKey(key); err != nil { + return err + } + + pk.PublicKey = parsedPublicKey + return nil +} + // SerializeForHash serializes the PublicKey to w with the special packet // header format needed for hashing. func (pk *PublicKey) SerializeForHash(w io.Writer) error { @@ -681,6 +849,21 @@ func (pk *PublicKey) algorithmSpecificByteCount() uint32 { length += ed25519.PublicKeySize case PubKeyAlgoEd448: length += ed448.PublicKeySize + case PubKeyAlgoMlkem768X25519: + length += x25519.KeySize + length += mlkem768.PublicKeySize + case PubKeyAlgoMlkem1024X448: + length += x448.KeySize + length += mlkem1024.PublicKeySize + case PubKeyAlgoMldsa65Ed25519: + length += ed25519.PublicKeySize + length += mldsa65.PublicKeySize + case PubKeyAlgoMldsa87Ed448: + length += ed448.PublicKeySize + length += mldsa87.PublicKeySize + case PubKeyAlgoSlhdsaShake128s, PubKeyAlgoSlhdsaShake128f, PubKeyAlgoSlhdsaShake256s: + publicKey := pk.PublicKey.(*slhdsa.PublicKey) + length += uint32(publicKey.Slhdsa.PublicKeySize()) default: panic("unknown public key algorithm") } @@ -773,13 +956,46 @@ func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) { publicKey := pk.PublicKey.(*ed448.PublicKey) _, err = w.Write(publicKey.Point) return + case PubKeyAlgoMlkem768X25519, PubKeyAlgoMlkem1024X448: + publicKey := pk.PublicKey.(*mlkem_ecdh.PublicKey) + if _, err = w.Write(publicKey.PublicPoint); err != nil { + return + } + var mlkemBin []byte + mlkemBin, err = publicKey.PublicMlkem.MarshalBinary() + if err != nil { + return + } + _, err = w.Write(mlkemBin) + return + case PubKeyAlgoMldsa65Ed25519, PubKeyAlgoMldsa87Ed448: + publicKey := pk.PublicKey.(*mldsa_eddsa.PublicKey) + if _, err = w.Write(publicKey.PublicPoint); err != nil { + return + } + var mldsaBin []byte + mldsaBin, err = publicKey.PublicMldsa.MarshalBinary() + if err != nil { + return + } + _, err = w.Write(mldsaBin) + return + case PubKeyAlgoSlhdsaShake128s, PubKeyAlgoSlhdsaShake128f, PubKeyAlgoSlhdsaShake256s: + publicKey := pk.PublicKey.(*slhdsa.PublicKey) + var slhdsaBin []byte + slhdsaBin, err = publicKey.PublicSlhdsa.MarshalBinary() + if err != nil { + return + } + _, err = w.Write(slhdsaBin) + return } return errors.InvalidArgumentError("bad public-key algorithm") } // CanSign returns true iff this public key can generate signatures func (pk *PublicKey) CanSign() bool { - return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal && pk.PubKeyAlgo != PubKeyAlgoECDH + return pk.PubKeyAlgo.CanSign() } // VerifyHashTag returns nil iff sig appears to be a plausible signature of the data @@ -859,6 +1075,18 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err erro return errors.SignatureError("ed448 verification failure") } return nil + case PubKeyAlgoMldsa65Ed25519, PubKeyAlgoMldsa87Ed448: + mldsaEddsaPublicKey := pk.PublicKey.(*mldsa_eddsa.PublicKey) + if !mldsa_eddsa.Verify(mldsaEddsaPublicKey, hashBytes, sig.MldsaSig, sig.EdSig) { + return errors.SignatureError("MldsaEddsa verification failure") + } + return nil + case PubKeyAlgoSlhdsaShake128s, PubKeyAlgoSlhdsaShake128f, PubKeyAlgoSlhdsaShake256s: + slhDsaPublicKey := pk.PublicKey.(*slhdsa.PublicKey) + if !slhdsa.Verify(slhDsaPublicKey, hashBytes, sig.SlhdsaSig) { + return errors.SignatureError("Slhdsa verification failure") + } + return nil default: return errors.SignatureError("Unsupported public key algorithm used in signature") } @@ -1085,6 +1313,15 @@ func (pk *PublicKey) BitLength() (bitLength uint16, err error) { bitLength = ed25519.PublicKeySize * 8 case PubKeyAlgoEd448: bitLength = ed448.PublicKeySize * 8 + case PubKeyAlgoMlkem768X25519, PubKeyAlgoMlkem1024X448: + publicKey := pk.PublicKey.(*mlkem_ecdh.PublicKey) + bitLength = uint16(publicKey.Mlkem.PublicKeySize() * 8) + case PubKeyAlgoMldsa65Ed25519, PubKeyAlgoMldsa87Ed448: + publicKey := pk.PublicKey.(*mldsa_eddsa.PublicKey) + bitLength = uint16(publicKey.Mldsa.PublicKeySize() * 8) + case PubKeyAlgoSlhdsaShake128s, PubKeyAlgoSlhdsaShake128f, PubKeyAlgoSlhdsaShake256s: + publicKey := pk.PublicKey.(*slhdsa.PublicKey) + bitLength = uint16(publicKey.Slhdsa.PublicKeySize() * 8) default: err = errors.InvalidArgumentError("bad public-key algorithm") } @@ -1123,3 +1360,86 @@ func (pk *PublicKey) KeyExpired(sig *Signature, currentTime time.Time) bool { expiry := pk.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second) return currentTime.Unix() > expiry.Unix() } + +// IsPQ returns true if the algorithm of this public key is Post-Quantum safe. +func (pg *PublicKey) IsPQ() bool { + switch pg.PubKeyAlgo { + case PubKeyAlgoMlkem768X25519, PubKeyAlgoMlkem1024X448, + PubKeyAlgoMldsa65Ed25519, PubKeyAlgoMldsa87Ed448, + PubKeyAlgoSlhdsaShake128s, PubKeyAlgoSlhdsaShake128f, PubKeyAlgoSlhdsaShake256s: + return true + default: + return false + } +} + +func GetMatchingMlkem(algId PublicKeyAlgorithm) (PublicKeyAlgorithm, error) { + switch algId { + case PubKeyAlgoMldsa65Ed25519, PubKeyAlgoSlhdsaShake128s, PubKeyAlgoSlhdsaShake128f: + return PubKeyAlgoMlkem768X25519, nil + case PubKeyAlgoMldsa87Ed448, PubKeyAlgoSlhdsaShake256s: + return PubKeyAlgoMlkem1024X448, nil + default: + return 0, goerrors.New("packet: unsupported pq public key algorithm") + } +} + +// GetMlkemFromAlgID returns the ML-KEM instance from the matching KEM +func GetMlkemFromAlgID(algId PublicKeyAlgorithm) (kem.Scheme, error) { + switch algId { + case PubKeyAlgoMlkem768X25519: + return mlkem768.Scheme(), nil + case PubKeyAlgoMlkem1024X448: + return mlkem1024.Scheme(), nil + default: + return nil, goerrors.New("packet: unsupported ML-KEM public key algorithm") + } +} + +// GetSlhdsaSchemeFromAlgID returns the SLH-DSA instance from the matching KEM +func GetSlhdsaSchemeFromAlgID(algId PublicKeyAlgorithm) (sign.Scheme, error) { + switch algId { + case PubKeyAlgoSlhdsaShake128s: + return slhdsaCircl.SHAKE_128s.Scheme(), nil + case PubKeyAlgoSlhdsaShake128f: + return slhdsaCircl.SHAKE_128f.Scheme(), nil + case PubKeyAlgoSlhdsaShake256s: + return slhdsaCircl.SHAKE_256s.Scheme(), nil + default: + return nil, goerrors.New("packet: unsupported SLH-DSA public key algorithm") + } +} + +// GetECDHCurveFromAlgID returns the ECDH curve instance from the matching KEM +func GetECDHCurveFromAlgID(algId PublicKeyAlgorithm) (ecc.ECDHCurve, error) { + switch algId { + case PubKeyAlgoMlkem768X25519: + return ecc.NewCurve25519(), nil + case PubKeyAlgoMlkem1024X448: + return ecc.NewX448(), nil + default: + return nil, goerrors.New("packet: unsupported ECDH public key algorithm") + } +} + +func GetEdDSACurveFromAlgID(algId PublicKeyAlgorithm) (ecc.EdDSACurve, error) { + switch algId { + case PubKeyAlgoMldsa65Ed25519: + return ecc.NewEd25519(), nil + case PubKeyAlgoMldsa87Ed448: + return ecc.NewEd448(), nil + default: + return nil, goerrors.New("packet: unsupported EdDSA public key algorithm") + } +} + +func GetMldsaFromAlgID(algId PublicKeyAlgorithm) (sign.Scheme, error) { + switch algId { + case PubKeyAlgoMldsa65Ed25519: + return mldsa65.Scheme(), nil + case PubKeyAlgoMldsa87Ed448: + return mldsa87.Scheme(), nil + default: + return nil, goerrors.New("packet: unsupported ML-DSA public key algorithm") + } +} diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go index 84dd3b86f8..ef821aa616 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go @@ -23,6 +23,10 @@ import ( "github.com/ProtonMail/go-crypto/openpgp/errors" "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" "github.com/ProtonMail/go-crypto/openpgp/internal/encoding" + "github.com/ProtonMail/go-crypto/openpgp/mldsa_eddsa" + "github.com/ProtonMail/go-crypto/openpgp/slhdsa" + "github.com/cloudflare/circl/sign/mldsa/mldsa65" + "github.com/cloudflare/circl/sign/mldsa/mldsa87" ) const ( @@ -81,17 +85,21 @@ type Signature struct { ECDSASigR, ECDSASigS encoding.Field EdDSASigR, EdDSASigS encoding.Field EdSig []byte + MldsaSig []byte + SlhdsaSig []byte // rawSubpackets contains the unparsed subpackets, in order. rawSubpackets []outputSubpacket // The following are optional so are nil when not included in the // signature. + // The exception is IssuerKeyVersion, which defaults to 0. SigLifetimeSecs, KeyLifetimeSecs *uint32 PreferredSymmetric, PreferredHash, PreferredCompression []uint8 PreferredCipherSuites [][2]uint8 IssuerKeyId *uint64 + IssuerKeyVersion uint8 IssuerFingerprint []byte SignerUserId *string IsPrimaryId *bool @@ -198,7 +206,11 @@ func (sig *Signature) parse(r io.Reader) (err error) { sig.SigType = SignatureType(buf[0]) sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1]) switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA, PubKeyAlgoEd25519, PubKeyAlgoEd448: + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, + PubKeyAlgoECDSA, PubKeyAlgoEdDSA, + PubKeyAlgoEd25519, PubKeyAlgoEd448, + PubKeyAlgoMldsa65Ed25519, PubKeyAlgoMldsa87Ed448, + PubKeyAlgoSlhdsaShake128s, PubKeyAlgoSlhdsaShake128f, PubKeyAlgoSlhdsaShake256s: default: err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) return @@ -216,19 +228,18 @@ func (sig *Signature) parse(r io.Reader) (err error) { return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2]))) } - var hashedSubpacketsLength int + var hashedSubpacketsLength uint32 if sig.Version == 6 { // For a v6 signature, a four-octet length is used. hashedSubpacketsLength = - int(buf[3])<<24 | - int(buf[4])<<16 | - int(buf[5])<<8 | - int(buf[6]) + uint32(buf[3])<<24 | + uint32(buf[4])<<16 | + uint32(buf[5])<<8 | + uint32(buf[6]) } else { - hashedSubpacketsLength = int(buf[3])<<8 | int(buf[4]) + hashedSubpacketsLength = uint32(buf[3])<<8 | uint32(buf[4]) } - hashedSubpackets := make([]byte, hashedSubpacketsLength) - _, err = readFull(r, hashedSubpackets) + hashedSubpackets, err := readN(r, hashedSubpacketsLength) if err != nil { return } @@ -257,8 +268,7 @@ func (sig *Signature) parse(r io.Reader) (err error) { } else { unhashedSubpacketsLength = uint32(buf[0])<<8 | uint32(buf[1]) } - unhashedSubpackets := make([]byte, unhashedSubpacketsLength) - _, err = readFull(r, unhashedSubpackets) + unhashedSubpackets, err := readN(r, unhashedSubpacketsLength) if err != nil { return } @@ -336,12 +346,48 @@ func (sig *Signature) parse(r io.Reader) (err error) { if err != nil { return } + case PubKeyAlgoMldsa65Ed25519: + if err = sig.parseMldsaEddsaSignature(r, 64, mldsa65.SignatureSize); err != nil { + return + } + case PubKeyAlgoMldsa87Ed448: + if err = sig.parseMldsaEddsaSignature(r, 114, mldsa87.SignatureSize); err != nil { + return + } + case PubKeyAlgoSlhdsaShake128s, PubKeyAlgoSlhdsaShake128f, PubKeyAlgoSlhdsaShake256s: + if err = sig.parseSlhdsaSignature(r, sig.PubKeyAlgo); err != nil { + return + } default: panic("unreachable") } return } +// parseMldsaEddsaSignature parses an ML-DSA + EdDSA signature as specified in +// https://www.rfc-editor.org/rfc/rfc9980.html#name-signature-packet-packet-typ +func (sig *Signature) parseMldsaEddsaSignature(r io.Reader, ecLen, dLen int) (err error) { + sig.EdSig = make([]byte, ecLen) + if _, err = io.ReadFull(r, sig.EdSig); err != nil { + return + } + + sig.MldsaSig = make([]byte, dLen) + _, err = io.ReadFull(r, sig.MldsaSig) + return +} + +// parseSlhdsaSignature parses an SLH-DSA signature as specified in +func (sig *Signature) parseSlhdsaSignature(r io.Reader, algID PublicKeyAlgorithm) (err error) { + scheme, err := GetSlhdsaSchemeFromAlgID(algID) + if err != nil { + return err + } + sig.SlhdsaSig = make([]byte, scheme.SignatureSize()) + _, err = io.ReadFull(r, sig.SlhdsaSig) + return +} + // parseSignatureSubpackets parses subpackets of the main signature packet. See // RFC 9580, section 5.2.3.1. func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err error) { @@ -455,6 +501,10 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r sig.SigLifetimeSecs = new(uint32) *sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket) case exportableCertSubpacket: + if len(subpacket) < 1 { + err = errors.StructuralError("exportable certification subpacket with a bad length") + return + } if subpacket[0] == 0 { err = errors.UnsupportedError("signature with non-exportable certification") return @@ -618,6 +668,11 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r err = errors.StructuralError("Cannot have multiple embedded signatures") return } + // A Primary Key Binding signature must not itself carry an embedded + // signature, otherwise the structure can recurse without bound. + if sig.SigType == SigTypePrimaryKeyBinding { + return nil, errors.StructuralError("embedded signature within a primary key binding signature") + } sig.EmbeddedSignature = new(Signature) if err := sig.EmbeddedSignature.parse(bytes.NewBuffer(subpacket)); err != nil { return nil, err @@ -637,6 +692,7 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r if v >= 5 && l != 32 || v < 5 && l != 20 { return nil, errors.StructuralError("bad fingerprint length") } + sig.IssuerKeyVersion = subpacket[0] sig.IssuerFingerprint = make([]byte, l) copy(sig.IssuerFingerprint, subpacket[1:]) sig.IssuerKeyId = new(uint64) @@ -694,14 +750,14 @@ func subpacketLengthLength(length int) int { } func (sig *Signature) CheckKeyIdOrFingerprint(pk *PublicKey) bool { - if sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) >= 20 { - return bytes.Equal(sig.IssuerFingerprint, pk.Fingerprint) + if sig.IssuerKeyVersion != 0 && len(sig.IssuerFingerprint) >= 20 { + return int(sig.IssuerKeyVersion) == pk.Version && bytes.Equal(sig.IssuerFingerprint, pk.Fingerprint) } return sig.IssuerKeyId != nil && *sig.IssuerKeyId == pk.KeyId } func (sig *Signature) CheckKeyIdOrFingerprintExplicit(fingerprint []byte, keyId uint64) bool { - if sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) >= 20 && fingerprint != nil { + if sig.IssuerKeyVersion != 0 && len(sig.IssuerFingerprint) >= 20 && fingerprint != nil { return bytes.Equal(sig.IssuerFingerprint, fingerprint) } return sig.IssuerKeyId != nil && *sig.IssuerKeyId == keyId @@ -918,6 +974,7 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e return errors.ErrDummyPrivateKey("dummy key found") } sig.Version = priv.PublicKey.Version + sig.IssuerKeyVersion = uint8(priv.PublicKey.Version) sig.IssuerFingerprint = priv.PublicKey.Fingerprint if sig.Version < 6 && config.RandomizeSignaturesViaNotation() { sig.removeNotationsWithName(SaltNotationName) @@ -933,7 +990,7 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e } sig.Notations = append(sig.Notations, ¬ation) } - sig.outSubpackets, err = sig.buildSubpackets(priv.PublicKey) + sig.outSubpackets, err = sig.buildSubpackets(config) if err != nil { return err } @@ -996,6 +1053,27 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e if err == nil { sig.EdSig = signature } + case PubKeyAlgoMldsa65Ed25519, PubKeyAlgoMldsa87Ed448: + if sig.Version != 6 { + return errors.StructuralError("cannot use MldsaEdDsa on a non-v6 signature") + } + sk := priv.PrivateKey.(*mldsa_eddsa.PrivateKey) + dSig, ecSig, err := mldsa_eddsa.Sign(sk, digest) + + if err == nil { + sig.MldsaSig = dSig + sig.EdSig = ecSig + } + case PubKeyAlgoSlhdsaShake128s, PubKeyAlgoSlhdsaShake128f, PubKeyAlgoSlhdsaShake256s: + if sig.Version != 6 { + return errors.StructuralError("cannot use SLH-DSA on a non-v6 signature") + } + sk := priv.PrivateKey.(*slhdsa.PrivateKey) + dSig, err := slhdsa.Sign(sk, digest) + + if err == nil { + sig.SlhdsaSig = dSig + } default: err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo))) } @@ -1113,7 +1191,7 @@ func (sig *Signature) Serialize(w io.Writer) (err error) { if len(sig.outSubpackets) == 0 { sig.outSubpackets = sig.rawSubpackets } - if sig.RSASignature == nil && sig.DSASigR == nil && sig.ECDSASigR == nil && sig.EdDSASigR == nil && sig.EdSig == nil { + if sig.RSASignature == nil && sig.DSASigR == nil && sig.ECDSASigR == nil && sig.EdDSASigR == nil && sig.EdSig == nil && sig.SlhdsaSig == nil { return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") } @@ -1134,6 +1212,11 @@ func (sig *Signature) Serialize(w io.Writer) (err error) { sigLength = ed25519.SignatureSize case PubKeyAlgoEd448: sigLength = ed448.SignatureSize + case PubKeyAlgoMldsa65Ed25519, PubKeyAlgoMldsa87Ed448: + sigLength = len(sig.EdSig) + sigLength += len(sig.MldsaSig) + case PubKeyAlgoSlhdsaShake128s, PubKeyAlgoSlhdsaShake128f, PubKeyAlgoSlhdsaShake256s: + sigLength += len(sig.SlhdsaSig) default: panic("impossible") } @@ -1240,6 +1323,13 @@ func (sig *Signature) serializeBody(w io.Writer) (err error) { err = ed25519.WriteSignature(w, sig.EdSig) case PubKeyAlgoEd448: err = ed448.WriteSignature(w, sig.EdSig) + case PubKeyAlgoMldsa65Ed25519, PubKeyAlgoMldsa87Ed448: + if _, err = w.Write(sig.EdSig); err != nil { + return + } + _, err = w.Write(sig.MldsaSig) + case PubKeyAlgoSlhdsaShake128s, PubKeyAlgoSlhdsaShake128f, PubKeyAlgoSlhdsaShake256s: + _, err = w.Write(sig.SlhdsaSig) default: panic("impossible") } @@ -1254,11 +1344,11 @@ type outputSubpacket struct { contents []byte } -func (sig *Signature) buildSubpackets(issuer PublicKey) (subpackets []outputSubpacket, err error) { +func (sig *Signature) buildSubpackets(config *Config) (subpackets []outputSubpacket, err error) { creationTime := make([]byte, 4) binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix())) // Signature Creation Time - subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, true, creationTime}) + subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, !config.GenerateNonCriticalSignatureCreationTime(), creationTime}) // Signature Expiration Time if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 { sigLifetime := make([]byte, 4) @@ -1357,7 +1447,7 @@ func (sig *Signature) buildSubpackets(issuer PublicKey) (subpackets []outputSubp if sig.FlagGroupKey { flags |= KeyFlagGroupKey } - subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, true, []byte{flags}}) + subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, !config.GenerateNonCriticalKeyFlags(), []byte{flags}}) } // Signer's User ID if sig.SignerUserId != nil { @@ -1391,8 +1481,8 @@ func (sig *Signature) buildSubpackets(issuer PublicKey) (subpackets []outputSubp subpackets = append(subpackets, outputSubpacket{true, embeddedSignatureSubpacket, true, buf.Bytes()}) } // Issuer Fingerprint - if sig.IssuerFingerprint != nil { - contents := append([]uint8{uint8(issuer.Version)}, sig.IssuerFingerprint...) + if sig.IssuerKeyVersion != 0 && sig.IssuerFingerprint != nil { + contents := append([]uint8{sig.IssuerKeyVersion}, sig.IssuerFingerprint...) subpackets = append(subpackets, outputSubpacket{true, issuerFingerprintSubpacket, sig.Version >= 5, contents}) } // Intended Recipient Fingerprint diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.go index 2812a1db88..74a192f9c2 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.go @@ -158,7 +158,10 @@ func (ske *SymmetricKeyEncrypted) decryptV4(key []byte) ([]byte, CipherFunction, func (ske *SymmetricKeyEncrypted) aeadDecrypt(version int, key []byte) ([]byte, error) { adata := []byte{0xc3, byte(version), byte(ske.CipherFunc), byte(ske.Mode)} - aead := getEncryptedKeyAeadInstance(ske.CipherFunc, ske.Mode, key, adata, version) + aead, err := getEncryptedKeyAeadInstance(ske.CipherFunc, ske.Mode, key, adata, version) + if err != nil { + return nil, err + } plaintextKey, err := aead.Open(nil, ske.iv, ske.encryptedKey, adata) if err != nil { @@ -291,7 +294,11 @@ func SerializeSymmetricKeyEncryptedAEADReuseKey(w io.Writer, sessionKey []byte, case 5, 6: mode := config.AEAD().Mode() adata := []byte{0xc3, byte(version), byte(cipherFunc), byte(mode)} - aead := getEncryptedKeyAeadInstance(cipherFunc, mode, keyEncryptingKey, adata, version) + var aead cipher.AEAD + aead, err = getEncryptedKeyAeadInstance(cipherFunc, mode, keyEncryptingKey, adata, version) + if err != nil { + return + } // Sample iv using random reader iv := make([]byte, config.AEAD().Mode().IvLength()) @@ -315,7 +322,7 @@ func SerializeSymmetricKeyEncryptedAEADReuseKey(w io.Writer, sessionKey []byte, return } -func getEncryptedKeyAeadInstance(c CipherFunction, mode AEADMode, inputKey, associatedData []byte, version int) (aead cipher.AEAD) { +func getEncryptedKeyAeadInstance(c CipherFunction, mode AEADMode, inputKey, associatedData []byte, version int) (aead cipher.AEAD, err error) { var blockCipher cipher.Block if version > 5 { hkdfReader := hkdf.New(sha256.New, inputKey, []byte{}, associatedData) diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_aead.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_aead.go index 3ddc4fe4a9..716da9d839 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_aead.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_aead.go @@ -68,7 +68,11 @@ func (se *SymmetricallyEncrypted) decryptAead(inputKey []byte) (io.ReadCloser, e return nil, errors.StructuralError(fmt.Sprintf("invalid session key length for cipher: got %d bytes, but expected %d bytes", len(inputKey), se.Cipher.KeySize())) } - aead, nonce := getSymmetricallyEncryptedAeadInstance(se.Cipher, se.Mode, inputKey, se.Salt[:], se.associatedData()) + aead, nonce, err := getSymmetricallyEncryptedAeadInstance(se.Cipher, se.Mode, inputKey, se.Salt[:], se.associatedData()) + if err != nil { + return nil, err + } + // Carry the first tagLen bytes chunkSize := decodeAEADChunkSize(se.ChunkSizeByte) tagLen := se.Mode.TagLength() @@ -131,7 +135,10 @@ func serializeSymmetricallyEncryptedAead(ciphertext io.WriteCloser, cipherSuite return nil, err } - aead, nonce := getSymmetricallyEncryptedAeadInstance(cipherSuite.Cipher, cipherSuite.Mode, inputKey, salt, prefix) + aead, nonce, err := getSymmetricallyEncryptedAeadInstance(cipherSuite.Cipher, cipherSuite.Mode, inputKey, salt, prefix) + if err != nil { + return nil, err + } chunkSize := decodeAEADChunkSize(chunkSizeByte) tagLen := aead.Overhead() @@ -150,19 +157,22 @@ func serializeSymmetricallyEncryptedAead(ciphertext io.WriteCloser, cipherSuite }, nil } -func getSymmetricallyEncryptedAeadInstance(c CipherFunction, mode AEADMode, inputKey, salt, associatedData []byte) (aead cipher.AEAD, nonce []byte) { +func getSymmetricallyEncryptedAeadInstance(c CipherFunction, mode AEADMode, inputKey, salt, associatedData []byte) (aead cipher.AEAD, nonce []byte, err error) { hkdfReader := hkdf.New(sha256.New, inputKey, salt, associatedData) encryptionKey := make([]byte, c.KeySize()) _, _ = readFull(hkdfReader, encryptionKey) + blockCipher := c.new(encryptionKey) + aead, err = mode.new(blockCipher) + if err != nil { + return nil, nil, err + } + nonce = make([]byte, mode.IvLength()) // Last 64 bits of nonce are the counter _, _ = readFull(hkdfReader, nonce[:len(nonce)-8]) - blockCipher := c.new(encryptionKey) - aead = mode.new(blockCipher) - return } diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/read.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/read.go index e6dd9b5fd3..c6e4b592e6 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/read.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/read.go @@ -23,6 +23,9 @@ import ( // SignatureType is the armor type for a PGP signature. var SignatureType = "PGP SIGNATURE" +// MessageType is the armor type for a PGP message. +var MessageType = "PGP MESSAGE" + // readArmored reads an armored block with the given type. func readArmored(r io.Reader, expectedType string) (body io.Reader, err error) { block, err := armor.Decode(r) @@ -118,7 +121,9 @@ ParsePackets: // This packet contains the decryption key encrypted to a public key. md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId) switch p.Algo { - case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal, packet.PubKeyAlgoECDH, packet.PubKeyAlgoX25519, packet.PubKeyAlgoX448: + case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal, packet.PubKeyAlgoECDH, + packet.PubKeyAlgoX25519, packet.PubKeyAlgoX448, + packet.PubKeyAlgoMlkem768X25519, packet.PubKeyAlgoMlkem1024X448: break default: continue @@ -259,7 +264,7 @@ FindLiteralData: } switch p := p.(type) { case *packet.Compressed: - if err := packets.Push(p.Body); err != nil { + if err := packets.Push(p.LimitedBodyReader(config.DecompressedMessageSizeLimit())); err != nil { return nil, err } case *packet.OnePassSignature: @@ -407,7 +412,7 @@ func (scr *signatureCheckReader) Read(buf []byte) (int, error) { } // If signature KeyID matches - if scr.md.SignedBy != nil && *sig.IssuerKeyId == scr.md.SignedByKeyId { + if scr.md.SignedBy != nil && sig.IssuerKeyId != nil && *sig.IssuerKeyId == scr.md.SignedByKeyId { key := scr.md.SignedBy signatureError := key.PublicKey.VerifySignature(scr.h, sig) if signatureError == nil { diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/read_write_test_data.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/read_write_test_data.go index 670d60226a..7e6f79bd83 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/read_write_test_data.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/read_write_test_data.go @@ -455,3 +455,20 @@ byVJHvLO/XErtC+GNIJeMg== =liRq -----END PGP MESSAGE----- ` + +// PQC keys +const v6Ed25519Mlkem768X25519PrivateHex = "c54b06677485801b00000020dcb4935cc4c860f8deff728e438f34731b29d6dd3fd70dbaf3b07cbaa5130afc00adfada8414ee2a28c76837b8ff565c6989fb67aec37b5e6258f0bfbc66b72780c29e061f1b080000003f058267748580030b0907021508021600029b03021e0922a106c789e17d9dbdca7b3c833a3c063feb0353f80ad911fe27868fb0645df803e94705270902070200000000343b10806c62c4adb4f7bf51fde01268d4f0d1b4123e7d158f0df1d7b46a8c00a26a555e0e104fd8f522c8e6536f04c7f9353d37b0031e4ea1e42941b2788e31fe47f399ef7d2492ff9cfb599e6b976925d20dcd2e5051432075736572202854657374204b657929203c7071632d746573742d6b6579406578616d706c652e636f6d3ec28b06131b080000002c05826774858002190122a106c789e17d9dbdca7b3c833a3c063feb0353f80ad911fe27868fb0645df803e947000000003e3110f96f3df035f1b4e5b9fde992864823d75c2a5b518cc2246d9a838397a5f71a41e746ebfbb96009e43814e96c76b6fdbbbfadc1d9b8e9f77aa51ef89da067abaa6e620b109e52e94df9d6a97e8107bb07c7c46b066774858023000004c022150b430cf724ec19b8be55df9bcaade327085711369404a575c8023443b05f5e4242dd8374b0650b0752c8bd9052945131ffda29e27727fb427d20a78aceebb8e3d9aed9474d03f5cafb9c25fac18675354dac9ab7b3b47f064b5535604c1b4b7e79806d22d41ac7062e72c3a7b5c3b7e38b87d4103e6472002f1b0737a2ab64f09ea9f17da694c1f14025bd54742404cfb72caec45c3a3147b1d3a1a56338ab31769f1fc8cae4aa9925b8c1296c0fa3b6c8b0105b2e9aa4f724316fb61827a550306922b6b47058dc10c531834de7bcfc5c9430862494631ec261bae5190aac130a202b015fb943d5c43b7e2b04a7b63e5a8395a9ab2ce85b8e58a24b221cab83e03dde852c341846cff8848097a13f683c0103cd3273be22272023041d57e60946b7962af428b18307c6da2941158a4579a6ac628f1587a8cefa28eaa47e2489af203832d2057f784ba7f2256841bc6e0573c841724e89c3853e25a35e2b06ff41b7acec9113da348af97164f92edaa29ac9f16d330c5b356839e22795fee45fae34511ce9cbd126b18a063c374148c1a4c1e2e31ecaaa611be462ee74a09cb5716844bdfedccd88a960b2e02e0b993b13e5cf0289c6cbd2249bea0727d860d1728dcefc8d47fbb05a10765859850d107795d544dffc212cb7bbc8f9a9b481566772762da685a93c94868356eaca5191459e34c828dccc514b7420981197aa8bbaffb453dad755ad6218f1624ee5298c9d972b27aa17dea298805889260093b947a0aff70d34934b13fb21c9e7647717c6ea36904b3acbc4e5a0d1f047b6b775b27596af20a87f08bbadacb71e33672a335d75f8828635a42e9bb91f675833f0b37679a63a593def5bc981e67a4ab8af525c0b4c70c8915a95af917e88f5c753e59dea1714c6b207e1e5174c914851889a992a9bdf9720000cce0414bf0cac03e3aa4e511721c1135151bbb8eea889138013e886b475316409245ecda25704d7bdfa88ac3c372d413c7f5596a4b64bcae2173e0cbc2e32242e40ca1ebf40a0ccb96bed7a71bc26841983a2153272745b6585ea6685e677934a6e139958f003890447753ca3c40f3c2a0f4c0e07168c4c440688fa87dfd10db38ab4f0170e5e300dab0b63c55a2d248bab94173182c675e9164eca2691702b37e7c00cac4c4c49c35f53e1c120e36ac5193308f3aa9f7b0233340ef9dc09bb1354a0460371402d628b3cfb505d687bc669e34c63712ec5059e00940437876961f7b6f6a95c60ec1c1d1b58a2c98b73b39a1cc43bc270b37497b2887a1b00881564666f0325bac3d713950776a5376c0e04a63bca2bebd8183cac6c98b7a26f7268cad7a3b4186769ec727de085864b07cc996ee3c97ae5f0c51378793e6aa3f2f4467c58a4daa6c8ceb535d5a95afc88890fb467c1340262e3befb22816bbac2d6a5c25c11598b1070c136af1de1003cd9cc996c437e76b67eb36714a46874369333ba3be86b3bae04c878b03341f662875c802694b08c47150d974845a453ae42bfe0f27354719be30c243b07cba0f10108cb80613c5fa8954481d062ea952c3da10e43391478878e560a059cc84fdfe376d9f31690205cfcb60e4e1b4f5c55ad1e4ab98e69a3f9a8aec8639a69d71c04a593bf1968065cb6e500037db608da8226b55bb52438c509fe8f43be1459211ff44be64e0b0c42afd33c808b0d4ca84e4b5e2d3400c04dbeb8360fc5ba3ce71959dbfc869de7225d2f0cbdfa81cfc64e23fcb40b7c51b27ed9159da710068ff5151ba1049291cfe07ab8b17b8ec70bb5fe30fea1ed4032e3dfa776f44ee801f1db36733e20e56743605f7a7a01e9b8e738df313efec28b06181b080000002c058267748580029b0c22a106c789e17d9dbdca7b3c833a3c063feb0353f80ad911fe27868fb0645df803e94700000000c8ad10b141bd6309335f12588a8f91a6f09ce41b791f46759b76749645d183bca864662cef93ec621a623f539731e89c0df2d3500095875fbe894133680ba6e8c57f9f55e2dde26718107e0becd3ebeb712b04" + +const v4Ed25519Mlkem768X25519PrivateHex = "c54904677485801ba10e26cc19cebd413cb3298af747b30c690399b94d01c20f3625570bf8d187b30038cd64c28be9b03ff5a82f9c764835b76cd7b6929732a4459d4daa5ec497605b10e5cd2e5051432075736572202854657374204b657929203c7071632d746573742d6b6579406578616d706c652e636f6d3ec2c00004131b080076058267748580030b090709907102ffed3b9cf12d351400000000001c001073616c74406e6f746174696f6e732e6f70656e7067706a732e6f7267e5255b2a98190a3f60982e0db16ba257021508021600021901029b03021e09162104342e5db2de345215cb2c944f7102ffed3b9cf12d05270902070200008aff351c4791862b0d95afa1f3357ebd0f476c26f9fee920a411b9dbbc7383650b09a4c9b3f0ef34697f702f8485643c064d7e74a4abf5fc05066c5bddf9314c4604c7c469046774858023b087eaa031ebdd5503efab23f493fed388f31de0214d79e83c5dcdec2b36f35501f80c28e83087908f06b8cce83c4e013acb98bb54725992fbc594c6b53aae6bc8921cb468a8ba6974beeed0ce4851a7d869a7144669c60115602ba16f963a4c557df7ac09f7cb3015d924cc967f30c61449d90a25d12b3e9b82f6872b7be21d1ad390fd33c23297627ec3c1b9e2399c691c663680653a77ac334e76a3b4e5c1c663c0a276a68d54c3c48daa8a80294067bb9c00f3b31f27af7d8a00a8836993f037b55bb540e55e26856924dc8686506f986a1ae8c772b1d5581e7a0dddf60ae335900708c244b7cc052a61fe09af063658c300438642b0ec173673d0b83b1b1ffde96bafda0364b4b0a03c74be6479f727aa577b9925a5603ca058bdb8b923d891f27aa1bbc752af2b731015be118c96c1204e462a4750d312c0f88eafc2be70066e258b6ed7a6cf35370bf04a61e55346ef38297807075ca7b82a434b7a257d2ab35f235bc0eee65d3c1604d8053dea1c4c23f417b32aa54252a7d71bb6d1f83a0df8247893167159afc48579afaa1c491a594fd86f90405492d999fa4855dfe7c39a32cc08d6310fbb84636c42baf7c77c26216e297500b07d4c7c6745e5a5f0e6b505e30608040f72523b2e903e5d84674f471783e217424a26632931057439d2670313892c7c005134e30da347c38a0a237e83c4ed07362ad744c0011b36f43d2d84502e32bf5d91815b1405dd205802625f70d51a7083a430a56265fa551373af908974eafaa46342ae33207bf72817f7cbc3ccf55b16848482aab6ed45796a4329510111314a0d1ea80f29226d67d167695a944336634446c443cbc92c0698c4b242ee3a7dbfb3252b1b3f082a2a48816c7f29446c5100ce7645a86b681ba1795fec2b03fa855e99c2b76163e86b41b65951e52c20eb36bfd897ce9ed76d0f7830e66ca281c58f714b017fb19bb92b7fe619807052665d7c6b72d6739ec6caf46a06194a4123064442598258aa2f81b300a55b1afad64a58c4be9a2b91f208cbe81806bc05b232a78657297167eb52a85bc52d53351c55c67b7270fa2b04030a0bedf3392599bada17a7c2671d7c81280a27a12a0c173cc4cf758c8b6ae6b0289c8e8ec99d690061cda74b9c3300f687920d55ca46e52bdb71b829f20e0d85bd980ba49b1acacc620eebe7abeae15f8f0164e896325b45965883ce920cc9cdd81eefb46219ec4cdeac44ceaace45217c8434692ee4c07f76cc1afb4a8365925de12bc8031e10641303d1bb5720560e559546b0a0df9766aa42bcfd745cd618159dba45442b57eea557aa34b4911abba7114b6e334f9db9782bf91f68a64f7a94021dca26ab060825c27a04f7c2ab59b837550a31a645a2b22384419967c7a87ce16533a020e6b6234e4b01b2391d017a4371c00cb7680ddb817d61501938a47d4e9442bb336c3d122557bb6dca6b4741ac624fa0881c05c6c04320b7e027a9b4bc477cb24ad63624b7c26510cdbd114a6d8472b99a6e0009b322ea149a298db3843a763460170464d6f03643747856219b5f7608c2f5c131c09d58f90e633a485202875e8605c512690927c7622c812bf11edaa04fc14481a0b25fcff533a84b3880ba4b91d36d9bf55a5ac45980c3954ac11d69f8b1923b934d93ca473431cef19d6fab6b9c07a5d42593f8f8a3da7b656c3f7b335ceb7db3e43c3200fc745286c7f2ba327528f1de1289237ac7066b453388f22b31ee6294a2db569459c8a7a01b708716bf69ae6408a745527e40e17ed2d3d9f949455df7f44ce41ba02d254ad08d4d6407f55b2c0579d5cb3a6691e9434ad77771797bc6250b562d2ee5c2aa04181b08006005826774858009907102ffed3b9cf12d351400000000001c001073616c74406e6f746174696f6e732e6f70656e7067706a732e6f72678155a7e6d32ac7335ff1a029978df850029b0c162104342e5db2de345215cb2c944f7102ffed3b9cf12d0000e7fd0c2752c2767bcc0e3350912fb51f61fb5adb5840a6c4ab6ff28f68565ae2fd59cf66eaff0fb66160b950563d84f4d5ae2312f6f7b4a149dc2d2a1325f3029b09" + +const v4Ed25519X25519Mlkem768X25519PrivateHex = "c5490451d0c6801b244fb7c37b22e30389ed6ec54a1a513c17c0abdf80a1ba08b6b924cc7facb71300aedf469957087ee36e5e890543f9c43c5d053ff79943de26295c1602ade2d4420e7ccd2e5051432075736572202854657374204b657929203c7071632d746573742d6b6579406578616d706c652e636f6d3ec2c00004131b080076058251d0c680030b09070990a3687fdca62e4844351400000000001c001073616c74406e6f746174696f6e732e6f70656e7067706a732e6f7267ac576013c5e068f919493327ea248a80021508021600021901029b03021e09162104bee82527bae0f931a3195628a3687fdca62e48440527090207020000ec02fc28e4ed43d3e3bd62e463a9c60966bfefcc3a289f0407143b38c05fa362f13fc3283dee6dd6c5bb66c65dd369aec120a3f8e70887574e6457efb50bd5b7b90bc7490451d0c68019e87a90f1715ab506de1fa099f575058a214b1f611cfda15e5ae5b6a138f4ef080034cdaface40ae3ff622181e59cce866bc1f456b478f11df0eec634cdc34adbcb140dc2aa04181b080060058251d0c6800990a3687fdca62e4844351400000000001c001073616c74406e6f746174696f6e732e6f70656e7067706a732e6f72673a96950d02bebd6ea2ac52f30c9c1ebb029b0c162104bee82527bae0f931a3195628a3687fdca62e4844000009d218ba560b297d397a966ee38af514aeca31c64acb148ee4d2e3435da04217fcbc149990a17ea54ff08d9015b6c61b7305bfae4f64284968d95a4e2de9f32fa30dc7c4690451d0c680230bbeb5c7810c9ba3633c24273be8a411b84d1b4f23144944bab803f8df44d44946bb045de778267b3b86e15c745cc9c6aa5b92cb18fd6406ee95276d98c8a66b7b3395271d0a1d1181273b406870b4a81a06c2a689b86fd29e837a671b7c1fa23b8c5cb5a5cc6b782c6c8c3dc833bea090efd4302041217211959f913fb1963cddf284a848bf23104a4d18b78b46935363c5e705a77137660d07433f6c38780c94c1949ad8807c1e6bb77a4bb565c3525683891cd220692536af026369826dfa40c3672856384086da21064cf1aa07b81bccf021312129f6e52c19fb72597817d5e205512b8811d128f7b68e53c250d33330392b7788cbbab7d82cfa777aeed5154141b56805c94d7b2542949b42dc851ab90203987410956570b5c881132c0e88ca790c8adb8c97d5d6b5a21469d01949418ba33bb35881ec166068884d53bd53e7214f0a4885a21c54c69326755856c62c0223499e2801f99a96e5734e6a97bf181acd0ed53f27f27402da9fb8b65e40214fb1aaa74a5985b8dcc66d98160448b6d6584d1a467047dc86cb131d529219ece2a86726b57f9b255e514f51e420feeb9abb666bd1372514680cbe571726f0cdde4b76c431113777be79d0162ce8651df0663eb944bfc2a470cc9fd5bc7eb8489db4b50433f81106c2c26be209724396cc582312105781c91a0231102a1911fab74ac3f8a557da5cf756556eb2a967c05161aa2fd815716ab22376a7a31418ac99745a00338c8a89aad4832570069176170fee458391b5b6036ac2470cc09507972eb562f350a9734aa70fa2c03c927a09849a34a2303ef9aee7387a2024b7124b8f4a32abad9ccb075b933827364e9ba01604a4c8584e84336852d83fa067683c14763e7b89eb944ac4eb4fab27951d633696a72dc2e892ec38c242330d1639b65a34b9fd25c00d0b317ae4749acb6ed595c2870828d5a16228b6a26e2a6a18b5c05bd70a0c632057874a1ab78b82594e7a6b976c089d71380c9e4acf5eb57bdbd47fdc00349db59fd6e788a8b3801d62c641f547915165219a68fdfaa39425a5f65410aa9c3c5df3a63ce54600fd9a2da64ddaf42073429676f82237825d4a20c100d15dce709dda4677c7a1a0196371a4fb910da0231220aefd359d008c6054826a1d9a6391cc075d0a74b5367ccde57438d4bbfda375f5f68dd4dbc5682c3d4764a8c0028923c6c40c67a869b9ae298b2731d0b346d7a2f08aa974c460a1241eb5f2275a8132f457ce71726b507c7c02c08938633842224f6b0683ebe129121c196a1c50d2bb4ad016316d7973a3a92bf5391e29c183c8f5afeca2b4b027962591682a5757ce882674103411a5626a05c41708bd1fb15d7a278fb1c224699064f245bb62c58baec62ff50729ac0a66926412dea40c37c5736ff3c456ba4caeca153f6057448a7c05328fb40b7c34f70177a30a25474bcb0631586851ed138a5655680c8cae6cf72aeea684ebf6b1cecb3175e93b12353a10683ac77c66dd540ac7fcc80f14a94f410101ab2ec7b2802a4788ae608b4866a1464b3576a70f652b8d1f8ab9b95a5636babc3427122443c8f52c7cf0577d06e73807c506a2937432b4ad575a3ba17b4e923c5a090baa8fa33e8c7b3611b7b31a46450b1a5e0ab4560336794fb6c6855112c7b56c6879be8e84f0db98d8399c4200f4a6cfe50cc3a99a061b992bcdb93e0c10c79c007b39a7a68a3e910b413ffdb333e0cc3899b73ac1ccb72f47508ef3436824baabf16233bcd06841f209b7be1a8112d46c83c95b1eae991d6a5329785f3fa29eb7b37c28f338747cfbb6ff348b4038ce982256a96c8739d705987b455fbfa913002e43c2aa04181b080060058251d0c6800990a3687fdca62e4844351400000000001c001073616c74406e6f746174696f6e732e6f70656e7067706a732e6f726788d0f59998445c883c9d969ff3c92983029b0c162104bee82527bae0f931a3195628a3687fdca62e48440000c1beb78a7f5586f1c01178eedd3faa2566206c06f06af9d59296f831564bc0e7447851441083487c0d0c9d048f1c94490083127a7d01af29b4a4d050000bbe4bbb03" + +const v6Mldsa65Ed25519Mlkem768X25519PrivateHex = "c5c74b06677485801e000007c0882818406201bb7baeff2bffbe848ce4596c649cc6fdd95ce04c2a1653ae1ab1b8b7081bfeb551b5a0ff6e49fc01a26d0905fe85021ffbb7ef97a9f2065455c7481f0057b90b806e10dc2f45b237ae98bfbaa03e68ed614dfb659926ddb4df0021b8f51ad26c641cbe980c9300b6a52d7c15f079638a0d7c7b6574b285db86aa9aac8e910c37c3fbc44f63cc34ee5d80fc0d351b7490366b0418d914f5ed36765a1b42b94f0e0ad5013543b50c4583d18bd41a2df2d7062e0009d48ae10d3bbc61c22e4641c4c772dfcb2d87edf84c6acccdba824a4fa025e5b07f1eba47d94faebdb66205802fb7494916ac25a339dbdc783d4e3c54aaabce53f4b14a3081be64ff8fe47b1f86c2d739648e428698e7ce95501be02463b2b582227991329adf163bc8356eba2f626d76cd50b4c9979314a0163e7fd7ec47479d04bcce337678324b743f8badcd6ff01b9631a8c6dc34ecfacab634df6e8152678c8326c9fcf4ee7e2838f85e9d053d7fc85643f4e7505caaaee4d7b72bd72541ae1dedc35cef50b85d1658182e2f28c47580d6acd96a11398261e1e68a7a9a5d39a40d80c3d996846d628b6842ab78606112ab6310a3e196c88d44a5c454e1eb9822746e771d23e8b4cbbb90e8c2a1c19d22c8410e2cab35db171169483e5eaad7afb629a950908218992f4f3ed9791cbbce973877466f655d07ab4635e5a1b19b60e05221dd051bb0533360070ac7f44cf7f739831b2639e3a43355b1f30444e50bbaae7f579749943510b10f7cb5f6f3a0816cd8df03425c670514f7d62fd9c7b9c1e7b371301dfd37a7027378de241fc9fbe49dceab675f1696e8334e6fa1ae68ef2358a9240b3de496f46681ff777e7ee75d1df8bb5f2bb60164ee82d94fd3bcc97a6fb44ca7fd4cb8c1a0b9f0272a95cee3507ce1839db9e6f0c657236f86ae4abe76d52133ee3ecb8febf196dd7b25b9781c52c51e49db1d77100b2ea27fb34028f21c404a3b17f01b7a530219d5acd6ddb4e638826aa1007ec7a8faf6c3bcd7e91adae0fafbbda9254f91aeb7d3e880a4dd51aa16cb9a5e90a627297caa9b4df8ceeb83389fddee31a8fd434fea854a4cfdbb56ba87c0fce9c64cd1c97c9863b7703260f35e29f50cc9de111be4e5cc402f8e70e73a8d53891b616231cfb1a8d053a2290b91614c848b166a7f99fcb1d248549c66af6a0cf597d39825e17fb034fac2b46e2363e9e42221adcc3df5564bcdbec309bf87ddedaeac27a33179f76ced85db6e581aaa77b9912ea9ab381e9fc6ca5ca028511532f4f31918b8cc9a7f7541acd3d3f624a85bba1c6ef8163104d52b75634ad9f53ee7e783fab1bc47564cc0d83f8f45544edf18c968e4b8d6aaa0f46747423355d4c74330c88e87ebb89d3796ee01047523d78105242ddfcaffd892052460db2a10c8d4c94e75bb80228cc45a85380f0d2277353836634f1f8af03aed28c89848d87709a9f33c12e5ae19c896b9a8b562d6d1703c0523da88c4ea8ad2f42ab301a524b4b348dddba14e14f094336f6c26439df5ce6c43a7ca18aacaab2954a14ab682f8439ba514d50ecd2616b7845e0d911db06919e54bce08e22d204c21f78a63e810e5e4b2d1247dc45172ac2bc8d4b4aae4b24f51b58fb71c68c8d36c7cde57550b1c7fbabf6c3598667b0646968c6a21a4af66c424345cce0029f4989e69bf9a784b3072b9ad04d72735d1278c5497d12c984c461c9e2418873b9402a1f67d0c939645b29bca83360472d7333000867193c382c37b9e3fe84e3d527a1ce42d752bac88b8a277dc44c6ab6da4b92c8af33e209b13b9ec1fe8c26479e81984009a6c5a41d58289b46b3a5264d8d247977dbcf8d69d2768cc8e85d4ee471a5964b7626d9142bb245ad4d4a401abe97529a49bdb45340481a7f5b4c6b1fc5026d5e907113fdd12b0bb8f9e631140c42e747d6a37a7e64b2aea3c79ca491fe6d7fd8beabdcb9d16ee6d5ac67318e4989b8ad288be42eaf8722489117a2ba7eb8b10e8d7693989d8adf689d21e9e41f84275f70afe147312b18e498ab78b2dca2ab95a5da735c916f9976b8f4ccc10650c1508d3ed58706598ae7216be74039630d3286a03693185b1b854e49ae53b254e75f3234520e74d4c8becc1e025cbfa616de275c14765eb94e4b903d729e70dfd2ac1f32fe2c656f50ba05df78049fc0849ae2261d16d30ee6f4ae92a75b8a78d29d2fbe97f5fc09c1da81d6938fb1ac2bcf066818d8965b58a999d3c4814f2972c56c37d6d216ab5f6d93b723f7dbf9e40280d9d63997a296c9ddcfbbd63d0dc005a3e0bf7fb66e722bac98588afb91d18d307d597c9311ad0f6c1070d1431746f93ba2ddc44d99d3387b45996d14acb909f873aedccf37b0706883b83d99f54f4231b5d7841610c839366d4ae277107f5c2b962c883ce0e93161f142453e8d6d4d0d62e74190419769bfd7355276f915a854e0a178ef92cb714389893372ebf92f572d5255eac4ee11f56951250934fea14e49ff14015102efe1614229d38eab373aa02f6d5a3de3eba8fe88c7e65c72c0bd41db5f4cfa1c9ccd4755eb05b0067f5402699804c4b49d2abd135494105c785fda90037671b27e95d4bf653dc79f167db49fc55e1876761623e0ba69fe9c3fb4aa5561e0f3c57b2a640b89419d522f71d292224ec4400c8d16f7ad64a112d3d98774af029195e31926c482786d7107dd54cbce2c4531b8344b1cf122328643208cf7e37e6affaf20b14d30bdef25e5914fdadd72d0cac2d03a044b0e2b7f11bff7e3cc388eafd85f90044a03bdc2351319534788a215cf0a45b49abcdc700166ed211ae09974e7846b4f0bec69e4fafce3ccbfdbe53ce8e63e1a8a399f7c85615fd368695487363317cc2cccc061f1e0c00000040058267748580030b090703150c08021600029b03021e0922a106a3e2e14b6a493ff930fb27321f125e9a6880338be9fb7da3ae065ea65793242f05270902070200000000af2010c71d71be4816e273c0bd5d4c0dddc175685e5bb6904c01f637b71e20b214f442b39bc82608afa9dfd83758b494b4092e3d573a9dbf94637bcc402829a21e8272fac465a953490b44ef47a47b7cb1e803c538af16bf9be95e28e012289753add53d158708d7f59885fa8448701b3dc6e9fa53be60f0743b0340b7164549bcf00e35d73709e01df8548c4cf39dc6aae9763bda8f1f0be715f2385dd8f297b94771392755f6110e0efeb96a586c601304d99fa06b8f170736f8ba9af6bb5db2837014119213f3e03406b1b8b21965cccd814d84f8b12758d087aebfe729c2ba976cc0006269732a314c5299515087b88cba11e047f69664b9d65edeed0dec8f2e357c9ac70c4fed3ff5a6e7ed698fda111896aade4fcb1752d81147cdd814c09a676fde554b3c9792ba2d9f4813de38798140b7f80f30ee8f606e108000717214e9b5f8cb8bd4d1f709c9af671a1c3a9bb2123ef5eebb92a96cdf6b8e0af52a007e2e3b720cbf85754323f2320de1d70226693067901275242c2c4f24ce591ed73f1dac0c42df99ca8b341fe5b568760e91c9eab0440d1a4094eab07a9d5c520ea1ce9076b1bda3d45bf93582782014ea05d89ea6c61c8fdcfc8e18795463ac9e124c21875bdb3b8b0f0fe89973233a16ecb6dafc3e2a30fa900c584a230e8c299e64e15b061de383e5e0666c955331c609d946c4b23e6535b55a3fd3c2f354b8a93fac6f325535a2588ae627942173cb844a41d832a4b27d2eebb63a94fdccb31960a2e4c2ea19e687d342ce43a941bde41249a99102076ba79e335b6b8619674fcd99625fcc3bb0aa5ab52a6af81ebddf36f085fbe91fcc675660fab363ec13dec7c25bb93a5eafabc548ac74c675d1f61d3a9459ad52a11e38662e5f7cb24131270de9988b51537a7a797a3d35457dd13a418e0b2d799696bca6dd1f58cf55c45b04be6b292037c78995b5ea32fcbd20570f73f1f522ed901523ffd0fb136c4ec45d975cf2a5628e446c463378e74ce9ef749691c6386da8a40138b0d0c8ba94928c504b9b88346b68f0998e96717023c2b40b397ec108d46b3a056e4aebb8b264b16a1b24ebeb75453506e3418655627841e4e91801a1af765cc4cd9406f7b4dc369b0851083f1b62e429653cd13371e4f6288651ba35c48b142f9456f6f2eaeb457d2bbf350bcdf3532b3b35854277504530404e215939b0aa7c3b7ddd9008eb3b1f5852fe0eb906d5e5c0cb7c2b9a73fdcdc6634a9652c402de87df2f1a787be7cf0fb273c9bb733d9dd5325afafc1ab7086ceb3df2830c43f585c09e9bcad19e8504b13bef6f8f5aefff7b58e33eae6b079508a0df4ec383e96a2ef0f6080b2a0e815135efeebeb821c2241f97ab85419c3aafcde5e299eb0c6398b58a16c3d6efbcc42a9f5f24d0db3be3238656be33ae58b4367f9340840f6969a1c93a61b0014c77e7bfaf3eb3616317cc79c1778989e859326c77d19149e0be33e6fbfd88c63b71fdbb2b231ea137ffd549e923f31b9a82e3e2fafabf798808798388b058db5836870d7395f8d0d2cab2dcb45e854aeebb1d2d633e74516f432109fccb0f253ed71a5b56d52e4a0b2a498113aeb7761bcddbf397bf82fcf211356e915fc4beeeb8e0c5da0a94b08328919ca6b4d80949e9bae474e0032f86420231132c66659bc07ed776fd8f81c46767264e31cefbb86105bf627812465a6dd06ac973e49b5031f1f3efc8c9197c41da0d7e674b6134bfd241e403715d4302e3839c78540631a3ac6328a36f535a8334b7a6e387e00fe142cf2c87eb028ae2d48e522925f4a0183b237a0879d9439c9b2ba17b04f351bbfe50bdb1e59c48dcdb74d1871b06bbf07b1bc0227ddc47b2b29cfe7cd796512847e9857419fb91ca98a73d4bfe07be0fe969cad4d08599e61692a69c21aa6172837ab59059435ecda1d3fc6f18bd6f22ce07cf57627ce16fd8221e635e5e9485031ce4d7b5068870066d036af682248acce35dfa21c4b96b952fca084c4222760ae79a1a06cc8a10e47ab8c44ac9cf3d87acd9a4fd653ff897cc1b693bbe9a07580efd17612815ed2d290977ea538f82fc1214128bef9edd385f372d9b158fb0db38667000ffb11e78c1f622586a37108b5f4011c659ddded2100441de95e41d8800051f98053f3b636005381225934941f33481e9c22cc501c68cd34bffe130473e222b450eb2c90caef7a5a68140c660e74e2855869cb5255313d2bd17aaf9b941775e3472d4ce0f283cd4538ce907092a79895ae1d2bdfd023db7c9551c49ea9da264563cd1f0d00c407fad2207cecb8f871ba89bbe2a9ac6e7122179e01d81f98926f1d09a1bea15fc6eac2bd41bae9ec258f51edc4d72ab0ab2ffe0d230a7906e54b04137550437e50dff1b5de276aafd8d4428cf0c8dbdcbf0c555899418051eafc43e99e76e1a0085a6c09a4647bcaf1c56e304b56f06a4bff5151a9b5a15c444fd70e753fee6fffe351d3016af41a7b5ccb5d3e89e21f155c162cb3722573257e07867af9fdc1f8ea2a4e83324c3a1744c4b8a80f9fa0445bbf1523e3ffcbc6e8087e717dedf969ed23f2ced755350ea4bea69e5731586e2ccd20172a731528c1cd84a9552ba831c2596c11de8f0dbc693bed952126fffaa2ce6244931948871af586321b4ba549326226e7e309dc9fe53858cc94d9d9622001897694336ba95a4f6bf9897662e28135783cc73f171528d37907018a09e341e6582b0b8f873d32f4968c1d94b42791dc1a0ef06ccdcb86c82edbfa1147217167dc9812b4978748040ba79e7b96433b0786e490ad2072d147fc1d2c8e344b960edab300ca3b0e4962ed7fe1486bed244def582c074c9f50a8b707fc1f94d03c34f131d9c7772f2b884ce9b2ae0e5017c24b24e9760aceb8190f7ba9bc03f71314fe3bfc745999482a04b712bee5bcae7c736684e253dca33b5c6c89c3bca1bb1cf9eb8abfa12fd3f693db14e606345c439b28bedd1e6fc831c8f698d6b04d0122bd5db7f5e07c4ae3d088bfebf95d6167d276c006c494d2f405cf31dd6da0c1104ce40b51ff93a13b7dda3fae64d2e30a821c0ff012c065161553f8737e140f372a9163f46734bfa12cc1aefc8706260b2436367dad817447570dcccf114e73e56ae2935024e2a6f7bc0760b12dba3b81dc339c536180db504491eb8c9940d1ca52ba708965f2ba629901275a3260578e588ac0cf229a6954b7eb514e0bf3ea5473165ac04bd05d90d3cc25aa6738e7d878ee27eb384669c8baf0c694961cc1f85f4fb95b0a92211d9ece9b4135239fde33c41cf3de025316e74e2a8778fa680906a60098851c5090e4aac4507ab0c8d66cbaad10ed99e7a583e1841ce07ba1255e2b1a08fe29a2949213383c20a0244c28066edb9947af7dbc38545148e859da3e30522d410431f2acc236112a548f663051990554c93c2e914a443e034af28dd537f94a0a6f828c35a0de97ca020423be9ac569f4dd10f42e9b928d87a170df04e675e59c220e47bf554a92d920023f5e954627a5164b56df2777ee2978790b689f45a5ef1b80de8940b0dc79c50b6cf8839cf15031cee7ee4fe10d38a13bbd8b9b3b2f7d7bab326d77fab4a7fb77b7eed56434f2f5e6c5bc932b400ebb21fce257934d8b325e414de97610024d8a9e68e9adebe9065d802c0707f21b14f8fe66b3510c7b46196ace703914a0c9f6fa2e2afa06e5d530d1b329e8727a6fbefeecfb006ca9eaa504f15abff75bffd46b166a71dba1561985e716268f46164c6c9075f708d4adb05e0069749bfd4c990313fa655edae4cb3da9ea6245b65104886aa380ef5150c8840701b1c0f6ebb922bc33d8296236f7ca8052dfca6a662a411a8f7c6ee173394921a56f48b522d93d19fe03ee4dd781695335cc27c713a27c543630a1ccc0de90a0df344b1e6390c078f7fbf61351557952247c87643f61e8ab9e2ae64e09883981959884d490f096861468d4d5ae2931854d78656f0f53a4c6be55fbfcd619349137097b4156868283d1db63a93a439ccba8d78b4ce4d326f44f29a8695e6498289a47da8535f46f942e551b82682426c635c06ea95cdc4f140f19cba838568d33752a794e52ad4a6e6e0b6d1ff97e3353f9bcb5e9a08235f4800b37f0bc425b848b9c7803ddf6ca8077f3bfde80d6acf1705f69e2e231ad2ec1b4ce80e007fd78d289ac8f3ee2dc06ba511ed3de292e47691fc0f8f3034b62aca174d9be53daff46197aba5a6b3d055acf68eb54d4e771b429f3779b49c993f8fb3c07e70040886af5c4736b006ad00910d984251eef4661592593e98591fb074d441c14ca86b01de539616e3dd9aa1d87ceb9d06b310e70d0db239ecc0f8d410248b0580a7b4a846b87cb7f2af2a2ef18774a2cbdccdd14cea056febc588fc7e9d1fbf4fbb77eab18561611d2cf7acd01c766568ca435e161bd7c81748cb5289c12a9cde3d76b35f16b0ef335320fadcc8c091843960d8fc9c7abee39edcf37adfdfb444fc5537d98f566406335c4e75e324e1abebc53887ff3358f2b8892ef4896a9ea1ef4f3991005c26546fc0a43e5b60483cfb906bf9b1700f7559098b4190b8c93b986a365cfbe05631946d07a2a1abefcf4b12b281b4e42e83b60de11cb6e1081f7fcbbfab70c98c32ce30d5cb006c6146381d21ca90190b92982cfbd175b601aa735271aa2cf64c0f45aeda181e499ed6030724518091d5d9ebfe3650a0bbd6f8ff0f636f7eb2b4e1f2124c8d95b7d1d7e9000000000000000000000000000409131a222acd2e5051432075736572202854657374204b657929203c7071632d746573742d6b6579406578616d706c652e636f6d3ec2ccb806131e0c0000002c05826774858002190122a106a3e2e14b6a493ff930fb27321f125e9a6880338be9fb7da3ae065ea65793242f00000000cef210136a34bb166cd1ac8f015ec36677fc2b4c07ab186b8368d88b3d5e1858b26c37ed05ddae78ed19919881d0aa06ad40d2264fcd61cac7ab72234908763cdc3e3fce5165d0d91257a095f77615322d6a0a537aa98ceb23096bc71f03125f401cefcc63119d8ffa8c44d52e7d79cfafdadcc00d5e136f244b1783c566e8bc13bf97ee289e28715a4eb32e76c76d3f5ae06d257e8e27ca8674a43e0359e70ecd3b750f87ae8c30c076997a93182427773e285232e44034e33dcc7baa2ceb738e9c54b49d031e63a6c040f1d6e4d642a94ac367268b49dcd507eb2aa910155167445c9b2d6b3bf9f7fb1c1d337f686a78b0ecd5d06ff55b04cadf9bc6dd7ffff4e364d3edaa0e9dd0fe9f59469ca9d4bfcb3e2c51ceb4a13ef2bdad9a9eb3fccad0567742d4c071396a38d845e297ac638eb428399fe0b1d869e7d2e6312e27df3a6be86532168dc582dfb5816721ecc450de253f529bfb318a5555984c3b030f158e3ace1928ac473e7e219c2856cc547d0a6af5d81c4035b5d46b9eac2eb827936df40f2a8e4c77baac19f50acae0bf90df49ea4b9a066c49def63fab3f320acae80dac825f0c3e80b7841011998739075ea1653762f8d7d9b1487b63ec6adf3e569e73fbd5812063b2a8304ccd795cb3414d227f4f6c6f101259317521e35115ace7e6f6bba4276cf5e7451be1f8d9849ae15f4a2ab4451688490d25cf9fec170ed45d8d845116db20a2685931218c550f28a49f8cca2fe5462f7d849b7346cd2974686cec1593933493002a3811b7d8b99281624623ccf2a1e97169256b780be7ce6572fcb154f6169be5ca914398835507b78b30d34bf928acdf61d929cb95fbf57e04781fc145e2cf1b0a46f8ab335e513c2801116bd7379b825321160ed1c5ede4dc2a015ab9e07b5e0055d9a743dbf60af4a792a5364f0957576658daf17c0a53a0574e8ae981bd43bf5e70bfadd5bc3e80aa544b82c32bc34185966b0b8dc623e8a065dfbee0f16ac0f1187acecefd86fc2aaf4badcbb851fa8c39c143967e95ddcee5300a366401156606128b2afba18920e1f7ad867ee8792b045a0d7655270ccb246cc38582bc2bdb660e8fd019fbc6bf1d8438008b74c135017fc498e1e1e34166a682989ac284821589e815531d8832e469924153b3b00d88986a5deed109abd27751f42d2abb02be9ea9ac26b412ef55c6f40faa594b7b52978890ee0f6fd4ee6915d28ac6a26cf4475cb95710b2463a728fa4f7fca5f97aa90002fe43be2a9979b4372e29e1b8b7d29939dde083c8ccf286275c0822f98471e05f5c41c57fa80736c6cbbe1e3bf53bd189e6fd847f94115bf6b32fb5537c4958723138188d3e10409470d4678ab7886e5dcc0737e4932a5c45c86a768fc0b4d7ecc20b6004b6cf17ff7153ef9de5b78d0d368216d9b137dfc538e4831915b277d091d1bc30c1ce7394b8fd2c764effc301329d0934eb50469ea883132f88a7e15833170eabee288fbb0df13af7592892506890ac62d231a8b1f78ec00eaae29125637c6a77a43f0e9bd3d53964d911648db8e294e78d291a42d350b7cc5a1411f068f2e8f6fda3aa36d7c848057c3e49edb1ddce239e6c99d84ba419a866ef82440a53afc8b06492943444b29167f261b156f3291b7169c55559363b7e20bd802b7137684d3bd0e7678bce89ddd6406733e576687068dedd152e3877306dd3e2993172b73875ff0c4b314473f3575f889bcd1ec644a0e8646e781a592a8ce4dc8f69173ce9e03eec95c0bb49af8a28058dcb272825b9b75f5a36433c0ea62fad4f9d974cdf229f1f5994a571a2c358db74eaafbdfd4ec6b11da0fd14588a55d4428e5b62f737f3e840f75e697c4b588b4e2a504a0c387f5186d967af57c8ce938206339bfdf57a98fe5c6dae3775bb4607fa3e9cda2c8edc634f083fd9cbb9f70305cc90324107c44dece73a27704deacaccfe53233879d3ec9c5d028676cd7b41503bd8ddeac16dbd63ed0e3d3b2c45ffde160ea8b8377c3521ee7b06dafb863826df941ff957491e87f060d36b5bf03b1ff7d47d2a892552a08ad15f0c49ef49d185b6d15494fdf9f47ec73b723983f0fed6a1ad4049d811597b2e9f48b2aa213a4b29d6c9c79ec528a146274e10a068b9e6ceb73b51e4b81789020d0735b4ca15a25f5303438cfed060b28cb19e2e4918f0cbd2038662f0f2b0f658164ca6912a085082be2268a9b114b1cab10bbd0b223fda3b220c321031311177bc980a35980be67f02254bc7f9a2a6b606a850d32f779830d2ce2741683b8877976f2905976ed6a2e7cf6058c0322ee139542889b1d2cc063e1c1c48b9b88930a3e9c669f04fee3bdb49ec47d8c4267c5a56d07e2da17d9b42a842fd957eff87b9114d97719a1dad824374923130b3f2efc7fb23293a93d7505eb4167fcaec738a1882a947648a03b3de2f021657933cfe00c17187052ff002656efca190d2dd18b2d3ba9993df78034958de062cfaefd47aefbd78e13b65bca34acbe42c7e318a15baaf8ce22139bbcfe5f7ebd71654bc41a03815ba26a83c5b525f90cf6b681eebf2c30cdbc47ed8924db516f676cb3a85e750b31b50b0729a6db30a0588afd270da31ebee968a3c179168ff40c105fec03ed185837ecaa969629a094d4d1dc0f4a68cf075811abbdb80dfc29c48d1f1a526919af1a518d19dc3ff2b5f6e139818029e2929f7daaaf70b74e02893167549203bbeffce633adbc3bde037ddb30cd6b7d35ba87ba2f335e3b2a1b37bbf4dfc6c6b66641b699387743c636ef74e514292ec5ad61fa2df2e31c82d72159bd417acd0c47a8ab73038f28600127aea4df03d00a938830012e1a77fffc0ea206e27c8c4e0e4deb58c7744a3a6066f9b4da0b39cc2ac101efb1ba8417e4ff8aa15fd7a38f1c751b28a32579bf642f37680ecf5e46b0d291616b1ed0e34ad3eeaf95cbed402b192fc6b8080d81b41870f66c3298c0571327de413064ffbdf8a62963a4d30a398f364f00f6f79815a7b0ab86a2e22c9d68cff922a6ffc661daebd692c9115e29e457e1ba4cc28ab44c123e06831e10c15ac3d30f76c6b96fdbbe7ea4cefb1168ecd516777613a1b4a4a0566d67dce18d1b741c6698da6a85b43aa6e0eefe9141103a7863140b46dddcac197c1a835054e635f78e94a2d1a2e53cf8ca0e4418eaefc478d021a73c764dc971ba3ddd172cdba9a92e03f05780e5ad3657d797b914c32094e359bf60cac0bf46bda312bf219c32c27a5c027618e97b4dd08db8bf6c5cf92a5fca1b15853bd099e8f4bbee2e1373e52e40beadaa8761d610d739a697c194a5b0cd9181829ec7e3918198e62966b108b5a8ac37f6c6f3ac3ebc9424960b094c7ccbb1dcc063a333766ddaa7b460637c0b69a80fc8330921c7ec7f2295a8d0ea345c0dab5fc56e8b5fcc75fd3314690666ca56db705cecf5438bf78df3c7cbdbd76de042cd03c3e5467aad168476ef202098262ca9341b53c98f30674bb492d467781edda7b9e3de8c0900028cd7ddcfcf485f73bdaa9be55a4ed29c1b12aa49403afc74473188b9a2f4da3f720c27323ec73dfc78d64552647df49a34be87cb5aed75ebff4bb1afb07ab12fb38e20eb09f9d91ef115fdd6a7e7b79fa96cbdca3f27450bb360e007627a7fb88ba3be90df54030d71daf516f78c44e238504b5f06e2d9388ebf298f36e6d1a39b04694c3bac4061ea6964fcf0e9f852cd3face07b7446b98aac85e8740065d387ab07fa9895bf071a610333f1f33978ed0416e2fd8939401004ceccc9aba5ee6b814fa1ee7afa2425ab03da711c8e6df84aab2f656cdb3eeefaf6541d99c57c9c1590c92177ea53b8c4da795bff837cd36b8d98f6ae80b606beb95721b48c243bfa5a46d00b52e6d68530c2291efc8f6afcfa04b59ca2116ef0b4c0c948fb4ec5d6a04644f07781f41dcbdae9ec39031b40b565fd7c5b5eec207bc137e7e5b00348cc2ab37967f557fd9e8ad06a5ea56ad729ed381c73ae73456bf3d346da49fd4b4dac032e9c4e6e73f86ae937f9520ecba9bdd66cc04c61610c08a1963811fb9020eaf6a1cb0963563d98b98bc11c43533c61ed9e5a98116aebcad20a6a42ba01af45bd9eac3eee6fbc83cbe860d761ecd80ec5371b5f66fc07e4be8dd3c8b8f5402fd84990a969bfcef1a4006c4748b19c97c452bcc02356eb4a3764c027f8260dc8a20983b3ecb95de320b360ea08c0e2d25d22a638a94bd3b154cc4537d4df18f9f7f6a98413917bc13b3ae6e01c302183a6912be5a99ce8019919d4b7e4e85895a66b9ab0a60e16b860d13c2cef3ac1e197da51d96493db12af2ba3a79f454bfa84b20e8ea333c909089e911f00dcbdee682df0e8507d1c52961628262e8c7f9180451b8ecf5361c4584f60c7b5c1cbe0ba5e3699cfdf3a234e535777326ce7a58697251489016fb8e56d2f2e0be9747c93e3fb861ddc648c1808a4ebbf44215d3f9111b7d8bf3497a229a1ff9aaa63777afb32e4c5a433fc9547e2510b00c13ec8a4901d58119e519309ec3a4d791cdceaa3c69e61814c35c93d9953fcfe5c40b42997014befec023fd0da277529997e4149cd70f3bd68d2dfb5c63f0a8eb03c2c9548d20e86035c13e123f687de4042f4e2032075691aaffa41610c0a762c1fed57ffa581ec5f0e1d217d5b242f6289fd7680a265001a5a77bfcbc272969a8b938b0dbe86587a1bac00b1d2c87989dc1d2ff2a708493bb2f5c7990d80000000000000000000000000000000000000000000005090e171c21c7c46b066774858023000004c08d197729ba24950ba78dfa3eacfcbb25fda4f745cb58615ac3934659c143ea5d815a5f5bc88d35f781e057bb991a9a678a7bdf8abbbc1b1e5d43b41b6c77135a17e5f4b0a2436972891b178480a1e5c841428ea62c606ab31c496b11e53045d29b39c5d1aeb9c947275a576ce39c22da18a2da67f9382b3c7acc2179cd89fca6216cb010d2cb92081c7a5a507be81c60f56ff097cfef712fb6e8cf7d3225da76caae7c459c258c582a74a7654f9daba64d091d216c12384197818c19ce4b37cd3998202b452ceb13a54aa7a95a31d4036ee25341d0d2b28be5ccc7d1508a73b0b25858be3539f6187a017366f7956112775659543651d0b08115ab732a022928ae4d309a9d67cfcdf2b53112760a1a44957b77126181fe52959d6cc862982b8817c6c00b6ef2c3b1161ab7ca81a49b6a574a35bee9eb9b61f7a24255c993f707baa973edd9455a43709eb3a14ecc2ce8f915ef93040edbb13bcc1a81c9ba125cce487bca8e5b2deacc5cb7cc67abf84692ac4caff9136f834a1d749087ab612168c299aa2720ac263b1ba3588a2cd63ba901d596f6807c9b51a49aa080f25a992538c26de968a4e36e5ce831cb94bb32f51ef530c6bf0737880c671355838ed0c80f29756289249c5291edf385625a3383084fa8a536526820e724c32ad8679537cee3c4010ecb0b81cbb635301c09d90647b29644d3b8bc03cf47e2421a4ab6fe1b43342b10a4b297349869e7e16c21e0c8a9c73716682238ac697ee3177db84e4beab0602576fb1750e328a54954ba068b51c5323bb98cab95cb421fd21b280605af694d6c646f484b7597161fb36aa331c6786cb76769fa6e9fa9049ac208ded470c4095c35fb52b8043a535510ce247d74397e535aba0da01ab52bb84454401c5071fb421220fb5572e1862dfa7b62a43ec2606e1fac255f328681f21e00b791212091002c7b8836ac00c37d1ce7767268bc5e02491f7282c4998a86c656b9a75c1b043b928a02e2642deb5232cc7373dbc171dbd6b00c28886958bec8d00091c77899813a97216313c82e237bc223b7b826b956d42c3cce7150ffaa1150bc6bba26031aa99aa7b8bace29c5fe6551947ab0d3421a40e52265388bce2b5528aa56449171464a4ff1f92ad4683040d210b7102ffd956fe8337f0956aa0e5204987cc5530c38ca4ab4b9d536159687ee6ca2d83132911669b113a462bc7842852eba0431981a269e5c80e637034de946e9ca537eb8c8c6d98eafb498b4a3645eba31890a573f2120b055a71e1060532c06069051393655f3946bfd9b43fe1cb262697969db29c856ce6412cfdca04632358030f099829a7cc8babd954892a1a8aa7c34989d5c1175e01b5d451ab94043d22a851ef204b44618d39758df14c8d1a51e94b72ef5e63014ab600bc040fa6976e4940d37c6ceed789e01023c401b6387949e8d172e089a5eb35305dfa71ba741ba7c78646f9271a8b7c8df962d16e799e42aa32d5b43daba51c09c26bc19be575357be6a43cf30a9795a79bda2bc4c71c3a19675306509f0a08394fcb55e43ab85e7937576ba39025a401a853c0a3955291ad560c4d2e32a2fd17b89407d9fa1ba9f876b09664ba7f25dc2369f4b072ba73337986b81f618b2be6bbfd5ac139f07a13ad6a8ce927b3b8ac12c94116b4c337174dd990b05bded12619c44413d577686d60e8015b15d525aed67832b00daef302123549f1bb54990e8a68678525252f14526595174d11fbf14210c01ac2b8b3ff98c0bc74a7e7e9be3353fdf69348d63bd941a09048f7788a00bdc8dfcbd4bc60ef0f3aac43e691c84df411ad6f08c85c9273abf0d5d7a74a7da6b3380c2ccb806181e0c0000002c058267748580029b0c22a106a3e2e14b6a493ff930fb27321f125e9a6880338be9fb7da3ae065ea65793242f000000001961100e385bfd0a184ad45c1d631e63803881d2a4439c71bc6f2c97643aacc4802234b6a4d0e9227b36cedea87b01cc1ba64eed2b33bc3453c1e1cf44e82a34050be0f657df8a42fbed9d08cab3997dbbfc01511118a6a78bb70628a155cc6fefe3968d7eb176213cd6d2f98bd4f1c3a93d33f3f15132b5cd7d8faac742891da5998bac1dc8c7ab0ca362d363a922866f9014c411cb662ab984fad79c5c7e1da4f7d739c78fd277eb0a9db395a672befd81af1d3a70d3f77839a2aa23343fa78c79c724bca08dcfafb1412fa16d28f325506f0445b1b872f8c44a4c3bdb08915c5556e3256bd66eaeca1d909b41e05572a3c26c0caad646df33e53ba86f7886b194fbc2dee3343a01b3f30148d2bcbb59238179f471fa647a1ba6f971fb10b7c25a03834047217fb00f6c41ac1eaf739ba2467f1a6e98dda8020e8f99fa2f28a59923abf9020f6c14c0b082abb3e8c32ae685e15ebf1a0cade9a92595d0a9b76c3a4a69a528e4f6ce48baab8d4ff8a4b88f3a9bff77e25acf9c49a0b8dba2b02f43efcc57989218c327078d151e9db4d9d6f1174d49199d7d5f09040df202efe66219962e81d3271384fd6fa0872b201e318a07335844b01b1456092b1580ec4e49d15d4057a012a920263431ea23359644d66ddd82f86502f79c990a2c0abd2508c7721e8367cce1e09efb7831681a01be69de96a9f1078f33cf6552970bc672dc91dc2fb3b80a3373592d5a7456af13bb61e334ef228f454131f06a9a5d8ee1775620b388c54b577daa7c8120c16208c0c8e99e48fe85f57c3949c885339c147b7f46848620bfc9910d6a2c0e6397fde9f52cdc2b740ca65842645326520ada360878d4a463cce32ffa77f753a63a94d562612ed3b93eeb7a29492260a4ea674f151e23c0d8ee73cf50d52f88f90bac04c2a68dadfca107be434ddc065c624bf96e908aa839cf0f692d13fe4e35fc87f28653013d5b2bcf110cb8b2cfdb2f1458db5cae2a71b5c80668508e251097399887d5091f45865aeb7db80f9db920030536ece8d6e3fe03e002811d49e645227de59eb35f538d586c5103c3df3057813e10f2707e73d6699bf569b2ec07cb56c082d96dc14196cf8ac49e75ce41c28e248274686af8224190e062ecb14b6ad68a9bd1e1d7737ca708702fc486a666c5726ef724b694b822beb1e4bd26e5c5d6c4e73c352c0f1d80348edaaf24485d297d5f4332559e33c70455f3e50af046d1b3b594a89d436e760ed79d1dbd584ab85bd25d84e93f4271cc0ce4d6b66eac047988a071fb2f2d0735066140e714b4adf20aa9e59f49caf5846cdc58ca6bdaec642d2d3225f020e35be9fbfe2d77e02ef84feabd21b18e1958873cf43e440857e2229f00074e07b4c189adf92a55afe1f58fbe3246f3404624b08dd77d9b7116ca408783ab7a83b9c0c86f2f259ac46c9f8081ddba99315a18dfc6382735a6765056a2bd2d1945c2542326afb39934c826f6bd00052c4aa44740f4f280c7660551bb5e0c04ea6d4f1558529453b62beb3d0f0419ef6674d147eb7f64e11d0e6f437d781a9947a250cc2bbd0f926ef08eb1743146faea3c8b636c249b1bc72cb58a5b4bba82be957745dd146a8ee25f6911270df332930ab49e384439ff35198d797574e961b985e1df4fae572d5b1b917a8aac5e9bcef7c89be4bf08d5159fe4ff176627c4b95e9edf8a70692ab119f907781b6aea42352a37538dbf3f9f8e4316cae9930c885cfd43723edad8337c99b9f60d42f02c4d8f4e349d12881931757fbbd17f1d53d3411b967936c326ec0cc837658359abefd1d8b11eedbee4b9fad4c020e77c9bd85e8dbefc1e43960d226eff5d6c011657d8336b25a1e981cb73250814e13b109052358e2c9bdff8aff1f9b497bb5232dcd5dd868ea135a4c427d4a13eef38ceb4c86e4a13dff938404cfa5f35f07ae3a0be5c915f2d9fad43428c691f3bae3a379f0d9f3fa8b836fcd50d9c35cbe463e7c1a74e3a8174a89e20894493b3af9cb20673f0f399b2b768e4d4ccdf3ac5d4cc14e1f8c4763a9c97c75301f463fbc46b9d490c11846faac3261fadaee3e5a96649d9b017ef1fa7fcdaa6e539802ffade5c5a906e20ae062dabc2fbd8ff44b76beb17493dbd5acedbb518a3fd1ed2a44768524ebd4fa3dd4b444089b884e38f180abcea3698550ab4d4c708b5a01ffff55bf303325322ac44c97cbfea7a2e13ddc82d97c1f94298cea435fb13c0b2a6c1be27e53149cfd616c849dfdc2bcab289c56506d24d616c8fd7be463e27a6153e4b0deb37653756ffc4584bbfedb3b5bcab39874ab34eb7005f30246497023ab431cb70f29eb50f86c1cedf2dd4515a97f19fce878686275616c526958d10e66435cc7b3f82932090d55a87424eae10e8ed891a4d4abadb8aeea1c1d20124b15312f63037883655a61b74beb5d8df64d32fa0995ff59cf29c5eb93da1ba80fea67d1b297e515e813469497a7731748088463ba0815e2e7a728a7ef1b18398d1db7b98b22d7e6dade33af490f41bd583857a1f9c8ee8e881454b1387732b243b5404557dcd4ccf4e976b52607751bedda2802a55ef0f2fceab335dfbaac722de3e0891e16e660b6a442a303c4838de601471a46aed4379451a362a314c4f39b8ec3067ac21fde6dbe85a0441754ce09d1ceb9919ee588be7548cc762fcf094e990dfbff26c25d8d7930f56201e87d1dae64606b2c17444f2bd933c5702d58d83701cd4b0ac030a71947c040003b5d028e1612b77965e303ece0be2152bb1e3cbe7e3e4d097d74151c31f58357221c7a7de3f20e27fa189bb157a8fcf96786b601bac7746dd3112fd438b8ba44c37488413da1f60f3dc31e340e66426d5db57f45695fca917baa567dbc71d257ae94b575733e314b81cc56386ad4be0ea8d51feb624c6c5f26ba180f6ac2e60cc1b4bcef0ba36a502c04814ab557a6c54f26e7ca4dae42ad1e1d89be5d23d842d8855c45630af55c8d83399c0cf2e0dee4cb88fe8e55a3308f727c8f53446e16f2481da8516daac27a1a69c39b8caf841823b8b5b129a6a3d80bc00b162c9414591d9bb9ec7e3daf531747893bf2683d4789ceea96c53c4c68906b997e91bf43f9552c42bef7ddf9940d0414ca577366f0d2950abc4c6fa2041b3d9d48a4239d0bdc020ea4de275d0ea5685c77b7322855596d84cc6325aad40e8ba2cbefb72e3a94f3682a05cdb5cda41ed47aaf9a8ce1e9c19aea48d0807e43cf473649d3d56f7f90f906c965109b15148026993e9947c764ac52c1c4f9cde0210ba5b519ce66113cc7e054daed28f763f10b95c4e32daf0c8bd151daa39dffabee6f70aa2cf9a04d664d69812c20f19984959d28e8244b709c6e6810f7e68799b651902e3736a2440959c7eebdcd55392264eb251e3bea1eef03ff44d311be0305b232d1d70a088429b10c91f53ec0c4b7f73d5160e0731b5f9d3c42b5c54d5cca6cf447ca0023951db7b39211317318b9ba7aff3dcef059a2580f802cc0d4e6daa767dfe99964450490c57991dd9e456c54a0a042f3790b370485f6a1e9c4320b02e1eb2c8f41fd28a5e6d93ee0cf79589a59b7f300807b5ad4bb45b672207ef0d7124cdf421ed6dd28cb5df9352411e62415e12cb038e7979503c4cd4120c687178508e385a85510d29fbb28a681da102ad1a777a3fef0c16f86f264fafc9d437fabed4f6e79b82509179ea671ac91dd75c0292d2a9f2c6d92e2450adb7855012f10ac081842039c1982377ad31913dd3b5413c21c48f8e2ca49ffb2361137e348cd6a4ef4a00e29b59a8c7f866696c5c961b03686a7e62c2be96410721fe7d8a2d7456990dff545467e19cff32b595b98d0a8c984a7c61471cb84e094cd254015768437e16fbc6e8d0eb7a6914fe47657ff6905f8e5e2241f9f6f0a397ccd5adfdf9034f451ecb73918700c6f32e82dbf2e792f370d4cf954f3e4e0d4c990dd71c7e16884efe427a83bdbc40c3f642f5c28259bdb37fc52e820b36bf343566a028ff50b345930641cc61667a9f7f041b68a9773145a34edd72535ebe2d9214a29f35fdd580c56622b5faa60f79ace41053bf41e2eefd55f6cb2fcd103698420a34ba66c630e467af72a16f50b86cfcae300a5c12172e3a43219355641bb57e067407850a162c199aea8c1120743bc436cec310f7a331cb08acda476f800664dacd5ba09a190bb1c4e109fc07e2956a85171e74aad091d0d78a2f0511ff5b8c9127675548df8153acb27d038c3f17d44bf420937639343bfe24f18d72b4bec65eca86a481167ebae76d2e4f31d577f9fa54d48aff54080a3cd991f37012c56231b8619be792ec96e7a4594c8c0ffb36396fe570046eb457df73fb2ceb8d491daca47e9ee7c8ccac9de45473cb175534251b004e0a13a95d68151dd2e6a0bb23ccb1ed89872e9251da24b5e275645f147a7f7b6e0b45cf4902ed9d4c4b9112046a95a81cb00a38977cf86081e00c92869fda200fc824fa628a7ab10ed1e68fe78d0c6c5c1f160480eca2b491f3dfb590054e23ba2b9e45c08d9c41f6056edda9df7598f7c57ffb0656b5a03f0490961625d2db8e945365a3774b1e7246fddeff3310fad7b6a24bda5cc1617d8520c736f766f59c96d9671d34ff9c706bfec69ba5dc5219dacd53d4c48671d43e2e61dc5ff0417e463c7aa294ee8d8551188d5e0b6a45f7356fc9da002331393a5b6b97bad1dc217c9be02d445298bae9192024576268a4bacd14184c7f9da3a60000000000000000000000000000040f13192229" + +const v6Mldsa87Ed448Mlkem1024X448PrivateHex = "c5c74b06677485801e000007c0882818406201bb7baeff2bffbe848ce4596c649cc6fdd95ce04c2a1653ae1ab1b8b7081bfeb551b5a0ff6e49fc01a26d0905fe85021ffbb7ef97a9f2065455c7481f0057b90b806e10dc2f45b237ae98bfbaa03e68ed614dfb659926ddb4df0021b8f51ad26c641cbe980c9300b6a52d7c15f079638a0d7c7b6574b285db86aa9aac8e910c37c3fbc44f63cc34ee5d80fc0d351b7490366b0418d914f5ed36765a1b42b94f0e0ad5013543b50c4583d18bd41a2df2d7062e0009d48ae10d3bbc61c22e4641c4c772dfcb2d87edf84c6acccdba824a4fa025e5b07f1eba47d94faebdb66205802fb7494916ac25a339dbdc783d4e3c54aaabce53f4b14a3081be64ff8fe47b1f86c2d739648e428698e7ce95501be02463b2b582227991329adf163bc8356eba2f626d76cd50b4c9979314a0163e7fd7ec47479d04bcce337678324b743f8badcd6ff01b9631a8c6dc34ecfacab634df6e8152678c8326c9fcf4ee7e2838f85e9d053d7fc85643f4e7505caaaee4d7b72bd72541ae1dedc35cef50b85d1658182e2f28c47580d6acd96a11398261e1e68a7a9a5d39a40d80c3d996846d628b6842ab78606112ab6310a3e196c88d44a5c454e1eb9822746e771d23e8b4cbbb90e8c2a1c19d22c8410e2cab35db171169483e5eaad7afb629a950908218992f4f3ed9791cbbce973877466f655d07ab4635e5a1b19b60e05221dd051bb0533360070ac7f44cf7f739831b2639e3a43355b1f30444e50bbaae7f579749943510b10f7cb5f6f3a0816cd8df03425c670514f7d62fd9c7b9c1e7b371301dfd37a7027378de241fc9fbe49dceab675f1696e8334e6fa1ae68ef2358a9240b3de496f46681ff777e7ee75d1df8bb5f2bb60164ee82d94fd3bcc97a6fb44ca7fd4cb8c1a0b9f0272a95cee3507ce1839db9e6f0c657236f86ae4abe76d52133ee3ecb8febf196dd7b25b9781c52c51e49db1d77100b2ea27fb34028f21c404a3b17f01b7a530219d5acd6ddb4e638826aa1007ec7a8faf6c3bcd7e91adae0fafbbda9254f91aeb7d3e880a4dd51aa16cb9a5e90a627297caa9b4df8ceeb83389fddee31a8fd434fea854a4cfdbb56ba87c0fce9c64cd1c97c9863b7703260f35e29f50cc9de111be4e5cc402f8e70e73a8d53891b616231cfb1a8d053a2290b91614c848b166a7f99fcb1d248549c66af6a0cf597d39825e17fb034fac2b46e2363e9e42221adcc3df5564bcdbec309bf87ddedaeac27a33179f76ced85db6e581aaa77b9912ea9ab381e9fc6ca5ca028511532f4f31918b8cc9a7f7541acd3d3f624a85bba1c6ef8163104d52b75634ad9f53ee7e783fab1bc47564cc0d83f8f45544edf18c968e4b8d6aaa0f46747423355d4c74330c88e87ebb89d3796ee01047523d78105242ddfcaffd892052460db2a10c8d4c94e75bb80228cc45a85380f0d2277353836634f1f8af03aed28c89848d87709a9f33c12e5ae19c896b9a8b562d6d1703c0523da88c4ea8ad2f42ab301a524b4b348dddba14e14f094336f6c26439df5ce6c43a7ca18aacaab2954a14ab682f8439ba514d50ecd2616b7845e0d911db06919e54bce08e22d204c21f78a63e810e5e4b2d1247dc45172ac2bc8d4b4aae4b24f51b58fb71c68c8d36c7cde57550b1c7fbabf6c3598667b0646968c6a21a4af66c424345cce0029f4989e69bf9a784b3072b9ad04d72735d1278c5497d12c984c461c9e2418873b9402a1f67d0c939645b29bca83360472d7333000867193c382c37b9e3fe84e3d527a1ce42d752bac88b8a277dc44c6ab6da4b92c8af33e209b13b9ec1fe8c26479e81984009a6c5a41d58289b46b3a5264d8d247977dbcf8d69d2768cc8e85d4ee471a5964b7626d9142bb245ad4d4a401abe97529a49bdb45340481a7f5b4c6b1fc5026d5e907113fdd12b0bb8f9e631140c42e747d6a37a7e64b2aea3c79ca491fe6d7fd8beabdcb9d16ee6d5ac67318e4989b8ad288be42eaf8722489117a2ba7eb8b10e8d7693989d8adf689d21e9e41f84275f70afe147312b18e498ab78b2dca2ab95a5da735c916f9976b8f4ccc10650c1508d3ed58706598ae7216be74039630d3286a03693185b1b854e49ae53b254e75f3234520e74d4c8becc1e025cbfa616de275c14765eb94e4b903d729e70dfd2ac1f32fe2c656f50ba05df78049fc0849ae2261d16d30ee6f4ae92a75b8a78d29d2fbe97f5fc09c1da81d6938fb1ac2bcf066818d8965b58a999d3c4814f2972c56c37d6d216ab5f6d93b723f7dbf9e40280d9d63997a296c9ddcfbbd63d0dc005a3e0bf7fb66e722bac98588afb91d18d307d597c9311ad0f6c1070d1431746f93ba2ddc44d99d3387b45996d14acb909f873aedccf37b0706883b83d99f54f4231b5d7841610c839366d4ae277107f5c2b962c883ce0e93161f142453e8d6d4d0d62e74190419769bfd7355276f915a854e0a178ef92cb714389893372ebf92f572d5255eac4ee11f56951250934fea14e49ff14015102efe1614229d38eab373aa02f6d5a3de3eba8fe88c7e65c72c0bd41db5f4cfa1c9ccd4755eb05b0067f5402699804c4b49d2abd135494105c785fda90037671b27e95d4bf653dc79f167db49fc55e1876761623e0ba69fe9c3fb4aa5561e0f3c57b2a640b89419d522f71d292224ec4400c8d16f7ad64a112d3d98774af029195e31926c482786d7107dd54cbce2c4531b8344b1cf122328643208cf7e37e6affaf20b14d30bdef25e5914fdadd72d0cac2d03a044b0e2b7f11bff7e3cc388eafd85f90044a03bdc2351319534788a215cf0a45b49abcdc700166ed211ae09974e7846b4f0bec69e4fafce3ccbfdbe53ce8e63e1a8a399f7c85615fd368695487363317cc2cccc061f1e0c00000040058267748580030b090703150c08021600029b03021e0922a106a3e2e14b6a493ff930fb27321f125e9a6880338be9fb7da3ae065ea65793242f05270902070200000000af2010c71d71be4816e273c0bd5d4c0dddc175685e5bb6904c01f637b71e20b214f442b39bc82608afa9dfd83758b494b4092e3d573a9dbf94637bcc402829a21e8272fac465a953490b44ef47a47b7cb1e803c538af16bf9be95e28e012289753add53d158708d7f59885fa8448701b3dc6e9fa53be60f0743b0340b7164549bcf00e35d73709e01df8548c4cf39dc6aae9763bda8f1f0be715f2385dd8f297b94771392755f6110e0efeb96a586c601304d99fa06b8f170736f8ba9af6bb5db2837014119213f3e03406b1b8b21965cccd814d84f8b12758d087aebfe729c2ba976cc0006269732a314c5299515087b88cba11e047f69664b9d65edeed0dec8f2e357c9ac70c4fed3ff5a6e7ed698fda111896aade4fcb1752d81147cdd814c09a676fde554b3c9792ba2d9f4813de38798140b7f80f30ee8f606e108000717214e9b5f8cb8bd4d1f709c9af671a1c3a9bb2123ef5eebb92a96cdf6b8e0af52a007e2e3b720cbf85754323f2320de1d70226693067901275242c2c4f24ce591ed73f1dac0c42df99ca8b341fe5b568760e91c9eab0440d1a4094eab07a9d5c520ea1ce9076b1bda3d45bf93582782014ea05d89ea6c61c8fdcfc8e18795463ac9e124c21875bdb3b8b0f0fe89973233a16ecb6dafc3e2a30fa900c584a230e8c299e64e15b061de383e5e0666c955331c609d946c4b23e6535b55a3fd3c2f354b8a93fac6f325535a2588ae627942173cb844a41d832a4b27d2eebb63a94fdccb31960a2e4c2ea19e687d342ce43a941bde41249a99102076ba79e335b6b8619674fcd99625fcc3bb0aa5ab52a6af81ebddf36f085fbe91fcc675660fab363ec13dec7c25bb93a5eafabc548ac74c675d1f61d3a9459ad52a11e38662e5f7cb24131270de9988b51537a7a797a3d35457dd13a418e0b2d799696bca6dd1f58cf55c45b04be6b292037c78995b5ea32fcbd20570f73f1f522ed901523ffd0fb136c4ec45d975cf2a5628e446c463378e74ce9ef749691c6386da8a40138b0d0c8ba94928c504b9b88346b68f0998e96717023c2b40b397ec108d46b3a056e4aebb8b264b16a1b24ebeb75453506e3418655627841e4e91801a1af765cc4cd9406f7b4dc369b0851083f1b62e429653cd13371e4f6288651ba35c48b142f9456f6f2eaeb457d2bbf350bcdf3532b3b35854277504530404e215939b0aa7c3b7ddd9008eb3b1f5852fe0eb906d5e5c0cb7c2b9a73fdcdc6634a9652c402de87df2f1a787be7cf0fb273c9bb733d9dd5325afafc1ab7086ceb3df2830c43f585c09e9bcad19e8504b13bef6f8f5aefff7b58e33eae6b079508a0df4ec383e96a2ef0f6080b2a0e815135efeebeb821c2241f97ab85419c3aafcde5e299eb0c6398b58a16c3d6efbcc42a9f5f24d0db3be3238656be33ae58b4367f9340840f6969a1c93a61b0014c77e7bfaf3eb3616317cc79c1778989e859326c77d19149e0be33e6fbfd88c63b71fdbb2b231ea137ffd549e923f31b9a82e3e2fafabf798808798388b058db5836870d7395f8d0d2cab2dcb45e854aeebb1d2d633e74516f432109fccb0f253ed71a5b56d52e4a0b2a498113aeb7761bcddbf397bf82fcf211356e915fc4beeeb8e0c5da0a94b08328919ca6b4d80949e9bae474e0032f86420231132c66659bc07ed776fd8f81c46767264e31cefbb86105bf627812465a6dd06ac973e49b5031f1f3efc8c9197c41da0d7e674b6134bfd241e403715d4302e3839c78540631a3ac6328a36f535a8334b7a6e387e00fe142cf2c87eb028ae2d48e522925f4a0183b237a0879d9439c9b2ba17b04f351bbfe50bdb1e59c48dcdb74d1871b06bbf07b1bc0227ddc47b2b29cfe7cd796512847e9857419fb91ca98a73d4bfe07be0fe969cad4d08599e61692a69c21aa6172837ab59059435ecda1d3fc6f18bd6f22ce07cf57627ce16fd8221e635e5e9485031ce4d7b5068870066d036af682248acce35dfa21c4b96b952fca084c4222760ae79a1a06cc8a10e47ab8c44ac9cf3d87acd9a4fd653ff897cc1b693bbe9a07580efd17612815ed2d290977ea538f82fc1214128bef9edd385f372d9b158fb0db38667000ffb11e78c1f622586a37108b5f4011c659ddded2100441de95e41d8800051f98053f3b636005381225934941f33481e9c22cc501c68cd34bffe130473e222b450eb2c90caef7a5a68140c660e74e2855869cb5255313d2bd17aaf9b941775e3472d4ce0f283cd4538ce907092a79895ae1d2bdfd023db7c9551c49ea9da264563cd1f0d00c407fad2207cecb8f871ba89bbe2a9ac6e7122179e01d81f98926f1d09a1bea15fc6eac2bd41bae9ec258f51edc4d72ab0ab2ffe0d230a7906e54b04137550437e50dff1b5de276aafd8d4428cf0c8dbdcbf0c555899418051eafc43e99e76e1a0085a6c09a4647bcaf1c56e304b56f06a4bff5151a9b5a15c444fd70e753fee6fffe351d3016af41a7b5ccb5d3e89e21f155c162cb3722573257e07867af9fdc1f8ea2a4e83324c3a1744c4b8a80f9fa0445bbf1523e3ffcbc6e8087e717dedf969ed23f2ced755350ea4bea69e5731586e2ccd20172a731528c1cd84a9552ba831c2596c11de8f0dbc693bed952126fffaa2ce6244931948871af586321b4ba549326226e7e309dc9fe53858cc94d9d9622001897694336ba95a4f6bf9897662e28135783cc73f171528d37907018a09e341e6582b0b8f873d32f4968c1d94b42791dc1a0ef06ccdcb86c82edbfa1147217167dc9812b4978748040ba79e7b96433b0786e490ad2072d147fc1d2c8e344b960edab300ca3b0e4962ed7fe1486bed244def582c074c9f50a8b707fc1f94d03c34f131d9c7772f2b884ce9b2ae0e5017c24b24e9760aceb8190f7ba9bc03f71314fe3bfc745999482a04b712bee5bcae7c736684e253dca33b5c6c89c3bca1bb1cf9eb8abfa12fd3f693db14e606345c439b28bedd1e6fc831c8f698d6b04d0122bd5db7f5e07c4ae3d088bfebf95d6167d276c006c494d2f405cf31dd6da0c1104ce40b51ff93a13b7dda3fae64d2e30a821c0ff012c065161553f8737e140f372a9163f46734bfa12cc1aefc8706260b2436367dad817447570dcccf114e73e56ae2935024e2a6f7bc0760b12dba3b81dc339c536180db504491eb8c9940d1ca52ba708965f2ba629901275a3260578e588ac0cf229a6954b7eb514e0bf3ea5473165ac04bd05d90d3cc25aa6738e7d878ee27eb384669c8baf0c694961cc1f85f4fb95b0a92211d9ece9b4135239fde33c41cf3de025316e74e2a8778fa680906a60098851c5090e4aac4507ab0c8d66cbaad10ed99e7a583e1841ce07ba1255e2b1a08fe29a2949213383c20a0244c28066edb9947af7dbc38545148e859da3e30522d410431f2acc236112a548f663051990554c93c2e914a443e034af28dd537f94a0a6f828c35a0de97ca020423be9ac569f4dd10f42e9b928d87a170df04e675e59c220e47bf554a92d920023f5e954627a5164b56df2777ee2978790b689f45a5ef1b80de8940b0dc79c50b6cf8839cf15031cee7ee4fe10d38a13bbd8b9b3b2f7d7bab326d77fab4a7fb77b7eed56434f2f5e6c5bc932b400ebb21fce257934d8b325e414de97610024d8a9e68e9adebe9065d802c0707f21b14f8fe66b3510c7b46196ace703914a0c9f6fa2e2afa06e5d530d1b329e8727a6fbefeecfb006ca9eaa504f15abff75bffd46b166a71dba1561985e716268f46164c6c9075f708d4adb05e0069749bfd4c990313fa655edae4cb3da9ea6245b65104886aa380ef5150c8840701b1c0f6ebb922bc33d8296236f7ca8052dfca6a662a411a8f7c6ee173394921a56f48b522d93d19fe03ee4dd781695335cc27c713a27c543630a1ccc0de90a0df344b1e6390c078f7fbf61351557952247c87643f61e8ab9e2ae64e09883981959884d490f096861468d4d5ae2931854d78656f0f53a4c6be55fbfcd619349137097b4156868283d1db63a93a439ccba8d78b4ce4d326f44f29a8695e6498289a47da8535f46f942e551b82682426c635c06ea95cdc4f140f19cba838568d33752a794e52ad4a6e6e0b6d1ff97e3353f9bcb5e9a08235f4800b37f0bc425b848b9c7803ddf6ca8077f3bfde80d6acf1705f69e2e231ad2ec1b4ce80e007fd78d289ac8f3ee2dc06ba511ed3de292e47691fc0f8f3034b62aca174d9be53daff46197aba5a6b3d055acf68eb54d4e771b429f3779b49c993f8fb3c07e70040886af5c4736b006ad00910d984251eef4661592593e98591fb074d441c14ca86b01de539616e3dd9aa1d87ceb9d06b310e70d0db239ecc0f8d410248b0580a7b4a846b87cb7f2af2a2ef18774a2cbdccdd14cea056febc588fc7e9d1fbf4fbb77eab18561611d2cf7acd01c766568ca435e161bd7c81748cb5289c12a9cde3d76b35f16b0ef335320fadcc8c091843960d8fc9c7abee39edcf37adfdfb444fc5537d98f566406335c4e75e324e1abebc53887ff3358f2b8892ef4896a9ea1ef4f3991005c26546fc0a43e5b60483cfb906bf9b1700f7559098b4190b8c93b986a365cfbe05631946d07a2a1abefcf4b12b281b4e42e83b60de11cb6e1081f7fcbbfab70c98c32ce30d5cb006c6146381d21ca90190b92982cfbd175b601aa735271aa2cf64c0f45aeda181e499ed6030724518091d5d9ebfe3650a0bbd6f8ff0f636f7eb2b4e1f2124c8d95b7d1d7e9000000000000000000000000000409131a222acd2e5051432075736572202854657374204b657929203c7071632d746573742d6b6579406578616d706c652e636f6d3ec2ccb806131e0c0000002c05826774858002190122a106a3e2e14b6a493ff930fb27321f125e9a6880338be9fb7da3ae065ea65793242f00000000cef210136a34bb166cd1ac8f015ec36677fc2b4c07ab186b8368d88b3d5e1858b26c37ed05ddae78ed19919881d0aa06ad40d2264fcd61cac7ab72234908763cdc3e3fce5165d0d91257a095f77615322d6a0a537aa98ceb23096bc71f03125f401cefcc63119d8ffa8c44d52e7d79cfafdadcc00d5e136f244b1783c566e8bc13bf97ee289e28715a4eb32e76c76d3f5ae06d257e8e27ca8674a43e0359e70ecd3b750f87ae8c30c076997a93182427773e285232e44034e33dcc7baa2ceb738e9c54b49d031e63a6c040f1d6e4d642a94ac367268b49dcd507eb2aa910155167445c9b2d6b3bf9f7fb1c1d337f686a78b0ecd5d06ff55b04cadf9bc6dd7ffff4e364d3edaa0e9dd0fe9f59469ca9d4bfcb3e2c51ceb4a13ef2bdad9a9eb3fccad0567742d4c071396a38d845e297ac638eb428399fe0b1d869e7d2e6312e27df3a6be86532168dc582dfb5816721ecc450de253f529bfb318a5555984c3b030f158e3ace1928ac473e7e219c2856cc547d0a6af5d81c4035b5d46b9eac2eb827936df40f2a8e4c77baac19f50acae0bf90df49ea4b9a066c49def63fab3f320acae80dac825f0c3e80b7841011998739075ea1653762f8d7d9b1487b63ec6adf3e569e73fbd5812063b2a8304ccd795cb3414d227f4f6c6f101259317521e35115ace7e6f6bba4276cf5e7451be1f8d9849ae15f4a2ab4451688490d25cf9fec170ed45d8d845116db20a2685931218c550f28a49f8cca2fe5462f7d849b7346cd2974686cec1593933493002a3811b7d8b99281624623ccf2a1e97169256b780be7ce6572fcb154f6169be5ca914398835507b78b30d34bf928acdf61d929cb95fbf57e04781fc145e2cf1b0a46f8ab335e513c2801116bd7379b825321160ed1c5ede4dc2a015ab9e07b5e0055d9a743dbf60af4a792a5364f0957576658daf17c0a53a0574e8ae981bd43bf5e70bfadd5bc3e80aa544b82c32bc34185966b0b8dc623e8a065dfbee0f16ac0f1187acecefd86fc2aaf4badcbb851fa8c39c143967e95ddcee5300a366401156606128b2afba18920e1f7ad867ee8792b045a0d7655270ccb246cc38582bc2bdb660e8fd019fbc6bf1d8438008b74c135017fc498e1e1e34166a682989ac284821589e815531d8832e469924153b3b00d88986a5deed109abd27751f42d2abb02be9ea9ac26b412ef55c6f40faa594b7b52978890ee0f6fd4ee6915d28ac6a26cf4475cb95710b2463a728fa4f7fca5f97aa90002fe43be2a9979b4372e29e1b8b7d29939dde083c8ccf286275c0822f98471e05f5c41c57fa80736c6cbbe1e3bf53bd189e6fd847f94115bf6b32fb5537c4958723138188d3e10409470d4678ab7886e5dcc0737e4932a5c45c86a768fc0b4d7ecc20b6004b6cf17ff7153ef9de5b78d0d368216d9b137dfc538e4831915b277d091d1bc30c1ce7394b8fd2c764effc301329d0934eb50469ea883132f88a7e15833170eabee288fbb0df13af7592892506890ac62d231a8b1f78ec00eaae29125637c6a77a43f0e9bd3d53964d911648db8e294e78d291a42d350b7cc5a1411f068f2e8f6fda3aa36d7c848057c3e49edb1ddce239e6c99d84ba419a866ef82440a53afc8b06492943444b29167f261b156f3291b7169c55559363b7e20bd802b7137684d3bd0e7678bce89ddd6406733e576687068dedd152e3877306dd3e2993172b73875ff0c4b314473f3575f889bcd1ec644a0e8646e781a592a8ce4dc8f69173ce9e03eec95c0bb49af8a28058dcb272825b9b75f5a36433c0ea62fad4f9d974cdf229f1f5994a571a2c358db74eaafbdfd4ec6b11da0fd14588a55d4428e5b62f737f3e840f75e697c4b588b4e2a504a0c387f5186d967af57c8ce938206339bfdf57a98fe5c6dae3775bb4607fa3e9cda2c8edc634f083fd9cbb9f70305cc90324107c44dece73a27704deacaccfe53233879d3ec9c5d028676cd7b41503bd8ddeac16dbd63ed0e3d3b2c45ffde160ea8b8377c3521ee7b06dafb863826df941ff957491e87f060d36b5bf03b1ff7d47d2a892552a08ad15f0c49ef49d185b6d15494fdf9f47ec73b723983f0fed6a1ad4049d811597b2e9f48b2aa213a4b29d6c9c79ec528a146274e10a068b9e6ceb73b51e4b81789020d0735b4ca15a25f5303438cfed060b28cb19e2e4918f0cbd2038662f0f2b0f658164ca6912a085082be2268a9b114b1cab10bbd0b223fda3b220c321031311177bc980a35980be67f02254bc7f9a2a6b606a850d32f779830d2ce2741683b8877976f2905976ed6a2e7cf6058c0322ee139542889b1d2cc063e1c1c48b9b88930a3e9c669f04fee3bdb49ec47d8c4267c5a56d07e2da17d9b42a842fd957eff87b9114d97719a1dad824374923130b3f2efc7fb23293a93d7505eb4167fcaec738a1882a947648a03b3de2f021657933cfe00c17187052ff002656efca190d2dd18b2d3ba9993df78034958de062cfaefd47aefbd78e13b65bca34acbe42c7e318a15baaf8ce22139bbcfe5f7ebd71654bc41a03815ba26a83c5b525f90cf6b681eebf2c30cdbc47ed8924db516f676cb3a85e750b31b50b0729a6db30a0588afd270da31ebee968a3c179168ff40c105fec03ed185837ecaa969629a094d4d1dc0f4a68cf075811abbdb80dfc29c48d1f1a526919af1a518d19dc3ff2b5f6e139818029e2929f7daaaf70b74e02893167549203bbeffce633adbc3bde037ddb30cd6b7d35ba87ba2f335e3b2a1b37bbf4dfc6c6b66641b699387743c636ef74e514292ec5ad61fa2df2e31c82d72159bd417acd0c47a8ab73038f28600127aea4df03d00a938830012e1a77fffc0ea206e27c8c4e0e4deb58c7744a3a6066f9b4da0b39cc2ac101efb1ba8417e4ff8aa15fd7a38f1c751b28a32579bf642f37680ecf5e46b0d291616b1ed0e34ad3eeaf95cbed402b192fc6b8080d81b41870f66c3298c0571327de413064ffbdf8a62963a4d30a398f364f00f6f79815a7b0ab86a2e22c9d68cff922a6ffc661daebd692c9115e29e457e1ba4cc28ab44c123e06831e10c15ac3d30f76c6b96fdbbe7ea4cefb1168ecd516777613a1b4a4a0566d67dce18d1b741c6698da6a85b43aa6e0eefe9141103a7863140b46dddcac197c1a835054e635f78e94a2d1a2e53cf8ca0e4418eaefc478d021a73c764dc971ba3ddd172cdba9a92e03f05780e5ad3657d797b914c32094e359bf60cac0bf46bda312bf219c32c27a5c027618e97b4dd08db8bf6c5cf92a5fca1b15853bd099e8f4bbee2e1373e52e40beadaa8761d610d739a697c194a5b0cd9181829ec7e3918198e62966b108b5a8ac37f6c6f3ac3ebc9424960b094c7ccbb1dcc063a333766ddaa7b460637c0b69a80fc8330921c7ec7f2295a8d0ea345c0dab5fc56e8b5fcc75fd3314690666ca56db705cecf5438bf78df3c7cbdbd76de042cd03c3e5467aad168476ef202098262ca9341b53c98f30674bb492d467781edda7b9e3de8c0900028cd7ddcfcf485f73bdaa9be55a4ed29c1b12aa49403afc74473188b9a2f4da3f720c27323ec73dfc78d64552647df49a34be87cb5aed75ebff4bb1afb07ab12fb38e20eb09f9d91ef115fdd6a7e7b79fa96cbdca3f27450bb360e007627a7fb88ba3be90df54030d71daf516f78c44e238504b5f06e2d9388ebf298f36e6d1a39b04694c3bac4061ea6964fcf0e9f852cd3face07b7446b98aac85e8740065d387ab07fa9895bf071a610333f1f33978ed0416e2fd8939401004ceccc9aba5ee6b814fa1ee7afa2425ab03da711c8e6df84aab2f656cdb3eeefaf6541d99c57c9c1590c92177ea53b8c4da795bff837cd36b8d98f6ae80b606beb95721b48c243bfa5a46d00b52e6d68530c2291efc8f6afcfa04b59ca2116ef0b4c0c948fb4ec5d6a04644f07781f41dcbdae9ec39031b40b565fd7c5b5eec207bc137e7e5b00348cc2ab37967f557fd9e8ad06a5ea56ad729ed381c73ae73456bf3d346da49fd4b4dac032e9c4e6e73f86ae937f9520ecba9bdd66cc04c61610c08a1963811fb9020eaf6a1cb0963563d98b98bc11c43533c61ed9e5a98116aebcad20a6a42ba01af45bd9eac3eee6fbc83cbe860d761ecd80ec5371b5f66fc07e4be8dd3c8b8f5402fd84990a969bfcef1a4006c4748b19c97c452bcc02356eb4a3764c027f8260dc8a20983b3ecb95de320b360ea08c0e2d25d22a638a94bd3b154cc4537d4df18f9f7f6a98413917bc13b3ae6e01c302183a6912be5a99ce8019919d4b7e4e85895a66b9ab0a60e16b860d13c2cef3ac1e197da51d96493db12af2ba3a79f454bfa84b20e8ea333c909089e911f00dcbdee682df0e8507d1c52961628262e8c7f9180451b8ecf5361c4584f60c7b5c1cbe0ba5e3699cfdf3a234e535777326ce7a58697251489016fb8e56d2f2e0be9747c93e3fb861ddc648c1808a4ebbf44215d3f9111b7d8bf3497a229a1ff9aaa63777afb32e4c5a433fc9547e2510b00c13ec8a4901d58119e519309ec3a4d791cdceaa3c69e61814c35c93d9953fcfe5c40b42997014befec023fd0da277529997e4149cd70f3bd68d2dfb5c63f0a8eb03c2c9548d20e86035c13e123f687de4042f4e2032075691aaffa41610c0a762c1fed57ffa581ec5f0e1d217d5b242f6289fd7680a265001a5a77bfcbc272969a8b938b0dbe86587a1bac00b1d2c87989dc1d2ff2a708493bb2f5c7990d80000000000000000000000000000000000000000000005090e171c21c7c46b066774858023000004c08d197729ba24950ba78dfa3eacfcbb25fda4f745cb58615ac3934659c143ea5d815a5f5bc88d35f781e057bb991a9a678a7bdf8abbbc1b1e5d43b41b6c77135a17e5f4b0a2436972891b178480a1e5c841428ea62c606ab31c496b11e53045d29b39c5d1aeb9c947275a576ce39c22da18a2da67f9382b3c7acc2179cd89fca6216cb010d2cb92081c7a5a507be81c60f56ff097cfef712fb6e8cf7d3225da76caae7c459c258c582a74a7654f9daba64d091d216c12384197818c19ce4b37cd3998202b452ceb13a54aa7a95a31d4036ee25341d0d2b28be5ccc7d1508a73b0b25858be3539f6187a017366f7956112775659543651d0b08115ab732a022928ae4d309a9d67cfcdf2b53112760a1a44957b77126181fe52959d6cc862982b8817c6c00b6ef2c3b1161ab7ca81a49b6a574a35bee9eb9b61f7a24255c993f707baa973edd9455a43709eb3a14ecc2ce8f915ef93040edbb13bcc1a81c9ba125cce487bca8e5b2deacc5cb7cc67abf84692ac4caff9136f834a1d749087ab612168c299aa2720ac263b1ba3588a2cd63ba901d596f6807c9b51a49aa080f25a992538c26de968a4e36e5ce831cb94bb32f51ef530c6bf0737880c671355838ed0c80f29756289249c5291edf385625a3383084fa8a536526820e724c32ad8679537cee3c4010ecb0b81cbb635301c09d90647b29644d3b8bc03cf47e2421a4ab6fe1b43342b10a4b297349869e7e16c21e0c8a9c73716682238ac697ee3177db84e4beab0602576fb1750e328a54954ba068b51c5323bb98cab95cb421fd21b280605af694d6c646f484b7597161fb36aa331c6786cb76769fa6e9fa9049ac208ded470c4095c35fb52b8043a535510ce247d74397e535aba0da01ab52bb84454401c5071fb421220fb5572e1862dfa7b62a43ec2606e1fac255f328681f21e00b791212091002c7b8836ac00c37d1ce7767268bc5e02491f7282c4998a86c656b9a75c1b043b928a02e2642deb5232cc7373dbc171dbd6b00c28886958bec8d00091c77899813a97216313c82e237bc223b7b826b956d42c3cce7150ffaa1150bc6bba26031aa99aa7b8bace29c5fe6551947ab0d3421a40e52265388bce2b5528aa56449171464a4ff1f92ad4683040d210b7102ffd956fe8337f0956aa0e5204987cc5530c38ca4ab4b9d536159687ee6ca2d83132911669b113a462bc7842852eba0431981a269e5c80e637034de946e9ca537eb8c8c6d98eafb498b4a3645eba31890a573f2120b055a71e1060532c06069051393655f3946bfd9b43fe1cb262697969db29c856ce6412cfdca04632358030f099829a7cc8babd954892a1a8aa7c34989d5c1175e01b5d451ab94043d22a851ef204b44618d39758df14c8d1a51e94b72ef5e63014ab600bc040fa6976e4940d37c6ceed789e01023c401b6387949e8d172e089a5eb35305dfa71ba741ba7c78646f9271a8b7c8df962d16e799e42aa32d5b43daba51c09c26bc19be575357be6a43cf30a9795a79bda2bc4c71c3a19675306509f0a08394fcb55e43ab85e7937576ba39025a401a853c0a3955291ad560c4d2e32a2fd17b89407d9fa1ba9f876b09664ba7f25dc2369f4b072ba73337986b81f618b2be6bbfd5ac139f07a13ad6a8ce927b3b8ac12c94116b4c337174dd990b05bded12619c44413d577686d60e8015b15d525aed67832b00daef302123549f1bb54990e8a68678525252f14526595174d11fbf14210c01ac2b8b3ff98c0bc74a7e7e9be3353fdf69348d63bd941a09048f7788a00bdc8dfcbd4bc60ef0f3aac43e691c84df411ad6f08c85c9273abf0d5d7a74a7da6b3380c2ccb806181e0c0000002c058267748580029b0c22a106a3e2e14b6a493ff930fb27321f125e9a6880338be9fb7da3ae065ea65793242f000000001961100e385bfd0a184ad45c1d631e63803881d2a4439c71bc6f2c97643aacc4802234b6a4d0e9227b36cedea87b01cc1ba64eed2b33bc3453c1e1cf44e82a34050be0f657df8a42fbed9d08cab3997dbbfc01511118a6a78bb70628a155cc6fefe3968d7eb176213cd6d2f98bd4f1c3a93d33f3f15132b5cd7d8faac742891da5998bac1dc8c7ab0ca362d363a922866f9014c411cb662ab984fad79c5c7e1da4f7d739c78fd277eb0a9db395a672befd81af1d3a70d3f77839a2aa23343fa78c79c724bca08dcfafb1412fa16d28f325506f0445b1b872f8c44a4c3bdb08915c5556e3256bd66eaeca1d909b41e05572a3c26c0caad646df33e53ba86f7886b194fbc2dee3343a01b3f30148d2bcbb59238179f471fa647a1ba6f971fb10b7c25a03834047217fb00f6c41ac1eaf739ba2467f1a6e98dda8020e8f99fa2f28a59923abf9020f6c14c0b082abb3e8c32ae685e15ebf1a0cade9a92595d0a9b76c3a4a69a528e4f6ce48baab8d4ff8a4b88f3a9bff77e25acf9c49a0b8dba2b02f43efcc57989218c327078d151e9db4d9d6f1174d49199d7d5f09040df202efe66219962e81d3271384fd6fa0872b201e318a07335844b01b1456092b1580ec4e49d15d4057a012a920263431ea23359644d66ddd82f86502f79c990a2c0abd2508c7721e8367cce1e09efb7831681a01be69de96a9f1078f33cf6552970bc672dc91dc2fb3b80a3373592d5a7456af13bb61e334ef228f454131f06a9a5d8ee1775620b388c54b577daa7c8120c16208c0c8e99e48fe85f57c3949c885339c147b7f46848620bfc9910d6a2c0e6397fde9f52cdc2b740ca65842645326520ada360878d4a463cce32ffa77f753a63a94d562612ed3b93eeb7a29492260a4ea674f151e23c0d8ee73cf50d52f88f90bac04c2a68dadfca107be434ddc065c624bf96e908aa839cf0f692d13fe4e35fc87f28653013d5b2bcf110cb8b2cfdb2f1458db5cae2a71b5c80668508e251097399887d5091f45865aeb7db80f9db920030536ece8d6e3fe03e002811d49e645227de59eb35f538d586c5103c3df3057813e10f2707e73d6699bf569b2ec07cb56c082d96dc14196cf8ac49e75ce41c28e248274686af8224190e062ecb14b6ad68a9bd1e1d7737ca708702fc486a666c5726ef724b694b822beb1e4bd26e5c5d6c4e73c352c0f1d80348edaaf24485d297d5f4332559e33c70455f3e50af046d1b3b594a89d436e760ed79d1dbd584ab85bd25d84e93f4271cc0ce4d6b66eac047988a071fb2f2d0735066140e714b4adf20aa9e59f49caf5846cdc58ca6bdaec642d2d3225f020e35be9fbfe2d77e02ef84feabd21b18e1958873cf43e440857e2229f00074e07b4c189adf92a55afe1f58fbe3246f3404624b08dd77d9b7116ca408783ab7a83b9c0c86f2f259ac46c9f8081ddba99315a18dfc6382735a6765056a2bd2d1945c2542326afb39934c826f6bd00052c4aa44740f4f280c7660551bb5e0c04ea6d4f1558529453b62beb3d0f0419ef6674d147eb7f64e11d0e6f437d781a9947a250cc2bbd0f926ef08eb1743146faea3c8b636c249b1bc72cb58a5b4bba82be957745dd146a8ee25f6911270df332930ab49e384439ff35198d797574e961b985e1df4fae572d5b1b917a8aac5e9bcef7c89be4bf08d5159fe4ff176627c4b95e9edf8a70692ab119f907781b6aea42352a37538dbf3f9f8e4316cae9930c885cfd43723edad8337c99b9f60d42f02c4d8f4e349d12881931757fbbd17f1d53d3411b967936c326ec0cc837658359abefd1d8b11eedbee4b9fad4c020e77c9bd85e8dbefc1e43960d226eff5d6c011657d8336b25a1e981cb73250814e13b109052358e2c9bdff8aff1f9b497bb5232dcd5dd868ea135a4c427d4a13eef38ceb4c86e4a13dff938404cfa5f35f07ae3a0be5c915f2d9fad43428c691f3bae3a379f0d9f3fa8b836fcd50d9c35cbe463e7c1a74e3a8174a89e20894493b3af9cb20673f0f399b2b768e4d4ccdf3ac5d4cc14e1f8c4763a9c97c75301f463fbc46b9d490c11846faac3261fadaee3e5a96649d9b017ef1fa7fcdaa6e539802ffade5c5a906e20ae062dabc2fbd8ff44b76beb17493dbd5acedbb518a3fd1ed2a44768524ebd4fa3dd4b444089b884e38f180abcea3698550ab4d4c708b5a01ffff55bf303325322ac44c97cbfea7a2e13ddc82d97c1f94298cea435fb13c0b2a6c1be27e53149cfd616c849dfdc2bcab289c56506d24d616c8fd7be463e27a6153e4b0deb37653756ffc4584bbfedb3b5bcab39874ab34eb7005f30246497023ab431cb70f29eb50f86c1cedf2dd4515a97f19fce878686275616c526958d10e66435cc7b3f82932090d55a87424eae10e8ed891a4d4abadb8aeea1c1d20124b15312f63037883655a61b74beb5d8df64d32fa0995ff59cf29c5eb93da1ba80fea67d1b297e515e813469497a7731748088463ba0815e2e7a728a7ef1b18398d1db7b98b22d7e6dade33af490f41bd583857a1f9c8ee8e881454b1387732b243b5404557dcd4ccf4e976b52607751bedda2802a55ef0f2fceab335dfbaac722de3e0891e16e660b6a442a303c4838de601471a46aed4379451a362a314c4f39b8ec3067ac21fde6dbe85a0441754ce09d1ceb9919ee588be7548cc762fcf094e990dfbff26c25d8d7930f56201e87d1dae64606b2c17444f2bd933c5702d58d83701cd4b0ac030a71947c040003b5d028e1612b77965e303ece0be2152bb1e3cbe7e3e4d097d74151c31f58357221c7a7de3f20e27fa189bb157a8fcf96786b601bac7746dd3112fd438b8ba44c37488413da1f60f3dc31e340e66426d5db57f45695fca917baa567dbc71d257ae94b575733e314b81cc56386ad4be0ea8d51feb624c6c5f26ba180f6ac2e60cc1b4bcef0ba36a502c04814ab557a6c54f26e7ca4dae42ad1e1d89be5d23d842d8855c45630af55c8d83399c0cf2e0dee4cb88fe8e55a3308f727c8f53446e16f2481da8516daac27a1a69c39b8caf841823b8b5b129a6a3d80bc00b162c9414591d9bb9ec7e3daf531747893bf2683d4789ceea96c53c4c68906b997e91bf43f9552c42bef7ddf9940d0414ca577366f0d2950abc4c6fa2041b3d9d48a4239d0bdc020ea4de275d0ea5685c77b7322855596d84cc6325aad40e8ba2cbefb72e3a94f3682a05cdb5cda41ed47aaf9a8ce1e9c19aea48d0807e43cf473649d3d56f7f90f906c965109b15148026993e9947c764ac52c1c4f9cde0210ba5b519ce66113cc7e054daed28f763f10b95c4e32daf0c8bd151daa39dffabee6f70aa2cf9a04d664d69812c20f19984959d28e8244b709c6e6810f7e68799b651902e3736a2440959c7eebdcd55392264eb251e3bea1eef03ff44d311be0305b232d1d70a088429b10c91f53ec0c4b7f73d5160e0731b5f9d3c42b5c54d5cca6cf447ca0023951db7b39211317318b9ba7aff3dcef059a2580f802cc0d4e6daa767dfe99964450490c57991dd9e456c54a0a042f3790b370485f6a1e9c4320b02e1eb2c8f41fd28a5e6d93ee0cf79589a59b7f300807b5ad4bb45b672207ef0d7124cdf421ed6dd28cb5df9352411e62415e12cb038e7979503c4cd4120c687178508e385a85510d29fbb28a681da102ad1a777a3fef0c16f86f264fafc9d437fabed4f6e79b82509179ea671ac91dd75c0292d2a9f2c6d92e2450adb7855012f10ac081842039c1982377ad31913dd3b5413c21c48f8e2ca49ffb2361137e348cd6a4ef4a00e29b59a8c7f866696c5c961b03686a7e62c2be96410721fe7d8a2d7456990dff545467e19cff32b595b98d0a8c984a7c61471cb84e094cd254015768437e16fbc6e8d0eb7a6914fe47657ff6905f8e5e2241f9f6f0a397ccd5adfdf9034f451ecb73918700c6f32e82dbf2e792f370d4cf954f3e4e0d4c990dd71c7e16884efe427a83bdbc40c3f642f5c28259bdb37fc52e820b36bf343566a028ff50b345930641cc61667a9f7f041b68a9773145a34edd72535ebe2d9214a29f35fdd580c56622b5faa60f79ace41053bf41e2eefd55f6cb2fcd103698420a34ba66c630e467af72a16f50b86cfcae300a5c12172e3a43219355641bb57e067407850a162c199aea8c1120743bc436cec310f7a331cb08acda476f800664dacd5ba09a190bb1c4e109fc07e2956a85171e74aad091d0d78a2f0511ff5b8c9127675548df8153acb27d038c3f17d44bf420937639343bfe24f18d72b4bec65eca86a481167ebae76d2e4f31d577f9fa54d48aff54080a3cd991f37012c56231b8619be792ec96e7a4594c8c0ffb36396fe570046eb457df73fb2ceb8d491daca47e9ee7c8ccac9de45473cb175534251b004e0a13a95d68151dd2e6a0bb23ccb1ed89872e9251da24b5e275645f147a7f7b6e0b45cf4902ed9d4c4b9112046a95a81cb00a38977cf86081e00c92869fda200fc824fa628a7ab10ed1e68fe78d0c6c5c1f160480eca2b491f3dfb590054e23ba2b9e45c08d9c41f6056edda9df7598f7c57ffb0656b5a03f0490961625d2db8e945365a3774b1e7246fddeff3310fad7b6a24bda5cc1617d8520c736f766f59c96d9671d34ff9c706bfec69ba5dc5219dacd53d4c48671d43e2e61dc5ff0417e463c7aa294ee8d8551188d5e0b6a45f7356fc9da002331393a5b6b97bad1dc217c9be02d445298bae9192024576268a4bacd14184c7f9da3a60000000000000000000000000000040f13192229" + +const v6Slhdsa128sMlkem768X25519PrivateHex = "c56b0667748580200000002040f0cd1cd872cc9d8f3f0d1e934016d1bcb6c9e969cbb1f15b4385ea7dcd86ba00bf4cb70066e1856e697ba3ce84cc91f1576fd7f9c7836c3a9af0cc5c79e0fadd40f0cd1cd872cc9d8f3f0d1e934016d1bcb6c9e969cbb1f15b4385ea7dcd86bac2de4f061f200c00000040058267748580030b090703150c08021600029b03021e0922a106eed4d13fc36c78e48276a93233339c4dd230fd5f6f5c5b82c63d5c0b5e361d9205270902070200000000a7251027b424726ea0a93237f7b4b67994eca5e50b3e69c97576f8396dec90bbb43eed2710129065abd9db50900e0c855b6131303e5bddbddb7daf893c9b9fe71c240153249e434288a751c1f788882f87c57a4de8a3ef1e619c8d7c0cdd47cee78b3cc2f275435cd30246e6745b87838c089fa03069b6191824550a8646180925dc4c7445da4cf0d3b080ff7c2b8650b7a5d00007122a557c5dd73f44ac372e7ded054e8067e10c6fc3fc9935c49032e56c7512c36c820e6a91d69f81edd4d51b986ee169296959fb8fbc4aa96e3546da6756c58064b858fa63450eb4cc54ea20730e28f0a155c439338104d973e89cbed6d36bbfdfc4a0ba13e4e83419512bf3d7eb1f2d0be7c859777e05cfb4170c985d1d38fc1d9508c112a30608292ae2ad43775521176f5ae1b2b21921a0503e4937b90071013b6275b00e0c9ac04308b93f7b5a68b6da91f8451db9c551f02740fd90507a28507339b52bafc3324fb60f0dda7d5b9ed06f0f650cb333bd0914dc7a75cdfe233681ac5b6ba8e8ee275e2ef7a10db3d39c07bbd7a5ebefd6314c565d44894592cb41a41c61961841b3ce447da4086cac8e808507f04ea9dbc1a4e15a50e066dca0f10d3282da2d6a980d84c640210490b1550ddcf3b8b3f0b0bd48fcfd6ed7bf79abf1babc6e9accb894e754644e1757ee88c4bdacd35d8e6a0ae29ca960993ea428a7dc573badcbfcb67e0f5d1f63566ba92bf6050a6b49e0f2e23ae3a4d3a9724cead267f761839407e2e343505ebe6a93bd09b8b3c27e3e745ce009560e4f6be0c0f738b3cc2d8d12a44ee4ac13b87948de1e15557b9c6470b4ca85a34177dff47d19d0484f8d7253c0a8461d2e462816ebefac3f4026b336fe29d17e380da510e37c863e52b68445760eb5c666de50660412bf685bc97b025637e4bc2993d305ae607943d77e68a8f097ba7375f0d637219806c9002b330645caa2ecfce83e3239785901d1ec51d37c69727672ab0e319d32df0f41eb68d4b654e7883ffa608e4d0aee8a72040494ee06ea718c78eec83cf9ad2f4099da319e22f42954ce0e84910d1e47c5f29f0afde3592905278206ae3bf3bd95253a9a87c219b4f1d9b89c705a77777b3dbfaf9cc5e32634a40cba4916fccadbd85fc92b0bdf8b43f63bdc23fafee0f52619c9a775d032c4de1d19425b68a21b37a1904a1cecb68d14d980c763b191854c25d7ae2a9f84e9883d3986fc81f14e6a5b328567713cbca12534e15cc6db3006b4df782cbce65e9c068ec0621d45d991524d8c25a708ebcbd0ae4df70190e7ac9cfa4e64d52c0d8c986033a4c7cfb454741bdfd3d90a332bca76f7a4cce55c5b76c9ef350891aa96642f2e312d336205952567182670325bac4071abb1078715118e22af1a9da000f687517ef404943b76c85763d0705c9098d9e3b64672f193fd9bb9bbf98c1a8c4ad6c63359bfc64c21302d2db8d0bbc87cb07a083abfe252b0be6a144bf39d3aac0f50d2bd9bb63664f1d486673fef8fd230e05ea609dcbc3a3d83999964b7ee9c340a4cda19fafd6289617e4652b8d23f001374613984125e1eb86f1b9a70e189c71ce13116cdb18428b55567737b14f4833d93c28e18642c387cbf802a3112ecab7513c05fbaee4faf03c24a59b259891c2d2e39c9277bf381e34467bce5837358b6367b0a4c1eab2433f13a141dba6a1b31ae4143320c93c14b4ed407b6ff6b5d3295d6b2c3c603474c15de1427bdfc6752a4dd10724292b82766d13b4a7e73158df559c0150e2150bea49e41eeaf3d2ec85c9ce63fab63cb30220860dc831fe9d0b2048d0df680e27be7b1b99ddf3c20299ebf613502bbd3d4eb4af9a30906fd664e06671434dc136ecdff12fb6a9e927240264e0fa842df3175b6c422531ad318162286fc0699c9f503f4dfe8504bb264d901fc67a29fff012cad19ff0432c451d2977c3d76cfd54415cd96b4ee78e7d53582cf6cd437c46bf6842ec44ef7c708fef7caa56defc7879a34bbb55b67b891ac0d63a66a0ba43155e880a52ca440c18af2c617c654af262b5614947dba18ec3a064a9f5d157939ef5d5a58372f2a5635446275d6322b793228d25ba2dc9896f6249e32374c4fb22dd734a5f372bc6a788b2d310567dde0a5e114a2886b6bb91bbb80b488a90cc26e42146cadc8619fe9be2098bc4024023ac8aa4c104044969831e5507d1fd98bc2d916c5864a9e474ad12220e9c212918b67b3a7cb4f9e648dd4d2bf809d017864787497f2c15aca1640324c05d3a5e1df9f4db04360d2daa32e7af45312e17d252ca120d284fb9969da8a675a6b4dded396bf380180cefa2372138939a340abb6678bffc6b25d018f36920957ae46b0e9531bf9d5557b650dfbdfa0e48ab6a126e19849e8c7a1b5c0da82c851b45314435abfaa8b59e76413d52c63fb5131727bd76ea1b9e4e3bf1f6f07705b941ab29c2076847d8f2a840bce3bfe450bfb23248116b3c221c36d450008b8b66b6f79da603023d4d83a76bbfddf5e0fd6e85ed1e3fe6581ff3b87d1a3272f76026f707576c11ffb439b5db1b91a4d27beeb3115a80d6fae45b88d3906f8d09c281ece0e6c55aae6c227827e0e5f3b30273214714e40f078441d8f6bbe98ef9b46324673c978c9a4d750e546d544ca009cda1465e3169ac36e96daf9aea12b3e41595afaaaf3208d0e70184b8563e08b0cac2aa0ba6b83cf4a5168f0160614cca3be157e8ca0cc2b6b435e8d4ec9cdf9639e6759bda9c062015a6f0b8642073b61354e005c333afecfaf0eeb9e301fa5c409ba9406048a2f3b19b6c74cfe4b9f778d43345daf3c4abccb01f5a4ed4187d02faf1d17cbc0aca44ad9a4e05d42b6ccc361324d8655f1af41f00ba2aa9285fab5d2ffcd4a423eb180c321dbd809917918db2c49c1c0e9ffc157f71c9c326a3f93c852af24969c59a19de75bf732bd1f41aabee1561a809a82abc8399af28f14cece5fdbc5bd812e4448910725fc28beea0473bbee9285561bffc82a38ea6c190ba65ebb040619c4b2e22c973ce74c4d415c3ce992eb7ecc6027c05ba3ba9e4bb9d0fa4f52d3adf8d170801bbcf42d6e26061935a070f8d0944f0b01c7c04bcf8651f67a631f2e19438c638a4a1e6c033e0961d4e2a69e581dd9b9a6b16d2b67b8ca7dae6269cc29ddda5c8dd4ad88278c36c26284cf97a9956ee91afd1013ab7817e547b31e1244c8fa1f8db5310676600269a98fe6db9399a069faed90af931b3fc1858d9e961b0fd6a49df5bc28210d4487e7c9f80376d585ef1775425fe5c05348e12019269357f95e1516893db1a09b48e092de9a094545c026a68ee53b30b458e7752bd1e2de8287008a830da057b5f54354804b6e21b1d3242239311c56781eaf74fb1f7c9e9a6c3526f142a8155488540c7a527850d6741ba88fa73a3590f6e3a38332258b071d66ed11357944ebbc22582340caa829807332eb1c1a68c13e8dab1ef82a68502027b13a6cae703c6b2e73952d203945a9eea3f3b006f2ff1971a8c98c42e1620471b7c572be1dbfb8e7018a65c63e43d9fb339c58cc2819aa50932e6092a34db5e105485fd40782ccef9d639ee6e276af9fb47668de24dc8afacedb259c3ace29aee54d7926c91c2517b3d96401ab19c21a13edde5235fea3c8ee8a0bf86c57e966df903e8ad204f32995b8c2f5f3b1210da69818658a7ecc5f496fbea5c504a69e2cdefa0abe6cc68a32b7fb0484fb1a0b1c857a36fdcfb8d35433e1e701e5d68b0e528108629ef64c6797ebf1d41f72af0769f497df7db8264294f089893a427a8c291ae0e6c2d5a35c704637fa7c5268f926f6b2c8a84032fe2e09c7c31742e8b0b009057130ded3e31eb827a9c464d2d2bb4e8e34833e6de9c7aa8f46c99f57bc22202eb45923bac6e752fffcb9deebfd595e186137750ca3065d22a194cd19b10d2dc293a33c4f5f32ffee123f908167d83ca90db54a24ecd19bc7ad1c407eef0a5f6019172e79d67c8c67bceb07d26c2387e63e5ac59084a0e309a12a1147add471ec55ae650bc1f436f06862dc90e20d4152d7dd16bc79147875b3cd70ed9ce2c50e9549287a55293c7c1c955222458079fca07f741e6e4566c8b8c927228d1910a662605ce4f61e063391566bc117f01fc8dcb0b765a9613938e9a1a468a0ef73b1686b939f1699fae591741469622629d7b42e797ba784e4ac014f0fd53a615433c25fba2c22716ff6deafea88d0009a02fe960a55e1f4029307d38bf98120f8d6773739dde1b49d4f93c54a9dfc625c870ee0aa047d5650b49dfe069498c1a1e24af6e7cc1a64fd08a391e08c2c81efceaaecaf51d8e6c32935d02d0ef9385062f99281da81dc9108114c7766382d3beeff9570ffff3879fdd7854e2ee23cead72f1f8ffd84f73285097575766bebc17773dd86d770b3a0ac0b7346fa19b33e3cd6b938d0bad4410b7cf59a088e8bddbb80f0bd72f9ac6dc4cabdaab08814b286a7eb7164fa0441b479325af374e6734a64578c3d19d061e186fe89fbfd2fdee2f347e6b6255386884d08cfd100d0d59f7e48bc8427058e822785ff2a4947d2613ed30bed5a1f0ac6d99356ecc0fa3e9eaa752b960278a70f0109fdc02e7f1ea016ac65f84bbbaa7e4d91216a8e6e91701cf0c801755406b3a3524eb327c3ae01e4b17d7ac58b1fb42a0898b44c31458c3e6d07223787886f2c3df2678df2c7ed8cb2344e51bcb6b4d060a48e01420bf4bbe4d2282f342cf9cea9124fc44954fc29f35159634496c61cd8a4a443815f0e227d2d429d3f65fd5f86c7cea422131b984d7c4e1c4e3bce5a033ddc2b0c0f383d00c9310f1bd0fe1eca3355a1e28b3279943cb58592fbf555f371298b55af775b7d6ad271cd1c41fb2c45a8075d390fac7e310fac6e8b4bff1f1149477737c14176885063d7be27266f0407f1734496812adc805a5dce4657d775bb693677f107a940228af9b820b58004f3833e657b78c9c6eff5d02826ec24d85fe3c858c32d148bf5cf6d55335857c4f1cd3f2654df0fcf63afe706836fef36eeebb9caa93ccdbfcd2d9e136b2ae98743420fe1c7b681b070f5b5a5c3d96715db2e50b39b0e0d2ad994830f99e09f46da60ad09f3f80ffdacee10ef38ea5eb3c7f919390c2f79691eb89316ff1783f67abf4703404cf21c372bb2d6c1bf292330aa355b23e75c6b9c6a0b29698c0cf0a98f311b089cb19adee3046f7b00a8605f53375ad63089ceb8bbf4fe2240319821e30235c6576f178b8280ef41ec7db267a7556571089e316ad3da785aa2cc444edab6c53f22334cbf86d53babec2b517a0d132deb2540391818cfd55e7f9068c1425edd0bdb10869898c7b51176bae688f0de4ae097cc2f8355792f810fe7af65688f74ca418e6c75198cea77bc7765f0dbab2bc4ac1b001cd8cd23c258dea2c0046451ac6cb67965ccedbeb7cc31985988456af77835b358cf96f178982855456be832c604118c2caea5f94744a767b4e8fdd3b91cba15922d3a1321f3813fc757868e88cb47fd8a9bf232958d3bdbd64bc363c99de30079b099c787ec1225bb8a58beb728ce133ebf88a3fa379e42ceb33715c32e427b9caa0aa95047d498066f4fb60558d0c9ba44011fb110a1bb52bbc84a1d2ee3a77fe7b9c91ddf5838264a9b8155ec204cc9c0bbb1073bd119f3de10f6a2ca62083a7edc3f99355d6fb9ac62f6e91955dfcc23d57ba4930647f84caeaba20cd72c9beb3ab509cdd7b0c3ccba78211e5f860283e2be106cdb0b4b60eeeabac7dc33d2e4d1c937d978870ede9627f87b738051a5d4c5ff87e0224dd460fc7e56e14869a37e5e4ceb75692c747d547a4efea95ddcdd555e2b59d757536c1f05b9b62e982db3dbe8ab14eec2212abd4c71d53d952329a090e386d5f7c34da03d88dde2d09c793e637f32f58e785916bba0eec24b1c1bf252bf916b27262742dd38aa18893be2209ca9bdaba30216b5661c8321e7e059736ab930adb614f8f2edcc69f2dd14388637935daa9460b6203016309a4f8a1abc843f5281f7f33c246c5cc71e970b5bc2dd9663b3867a3350723354fd9465e3275243a8d5816e80d61e7a3dd747f1179c94fda772f62d262ec91af0295204b8444019f7b391d0caa09593ef363df052347444d8e44be62c24758a81bafc63176f81dc11829f265d65c9c19501f3d22068428bb0e1523cfb760248645e03fabb7587c4b66218781411ec9f8a4a07f20c2ae641f6aa4cafdd5434cfe24cd60fa206ca65cb350fa80162a37e06f6a0e2a2932070f3df67c51a984f432e10b72d0fdee5d92d0623316cd3553abadfd1621597a3077189a5da3a09de11ec9077a4975f4d078eed6607a75a8e98e863308632beafec3bcff9184398c511685f409b961d090d8b5f618908d7972121204f6be2d9606b1c9c24cebb7fbd86eb471f755fd96fcbfc6e6345d78e38fc79b87cb55268a63ca222972ae3ab6a90839377d209866f6738bc6a78a446f3b3d26bf7818560de0877dd6aed69e11080a7c391ec7ee72682f90f2c8768f573c8e17a153df5104ec97b108b0341dcb0780ef4d90aee55b5764a0b94095b121ff66fe0602bd1e818c2b1ccaea9a21e2000f97d532c44a88188fcc93bb1c9541df7a2a86a71db93e34a47dda386e7f5fefce006bf060374ceb09fb7ef23eccaa8adc0fe9d9e2bf1007c07188d3c0b575b7c7b45bc01616ecc7104818d5c2c99799af7a900a1f59b7d6d85a0cd8ed7a3afac3dbe41f0160f873cb99d3399d520be62252edf2e015cae243e908b0c3b292ccb2cacf26e94080eabbddfaa6f02524085d9982f5e08eb0fca455906f95f08e734e1690b3f37945043d3fd7f38d347cdc5ba18d62f77c23dcea5dedb6e96db0d76f34c6e861c673be2481a462bf3a72e28752b5f19bc5381c420ebaae3c8e35d888142c980016b41e83d0dddd981b0f3924244b72d3681ad093c9c1bbce6c3213f5d9a3cc59fb9690e9dd9b335ce7951733011c98dda2248d34e3f06aab109fb8e7848f30fe5e1306bed6ab329e940fa48d48cc6429aa0271e9d1603c02b9ee1dd27914762094e0184f97c4bb10214bc9a2c7345538e50a307c5630b56611270eee4662956e673cc2dd663895cb828776767a7c8395f3c981ae41befb440e5169229eadce9cba5f1cd2cb4de4ceff0e4f0bff9635dd7817601ce9a5f00298956dbc8a3655a110d95b355945978692ba3e96e2ce9b1df70974d4ed0dd52559aba77c163e22c80ad374f978aaf31214aed3abaa48e5f0d1a8498c8ee4536ee1931b63899558a7957fa6852c1e48dcaf981528c142eb6aab138f5cc6f90fdb7df1cca91e39a84059397f9b2120552d58d6ceaf61c6cbe2c257f34509c0ecf54eb6bf9c3ca7a42f4783ad4841b09898d13736ce1a3ba0b84aae5d163908cdf1199c6cf70887387e64c845cc6ef2191c7a0d698ed867b1400ebad6cbf09c207cb44ce6142b88687dc40496c29cd7ebc73cb515e1534f645b68ec7c678f5c25c010cca26d168eb71798e74a888e8f438dbc2cd88f02dc2887bdc4bf0343629989f1543f1b6b6bad1153e87703e04335ca58e60b71d2b8ce1a87e58e5931d24531589c0b04621c5f6c2b6c56795737cafc5f46f8bea3405b198df1cf6a2c7bfeb51004a009b0dec8594857865acfdd857545ff6685802e5c4385797f566fa3b30872e4a79419bc7262490ee07e162e7895f96fa727b5bc130a84a7453253bbd70ba090a8f4a58e99db2a441e4f0f88824913efe0f635d33900945f8b9ccc02352cb5fb075a8355585a8c80f1fb653add9f0a535c2c6fc9b18fa9bbe6d0b8a2da6a5756268b1e3cef96710cd3706619970b3dacc2b1fe05d91a317f1322378575eb2eb9487c88bc9a76d33c59420c955fc718750deea0f89dfd491cace45c028c2ba0ed587e846b46d0e097e0bbac6ad805e1d4060d95286cced00c584c9cdb433d56e8428bb3b33fbfb1981d1ad155f0c41b20db8fc0d0e4086e6e42d25e22316a477520eae121c49b6fad6f1e39290e6b168bb1827ac13e52a52061036840c6249385be679ff5d8fc6b02d5fadf0fe6f314c15ad13c737ca8f6a633174ccaa0f85af931bfc4c1e0f489bf7d314845525e78808c6f3b89c117a029722e55794c26691b7b46e36902a6d04aee6593f4a23a1be1984d0761bd1cf9a60b6fbccc16020b6a2951457993355764048fb4e0ad4651534b5c230af8afe5110f97626a184ea8721ba9d47a37e40d447109fee18f36cf16c3a660c1fda559424b0591b844a3bd111dc1a8adf4012c95eb40061a42c7b50e6678ab664a932fd461569a349aeeedbed1e50bd54cc3e4ca70b173adbb4f0909be5b54435eb0ff86fd18342f5138ebba1a727fbaaf89ac32aeeb0da49efc7e9f13ff2be303d28ce77f1c2b7d96e18157de2b0939e2c97424cde5161df8297845c288354e6444a0a476ad3345fb2b8825ff4bfb32bd176b91aedfc61f1ca0657e51f085ab42747bd122bdbde3e7c0bde7ca1adb214b804d1242bfc44f7d415295ea5342b4d031811df869ad25e5f1bba3a4845d387cdab19dd0d655ed5bb015634212dfe82f6d695c35b6c820bbd2da9836489d6222b163f7f893d38b6a56817ed9518d169edb27d9daed0087ed5807cad67d87797495ca5b1348be9052e2b735c54e44d2c1b8732a9b82d29370611bde4cbfac0a05792009876c4a97e734c9ffdee5ddd569a74defb35e9aa7c93c5e43a95285bb4724e3edf2ca720367724e5fa89ea0d77e154628f1347afc6be99a5103df580def84338407b0bdcf95268b6a33024ccd345a3e3416c45c81276cbc4c9c4760373cc5329ee9f84a621059ab583a3d866355f14778c80995ba92fe504df8a7bf60d128bddd6ddb5d019f9e761f957dee9d41f0754554ab476210ad7ab103e3f27c2f96df44b7082a9f4dffafb4ac2f4ec06d83f2cc765b8d087c6905b8e302739f838d76d205c4d6e6cfeddba3eb21847683f2e00a39b927f6ff14ac74f32c92e5ea68e178b88ce8025ea35a36382259460c497f7c4bdaa78157674231b072267052c4017abcba142bab5446ae6c4c4f3410806673ce8ec297d0e6b9449ac029f1beaabb0bb6d19e5dad3527ade2c263d3bc4e6a6c6a55e43fe1fe854b1f31514fcf925597e99667ded3e0a6caa3a1aaae5286a7f41db91669d5e4fc8d5935a73dcf1a5d690c6529ceee470237e95a078301fdcb5dbc338220bfe029053047ed3b32e48f61637e9a7a0b9b1285b8c8e46dcf7c144befe53ec92a197dcc0d788c77883b8cf3a3800264e8a563ca492e487ebd44b2d6f035846e957e7fc34da1f9bb2997e71a73cfeccf050a89f6b8afc550076ef1c85516e88372c67b67ca473b758e201e67b1fb99a9141fb153140c826e941ce6194a480a6ba778b4b86bb52d26750a6f31b4f39015ad38f512152dc62d769c00b57c0007994446a7fa54018c39c0cc1924da7d90a896dc340a3d117c1caa54a24c491110857703ffed073678175ad1d5cfb964826a2a7cc04991df1e5d6a50b294c6de3c000ab2fbf4d49fb8c6affc39c4662a6812838d71f9ae8b88e581d9573dabf4ab3ac04cf3f02cd864261f4e7659fb0068875889a7c1bce3f805a862ca3e3c611955a8cc5f610785b56db8c1340594dd810df192f0b7e679c817f29bd93463481dbb7de90c576a371a9caefe4e11cb0eb80ee792e95dda22f8f52b25791595996286f12ad32ab9d7420dca9e2e3d62966c950a877bd6aa83000e4a1964ddeb6de3518dfa11ec0b340ab22c4d41da1a921f8ce46c4a05204aaa595e22585b705ab4f86fe2b91fa63b5093c3d40352773f0ae0a14c938b72f15d332a48f85ce8fe4ae22bef0a0e195600e875c41219a67441c7a8a28bc9ada42cde355385c939519a851292a37ff3385840f179900682d5c579ba570ac8fbc4c32206c3f5a29ef0ed8a00270613001675d85552e250f51ff0509ce82adacce4a6d4d14245eb4e6ce40215afc984cde7d71ea9321f852fd4e7ce845b72ad7f7f72dec26f94493036033d8a364d556a6f698d69229a67eefaa41a03897f603c9a4a48d7b2c71494397e07d05ae294c18292c5d4ea52241c3dc29dca13e7b9e4ccba8fc7bd9deceb69ae5ac9c9cec2a9cd675ddbc5c3e8fad455762a57e4b8eff88f5686c0ff486a80c818e891326f9af768e7f01ce4345db3978de967a44a529d4fa64f549bdfec02ef9db780e73338ee128052bf2faf99b9a7c475c74d750b53be682c2fa6d3f8a7ea5d5e11e04d96cb4c891b3210b5704fce2b052091891587894202eaa46b0079306afb7d0231ce2db4b624768498fb415d1448da0caff7068f3a8bec703f8a4d82a83cfb87258843a8bcf9048420b5288db2d0184d3373397a9a0a17a72137dd35bc3ad0668ec8e37eb9489ccb4f6ade198eb0f0156db4aaf77aa952e19f5e45458be3b45dddb2f41a1c7023ce7bd4d9b83ccb063be1b1c799cd84a872f32eb0efa47e03cf542e248bedc6bf43a77ab017a0b90c788af5c596c5278b45ce5eee45e67f5bcde0b318614707a975692f70f074cb4dff16d98137625c7d8fc436a5c04abfab3c2e87a92a3bcb5d34d0e953b0274b1b37292bb7b8c5a8ce616ec8005d4c09012a977075b193ae21aef5ee380368360aaa60422fba78f77100891bddf2a62cd85277ce54adcb2abc3e4e27f5d9653b4f1c81b46ab71cf260d56a0efbc60f17e22e9df26e395edf4febef4c94e67b1230c14871fe8613707b77f82ebb433d1a8ecbab48e88772bfca42d1053f635014e937e01a78243c4d08dbec0ff43cc2fc977a0fff2b16ea5e920edddf1e16095835a62e1e364178ceb12de200bc86e05e306b14b2236719be6d39fa961c15652d8345fff3254684e85e596b8a602e6a4e7ece8d6506e27bb40f32d6049cd6a5252cde5f97c4b664f236166f946e93444c356758d1741b8c711db0062f23167c389d4812cc24a64fb2f0ecc20194fa3618b5f09647fa95f76097c20dbc151169bf9b4f22d4325cde5e477f5df5d2c7206974da11b4a7f13d0917f3fe66ee654d5befb3fe5aef2060c6585940dffdd13a13ff734bf271488f785468914eb1666e4c472b246348e124bcd2e5051432075736572202854657374204b657929203c7071632d746573742d6b6579406578616d706c652e636f6d3ec2de3b0613200c0000002c05826774858002190122a106eed4d13fc36c78e48276a93233339c4dd230fd5f6f5c5b82c63d5c0b5e361d92000000009714104acf3e5ca3cedd87b0c3791d34666b1030df8aac1382bf0cdc166bc220d4283f6d6c8d0c9720c6931b4aad01b7c6c8d7bcd070e1b3b4a3aecacae980ea7fa542af850f0f2548f3a9417e552d76a55271060d1c101b00383059c7e5d60315b8e7f7bf3bf57c184a5e6c0a313731ad0ee5bfd66bb4634a65bb76829c6cf8d4048ac1651c4bd8aee7bf125c6247f15f20eabbbcad54d38d18dc3b9461834c768af990f248ded6b37b1021e802779bc0205fab6819fe931e7e1f93f4cda105abe33a272a7e582a9dbd26c1a27a7ec72e8e1d14e73dc5022d1ab1ad62432d5e2d044898bcaffd5cbf46a89a906376892384ac57813dd4e0f51daf4e394a1151f08ca24a8520cc3ed84b38f45e0a156f150436422c6dce284e59ddc3a59ccda1e92583616ec33a2bd5860c9887a1818a8c37d7ed863bdf29fb499d1b7c380616efbb0224cb439cb473bba506d629559b49bc9647f65e341b4c1b6b9eff4ea0904328ac19c106e7b3532ecd5ad6299859322fde00e4d5b1482228de4e68f7bb002c87da6353e56fc5fb4f135604cdf115684af468eb034a38c24bf41877034d39fe9918760a8a7c8d08569e1b644bbcbefb61f14ce020d495fd33390d8b807f3a2e2d75b76963810e4a044ead8b0ba233cd4b4ca89399e775058a30f345bc806e0aea5e6049f04b45bfdc89036c4cab579c48f1980b91c8d85c532a7390b35cffc7a601d67cad9e19203432ff2420d184ebd13a51de98a15d686d781613f14cac5b16ec664dcff40f09466050bfde07b003eb96273ff68a6bbcb3d74cfb14d92c8c1f4d8038726aec06f8ec8f8701a16c04e080b04acdb8c8e07d0947ef3d3b5c94d1074bcac11d0d66ef58cd44d4917d0f2c6ed5bcbf471c2d80e6cb52667583135871b97d8cd1b61e1a1cd649538729479e09a952f14e544df3a2afb798a57cb95b874a77e40dad11d5d1b61dd24772b70c22ca5ea81ed945cb5239fbe958cd50c5891bc8600f521cebb2e65aacffa69195f0423104ad95f8a657c6d87357431934ab6407d32bd3b39c73a52d02328abc35bfd70dd7c5a77da41473f00e81e883f7c993377ee18597b6c9e70ba7ec4e920b2ec69f4c2bd3692b92d969e1acfa93780bed086c1d6b086e05ced3f43f8e3eaff8994b0882eb3c9d9eb13ec14d36338395a23c4ecf79eb7a275957d121e1303a2b50538aa9eae8bc2b80a9879aa83f2dff4d568487a8f372bc72da0d02619bcfefe0914403ee1ac395cd9175cbb6ef29132113f2903a0f0c94ae898d9902d79272495aaaf98b7a994f47b3e45ad7c7a24292df128abafc33b71ddf89c1f8cccea99cfc9a76a864f8c6e1ed3d904507752a9f10685c1b7cf5a90f360aea25577cc0106898561d02c78614dca0dea406f3cdbe9af656433bdd205f99f68344721ccb45c96fcc22958bbea556360b4d757936fc73e917515fb7078e73d676551f5541ca55a0370d0202bb799cf253b49e47d5cf185d2ce0e83b23f03fbb84b454f989c099996114f12b550a3975b4090899ee49e6e2581f23ce70abcf88b3c9b61d7586d5c6f3249983902f576bec309d1711282804fff2411256c060c1d46a77c18882b63e319760f55406932377b16f5b8400c4f9ede663fda55a20c4a19ef2794fe3015893f2b0a638a392db9be7127123834c04c633affece6fdfcd59c6c9add42dd984898f747b4a3fec8d4e74f6380381f6f0950542bfc9dbeabe8cda3526adfa44dc0566d14525f9a057faf6f72ce2cd010f23a6ea38bac5ef291febaa29e6cc091a84098cde15b41f801edd7f6b1d5b03faaf3fbcc365e0753a65f4dede2b91970bd7c4b11165986a5a30de470d6fbae5d7f0a04ca0dfa3b4ef09df38b435cb254c0e234c41fe45336de7cc41d9aba58a5dbacb58a8f8564829291ae08848e563ee7e19bddcead47208a31af8a4b92380a9440e4eb4453c204d53f9c4a3efabe6c61c17be0350540ad5dc60c6d14af7f1c56a484dc63724ab76c84eb10c59279e7ccd86bfdf85fe2afc718d4d5e9050805c44641b55913ff8f5d555d5a264aabcab4739a1d78bc2c29dd52d552eaac53bb3930e106bac2357c7cf8ff1de5a0bdfa858cfad9c7faaf7f3d6bad1112a01462a17a9b870817886fae35fb08e1952b0b99ce42df4e7339d64d914847a67992ede5c29886fdf592f730f478954ea68dd80ab2491dd8e58a38629bef2fb6af0bf9e74e06efcf1c9894813921a5481ee182b1188ad2cdb7921e3113d7a1f56b705c345300087762a0eda73c3d8276929a67b6fe11fca008e69b7cad940931162cf5201613e835057f800a214cd6a1da1970d86d33d2eb42b07cd989ae85186bec3a4fe0b494b1a73eb5658039d0f6cd445e4b1ddb4ee7e0d4bce8b61c795fdf7a8c31b931916774690c65a5deb436c69c3b8dc91a4d3e09ec61b1b9d3ae1fd385be565d1aa9251d4015b2ae3934441a90b47034446f9fe7a891f27e0f00f4f6b7f5779ff53e1376a3344e5c98ffbbf7172b0d23b6aba101408cf98d202df8869f6b52aee2a89d3d24f6e7fd16b32a07908dd2741896caa0ef392bb6a5ccb8967c6385edd7806e300397c397b595c248b543adb56732a4aa8b0dddc120a6fe64d92b40f14c0e471829f7d859c5914421bb3c9b8b2b1c0c2dc8d16a74b38eb37ae0435bf2120daaed9a588a8baf3ba607c19ece91e79bb66e422c3092671d5962a12c9dcc4d5a115f5c2a4681cdeffc98bb94e1bab01a5c4a0732653f370cb274da1df69cb2d0457a1cb1cc40bb47806bada8f1389e4d9ae260cb80bbe791952e39a555e9d81ca191a05b77787e284df5a6db48471054c5a54a74c2ba337f9426fa2d36b0fe5b13d3d2986b5b5da725e9c0b0aba100e272094a91c1029302ba6aa1386021c67612b0e8f7497dfb6a5aed7cf053f052dd55624c77d3bc4f23882a3b0c4ea4795ff673ace40e479938c5e5669f956e931a9943dbf8d8de14f26743ab0295e95b613ad2b65a3ade7a86ebedb0462e6660f56995c1f5ab9ee4c977beb33e82a2e3033969755de88e4f91add95ddc1722234ff6005e63a52a984b8e38e562a2229c85476c319265d5d7298c537a8e3120f0bfcb806d46c6bd9aa0aa590acf0ea13c544f2b01edca03a6d0eabe82144835e0ee85863c5c9cd09019593978e6c702f3d20e76e9e225f8c832be2e8d3ab95559b27309d74b5f9829682340a71b35c37d780579798f937e638be9945bbe49f3b0dff79a0f961d14f06d86b73fab98f3cb457d9c23adb14ea21f1585b8085c4e2bc5c24f557911293cd01304c83770e444547f4ceb7620aac20d777e5818162b14aa4f0725892aa448e00011abae4ab3f1f690a65356156858df611425064e385e700712e3fa773cf236995913a8110483888058352fc5d2b1a715e449f539e12add0d9608aee4991b1af40841064949154cc801f7cf8821ba60f8932810ea06bc8204160c24fece554ef9874798f2a09544f2ba8e6d6f83782037268d1c981080d900fc465380fe231085165d6efd5b85f2c0198c1d1b6a80d9580813fef3d18adeeda863c41ced2c80ac071ad3e7fd2e087fefee63e5d72130dd683dc75374dde01d2029579b58ae72dc1feffc380e951df1b9569f7ff2e4952ef52fa60f65b4ecaffa233157a69484d955883a9bc59c1bb53364b97d8684e8e916918215b80f7eb25d251cf2b9f06f9bb829f1a53175563a1773d1f265649b9c883a75a06bc927dc7f46bbcb26189d1d9748a577c6a440685c29bae7261004e2b92482031a0cab27cf1f85b44d43b9bc9af086a95cbf569aa92f1236bc4244036addaa9fe66c22457f2fc6aefc00b74674f4b06d05cacc0d24d0a8dde596e930cbcd0dd3cd95f86584b60e4d5ef2fffab14df7833bc3c233a219906536a567c2a2bed57c824e68a58b3eebf2983816b5da0c86406900b0f3d197da44a6f74aaec4a0cdcf1b66cc9ca10b17702f9488de2182385c463d8ff41dcd45d5c9ea0edd9f7522d4e2b33bdb37c7635ca840494fc0e6483e8c8685a472b43e56f975e4f73ef0784ee629701c96d8dab861bf8fb38ef4411df420144c863920da72ecc176ea39a9198640aae2b6a9bdaa53df60ff6b49382a3e4cf8d3b562774723919233fa5b387ca4491ca03eae9815dc512888ed02ff36ed0f97b3ce51748eb4f42805fa65a5bc194692722dbf8da9a4fb49a7669d9dcf25a3f23e58e01012184e633375eb6f5d17cb0b265c8817006bdd7b02bbdef5e5cc1c8348ec20ea005505b770d0471012c14668a6eb878c00c15a8f97c2387ee1f842d98f6f5bfbc90774da3716e825d8d382d64f9918cc1f893685465b6cdbcce057f0907f346d02cc4cff1cc06443ae80ba57288c415f33f40bbc845df5f6f5d0a9ce9487f2f5165de625d073b69c6a055cf1b09b4af1331cb5d18d68dcc03a60afc67081656cd7a5580f28a8478788db82508b5af9da9fff45aab6f5caa05a4f2ca864312a542fdcf9209a1088868325680a2ef50fddca12ff89171556578ef353f258d3b20019d0ea0ba1251977487f6a2b7ade765960891b711b94ebb5c81245dfc71ca50bf7769a9e057fcdaa7efc6de16fd4d5e07a50ff832ed72eeca28f305c89beefe184875790c9ffea4f2b7bf3b081cab9423d668ab880ebdf81bb3c7c62dea6b53a55a26ed7de3ad5026fe8c30c5c232cea48a3c868f50ea6cb04afddb68938e419862975fd8de84e32db5dea5865b39d27543fba55f08bdffa2df3c4323fcc796890e6fa97c1d732c85f326f38631f906971b8fb4c40ee46b1a22b04f308f6e90472d9dfcfb487653bcebcf59135e5ed9325c9efc01760861af4a18d917e7582517c86c2aaa06d8703e2cb9c4ade51abbe9ba2fd3572569a2e2d2109724754f1578de4f09c528e5b2b05f9485f0015c55f37501e76c38a2fff38d3cb4f8e0ec35b9b42ad062f3ee653f6c58732363cc2bc53f6a3cdeb18fabe7375ad339c1abf2f5520b9456fe6c8c95531b17a55060570703966f96d15a4002bf6a37e0fef30f25d74db01307f740fbdd0df0b9c34d018b9aaf0964d1a85991a2e37d32dfd29200725a15a1b4477b3a8ae572a7691003ae0e733605c39aaea73f212578932f2744aca9329835e1e6a7c00d3404a0020910e71733a053fbe6e0e5367a9d956027d5580e3a23f0e526ffd5a4e98c1a64cd122102b2273afae07e8499e4c54dbb0b52715cf91857942eefded90150046fc5c5f75d07eb3523780e1232c2c03896e429df1ef7350155a0d1d72c4ff9f0e1c01d67044269d3fd26a234d8502149bed954ca5b56c473bdd048c27c51b81d034847d83ab7e274d8d7a30dc1d156f66fd28665c8fba1a3576283ee394a102d733da683c1005d5ef1ebffcf3c03b2230d7acef724a54c4f3dc71846274e22ac1359de3acdc6c31428a74dce4ad449be20b7b050aa1a85b242a6c55831ec2273a9ea7a18f909abe79c0e29e28fafa0f67af742508cce1c0868163872412460f323790d6cc2ede57ca8ed9d4a1bb4e2425f94a742316aea0d9e6e778fe94cc18e058fb3e6604559f5d7cc13dd4acbd76652d52c518dab7236b902b3642ed9e6f90497b60fdafd6c833a5cae87318826686d0209cd00ede3e73b60708e061318f184d1205dcc49aa2bf497a49904d64d9c78a9e900c9be8b48a372510927550dcfbde604d4ada42a34a8954d5a67cb696f750049f40aac0014b8acbfc381ed6526c475c45abb1229c8c1c8d943830ded43ffebf6ac52af568218ebaa62aaf8568e26a77fa820e9a224c70d93a1f9d56b36b262584c9fc9175c9d6b16656109bdf8ec8609edff090c52eaab1f6f9c63973a359f3feda4eb0b677f63210fd8d92f27c626353c985c817d6eda17936658e6cc9d4dadebafc3a9e2405b8f96db78049d6e32b28ca7a660eab03919971f2c99b1e5d98d722a2bb1de84c79a9fb28232894c8c50f042c979b4c66c28b572cfc6041ff0eb6be3e18ae7dc0aa7f064e28ca9959c02c01b63d13893f7a09956476e8994b253f89c4afc45c2835e6d3d75fca70ae41172613a5cf04886d7cf991e4284501010c79ab12fd95e81ab0cdf5817af7532ceb19b5f850cbb958cf44215409f381ddeeafef5360f94bac9f0ee48b731261ec9e54d8250055d4abd95767de0872f9ea4404567ef4845e949c9102f9c0968217857657bf2446b26ba3d4ba67ef3c4a90bd3a88851cbdbe2b4d6b237536b0ca2b430b9e2d0ebb9e4ab55a9d446ca4b96c096452e6780aedcab4d93bac26eff03a6a848000319ac94cddd2e03e7367210076c9539867687e490f5042371043b665c3756a8f935355aa51e381bac717630d79e26e8ec29c001bd011f8be7cfd820b5ed7073ecc0aff52462432fe49b6c185f255f1ac448bb0ece24398473923e9f4743879efad27ee482599daa64d03f00386f163f7234df712dca11990e706a6fbf1f5ab0c83657eead00b6e07c377e02989630be822c9666539c478adc2d6110a3678046aea6bfcbf5ff58de77c96e7d428b3b8dda621f61f367defc65e9b0c5295db47c3345ca035e24c21d12a9cc1dcd7216805d384fac78290f498b51d631a585610cd7bd61cac7a0c7b64f3e9815a6a0489bc2d36f81ca28e5d26b9754d789d2373ee6185934251f66ee16d2cf89cdc5311bc4115bf2f10072159f24af5947713d380d422cdc1cdd39aadd01e14ef5147298240b3caf92c459c94f29db54c6e00e0df232da0353d71399bc7e3e3628bbd1bee3c30e3f7b193985e07100d7d0afad1de2553669384aebe289cad06a17870b4ec2c6f9ed93a05b162b97fcdf474fefee670d4e5c36db0261b73fb619ea37680a74563cba74c236cafdd5a8e6cc081f37fd03d926f666368ca834319d3dff67b8e80a2b211b18ac444e31b811b6fdb405ea81bd70d7cf713e1ccfbe3411cff27cc74e551f6b51c41a1caca940a79a25a0d7bec2985ec93cd8cc98903ab20a81c68742b19cdc24a680d8937d07966989d02d0138e2ff896462b6ef43245343ebd798ad268dd80da45460e5a0070cf86ac5433e71601722bb7a73ea3d78cebd486f680a95cb66edd2b82d1a41cdf43148b1aa4ea04dd73da50ff6a9bb27758edbdb66e05bdd57240d85bea9c22d926ca89c40a2016b57c408d8735f9457cb57887a771ee3863c73c80977126b71ef6d9674ec9ca0fd6e6e1e275f3971e27db48d6ce46824056ebdda3c93a16ef4070010e7eaf5760ac2f4a32d4f21084a95f9a991d8d4c29e26b08589e7106b8d7b3f3d5d836fb4c3928613612352b756097ca3f65b5996a1a5601ed3fe246a3acaf5d618c5f7fd2e44cc8b43cb03581277dede69ebbda14588ea85cf364d7c1ae2975c0c6091279ce14a71e20b23c2e57c03b157db366d0ac98188a1bccb5da5c01ed68f1805b50ca8564cc132253ff71b23e8a91ce02861df8b948178cec0ed3e46adeda6ca513a38414e3e183efc8022e0e5b9ef56bf1f9aaf13ec4123de91a17bcfb4d7a4f76e5c4dc5f44741b826fbc961e301006b05f7ce76e327dbd0c851aa7d7c131bb0fc1394a7eba97be48f4de620be51b6a6f38b8448c79ddb646008e3c77f4879954aad8337e3a5d5f8d7cd9a58e57139a7c87126f7c4b49fa33c31d7b41a9de93491cd285cd03576626cc1eded2e26b85fbe0ef969b24efb2186666928ec64c91f47bbd589e794bbf8d505ef3f288c937159747a6184b3cb2ebb2969cd039c222c6f0bfbbc8800eff9013b4cd599f5662d85a4142dc4cea60c7640574c59666065794b36c663a37cf08e887df46b3c3b897d669ddb54d7ac8ec984672bbdb069f280967890fcc79370713ecfc5c0db7f15227487ec4efeab4edc1acfedda3f9e0aa9317f18df5cef6bdf82623e5fe5140bf71ea72a16c1395548132621a86453f758ee3c69dbcfce599d6f329ca588d3773ceaf0ed4c28ae8dfea59ea708b91f0a0318556017ac6e326b22daa7f5d73b4e0c86e62b296d5ab62f45042c9866a52914db43c6ca758249d18bebeb112b2fd3690fcb1be9166f3708623b2031cfeb656c362b400b17f6a63d4ab96f579e7f5e7cd7c9b35a5cdc120e276d13bff0b6901db484c3d6015875a6833771df50707aad195f98183efca008ae80f7015b4a698d8e0dcd950c71e96ac5b4884e4a2a358d8839017a85a71c684ae9e4ed7d3bedc24495616da7bd4c7a30a5634057f78c6004bbfe57dbf13819dfc57c1d715bb5e2257bf417982d10586137167a64162b91957e890382694975b5b8623fce7bee6158fcd4ee81457c191b9bad614623639b8dfe0733840f7823d754811cc148d95c859d36fb95028d97ed51f3cb990f4e8bb1a26655496cc31a2f079fcfd7ed4e1d70288009e99534e79141c44147f3ec2f13093232e3c4900bfeeb104f97aff0d4b1be33dc4f86baf1129f8d748fb442520d5b6787b8b0499b8059995767b7885ff3cf088d85672bb39a58ff02ab2392ecad67c55c39668de61bdd08d28fe137cef62d20d23c85674789ee2e9a03f6a58ee8994b517baf7fa3791c6879176721f8245fee8db50ccca7dd20cf31574d3e631305c8a75730fdec4f58491e0665939e1c7cdbaa3d84f2a1a920a0a40bb14281b2a89cc1bc4a82982d3e33e6076c41633eadeaf18b717a55c4f64fdd0b197a6a0d39f0bbcf9ec2a8fc3cbae4bdf3466fe934c9ef0049052c0d1a07a681b0a68821fb837c15db4a3497b63db56715bd43dea8e44e2df8d0d936d960e36f0c203e397b62390bf517c311581a831ef5ec5af9abac2255a554cdce4b266829e5f0226169c52bc3286c4221ce1656f2326a49f9eecfde1b306ec6398028e092831c10b8dd414bd8061e18ad5e6d15776cc771b9c89a7a23bd0f4e59ff03ce1043a90080d81955f1b8bfab93ae293360824a0e230a904a531e6e916d926345959fca84e14d904af9e46ee61cff4e2fe70095592ee62215fbf2464577967dabd5e975987ca4b5caf5c2045f27c743d31aa3575d5bed37d144b6ed73080b44a89c00f685caa6cd3e9016d415b5aeba995de8152b91116ae4246ed736333846c548f3e29f012fadd6b839fb1450147eab6f88d4af147a37d61a7b1f20a558730ba03f813af6835fbfcd21a26a09f0cf51c11bae4af45f8c87d848ca05b611cc65fdcb608dce97a08672327bb4be22c4542dea66d68e22086509e8abe3630d4f8befa97e8b3f57f74594b9b9fedf28ffa7caedfc7b094bb465792ff034e3703716fd50735c2e0c6f9359dc663115f174587cab8479ecd422dad6ff46a1745ceb0c767b9ec299ed0e3265f256087146317fa4bf362ce068ec00ba7a19d32ab2847c86f868f0f3104c8aaa449905b4c84f1158c149ebe097bf43e98468e3713c4da1046da29b56baed692cc3eef4e8ea7cc1431d393a642959e9041b895c60224748b47ade48ad5f8ff54e65b4b11afe45f1615cc71d6d7b1e934857eb7e6d1616ea3d3c7eba5ec8907655e8734a17895d3a147eb93b75dc3fe6165c2a753fb2a80f863747767dd0dee078b812c557a96a2952480d62ea9dcc28d29c3a2066c3d05df4976869be132afa5b5235b96d1efe9b364fe93030752c9e0b9f8d51a65702639a67547490bfd7469ace809eca7285162ef110809e3a5609f0d3f3452fbc5b94b653d987d851a8afe702cb7b601b6ac003b9a515525b24e3dca91ad989bba6c118fe2fa54d75a05fa152bc277dce43fa60e0a7a40e75a2ef589ee606bf6ec53178ee7c30d13132ca507a671ec181c4fcc414b5f39804a5ebfd4b746d09869c2f9b82547a61ad2b630c6d430a1bb6eb67b1093d628a693b6baa8879909b22c23f5726764d6f150b66338ccbdcb10e0789bfbd101049382b2c99b8432196fd0f15ddfb560f63203e8dcdeecbc5164b1687295cde4c570b4bb3eed6392c98216f92d774fcd90c2b6199d9c1f55cb72716a8419051613187ba5e1c984c9f1e7920116c180c25c55c410e0fc77ff0e5cc6280d13a18d86909adca845053ae3d86f32ab986005dcea0867bcf1f9ea8ac30683a6429792dd9eda6fe636a39c6245fda11abd3a281fda1ea5b9b6b86089168f80ea2aeb40d02a34e43904bab7ef76ba80ddfc7238236bc5961580dae05cc2e6a75e3857f915b3dab758df785628747f44f3046769b3692357c639ef19dcde5b6f0bb67047b9e111b52e2b228eb56cb335b9a86c3b6fa4bcd03086fc79ede6f0157379bd391bd5b1ecd1fea134cd5905bade2457781a943314e384cee33ddb8a911df1c62c1f6898577dcb0dfd74b32987f54f9741e0634fffa7e7d16f738dc79954ee3490a21eb0e2d63ed03e90ecee8d35525b74763d618fa1ae2c724b26e644e106d947b0be5d6737184aa9c7a8f6fbfbabb1550607d03f6bff47cf2ca26110501afeb36080aa8cede4b65cfaaba74545f868fe70d14a081ae8e21e231c93ebb9bc7d37c6a7610ab6b4aaef23c6c274f4531a04b8b99d0a8005772a9e8c2448266eee355fa55c9967278266e4ae162d6bcfb8ae01386a691228a7c8eb36bf9721bc53166445f64b5d844d65ec4858fe87f96159b7063dcb94945a6c13d27f704666161271646c65babcf9a5ba8493513c9001379dc261e47498c5e51ef782d887f86f9216d1eb34b96eadd61c9d07035ba6f16172734cca55f466dd6df583445d80a65f1deb1c3355eadce790eef1d6a1afebca7b01aafda7d93fe1d16692a2193eb3334ebe9c969cca496d2afd76fc598c351f5a431ea50cd3be726f6a0c4569644809d29a6e995fafc754445df88d1b25ddf0276e9aefc7b7ba1900ac7e7b0e535364bb55c1781b4f02f0c7d2a9d12a92dbb5c2cefd1158d572f4b84bd3a9062670ae374f6bf574c819fd6e0a3bb3d3de541088c8e7005c86ad87d16c0b3973e83e28dcc59f45825aaa88be388dcd70b8a57857c254c9b40a9c6593d079b86bc056637dcd0b3bb2a5a606d98ab04b108eba162b344761c8373338fee4694f67d70360e9aae4e87f95315fcd0ffb566c907bfc72c8180e995ff525ecb9514a0e1d70330028b6b6228b0b896e9243b0039ef679df5d59163e65859c441b7bb05e93c12c3cfa6064381969598363e1e2bffd885468914eb1666e4c472b246348e124bc7c46b066774858023000004c02445747061e23faaed0a7086555bd3d4ef591a562fe04a2e78962b8abdb624180b0a6432db2733872f69e179427a5efda759dc6caf7e3c8e1a94cafa023769e9bffda44e1b49cc31a43a7138c7daab8c7704c7b6ebc8d43ab7f751a4b432233c593278ab361e1ac857720f2ac19ef1f26b604a25acc0769863ce7a3067f3c259c173cd13588471652889e0a6366c13a75a9511f386a2d03c1ac50c76b11dd6f454572b8bda126b0f76c2ae882f70757f242520eb70b4a0e4a1e2ca007b7cc5660a76a9a27083a725ddc42cfb2c13df78ba821a5631c65a443909169a8f1f306535557e51e755b85387e2d202b27510ed96553707b8ea8c14777cce303c5321cc0fd6b84c0b8862f3a442c1b7a3af9399f03531cecc40e2bc9a322c6abafc9c50309dfdb95004b363a9a340e29ca419e2370c5925882b78e97952870aa3c5fb21b3900ea00aabda16a525c0815595b455941022d7a2d5388107694aa3a6268ea00bb6e9a86c2831594cce13e51a3b637fe113290b874830228a8d987ac2b4c31b0930eb6c8acbe368af76c9e2924de9c84861d17702982985faada78684f1a452d5b40c601b76e483941cf3c4a0515d0359c648e725b3f928e97c2b6c718ac63767bc482cf7f538a547b11a97746a2bc0f8201a84948bb4b7691cf44c7477226b9a4ba4b46b95b55eac861527119e8a6130156030939957e324c7e9497396290385d463e4a804794c38355b37447021a8d667f5a3442d138cbb7b9dc325cfea9057ef51792711a41e6577bbd65b084c43a39811a523455abb55488816ec0b98b987454ad9b6b6a1523a172855098d15025d8bba12cbd95df0554232d603fc924f2a31b2c1a40d99c5ce9af0b635f2b4a8997c0682aa735bb81bd49783558b4c6970a734415f6c203d588dd2ec942755105a111de546c0d32c3ab2cb0f80620b7abb018ab7973d3b5344b5b075e962e4381ef99275a5c20b12637ac3a3308c24a57e937db6185ef9594375a25c7ac9c42e3a306094add336c724916cf2312bc64264277018e8b79dfd860003e187e0e07e7bf73e586cc925774b2fb681b359bf258b061d83af6680bd8176720384b8cf00872c6850e3dcbe9afa6dc2e4704a7077a5dc54d4a85850fba391b6747e6664e365833ce584dc6bc0474c5d039bb05c7c9f7b47771958468a8b03f88ac537877bfd3768a0714e796ac72b6158099b2c9db29564306039e63f561c3274684382e7529a3394a2f074abd390383c181488703717c1791285721a05a99a9f85eabbade76e73601fa8e54ab04b2fa451a35e59c183f37624c997ca669a87244e5dc4621e0599e095480ac9a475b103fa05aadb29155a43ad86f7112817ae84a1acb9871857d997426b3b29599d28a9aceb17b6bcf93474b770670a66228265beb6930378b686331760e033dacb03dfe36ecc825efedb8ee4d6b62f50a06126081ec20422e8a5d9572fd9a041966cbfd12a614b53272f2660f8451473787bbb98a441105af75acea0c8b71d7bb28455698cb8b423502dff02919148421c7307a0c9bb63103db755010f3c68313686d7e96cd7821158a456a540299e166c24ec4e032bc04f1329b8912a3dc7396ff66feeb080ccab075901710382b0790ac292228c26b50f1fa8a34fb2870ba957a7c69847e40ebe3cd3bc32d7be88d2ad75cbd1786b28fe733060ee1f6ea68e26e514fb0734a300794c0eba19e74d5ac945a9af20cf4e92da317e306058a9e1de8a10d2cb49e0bfa5f5b8b8a46b4dbf6fd58edec9d27ee22e36db42d48b89fad452740d956359274c1b2b32f262c1b05120c141be6e96b04322dd2b9600d248e8c07d35729fc119c2de3b0618200c0000002c058267748580029b0c22a106eed4d13fc36c78e48276a93233339c4dd230fd5f6f5c5b82c63d5c0b5e361d920000000066fd103816b447066fd38caf6cd90135aea9b5d391a9a12466834e7840ffb3b02f124dca6c11d3d60960b3699255427263d08fd33699f63b2e46731972863df5fe47193186c8f0b1fe194bf288ef976a37fb2d84c3160a24bf16887de9fff39c143f55fbbe47552bf46c06365dbe6cc15652373821ec397bfc5706b0131b6cfa1e8207a59095cb03440e3a99fef64c3329b5e5842e3881b71fe637c2c8207c6c64b701a405bd7fb7716a4eb20b6b80478fd42a445a240a1e58af3a67e468cb69e5e95b4187f1e8cc846ce33270d79ac3d6e9c2e0e26097540b89aba7e2963d24daf4d97d89a9bb8e60abf460187520bae08d3ec3c2379062fd1ece627c8289633b0d528bc0d6e654167bef5ed3cab5d9b75b7f52ad7ca3046a8f2a9ff3b20bed0bbbb5b8889e94b3602dc446e2a6359211c8de3492b27743e0bec98f0a31b4ac030b3eb821c8755d980e9e4cc91e91686905105b484b5421f95e95ce2dab2b02d76c1be5c1c777daed4251afab718c43c5786e42f2021cc6a771dfb4ea9c63128318ed75eaa583fa82bfb11269d597ca2c0e5c41b2c4e7265481284a6afb8b2f51c692c99f570992df59199004a8ae025a217013134150dca2927fde0bf31ad873723c8073231f0f90616bff6cd1f267a96eeed326db68ec1f60cc7fa8a20dfce43d51b21964114399f308be4e309382671b566c3e86f466f0d1927ec6b48a8580e15fa7cfe3971cec8f8ee92f956b72e28ba18041d3fcf37c3295a0e3b0148d244df7980a39f4ec33023384603f49e9269c44f839345a1dbd045ff8a2f27f37f5be83fea92b0cac64b88c6ec3587ff28d1cb1a451689856afdc4c34eb09be1d83a2299e57b6a0908f6d88d82d7ce281df0ef55b487d488fc5f34fdcdc077fbbb5d53e36fbda8c96ff63633f6b1df9f42f714f0ac00b84f2559d84ed27775a0883b5ee35c49496604b45a725bc25799e8e7dc00489f7fd8b229f484a2962a2b39e8ffb1e8396916731743be9b6bf6e0a04056bbc3b1b9387702f239f0d6c5471744620550dc249aca61d8247fa71f9493af392606b5e82d0febd21001f58738105a65c8ef5a6bf289a69850b7ddce714127d489c835e0159929c8a269504ea535374948182e4d2ce9f4327118a38cd0886d306e93b51a3f50af4193168d899ab74b427750b556e9d34cbff5f99d1973f5f9cd55420732a8d5cf057dfbc24b6037ac3b86a43d448fc5495cfd059527ca6ec4e8ce95ac3ae3434164da34d47e66293fc97f7001193184c0398b173e4e3e0ae1391b20b4951973d834a96f3a4b8f4fbba1c16e2920eb4b1b9d95d75c98a81d2eb8d0aad8b3b95d57f927d392b837ba0c63af3b137d5c6680a726941ccc7321ff6cd91ed73b1963d47ae110a83b48af1ce9f83d62bd4d3c60db50c97c63de7b31bef98f8a64bc62b0cf9dc186f061028c55a059cea2cd4dd85179bde0e09237c299f97b9bfe3b9c40798b685bc7503f6a3217fed4cd8644511fa255369a5e1161a5239b008e2b21045be837140bfa43291ed2cd55410a60c6492c00428446eac3efada6b91fc775094d7f7618e0fa2b0a62621f2fc0401014e8c01ee9d4a544a70ca219830b2515ce9e3f20512782adff67517be7dc3150b079e2b45e54e03650816db95256b910f44ca76cc655bb95730827bf4239746b73ba2354068c13ebd4f9eb2941c8e160bfc17229a05017af3a6793a302be64ff869a9940cbe7c0bb73a985ff22884876b8e78245d2ba624f497ceb926fd8435ff144c798daf03ea846976d8ec9c23b9956ea431be8df33ee79e7b7dc6ff6eb3c0861f7ff02b03f1da73ccb68e1ba9d75639483f728816c497e5c3cbeda02ab7269ff2d085ce5f99aa2eeae1d00000cfc355a703c94d5597c7a1289784b8b3d4c09d41dd56edd5a00d90b1a73f990432fc4dcd4aa52a025bd18a860ff9226503ad058e3aa7cd369d16b699ef596eeff7ee307c19db536fa6e1673c19dbf1997621f764ceafcbd59dacac2305d5880e608ac8c259b18d7e4289bcf4751c7699d42b2881a6117828cf488f81436d6d01dd3fa596d01f42d96451361b2719929a31406e35656a3c1f3871fff7010ecfa81b471d4b3f57eb0fcee45d67211523547b71518e57af120642d2368a7a5d2ef28a8be0a0a898b1f71c5613a8dc05208f9c2ce66f0ad627e1857da211b5d89553515909196a69c3196eab67f6297ee99965721222e2d699b300c2c987b3297b28f6705bf3956ecd632d5c94186429f0b4ceacd9167682751b2662b0a79e8081a8d65621513df1c3fe1f485f1efadd010f45466e9f493b37b0d495bd3c7263401740de73c0e275a524eace31e2a09fcf643da895e260e285b42c9764d33d44d7f21a45d6d95f128a4ef437592631125316f870dfd476ea6232d53a3ea538478a99c62267c85938eccbf716b32cb5938dc414de51d05c7c45809909d0ebcdd334bc9a71e724d4cc15502d3be6263e1cb6b510290986184a1270a2ff52388c2d7949b19ceee36e38b549ecc3b2e6acc0987cc5d4214c1b1fd8db1142af2c66422b58f38edebaf5db139eca6bf3ddfc843f966f9caae02cb03a47b4ae9760e25906d2ac0990de49506c94670ce4a9c6707dae2a44e499704fc8d4eb48c4647a24251ac8eef555bb6efdcd530c1b990aa9947c52119be1e17088cef38c8207a8d80611327b5268195e1148b34b9f9958903d80d9b6638fbccc730225f0e76cf4b9224db33fb4e81d60d920d6ebe43a0fc0fa540842e324d0fc2b98012584853b4c758318f2257c7859ef5c3b5d797e86ec0f318db6bfa794a4024dbaf03ae15edbe24070b4e41dc6fa864980a3d1a40bec4d544762ccf5d61940f0b52862399fef65ccfbcff696420cd47496a498a0b4710da9d681025e1bdcbc380bc5b2a23ba93edc7b060a5c71d9821031610897f9807818a3a550f1e130b1708f4fb1c9afbf64627fb57b3a78b888abb844340d176cbd4d029690802dd265b1a5d30818f80bedf0f2d89c063f873d3550578f2928669ccbae481c39852fc09809a76bbcf8a0e7be8cc8f0c220b539d2aecd5350707b0c09635ed896c2d5e5f3acc3624a46d10752868afdd7d2893fcd12844943bab530dc6089766fbd4e85a1c9555d849324dcc0f63add8240a7af13aa6fd994108afd387620b0a43517fd302013303274fc4b09875ad6eb4cbe90a9600f75a9e0fd82a72d1f00e93eba01be938992a28652efbdc822bbf8a25e71c0dfe29cb29570a331f45d86b7849495669d9c09b133c30b37a30739c7b8246aebf181f0d7a25b0383a8f99575e13ea31362b8cb754c7cace42543439f0f2b3e80592578dcc603e354f22220ada5175471da8f7c2dd491fe9674137df23a0ad5f7a214c860a844ba4af09029d4ba2ce941e09368385e1872ae9f18e8a1fc0f4ecd030ae304d94885906d0ee3cda087d4ceb1a1cd1a8ad3a2b23370e11028eae63a525ded51a3fdb1c91f34b60cf02b84107bebe9be3c6627b264f8ead7201d838f22d0eff3afb6fa64957af53de948b3ad2a288320f571c06032a1a4d11606920280b0bbadbf79a1c83dcb28088a90d466e0979ca304d420bfe2599c575482fbbd68ae20ffb5357324e22c3391ac600118eaa93b57140c11eef26643b55fe0f29a90c0738b997ae5adb97fbfe9a62ab85105d0cd600ca2fbf20a8c9d02a02caf7d68a365460e64c09756f0a7ff8adf0086cf3bbf08ebb145334a4890ef9055ee543f2174dd6debd3411d24c39149523a9a7291da2b5b391cc8d96f8cf28c7fbb7fdd1dfa0b7a3230c149733e68468573173eaae67e6affbde49955cbc1113990359740d7c5e20f44288090a1593bc092d3bdba66525fbbdd825b457ac417f8c1570be2ea8dd6eb17106087390dc5579189355cb15db115eeeb907870778a5dc660027c4cbc58c26280d92dcedb00f14c26a3d3f763f268b90984c85c3dab812e3476df99d9e06e899cb7b208235248d9395fbdfdb07483818d42ad809e58cd3646b122f47a8dc43e59bb25b01d352815a6a6c502cbba5217c716fa90881da1ac295e8c76093ca18236b0b268706174672753f0f121b9f3af285e561e581cac2ebb753fc4bf77752d213d0cac2b6789baeeaf6e3219bc11b78f5ce53253b8e2da01e77814792d4f505890f8fffcb2adf817ebbc9bd1bca048890582d2e02878742b473f62fa857297ff1baef423c5e8b45886cbddaf0a0a4209ea663f94f970edb344c94f853514a1a6de58a13414e35511bfbc4fcd37731be62e8f277ed6b2ed8369e06f1923873e8f1d52e5c7b93fc44abf4259588b5a1f82be56d69cbe942457c68f0ef795239ac35520fbee49b87541f949bfa5a3d8764f514abec31c148d1101e2ec20a02e8b489898629966162ecd4d10f8f2ecfa45308394367e69e39b395ac055851997893eb64bf42e39fb7f1ded792f163d317b2137e8e54f3afb706fc58ef65a984770bfbe4df9e922b8efb2fb36b89afd5b6f37f685de0f2ab6cc02be104c151209cabbdb2fb086fd9a500ec535d00fdec91eb788393d987784a7928f8db6dc806c22b1367f56d80706137c9cde5ce3793a2542d21797ce5434cb1ab7574a1c40f10eda061f2d1a643032891db4fd7606b732ecb91c2e0aa685a393ce197294cc4cc3212e0cd5529be51649a2febad58a0b3379ddba3c078fd35a1b030928bfdbe64faddf88e51cc246d4947e7be89f49a3a45509131084ce388b5b8377b740fb324d0aea8172cce6f3ed8fbd02697db6936166d8c22a89121886879ed7e624a7f58fb1f1edd7a4028a83826f1bc8552522d8a88a6a19254f74ca6ff6be002277d9de9ad0e73e8d683ec5a605cb7fd1af4749208d7b789c8aee58b4721c784001db4f4b20b6b52a957396748202016c108cd193a6cc18683e1f75a2b8204e559a5260a2240ad7d1845bd29136563916eade9f38a809d9a52ae11fd2b6161a29b998fa41358c87ec4155840433fa35dbb4ad076d705c8d8d2ec01e6127bf4e6a7aa53bf2f0324a7b543438e7dece9c1da1c2e499677217dbf5cf85575e2efdfd7db7f9224f98723304b47c6895543251293167723b7761bc64eba0c104f4c9cca206e1258cac94373422dd6b349488aa81ae2338af273e77cf667a7c1cfb8be5db8f8c6dbc6c319a6231e8a69c622c2f32db7e4d10db741ac8115716d6b4d9c1e94a31cd4df716f9cc401c75215bfcaa214e61061ef2f41b5f09d29f3f3c0ae821cd528fb0174f8bde3ee1e08c2c1c8767d10ba569c49ddfdf491716d3428a595cb9b462315e707a6de36255a8f433441882e09c460421e416643a96df1327db612b041e086a0f7d8256ebfd92b18924d30e461f2bae0dbea7e65da996180de1552125bdc47164fe0b12754fe0363c8c22456bbf1c32bd9ddc3b83a379b86bf8d5c45a5498b6271ce5289186db256ee66b3f224a49a570c6b49e76565482a3b6f8b2d3dcb3ad8554ab4abbe247d49bb2e76b55db13a53121c820c1daf640294bff780035791e4281c491435aa16e5b971eb219f034356d76ac26387469e2aa3933291017b5663119e725357f2e7f6c50e44869e2987a70b7266ad78de8154604f379a4c1b4d73b028264038c5abc2f91aba89c6e5350e3266cc5b1154f676ac7eacd67063270e2dbdb5edd330a1803da80f98004dd14cd453a2cca1e2a211e2c4c5e1b94815a0f5fe4d7c8d69c0a592a6a81adee498b77b3ec644950948d4be196e0ef8ddda8fad90a66b80414f9f23fa64dcf85fd8e33a51dc25df1c256d343ee70d3bb57f3cdc86975abdf7f9919bc13e57794502d3ca54ab84ff6dd58113b6938fe0f54befebe314bae572d8cef1b358d76ad759f07263b6c6eb282662fd335a325bda175d297eed26f3aabf2f4913a0e04b0497d1d2a28b57c435f7e3e23a0980467db9ae9b47f7cb008ea1440d8837f8697c360e1e519dbc2e8d775ce39ade5891ee8ba8d2804fcf39a13f29c91875769829840485b95c6fe5ce3690fdf1803752446b6abc27afd4d628097487632c8af4f5b65ca065d6b6720541b20729a3f9bbecf8fbc62043e6c7ffd80e14f8f8df19b44bd33632739099dfb0317a092f3a4e98967ff6c0d17b43d7a18f8fbc33c6210798b6c79383c43950d0fb4e4ef1f4c74d78be20b7b150aac6c03d015a5e688e860bf154fd53e3d2eef28b5058c2fe63b9b42b075a4e6bef0e509a31911787f2cb5682e74d4fe5c3885bcda8243a72fc87dd4f424dc9547c7ce11ab252c335c3c0a96008d3c766108ad295d3ee61b78cae6bf93f039b48842e941f609e609719818fa4f4ff7fbf76cdf8516f77efcc8fd64a4914636265d2d152b10e4a05aff3ee8db7c1ed5ffc2d80268f00d44750c56f0f519b5647b4848d5cdbec3c6da3884eb1bc9bb53209c6ceff5c712065e43d148adb643ca66465807719712c8dc7276d87fba765f0665fb2a27fe52d09590acbe083120c3e357f73cf0839f4abcc31ac41506750b77a888f04cb9245ca183bcdb65b4dfcb62bbea4603716caf073635a54c2f98373628385630d46954fb3724849bb93b85ac933812cc3118b9d2866d5e0c3943652c8df6696e41ec33f8e85a8a04aee14b21734eb1b46ab2e64f91f70f1c1ecb7d6b70d369be05f5ab79589a23883a572d7025d691e129faa50f58067ca957170bcade2201edb8df31f044368b413553799180cc6a5e6ac08d9b062ad36bb0ba5a066713299148b8469ef0d948cf260bbfa4a287c0ca7353410cde3243dba1efbb2a8a606bfdb8af3b882e97bbdc09252e4d4dd5edd76819068fb8cfd71ae5750ea091ababaf0262839eaad9892d9978cbce0d471062654523cbd97bad7ab8ac38eddbdd9e62275ec058bdbdd0023646c0eed75ad01d14e4e88c1fd92f940bc7025a80b4578144a389252aeb6e40fd753767710afc495588bb56996c669a77bb7c463cd0d6af383336c6eb9e12d205814d5452994b1eaa20db55e2ebcd22d6609a5af803c52fdb9a475260245cad2403626edd4240a01cc65c29c962f0ff010edf27e06474fcad6d80792b643a1e271433276de055688f25a9b571cb00d735d2adea48ec65cd4daa90dadd3d1874ed0e319e424cadfa6358e62df976d1d92b63a321f9325a7580cd6bc7d6b8c81fe3100fc755cf54a1d9396f7a6879a83849feceda67a5dbc6b56e3c4d5f421847e5535ba471c391a31dfd76614446ebdeeafe30c1ddb605a20a154349dfa2d981f2fe3f5353f610d6af0582651fafff5d7da1abfe1e969e4f1e619ca98e34faf49ab07d4225add08a1d243618464e243fcefb45ca816943104249b88567c64d22f5abfd585dd448c927862bf2a22d3fcbb658153ef467aedf7e506099190c064b74ec03f1e4e171e6fcdf726a8d7c1944ca2d2c3646aa75657b1b777c6d0adf36f01b9a5813335284617c3da7a500af0156a15134d768d73321324853549f62a82f88ed7206bb4cc7cad6b9822aec40a0642cff9880f101eb7111d9df92e5ba2b44729ce77547e8310e9aac412a5fa25954c18c9e1980a761cdd8030039f0a309017abf1a8a9e742f00059cb86da8476324ec8a0c7f71603557abfa52dc994bd25b54797908db852e8a8a8b78db7bb24563dd7d2470b3e8ccb2e560c41f3f49bf346167830d0849e32843fd1b2137236844378adea8909904f6ef50c88899393c5aa7d68c1dd477b506d797262f7b3f6ce54752abb23a6c13f8041cd9227c08f4e6826cf7a369f39a8594be1c21a0b66ff53d55ca4bbe599c96046bd142ccff19efbdde844570a4e5395e17ef6bdf873471b6098687178c32a56a5f858ab10ded20f5958574984e3bc779907716a49e4c067cc0f4e3918342e905cd42a6a275ed4e32ab6c7a9953294ddcfdd42543bb5d157886e63a38d78a5211a21c39ed00136bb44089e816bda5be42aad19c800dd02f15538607599744ef757a3100669790de0eb370970e7b432281461c8f665ffa76961b43539814ed9655a1cab5418f518903f18fbdbb8b60de02987f63fb8c130b222fd2fb164f0b7094267d817cd290f031b572202d849cc878d41706914b595a5ad7ba7afd12566e2a4abc612b5dae5c486d9a2346efc546b40512d0dcf00893a7e53fb2d8585f3f6956758fc5fb6de44809264b1f3e24b8da4da12ff44ac4e7f87d00f6f17ec71d2aa3f934ab9b10a0e66593e71bff0d4a9054f3fbdbd9362a6927966e4d94f70841ecf9588877cc5ab2024d52dc0ab8c6df2fd3d1e73a473210e60262719a3c5f4ea5d2e81367bd76689aea428560ab6f40bb977ce2436a84e4e7fcfd06d96bfce2e0f1773016f130148d0e5fab94d45a5783da0ad767f42e9374fd480717a88abfff0d202e87bc745aee1cc832a811ff3fcfb6c92197facbfb3cf50444af7e337e177d0911cfe5b6db2469e7f75e10778d83797eed790772961ed2d89c25204f296a35df2e665a8e3a6d02b7971cf673afeb736f90f3e1e41a8863349b056d4ecbe8fcc3be5f18d2b3762289168e6debbd59b207de93519774dbe04cb37f50149b96a291b0f4cf4ab3ab67d2f563b925e7f12e00d2f0dc261b7682e602ca20ab947f15bf61f3ce337f58564b8fe8ce19e7d372063811b962681d786225d6e3cb7a17c5a1721d9a592e5e0686720460afb447263e8c63d0bc720033031255f0ac98db5dbd45de4f150cc8dd9680a71de6d8ed63a28316faf6edad32e84345289eddaeecb70180c9a1da121d6bde8b6c54e2d4eb1ab231131e58715ceb18370c39dfa51a32ba2a603cc3fbca8cfa0337e9ef95c021f993193fb251791b9e06dd703f90872fb4e6ba0c7421d3df2c9946b142152f36066bf46c08732ca501897aafab9e863feafb8e35cbc71eb44b1a08e9c10a33ffef7641706f364154d01553fe1a4489aec6933219e6c94691c4feca2d4cbfe78bdaa60db5d41201409a005a44242aabb36b4a473dc00eb0d0c9e0b54d917a9e661fbfb68d10aa27589ede2352e69b25d974a0eb7c6aa5723144354c0b354616f21174f50db547ea69205c45d8a0aeafa12e56d66a090b4f90742357a9cdfd255fee7333ad322a4dbcf69d80146ab5f478ca88151b6e7d640817cdf2886c4d3f8b5da9dd174f7015fb4dd8ca0cf5359e04e0458928221406c66ed94cffa7ad6d5dc5aed8b7367e6c0333a4232f4df26380bc015beff21c27a6a05748c528077ead0254d90365704d7f9745fc9fd20d53b1d635ebcfee84efbbef9961465fcfac8e686072e1248fbb06e8e04db6abbc8403cacf23fd7bdff6a233cd11e2d6ee9862029cdd3b33390669028653e01a01472fad056d196c3fae66f0682ca1e67925377c32bae85158226b01f8b9791cd54b0d662e2ef246de5e773e88c50fd19767e583e20138a36f7b97f28582d3e511a67c8c55faa03623335a7704215a2ac65eb95690d7b179a5eb1ced67f1af99b8dfa7403a99e5404afece59a0ca52af32ee77c4f491d1426ab9a05f20ab8383cb6b552b88bc8f9be8435c338423ff445a27cfadaaccb393a3c5ea72dc9b4b3963cd9c59a1a7720acbb7926638f7a6a256b4c032c08bc1fa0432b23d5f345d4d8187ae10733511fd6bff52aac1c2c49ba3559c02b1eb9f5b376e88d38216c8777878adedbc3a18bac02d23b91469f86bee48ed4dadb7d2b281e591fcd656dae9b17646c17c9f3103a26ee46a3045742833dee1c37536564fdbfc9382472a75f7cc54d89f08cce6d3636c3db2ea6c095cc2604c3bdf423adc8c87b69e5c06041b2377daa5c4849fa74345eec258a1e7d9a40f75ef4dab1950c278c4dee4f0f12395bdb01f795630db6e70664b2eb6fa6f2b44eb672df14b0c368153f697f8a9393cc5c2785872e52f42c248c9bb73957b11b56367c118326829ce15412bdfba745a3b4de29d74f9accb431c75af1a3736ad0e8001b80db61de14f48edfb549bd5bb0468d91741a76616c9431f2da399b55a7ae53abc2a969ac2b64988b9709ccf3a03ada3e4c6019c3dcbbac1faf3ebef3bf82b5d4d3eeca0d044ebbe79f862b7e05ba71cca5c2e9c78f28747d79c4c0b291c4cc5e80d9100b20e190a18b4f691996f45279727c4cbe5fbd58e9e1e4394a6dce9452fd1647efa7f5c2353f17d896b297d72f4d9ba27e9c96ad1cabd82691bcf07f951644d43b6df90ba535ad7cfb6d23a49548646589fcc89db8979050b92fb63938c8b4f6dbed5f3ee98107298f8ce283893373ef8b33a5494806116d561d285ef11b07d01d892f85c8ba0a23cb885666e7ec5d834e1edad7638cb3d27998b0428e8ba5bd1fbf1628177777fb8faec9ee56f036e4643dda63bb8b2af33489e3d35c3ccb5304ed90992f2dfe344999b119d5a660c7cfddaae8f265c1cd527451965bb85905fbb7bf40fad89f42a0ef337703d37e5acc7edc467eebdb133de94e449ee91f1b272f3ac58f37998dfd207a3239bddca305ec99523b25ab3b35ca23cc9ba502155666350591fadc8383e442eaa980ef5452a203be552583853e042d1d526612c50b5952620d9f351589b5dd218ce95fc6f9da02b271deb5ba3b5d456f3cdce26683331fae7a6f699dd441592d40183d0ce4afbe27df61fcc836564d72ba4ecdd30820980bddc970d3029149542cb0a13d8ec4ec2f01063681df36fb3f24a89bd9177de18c49fb48c1b243f336504a112d7bb5efc53d0ec0397c4b8062a2818ae3f89f6509690a055fb9c16bb12980bebd212536aabdb9441ef4f90b5d5c6c59bb0150bbb77f71d2f534373bd741c87778286fc73be8b2eb877076dfa466ab9029b3239e8f4e41dd33c8253fa02ec4f3bcae2d5d5e8071855e91b01908e2123417d50ad19f7150c5aa8b1355fb46b8e65ccfdae5b82d599568ba104765923782f75c7909aa2235185fcda5b54de6c68dc84192e98b9c527de78b4c3ffe72b1fb0538ba341ebc24fad1c707b750b819fc152908914bab2554ffbd5b587097e5fd2667c79e9a35e2fd395f8a78f4914bdde8d433aa35ecf083e2b1f2cc01be93f1010302cd5abd0957c7cdd503b740bf8a641e91122b7925facd46e0b1b7907923b78f470ead572f887248a85e2902bb521d5d2950831cbac142e48d59d0044ab2b3929e018d9914e2810" + +const v6Slhdsa128fMlkem768X25519PrivateHex = "c56b0667748580210000002000f8017d34c91e111eeb8c78e8352f531a065f2a98d2ce117c37c2ad952029d500b97040ad04e1fbe74b10f9e651808cd292a4b8c89fa1fa964f65a9e4b67fa15f00f8017d34c91e111eeb8c78e8352f531a065f2a98d2ce117c37c2ad952029d5c2ff0000431f061f210c00000040058267748580030b090703150c08021600029b03021e0922a106d54e0307021169f7b88beb2b76e3aad0e114be1a8f982d74dba9ca51d03537f405270902070200000000221a104f4d8a8eb239423d8b4a7981243e8afe9fa8332e4bd7c15ca781ccb65554c38249a277a1f29a0ac7a5343e66ab61af7e8aa6d42006ecf48509fa894427129cbd6965c23404bb92d3f16b50bdf1f2cbc8f6c42e2a8d57354205bde907e792ad2e1a57ffefd771b5cedd961f65f1086ec33ab261c1d600e9c11f60986963f9eb0d7936c7e9d850f392546744a23d3d771d68a7e14fab6bdb2575ab491721e2e4a16ef76201afc040d5abd1bd9b9da6593d1001bd5fb408519ccdb2b4bc53673e596aac53eaff386f7a14d3d37c1d63e3846c523a1d799f2b919480707e209bae8819f072dcce7871a68fd521929b60434bf45fc69cf14c2d3835a0a671c8ba16901a19c3b438e39282809af6de75682c7eafc85b58380ce1c305493ca390b6a97030281c8bdd1afb8c026b0256d9b4cea36cf67cbc4f36bbdb0a1343d86444a177762333e06223147f00d851e3e715b18cdd5558bdf0ff049f461f81e49b32a0cf958c8bc5d9a7c20468e6252eba5af9f544f28c366f5403285223575ef94a4d4f6924bd327cb15e29a7d3c413ac41655611f4c2be8b620d875747f7bc810e37485aa1c993391af6932d78ac49f74fb4497964504d904885db9febd6b62c1f7a39254439249e4585c9342c3c9454f732d0e691ddb5d226e5ebe5f9ed1f4835f5a43e0fb5a07bd6ed1ee735bac2ed93be7900d93d4bc274886e10773bda2e2b2c6973f4482e0a2d23417d5a7b6c185f454f2fb1656ef21480b025fb4fe2ce17401b421e36e70c2da9f71b18bc9f79f62e2332075c4312acaae1c859ae6fac17f11e31a81fa019f0dd746c7f89d46502c05dc067dcb77656e1e977496df38f8e8e84582b97aa4a05916f6d05c8400e4ef779efc782b355b8a09099446ed3516f15fabdbbc51671be5780d690c531c8ee5a191aab16418573b6ecc071e309402e3d8bb1003c43c95db09147bcc45a71bb5d23f6b1f91b7982bf99ec66e772dc4906708b4975307b0360255b0826725ed263e0ec6e8affcfa831cff450d88879d1720bc4d8834b75cf113082ba9ad0f6ed69b917e71d3e54b4d248a66112be2a99831a865578f34e3219fff28361fb66f928ea4a6aeb0c78a216c2cc66f9b8ff33f6daabaa13eaa87021248da84be75ae7c87e61484530d53b535d72ed91cf63435cb707706b6c2338819605a43f98e18652345db431c429469ee49a7afe8d8ef9d6b672dc4993389fbfd4ad4e1bccd9a4a320a0c181e609a691521b8144bb1d424d03f96f772e83ebd32abe63b3aa4c54ccebb67b5e806dfc21202c3853462d8f406e66b810d9ba8fdfbcbdf3da1466b3cb5093a1a812f34def4198d50ea7816503ed230095e30099a762d12e7a028b67efa0c4dfe483263e432fa919f2560a7a55483c6e3c51d1706242d418e4a3359d8e286ca143a65aa005554e7bf0a08606a94ea5227ce2c849b390803c1c5bbd8b119a02b62282dda2d1ac709493fd14f53eeb9e8618aeb8245b03a54cf0177e0e1b1287be0177e2bddd29f082ea1ade7841a59a27d2606a576ef4c170d700d07d547b4edca9bdb7c38a2c126ac3e7e6971eab8e97bac04cfeb0a7897e3283426c229f7bab39b3f5573003c1b705dd8ae553b194e5ad4916866e1fa0c4c841b49aa79f02ba306873729a8228acb7d84f7d965863fb76973e288a23329407a576b568ad4fb08a7491ae83e26717e7f3ea95d27e30e2bdbb580c679f8a590ca4d7d7111e590cecce4b3c524ec562fe467c56202781840725e43655e6c308e7d24ddb7bd369fcc0fe67cc7e0513e1eea6b7d1d7cb0842b07cbf9d4ebd1c0d09fd4d3f8320208c8bbe0c5bf8e3e7280e767bd58b064db0f596bb92e9bcc0bc836d92c2ad487a1eec03a490bc5dface4b6366d9801022595a098b47648b6a9fead2dcfe4fde6cf18e8c5d79d3e0726dfd388160c1948ec4d64dd9800298feb2f2d8c3b8b1290ba17920ae5b72eddc76320aac47de4016033f3550fa34aceab90578e58cf5600d1bcb247c2a2b983e1afc18899e002932cc780630b2b9e0724adb71a7448717c84003931de98c99f5a7eb8fe09a7c275a4040924e17db4c3980b7948c9140774e478e4db32029f23294cddc2975d473b6dfb7827b69743762d5559ed3a5c287d960420e8a7104e7da97f64c2eeec9af5374edf60003bdc92b0cf759abeb1936a511f77d28d9c12fd61a39bbe3d9ffffff77ddc847ae90c9d0b55c5d46b6c1193689e18cd2b11b374915b6027dbaaecd1d2a87464fab8d5a1b3f3d924e8206ad46b3a590769e5a6e8bdbcd465088116088821db97766e0a070946640b1526b3a98cb92ad100dbff949592ca849557261b3c6a6a439a250b4fb85336b2c438739211b8aea7d4bd208886a0a3cb289ecbf376716eca2fd15c013a74d20272a059d4f5148468436b07f3f965d0146eabd53ce16d450417817de24b267b30c86e0cea36a57697c352904ae0bc65af05905c991833f6f92d1058719f599e3b9d39c80b1f13eaa0b6a633c82d28b5ccbf3a845cd5b571efebe47bd95b70738d51b60115932c55e41a9bd641584333954b05ec32a974a1e0b159855559a0ac198c2794f9e69e843a2ea4dd59697f639872c0fdfc21e3913f9c24db28e24f3afa57642bafdefa8440aa57c3fc87a4c6eadd6de13c1f6148a3e76a1c648bb185b681d83c62e37d6cbdd40b4eda0068887f53291048750b1b5f20ae1fa5d42796881d458e573409edded7e4bf09dd49ff0850a4a2f1f31f62bc91e152cbef789bed408366d34074a4638a373582df50c0cf4f10b5ce720a5ae4f054f0ab829cfc94e72f5f43a01505c36dcce4cf7c394c0f831f957b50b329756e9bbcb6deafeeb39e3446f01db4e110fd91fdc903a20a4c6b8a66de9fb811ebd7f84066f547496e9cda8f88a070dc6375d6aa46f290ce2bcbfe210876611f8a7bfceda76d4dce04461da899c5884dabdf510dfd09afa2a0d3f70208f2afd0cfe638c695df1a849c6939774101f556d16b5df7a0b92504a05ad444a0a5b96da945efd23c2a835c75f8557783ead939e419612937eec0551560d9c37f50ea1454d66d405c25ddf2104c9ef4c01773e21d0c904a4779bb6735038da9b031a0bf0273a8e3f2d856b608c3108a4b5be56923324dd74e309b5015c0e571831dd2a99ac2d80afb468899e198217882e28cca7a3aae0032f792d433ab457d624195ede44a25154f5bdcf95540dc0c3b3d19e2364eb393d74f3f1b676254758de722e822bf3b11a6b3f911c114f7e3174586eeec98d992f22f189357cb1ee99daf2ed2d7530d81b49e0fadb4ff51b1d8744a3f9b925430edf28ef3972f1816b1b3b0e089615c8d92a7145f131f32f6faf06654d70923a806de672ccfb420705b0e1e30f3612b6bdf28199fbdeabf8f3618cdb4e05935ecd32d694922b8d66887d9993ad8f012170ef5d0726c0f7ceb895bfdb518ebe7c44d8ac3e73f91aa7dbe2c717444a637ce41dc025f6ea17f805d1babddcb67d951b56da78faedd1ab79164e7e3e1d3a5cc33a130e36ba0a4bd190334d62c1de0e8f50b7fde25b2c033496fc2ca0c9e47f2e269aaffc7c4b65a9d8de51d4b8b6aedbc70693c591c874fd0d0d0df599a36f6c55d12f3b697bdf55758a1136dd50e9b359a288ee9844855dd61dce223331e6a4bad73de21cce3f9990f9471f8d6db6ac8935e0f6caba338a879244315a7b8675c2fd7857edb2834b99662bcad5bd8e3764fd44949af9629e206a92339ff3a0b5feddd2928cd212e6a7c657c1b37387aee9c6f5d50a784c978da0b6f1745199bc11c126ba0990eeb0ba10085162760514f3f713e2634e2b88d9596c045cfd563298f1215a76acff3d83f67ad6b3b77c3da68ab34e6adbb76ddc6c8902b4fec083fbf3922f7e27efebc76abde771a0ad775f8b34208906f7987d743e24b3518545f9cf7df15953d33c52a21f25ce270ed004597ffd2a412d628a3e63825ba3016085ef3b2eacfe598a4da752159058ab8917498948dc21fe9aba19cf147a72e99af30d2ee8f1bbe27be6aeeb6da64bf8c3544d71238ea5ac6f9bc292d84c41d2c5feca91cc6a5b96c4f506cf74e4058e3617557f463c170ab1294182d0bf78c9d579280b6a9f694f0b0825490a3a3416be47658b09e8144984e7b1de4760db4065303fa22da6e4bb9d495a261732c39fca739762b0a3aa18cbc6d2eeaa7ad82dc48a0cdf7e432185769cd5035000a5f2dc67b8cfe236e66cf10a8c7d3f328dfc00672a32aab1070050b2a55ff1b98996a445dfd698d77ece205717f8807a4183f6f444a7c6a00b107e94b0ea9459fa8619972f411eaf75f967cd6db5bcf280ed94a22c147579beb5983aa69410bfbde9fc3bf089b819e160006e68171c4b6206b90e34d95ef902dde2999cd5bf72c21757630d7d6ab08d5f27b2f232f9f77012b39195dd45f6d1107c52ff8f6579bb23984ef119d5673f62c609276b9ef6f92fb738b91cc17aaee00cc4d1c2ad6f9d7b7d69912a8677c00c123d01fd89666c073d39d1ae10fb072ad43e06c2f32d718bbf8f2cfa5587a3266dff215bd8851aaa35b9060dde1f05b27ee0120856e842687760fa47715d24913d9357d2c401323f852a7f1a5355b4ba839b5247c58186e298797eab83b8e13fd438bcdc52b703e63a96fe25a8a1ae4933fbf00c9d026615f6b6b3680d2d17f1fd86c971b4ae99bc166fd2a11e4c95fea8763be429ecdf7490ba54c0483f399b84c1f3e5ac2f91a1769a9761d2236c89f7d931a8d708215b2edf74ba584e33f601ae4b50a0639b290cc7b10e521ad1ca400c316cb92d5d21be4e1501cc0d347f367c8076edb47e86e1e695333464061ca6b16532c86337743aebf599d4f2a9b1f9f9283b8f0c07c03014ab8b57de9582902eb74b734cc93354f584496bae79a54dccb0eac7826dc36f2f1a76c722ec4f4b39ea1b745fd73cb1f44d23d89005a3d04241e077dd663655c897f071e40e3e7db96c781ff2d75763ef0949d0f4e1305939b4ac6c29fe716748bc9415a99ba14ab576cc0f039d790f1a8c6cc35cf4b5789da1ad79b56c710cf309890513854b3182a7590fe652ec8a0d388f47384d9da992f72edede624b7afc66952e9a419260dddf4a4ff3b539f2eaf72471a2085a21b00700d4d4adabddfb7d969a34549a8f4dd0a752a0fa74261338d554fd1f2227e481bc6ae90a6364d0fe26e63e9b8bcca6ae2ce4590c65196f4363b958e0bddd3c7c05a333abeae5ed0bf46617cf5a5dceb118be9e630079463d5a616bd09fcc8e4bb1ba47dd23a444b4e9408d1af8e7c2ccc646d4e03c5a4654a9102fa1f47025b83543cff870da1aa380e795baadbf0fa20075b7518b252f2ef6524aec90437b2dd65ce85fbbda6fe73e618211ce64f5ce8c04d1c8fc1bb74899b752be003cfbf675b0861be9ca00b7e3194cbae3d6ccfe3b69778eb74a20d198e28997daed68216d67448089411e987dabf329f97fb5d60a18e4a4937014a0482b3dd7cfa36fd4a46bb7f84900b1d025b9b6c17fd65c9a9dc87460f9573e490c0a99e5036c5207634bca05923f35cb48d13ed506e99e53de1432b296f147d84c6fe77b9457fdaa00c9d2f3050cf15ee332decbe924327f553f3dcb9dbfc3f56ea75137ba61a2f1dabb27775e56264aa4fd528e5950a899aa86a36b820b1c3b061d971bfcaba1bc7602eed1416d2f2333c89e2723d27bccb453d5040b439310c1b0c25cf2b241f33b22b03ec3813bdd06cf87f41444eab1a51f442be56908e5aa1aa8fe08f622a9e6e8f211abf1fbe3c9451bb8181a383364c70edbc3d168549ea2a366a01e30be3d46e6c70d2370bd3d8bf45248d36f3178671da5c195ee9a4b7f0b672f42e42e45415f58d6d330a67041946d660c566b3c0fab25c8b8ea884696a0d8289217c1cbad5ed99125be2ab3917e724596ad34da78a567b4f30ca3c482b5c2af1f4e1400a5d2f5088acaff194604fa2c0d211962be690047581b3289bd9251b9b9398b00ab0675a024b2f8d2666a7c42ebf0d54ef8dfcea0d478c0ef0f3b03b7199b23528569ed791a418d7641b6e514e4f2c52036b40d47e11f4108bd68635d83e86e7e364cb17ceee7df98ec6af22f8b9f0863f4105b72e2a9b6c70a483da6e8367935133c427aeb63ad9869f767f4799a24df2ded18d28c8f635eb8c4c7af4b4d9ebaa1cf62bc0777e870354146bfcd710e34cac5fa388c1b04a32db4a91ddba24ad94d24588e2cf527d546a0d924deb729d4b8d92e918a65c8fd45829a776c2eaa17a4661fec973b474d3c2b56592a34cf21cc100f2d52404cfec0887c123fa4ae994205f61b2b56ca94f8901309ea49922d5fc1b4d494674fce572165b7125902f0394fde1f02d2d663eba60e4c7d66f4ac5cac602f06c580e99b5c1f35a54d66293a1d383a9963472756bf7db061cb0dd7451c9b6dc503b195d42591d7b802edb0cb0a89b83f69edb27c5e434f3f2c500eb7466276b1e951b9be89c8d96edb2daddcc39169d28357376806c25953c6e9f5b1e94086552f15211234a53cffd12b454b0ed99b3ed280860479b1328f34ed89fbe36157a405a4b8e95866708d9b96440ff66f5ebf0e67fcafe093bf5743f5451d6361ac9114da5c4209699353d6f10510f525c8051bd1d1531e7c246279346612f2055e6315d486e84dfabdf295d95c647d5458e59cb1d047be67fcfad782bd709e9c94fe4c73ceb6400955879d3ab8ed0e2c0c4794d40111eb641de512f478ec82dd574cb2d1a0f36f072d729d7c6d2b058401a8ed43cb29220c57667b0ce8387071c15083a2f2f271e2d3888f6440a187488268a6b1c9cf06616e9cd759de2aaa92cdd82ae1c2dd694d151d39b76b930884dee552b0ee0346aadf2828a7a34e250909f28668d50c7b3cb8845c218ed604372ce5b19d3f0861221546339be889fdaa6bbf33ca497615a7d33630cf0f54f03ebe6585724b00d3aa0fa2654247ba5d866db9859f59f31a3c9838a3a2a98adcc9ce31e5a334153880bb936717d2bf61e9f5fe79f5c7c8dfa3cef2842830dcbaa2cd4f9be85e1f01c250f19a78ef189694f59e53bd8d1ff1024538a26df3ef664bf8577564f0dd06551ba2184cbcc42ae947689d4772a8657c0a96f3c48053496f0f32888442caec553ca3d72979be3e8d368be7577dbd6c9b6f956d601b297090781e308d195c2b59bf9737850af47aa59bb2013beeb4c9099b6777f5d71ff54055dbffdaaef1ba7bb9ae15c8825f691c055f21bed262fbcbb0f686dc3cb462734dac4110fa67973b8e2c354f0b47dd808c3e572988366934da7ac6fd9f50bea97d00367592f390df167af5d1d29ed20db867e4c30ef9a94eae1963caa8791ad66ecc3b24695c8442c21699c13ec2e3d018a55e1c21e0d4a3218f89a60974946f92096eb679e693e220139993f546a84b39eb46420ecbd2cc6f269bbbce3d8b485ff2a14c1b4fb6f669d793b50638f3d57e9203a205d4819eb9dbe1ddb637d16eae4da5cc6bc3c7c37ce35c80ef32c2e053442f480985d20830027e40ecdbc0c83f4314f939f669f5a9d044b81d5a3ba6ddccc91b2137af6930ea78b5e3f1ff60d29886fb504282db1e8f0645bacd9e2c8f43c8ac8e43329a419f0f3fb172d5bdf053456013485c1078a5a7b6f268bb57bf6b2e0e5be13c456bd4977c9c8001d994f10ab312d4ed722566f93243c78e4e3eb02637ff1c5e925f8a02834da7145792ede386877795fb258e11b30df1414bcef5059541a6c4c41b126475efaabadb269b928dce0fd16e1675bca15b13194ffed21bef5b4afd2d6dcd3fcc00fbae9a949ab0c73c04d1c0c334b498dc4e35dfd9983ab65c5e91b23cdefe24dee42fe38110bcf21ebd38bf57bad0f39c7d84a575572bcac840fed5cbd8cd233cfbcc277d21b2cc5a8c8f425fca5ad4e11634a11f1cdd19e72e3b6dc62d5814323ce5bbdce5874621a9aa7050e81f86cd21e3b2ad2d36e7f692e8259b2e2f6648b7f26b21fb47f73f27e53cfc2c5fc6ffac71b6454bed951a5dc4edf5916c7e48c6682a9b01c7c3ee5f42377c3e2778a82bd71e7a4f366255bcfe5c339443a593efa6cc235d3e8a27b17155d36348ef3e1b056f3d91ade502425828c5f5bdc842dd3cf1fb04f2ac78ccb00c5a88d9958d0392be3c198ad0f1da6ae6d4ef84ab332170852e486cb9701c22f92009d8123b7f85538d353ea018c09c6a9eb372534fb46d72d6a90c813d969b46ab43640ff66d0d82473d8e9fcfc4e5bdca23b0914b33b51554f89ed7a57acf485e285dadfcdb29d9cb31772e4b577c0e1c9ba5e24fa829d5093a22802dfdc85787ed5cfc0deef3a7b0e724ea39a1b334d1a88e2351bbcf1958b47206f4fac228569ab9a6b3eee31114a87c829ab601ad21443adc73788c37a9f9da1eb9cdc348a7c000a8be7c31dd5bffdcc3e16556b0242f6227f083977147ab088610a99b0748a6102463509ab09f717e9cad38b40dc827e9372011b93607f5164a0fd4308bb17dcb18be7b19f8dd666468f8a78f822556110c6d601f74845c45d28c714f97138470b797ccac33bf6d929059c6ebe08b14ee88210e7ef0710cef9497a08d70b27395bb6c9cb53681b043b8ec748813a562cfc28b317ebfba3325b8a229af857f4b25b25cf8b159d546adadcc6578aba6ba2a163ec198372241b8b5cae7278e99ade24fc6e1150f864d0fc584a177076326b24ea7a00c3d38e4c1154e99a0c50012a2e7039e01822251fc3a9dc8f8df8fc01b1bdb65f75ba18866b1b522f826550b9830b2758eb02ca56ba09f8ad22fe836dd4666563e9fbf1f21879abf0446e693f391a3abe73e44b6af35af3d75813069173a49140b9d5aa4831da4c50007b733957fcf36a3bfdf9cfe07eedbfadcbda5146f233f36a6c98f07dcd10da24e22040827fbb702496147e6fdb68b01f19c3035feceea4e27b1aecc499d5e24326a625d3f4a3562ca2c33b4d8592af71f386a03c13651760a4496b824e5dcf1b702f9b40ea754194a5e581ac4ca5e8a8c49282c905963d191db58a3fe298875dc5cfa41bfcf87b9a1bf7c05fdad92bdbc5816632e48c3abef2835982767d7485a79656e3d36c748d63419bad1c6060ef5ce858eb34ff34a74b7320e428db2e9566312c9e5fb6d7e97f87a10ea87e744e3b58f48da366be76df47996f0fd56f0e7ceb784e4b7c873b553aba4819836ff387a2c697eaff63e7473c2a076307e7be8579f1e443ab1384444c04261381775ac2def393bdc9e86e65c60595dadb77ef6a2944db171ce6a52443470b991cc552779d42a6313036a62d6746faa8dd4c89f2bf82febff6ad4df4ece4c9c2e1f1b747bc00d30b642bdecd2830e7393d0ba2e440ee37db00f4abbbdb8f84d47ba224adc9359575ab0759f51818052abaf3e82b2ca7b086a1db6f5831f562f0253a5ff63eb24ff1150bd6cd14b19fa04ded2aa0eb63d61852d37f577e4196e1d74095fe2e324808c598bb138372f21393f510ec02ab45cd7213dbc6dfebb7bc8c36538cf3348ee0eda56af0045f53f11f4523a9c7925a131e50778235324deb6885e1bf54c74b65ce1cce644ee56ee337e1672d446d3ca05eeeb631c7cb78e0baeda5bd7b1f8fbe1c974eb54d9d43b7952cdfb6ad14acdc12414a39de3555dddb1f9b92e4175bef35207b70ba32cf724d5ff35b955b29e960e5ce6eca8da9da493afa22c0a6a45ca038091d33e5418d6b70c9a0fd4b4347aa6d15fc3c99533e231ca3c85746301298b49fa315c8b93352271158a576f745506775f4dd9cb3d8941d58f638369ba36fa3b350ed4156170b1cee9fc8a7c5f61203b2fe9b550e3e4b20d41fb122847e1fd418efee8e540a98d47553a116d57839798ff61be9b93c50c1ef1d108335576365406c2d6bc07ba9f00a7d0da90ac7484af006cc94fd9a0690e410659b8a34d880b811d0faf63009095c545f87f88a70a23171624151da7fda1849353e4fecedc775b35c4d9e17eaff7d9570d23e048c2f5b81a6ec6b5d8e444d3a38a4331c41e0680c4907b414365b08cbaa13735ff401d4e529cb63752b40c081eb22bab5542d147abeb15f97d63f634fd3c8fab396994943a75ccee83beade09a71e74b69a970b7e621ce7b53182698c73574c24da7cd6fb2bc45cb038224b1b4b35696bc8d311e7c0b6764be9212d8cc553b9cf43e075c6b67e47e95ec7d5d4c5469fcf9109627920f8ae44b6585cb9a6bc760c019604c27bc01e7aa3bc17288c346aead012e634acda121a6673c741d18e391b10af6ef67f94b0757e697b7de25677505e3595c96791862284c6750be513552ce14f23da8f98dd03d41812d4ef300e27335fd3c5a567826acbb78ffd186f0636d10237b54ea337d3438baa263ff6de4694977c3733d43179cb9d8c0048e85982ec247fa2c45c26acaccd79211d65630a9ef779e664dcbdeb250c2d1d551b203ce77e223f791924092a4927cd62b115e63ec1e52f88e602d0710c51eee71cc85bf06952d983080213d52f1bffbcb0e2946a7df18e6a31e276a6653e5769eafc90389475515dd182096052997d1d729036e15d49c4ae52f3a463cb54ff67b40bb9fe3e5929635f3e91d9716f8081fa5f76303beeb571ee29c39ec7a1bcfa7f4c5278ffdec29634ce257919f94097338403d4de1f4c046009c65b05340cedb9cc7961c79a707a0523adf21f4343f416cadefcd51f8a6fc5982fe07e3dc794317a91c28ca6d0528305a7f9fea736ff009847e4f46c82fb95d8d498868e363cd21bdf0c70b550282e9861635b9f6d41f0ae0429294d3025d852f32c67aee94db41867239cd00cccc521e2b16eee648f6634225b0aa0903910216020a62ec72615c85b2e4cdc64afb7f470306d3400a571cfb053203d11e373ca4f22e9cb4de40f4f98948e84fef1a8227a32675c3148670bd7ecd41bb43122608d2dcb68dfa6e0ecf7c77324444c4e1cca928e8f007f7fac1740a3d33e7ebc45b64e3954d3385a79faf1093d1154c41ce358b3c97c2ab685aee5e25b11aafb82a25a158f613e5be6848033f15a769c00f669836363bb4df1546bf75018f07c8166f9a613502d8deb86cb876e77d70bf1e288be03214f688f40bdca8b6b7242681f777b9edfabf2caad03e608fd681803eeb5b272dc518dbad4e008e8be3898ff1cec1907eab6dd28c3820fcc5ee7f8743744e6fcb844a4bcd45d45c69652a55adc7a0936018b74f26246357d439fe9c049b4af7ddb3fb7fd85b368b588c850fa29186b10ff09ee005a6a6410e049e77a5d66f76c7f0efed3a25fde43516eb565f81349be1880042582b1f3e5f7027dc915add5201d9e0a8f99f8a6ed45152d1687ca258bd47d0d43b1c1550bc422d99277aaf5d81ebee1c184024be935fdbb892ba1cc645b9fbaae356d185a79bce686c66ba175292a18627ca49aacb100a0a2e2d3c7288877628553bbac93835a6aa5cc2a39246c32c640aa7f7b6bd8594a303d682cc58155a5776d5777af916ae2de67a14668915a388a996ca30aa7c3da5f37993d4b03b10221b21d4462a85ac4bfc7cdc74deb73c1b492990508224bc0b920e149416e5e84988deb3b5d813d9ec75e2df5bc25efa418bb4cf7003abc9cfa28883c92eda3e8549d54e1f74bd4eb50756e8fa0c9d5924064839caad775af657f4b9b71b9c725e488fd4786391fc6fe9fdbd60ad05027ae57b7b971f08b67007a79f3e6bd1affa65d0db00366b6793da173bb7be0ea3939cde8dad2188f3b7b8d072f34e96323c73551ec7489f1b491dbe9d8bd2a53df735a7d16a5522abf0aec0f056f1da24581441db249fa3987f0b3759d00251175cee61e3b1d56ca01f57f51a9a1c2454c1c1d07e6e665edab74812c1a1508201ca248242dd442d936a2a2eb1d99dd5bbaa066d9732e724e9d5f3b78be8e0fc1f3f352825f5812bb194a71f961582fdc0aece2dd97ceb17af85fb519b6e392365d23555af8ee67bd556e7ce9e9c57c0ae6c1de5d0f65f8b22bcc4c353050f32ea4e20265d7158326ff587fe090bc6bc370509cff3254c9b6010bd925feb30c4ac4efe7531c06edeef3647696434882baa5d48eb06ad410b0710b3705261c3ceb249a4d5b347b4c6a411ecb7b91481d8ae356336b8a5680c00f698f14a9acf03e7f707473daa04a878883b99349ac2eab44f7c1607de9b5c816e32ce39a9a86daea1527d86e0228a19ccad2b9829c208aa077d970b863fff6c205021cdb30aaf722b19337ebc9924ada8ae367bff0649991e8fbad24efdc244277eab508f488974c0b40325d269e0e4c06aecf7f307b338232b81dc6ae26488028c83cdd9eb00f5c1bd4f68879c3fcbaa90ae9306cb59123b2d36cc96dc36f0949526a9cfef36677cc0bad8fed68db5688cd3f7d1d812abc16be02c5fb8011660578c41a720e57516e708bd1702b02c2db9cf65b2a0d6947ed49125eef03dee0446dfe3ae78e12c56508d6e9dde955dcf83e0cc9a58fb28b293d1b9489faa92e33fc3f77db82abf7bf3928e41264d1ab2688cc61018b1f118b19e34b86427494c97df991188433d330bb5e629ab8644d1363bf0761e881615a83bac9c6d2e746498383b9709b91d2bf586af38ee5b69b4db4f10a7cc860bc4caa534cee3a48cf1044a56ec9c5f85d9e74f0633310f90a47b779a9b49c4c56b41637f67180cf9ec3a6e9d8b2cd5c8713c3886df246764b4b731f2f9aadeec0f656a60f07c0cc4082dccf50e5755d11e758b9e117b7eea0d7f8ea26394cf04d53934baa7f6e17b8f0fceff6312a5d98b701ddfeca46bb911ac8f801cb1a00cbdedc8695d81193eae5f263e467402d7aee5be97de158cb08a5f1f65111715b2f9d9f4b7ee1bc8e8e6aef700d037c9002aa17f355d9086b91629c7c640a47e7b22c8526132b4317d3e764b034e09630481c9aaf7e898920197cdda929dd8c3cb221b3825c5f2cc8734bfd070f121479ac3afb6e893da12292b417d4e2927f80e973012bb33dccea2d5c5ebe78ca9427854fbb2b65ae096992fdb530b7add8e0ddf91a4d22c3652d86ddc1cd0acb9b7657091e963c38ae1d1fc0037cfb8ef2c55c4a86042ea0a9658bc55460daeef8510c4146b9bfde20ea6ba1106df9fbd8b2b87a1c236b5b5da1033d2679d98f93308fd0a4c05a662432fdcfc64f5c658254e8a9b4266a26a867f09386c34c8becfd90abf654e0709c34b7a407c340bfad0d11b6bc83feadbe7188811d901d1a4c30904991240c6e34664e959d1295f8a59cdebcbf46de027a33e38497c93f93124ed67e38109f63d0c16ffd051d79df357bdc589f030505e54f0014b73014af55c96251b6ce222aba04bfce9a14f7c4e23376144c0553fd8e6419236c055d2dea6441400de0b3fcac9704a41f1011cb67c934e4f94da1898419d61bdb1e992c2dd7a2c6a0d68115383985000ba1ef27ac3b4a428763a18554f12f8f91c010d9580fa35629fe21cd71a3ad0c3ab3a6f38b356533f856e207e61fc9f96b2978a3e35ac586e4a04782e92d6972647866d4cb2d29d6ee56082eae49a8f0d37f8f06ad5fba0e521a47e0a8c6cebbffd42640e0c6a3cea88bf1a9dcdaa64f190eb4171e6e1778c35a8144259c885288575ff2135b04424e42414910deb6b75dc99ddab517c6ea36de1cf3a0b5627110cd65692d988828ac916e7fb7d26d33ef03776388406f5b6cd03d881eadf556b1fe210898a91c4039116e2dbaf8808b3594a4e69dfb2588e1ec186b4b164cc79430f7480cbe7b27c544c20c74702c5f80a644088c62cb4bb5041bafef548e9d825bd750702cbe18d4d803fe4fa5a6e277e65dea52f0a9445420993bb21a612d45b4185b7d233de1e23e454e4575827bd9fe52c91787e90a60df9aa4e087d3cc42fe914801763d6373c2a916060247cbc28a4be5022b9459b6c9eeb8bac63515b1d08478bc34e8a747a1e5f7a1b159eab51e821a3ba136329895b3fefc877b0bc00ce5ea9d84cfbcef3f31ebcb8db98b58f6e064f6d0913258f6ae5a8ad737ceda692e06a42383e26269c9fb9a032e4f9bc6b65bbbb5c524d04d673d64de9fc15d2472999c72b0a8a6ef498e4b2620380f94afef1563c1eeb6e4cece6bffd68a69bbb66389963f46e89127a8eece25d960bd6c6de1ab0a3c40406fa3953c78c08684f6cc01ea0e854dc8445ac337f461e373d7bcb1100f64f2f23533389ccda3c0bbdd88ed35b235b334b236f42a63261ec886a37d010a3d6c585cfeeaf8e1baa30c1537201660957fad4a71d1ac105b5303fa3ccec5ffeaa3536d2101b01bd15c61671e0732951c31e32f07797a4aa3c63d1840bf09767dd837ca413543b325f1b616261e71485a28186aaae675e5cc442be117b35917b1d25f9945a43716d636aa27e83ade833bd90d03098a49cf8b895dff0ca323829ee8076cf2c8e108230a0dbfb32e7523133a7ba47988167cda974ba9cd7fcb15defac1a8874b552ba2d3ce4c16ba8c7351ea14879f7c96f448a8a4ba7e47efc040b7724b6b8aa5645fcf769ecb56e73d0610ef56fec88b165019c532af19df614634f7f01308cf631bfaf6496657f1cb34b8c62608375a85cd97cc6cf5f2c3363954852370879b033207a8a1a7a78a25099dd612fd2230c2d914ef804d6a00c0a2a74dab7fb5b927018cdee0e7f146d257ab644bd4b4837e08f1bd5cae0170685e2973b6056c39f452d8c0a17e645e8533a92200ec407bbad2d127794eaa6922ca6838a82cac415507afe745987017a683235b556bac34e26531757789c90936572bb37bb6ba353fd271012f0fa3c17e10eab7dbd078f87a32bbb51064b4e33d2878f8705500d2669c5baba399ec3400cef5a2f8151b86145699c1d0f44392ae7eaa23f8a1d1a31fb53618eeacdb94a39bbf65d231cfd88304a11f2e2835bc444f2d0a3225bc38cac02f832f1f8b020df522b1c60f25538bf52ab1ae7876fffb0ff7bcd76b879583b35d176e145c791e33c62189d6207bca1c45f5501fbdb12fc45908a382d4f84be15c1fa5eeb13075b5d78b187a2a1eb8dbd26ff5cdd3640b2c5f832292dfdacc5da4ace49ef35a94e51c81b5fa987b9b2f513ce8de2cb1d831b3f057d730e433728d5bbec2a644bc6abeb1ff519b87b6c2aac8c5298c7d63944883b1f91acab9636574c641fc8752807b1573ab32d4fc0c09fa8c6b943fb81b91fd54125f87318778a9baa5461acb61d0370cc8e1f0ec0fcedcf710be406884d4ded2745f35ac0dd4ed59419d48a40a0622d54412b3ffd420edfd6cf8a96f0ef7d8ab231929543d313b77508b3566149061df08bd29decb7394e613f717bb96567f50d684022b0be22d5227b11fe23884a728e489cbe1db3b4d38d5a98672bda0cab9a8c881ad13e4cd616294b862feebda0c1e9be4f8da23385c62009214b844829d6db870ac4a73e8352ce67cc6b3dbc4c4711dda81e4d2087b120dec31f2430bfd2c8735bbda2f3f83c8b7beac9fe0ae03a83beeec58217e1242c97dfa337f222a6aebfc13a54ce70d5e036fac0cf09350c04614e91f2f210e65f499916ccafadc962b6983e05031bb30a9ea20d628c20faf5c86a5963bca780dba24333c4fa51e4ba67a82ecd23790fe2df708f93f24663e70b07cee9e1adefb74b2860ccf0f7313f68bce3442ba9b8937e4b68b1354575e20f75392ba2b1399793a42f29c45f94959130b50f8d63b9256678e4948fa81ba483d4695b18210c58f0207b9c60f5713a7f6fdcdb69df932a16a2d522f70bcfa267201c84db780539f031e28e95eafa94a72dce1d12a0aa9ad45fa01675976070211bc15f2b015d6256d5412733027346e5dedea8590d07ec5752ff0f8000895a759322a9c64df97e22ed0174472cb7b81c486b9a37ec87cd051e87f82bd6d315b1ba3e1dbf17591d5a64b2ec32f205acd1cdf6f221b7a7f118d296d73ed1c9bf5c56b4718b3f1f21b002c1da5b78a9f434b88787ed975e158105c6b28cb0f1976fb4842bfddcf29f9edba7734eb0f2c7694429831362db60dde5933326dce40cacf936ef42b94578791dadc6b67e77492403ce3b9edb91f6ac1c50cb792827de3388c28019fb4ee900b6e822d6401c8069e6aec9c72645413412df423b98369525124c3ce6904391f6a411df0f5398e5065f6a7ff4ccb094d4cec7ffa147d82f13fb6fe1a635557fb04bf7e864683d09035b13545dce69733568766d7b966313b17af1c305bf23f82ea7261d50127f01879560008de8053a7e25f3a0cac4fb1c93ab3a24a1b3fbf99c072127cf683fd36e9601f530279b1c0bdcb7274b3f6d6e27566b6c662042664b59082486d6d2fe18250ae52a455fdfcbda57d5d0e544983c75a644c3136b2ec6cf4f154546d95223a5ac11278b84f92a238a7a534d73fc880dca8d32862e38a1138eb99eda3ee63d5b7e66013cdcb8842ce5ab2cba55e90bf02740eaa55ab729834c91d4c8897ef15e8a2b43f6c3cd89b7bd71078d8e7ce6d3a87bdcd2ad58a465a98498c9cba1c7e91cdfc1498d4a28db53beea12c67d93cf44ed55810a1db9b4d38326a2c833963cea26a9d7de59b918570a75b9756081b35ab1ea61fc654b4ec4c7336b201a919a615cf04a5ac0d948c8b18478d0df17013a0736cad919af7363654df714d27018ff689944cfccfbe4dc870e37a81d26c0b9b99c8cd247839279392d5b4775870b8f5bffaa5e1fb1cdf88bb425a70e5d27452538ae8135aca7aa2e2d88bb54b62fb5c0e58ec9e0d9eeadedba9621f2d77b032e37d1513dfadf73ca901da4383505bd7de14ab1031f7386b1c413e8821a5b1c3540387e1593c35a8831f9abf245862e2d3aeced2eed34ceb45c7715abe4fd9231acabfbe157e9f5f76dfc51db62a8257f8548cf2345bf427bbc6a5606badb5035a01c4e26bb680eeb0851b704a33f5de6bbae1ecffab8e3e6d1ca6be6f7f49cb26fdd2b0fb1cc76a5524eb08fdc32925da45cd55b05218d3710f5fd85e4c7f73829b27591ff6cfaa3080aa38a45a688babc9cc2a4a0f4cf781104c87d9e7b35f2a8e1e27a3dbe22a984cb012767a97dc71d5cdaeee6f45778f1721eeb9cd8f8d8c3924062209d28277badfaac2a5c2c9fb50c296a92bc83a5f3cfd3e742df2ef82dfa49d97503e854f6387db23e3a174cde14582223fa09e0ee5a32c11a8b2c36d0f1e69c15f1b421e53f06c63760d099f7647ac20036b82258e3b0a662ad6801c9f6b8239e9cf6039c98689f7b60af521471f058189fbf1c9eb5675efe921e24710e6ed831f03d5f6d7406352b67d3e3c37b4986c02a5ab9ec3980958c4a262fb9ff23ed0c9504a7326859a01a26020c2d48334ccbd122815e32f4180059acb0cd271e09e842f8ce2d018342731ad0d3b5abd1969d3897c9e91130e89502afbd0c2bb946704faa73529ce2dd8c2af8785f2518730cd4c1d6acb0241de474a49aaa329360dc296b491383c759878547c61944fa58f48b07722a12aca1e654d2749dfad0a9667825b8d3a16c8d6b0188e5bb65b6478d2b79f2108fa9dc3ff4af453b5480f2f9e184b8310c320919912e6d02b81acd43092980ee9a54e8f2177955c24a829694fe476bdd87ce298207e39bfd29a888919110ca0fbe73e5b6f977ece7922e7387152dac4e9ab4a6c4dd9acc4835d7afd605775a5461cc7d57b7c81c45994a2b06823850d2a942b1087e3f328d7e217d9f6975712ce8b2b0ad210003736f0b83213b0130d23c5640212a3e5d47548b0e6f0015d625c64e5401f0db106a28bfe5f41d498fdd1ee18e218ea16575b98262b68a0bd916f794cbcd74f8f4ddd3a2db7291d3f6e7f9fefc77341f85c2178cad773fce5844794e6b7340197f8c5756952715043bfbb8f8d83bea9c71c549fc2994d5891f0cd4f345159a904271b22510f73c6895051f011b9d6310b7de615ea3b5f51b3ec11a47ef54a0a592aff144d2f67be0104696c661685da64d3acd667d9bff9126c63d256fd0c99e119ef93adc26960781cd69b2095f17b2b6f0d9423305199ca63e907d46529f178fdb0b66ef62417ac08ee0ac2bd3fc0a24b4279e1614cb2bbb66cb923af0bacdda25e61c1065f07cc93aaaebcfccecfee796b4b080693e141aaae4b20bb77940bd5895e3b7300832df2132b048697423ad90bd941557b42c5d61fad7c078aa92e0e73a5f372ddca5f2955788c1b740978562f6478632fd95d17dafe77785bb972bf96537bfbd1030d78969c008f7c4e724168b2d37381f7782d376c9a799b553ef223f201e3c4a83700641b674bfe1b5552f795ed77373cc2e3b3b869f0234b2587e6ab6288fd87025cc4f2fafd191eda90dfb4bc639880f62eb8a313b9a54f6616e177da61449237ab252537845b590db1c7919c2cd0240030233b9ea33ae7cc6df83613ec54349c2e375562354b1f788ecb2c51ce15056b28ef8975b94170a33010d6edcc91582d3f5ee16d8350a9ead9650fcd51833a48e347d7fc370cae71c58cf82ce01c7132357db47bc947a1bfff8f232215a5ca45da4396576d011d9dc98149955f9f45983efe832b6c018f9d7e5d49ebdbd79f47c6b34b6e3bb5483bdf879ba540e3318b8884eb629f1cc748f2ba5b67e1f4666db409f802054d5321b36a4381f84f63a9675d46edc258d7d9c8430508ce0a10997311f0b288410c26d2d1db2884ac198f125cb8648079766716ea7a0a2561ffe7da01e1569fc3d58f08740136aa8cce49fed4667d38c0c57848642ec1f06eaa20f0fd974813b475f74fb359ea8ad013a7aaa405f9756a4dfe3bfa58f666f77571cc4f61da40efa1a5d69c6743849e59deb2d0b45ff8d481f6a1e8dab98456131582f018b742f398b98ebdc95f6faa48b9bd49739681e10c2a5151228d468038f2fa738adaf4b57a8c2eb3b942500781503093db172f5309bbce1c304d4952d5442150d61e19086f4ec01c805d83707897620169d49228980ec3c1680c53578f6ac6cc0abd01df67e19ffe209e07fef01b4a957b8911b88d830e21a92aaf674ceb9c71c7b05543c993fbd785fb540f13dcd070a94da563e60a2049d870c86e576482b85fbaa7ad63b2c4ab9096d93f225f9d11a2b900958ad6a01abefbf510a25064231e2e6adc5346225bc7b2fbe22bf552b4efe8a509e3f4de5156d7b2c7e4a38ab867dfb894210b5f3784224d0b21498d60a5014832855cb001cda3e5a4b0743f02f3db0444ebf19681913e46d3344e75ddf803b54d04936a64543fc16f5a5c656f8c29fe1a375a8665c8a684918b7b935eeb8d1d656b7bcbb91cb1b6ca4e747a6642dbb3d5e25fc99e58387d883ca63c48dcf7e6807874c00e4698b96455923b7230298939675736b362eeddec777fa873fa107c4719ad720d10aab13add8955cfd88663ec2d132a49f0f5e8370bc86c259b93d5eee81c271fe3be2278f4a4f411b8894e9e3bce4c504e8737022feaa532fa056ffb2f32b9c0b810e27bb5a720a7f691c0586a4cf255f69b9c3dd7f0c1dfc1b1b44fffa9c9e980fe0daa8b0efed44f243478085acabdba7f2daffa1714122dc72a344a951d2183b937d57b07442b1b97d041bc26f3734e7b806c81daf795b0e12071bdbc5d3c6e7681ce5060e4554c65376f71c42529f86e6902b28963d162455805fa950b8923056dd5aa7ab1c98ba5c557e7bfb5f0d9741b628c1309a3d6fc409c3582a0da10ad7aaa5fc7a72faf291e9fe6d65c58c2214fc5a5faf5492ba31534c5c583e11cf7ecf2cae400afee4262c0294c6441ad4ba71bb40d65777b0b654404f6a6a4925b83cd79b9da5470d71bda11016d9c3241ba00c75a5e8b9dc646b3e2022b4d32c1b4b75fe33496ffb989aea6a0ac558b2abf35d4a1fffc416a511e05eaaa8fa503b3acaca3a4292740b7d051edc3d03328f861a2ece21a2e0cecaab02294f48862e65f2d16a4cba098196d71762376cb3fe43728b34b87c771dcbfe1844a9ae94f8b263290454362c0b1c4880eb2e0a3accd1facff762ea21073a2b8b01fd788e8614cc3605f97e1525513a02e4ff2f1778acea02e2a14a5204e50b64047e1603c61f3fa1be56bf7c0fdb24bfbfd408dcd80147689ceeaffee1ae6b51a5cdc12e8c73e8cad7a9c458adf5e33bfa7f31bb788de21b23852f330b0f10ff23268262a2557074ca487eb0852b9e9d5b4a20db2a918fa2a4172af919923fd2c8883f1366eb4e996173163bfed0d779d858a80714357c9813c68079dc328b1a1d761b693f942a3a9a0093b817205551aa8144f03ee7409fd208621e2fa51df38335dcc34cc4ef00403c92aa074d17fcbf75b3fc42fb56dd5dbb515d8714db37f49606c0b6720f04cfb73599049da1065248cac0206ae01e134a6de55f79dbea1e8ae1f55bc401dbae3add13444afc632a5d272884a692b229fa599e5e823eb87cd9b64fd1730b44caacce70d4e71e97124146bdb457155e2eab78d51eeb468b3cdceef9ef9c835085e890c4d59a6b6b2fb4e63b951cd54862d9d7ad7bd447e3335a741c1296cf51fdd57f72a03b1363d32f66e511c7853cc343436a6271147c0dd221d190e7183873f87b63b59ea911ea6f35e683914ca0f38bc9d0895b873147b6010aed30124093182a25d55face8d1d43a2f6092933cad08da38fc65c1d1eb6f996e0e48c3941171615632341f069c97d55ac08f0a1bad20eb83f36c0d3e34e82dcfb868bbb78575102286e593a3a937523b18394d11121eea7dd6617eb80127e74225091c13f1a1a95ea7f976845d420c114bad12c0675bba954c9c9faf283ee0dbba4b5063366672508c505348ce9840217dae4454824fdaf1c6a119dc937f0b5e8fe62ee770cfffbb9d4fadbe3ca122e4396fedf1790b29bb81b65312ff15fd562d7a052bf515a8b0de19b258549acf665e8ccfe965b125132f52ab451abc2b90420d79323a82c150cae02d6d152ba7ae6aea352722bbc600cd3aca86e091f09d8e2f3ad3e0784305c6d11ed6052129a204ae8e35866699b8b9e6ccca57a8438bf8dec2ad97cba73c4c6e84c917b7c260db64396c8eba7c61962849bf184d7783130df28cb597c1c341376ccb374b3d80072f9c7740ff8bbb133215d7bf950852152507c24cdc965a5c4109953840242f17a708e5a82a56998288b0ad36ef3d2b2abf33bb331fc8eb65be6ae81bf57b88748b10680696d6dcd060cf246466cc4343a38ff56cc776a3e3291c14414aef16d2be2854f007f181c30442d11ac0f44bfffa90979a30a2e7fc466070cc9c4010f04705473ff22504645bc873768a1ced4026ed2fd67b3113c0a492483dad01aa22ee6d775ba8dac433e902004fc1c10b86343a3c78b535787f0f19a592503a5894c721b57ad3527a86763cc68dc9c2ff84ed7876057589c3d98df5fef0906e2dbd768ed23b763c73064e0e8ec691c050efdcef5a0644ace032f2909e88b995807d4563698e54399c3eab188b8a8876cca679fd9b89f24e6d9f70f41ea7d2381f2cec000cb9b3c0ebe1a2f14736906ff55ad8a02f66e388cd17bbd403c25e1fef13459920bc866b184717542b888fe2fbcd922d3e0e7b21865cba0c0ce65e0a28e88a43330a93a1737a3be5a77bf32e7852252ecb902e9fef566c68eac7f08df246fe445af32d56176f05b003ddf056af504e077604ccb07d24eb07674b73b00285fa1db0e3ee16c615c4e6e9cdda9e1702e6dafabe26ca6da1f99641bee8ddd839bee583915ee8e37c297a6a1ca0ef25e856bd6ed6bce3f80009c6398dacae310735af4b6827a71156844048eee3be3604a111b06e7de80d0499a439f07ae3d0871366c85d701fb54e4d65ec002f4be595b43546a81edede08edbf8dffb26be3e4e596ea4fb327fea3ad68cfc9ca6b2d1657bf5e79ea56107e6d35632420bc5b649cf3c822870fb2af19390b792257fee54e68a53a7c998013b67fbfdc831ab19e991bd25ebdc0fd1592492a5b534d984cc145ca9ead395a3a783a185cdc78d27f20a1d5a62629985d6405359aec4852b21bdb294cdeebf09708406854380e4ffee425c07721c9a5cb2252f906fda0b152f9614589bc5547666b9468f3fa0a75aaec517a19f816fef4af897077df961e71ba46eae38a5cdac0898b21f72d5a25e75b26f9bc304ded94e8fd91258aa5e6e9a8d79ae76f2d33b85e74646039c85a7af80446b819478fb5ca3bb5ff03aaa671a869fbf532a7f56e8101da9c7aea68d255b718a9050fac90c7f51383318e8db993a2b8b5319133722003cd49a30486e5a9afe2b091f7cb864c3ae9c72d5f6058e3698d632ddea687fe70f904a62bc16c5859adfa862adca360e48c930c12902461f680eb71444bfda803dbc3cd2e37749117aed914500a95e27d8cc36fb14053f684486de34c3a91c916455d2c33828f79b83c8a750a5d8b7ab4d545ba7f87ff77bd7b0e69417d64857e11689dcd293d24a4978aff30cc439a607ab326b1055376727cb4a70469d83707a8f7b3e115cad4abbd0866627743f9853e37156c7135114e46da04509e81c1a58d80bd73422d63df087c1b2e0b1dd717f3da89c18d9fe3043bb1db4797d16cc959d6c5d3f31f67017142fb732c0f4b8b544cf63c8113f6a41f2877c5afd2d7e595ea49030782d130c7ea3a70b5eea747871f686ea6665a3fa9a5885ef77d5876fa97fa42718e2daf3e89cfff3ff63f6df1dbd4cd5c33159796b2c0d20ab199f98a82bca7c48b0c30bbb3a3f2c4c7e1c7e3dea1166ced8d69cc1fdb9efd7c61a547651e5639f819d77fa5ad4ede1d1ab181032fdc9c24c4a9a8b7293ae088597d35c75807170380b67179390e16d426403ba50ebe4530aebeaf28dc175ec339bc5be7d092bb7e5e4a3f637955e9bf60abe2639a2ddb897b9041f029b48db9ae91d09b252f6db121b2ed42ea20b77a4320f0329b4e647914e2ef2481006145ff05597c1e764f13b196ca1e94421d185cb19cbc29259b52aea005e7d4d5aed027145507c6d34f1c36192bd075832cc590b3238e419aad85200dc12b873ff6edcd8b85e4e3697defc249cc53c3e2f9754f8da0d31013e0a569681d680f00120736d941d6cdd41b3bcf1095aab973fdf7916bda22e8837be0e00458c12e6cf3261644b6fe498d03340b68ce01f2a28fcb42fd3a7987bd9d5da540e1c6e18797e9725ecb673d3db93a18972cc02deaefe6796983e300ec57bb471d5d709fba2d1e789ca8bbeb47a2160721a528c08371a7c80bdb945f7c481c1dbab98f4e21c99c298c9103b0b016db5eca0b2ddabdaa186ce74c31806bad1e0f69b4973ebb34b5a422ac115a1719bd47df88741efbe3f3bd65d6f3947c760f839c778fe20403e109b0aa1073dbd0b4bf080dc67754804ff3d4fa6765ad39f8d5c9ce93f781afdeae8282ecbea96ec997988e6ff8ce096cd9f914caab5f6fdbdfa86b9a8d3451120b5113843a7fdb73f475816c09b3e599a4c836150cee51c47f5df549958307f60c358b8bf9896d0ae6db6eef959001206015add26ff5655faccb081b01f04875682a74d9fcf04e46faa7c216165db5f594903d485dfddc58d129c631e9d84291dffaab25687fbd5d3cb6123ea7c2ef7ecc8886e1ae4eb0fad58b21c6f21e69b9c44300582165ba09823c471d1c5c7561a498dfadea9c16ac45046a9e4f95fa3cfbee5208c19ffa8dd9413d82bd82c74060c1bfd9e58b9cd1b1bed881a3c70eef25df5e2c6e3d9461d6298fd31590962bab01821a31746a0c87a04c154e2a574292618fe19bbe847914564724543750fa2b10f342a4b1b8e7549d4d510c57d151007919f88bd0da18d2ce3a038854e5ae3d79dce7ad5f7b1e950c2d28eb49b4adbaa8d643bed4dd3a6afec45e5c378e2a7983b4fc271bffd9a25097bea35ff919525278f5b49890b2c15f6bf553ef931fd94583205f087e517fe405f397deea09a55461aa3ba55d6af3597f96fbe9f6e2aad63f48f47ee176731ef50402539db69f60d3608cfe8aa7b11ce8de2a4305c63ca5e21f32a28409929e6ffb8c5a3a8405a5bee9ea5289dd685dd2dd7e4b464a2e1862265108cd6bbfba1d3466f84e79800f1b0e664a719828ea5a64e929a8ba1e1a4482a1c0044191d8fb1f200a5ef6149415e791c53dafbeb8a800b429908e4ecf3275b813bca47f19ab36860308fc33e3f46c2d4519934c248677426a74c2126efb1e93575d410e58cd2e5051432075736572202854657374204b657929203c7071632d746573742d6b6579406578616d706c652e636f6d3ec2ff0000430b0613210c0000002c05826774858002190122a106d54e0307021169f7b88beb2b76e3aad0e114be1a8f982d74dba9ca51d03537f400000000b28010df7c8f15bda383fbd565f844dc5e1b52377ec9c3ab8566d71d56b0dd610a575c716947d86ac7fd17dd9e69040dfd4c009bc5ca64281fcba4e9c827417e16d4db33602972445642dbb30043522f0647a1842b5412aa4fd17541733b4fb34e3d9520640caaa913ee311a394bfe719ca6dc95d4354b1482d1aa08c2c41da029163f0ba19e2c80de9d2acbb30210e7cbaa27ae4de7dc95a4b64fc162df137a4453dd81773f801f5e92f1b240d7865f190f0037cbe2c135668dfc00f076e7e29d8a951cd907f2e98b6b69f0427364313395a284c2e483d78d843f2a61a6de734c04270e8ce6f08161968749811617d72716296d81896fe0d3782d334eaffd7fc2d75071a09125a68021cab549406fae638d47f4701fe0ab704586e02dd513c3c9f04d9a7a2ef2b9412b7aabac7155e61a7398ce67fe89c23d546a466928ca375170c6a202de350a97a68c6e3a5cccdcf059eb129599d24eb46bebb5d4e8068d5a5aaf0a6c810bf54c06ae7aba2898a7288066161bc113b2427960d81cfd26cfe136577ca13f55a3c6b6e83d999e62c555c8be02a8971d1f017ea2a5719615952b9f9bddb6bec4b9c32226ffd2a2851c82761095f91872f48fb1a927b583c899d06ef4b22cf138b0e5a2af09c9a74789d9b9942d1fc513c77efecff8a55dfddd7016d02aeb3e5e3d0006df83d71f96482e5e990e6cacc97cb936d14d0dfdde5e82126c67e7876e0548c25d57832ca4e5b48fa421b53bf453c1e66bd5150308831ff5ba99ccea612d24022b4be4196eab5624f47b96b27a8fd9e4e32cd7c1a928599a1d7755ce08c3df4edcbef3d655e3f42e7a17d8a98fc9beb03c1dbaa726e530f6d1ac68e9629105fbaeab081924760126cf82f0dc00fd59fc637074a8567ef5d800ca7e096e0d5c33ab0a09c973aed59335a364ad677a5ebdb8b3358283b78badd7b4c69b89e4eea2c8fc321b5c9e6d7eabcbfcb93750b3e9f0b35adaf204da9e443348815616d805e5c2570dc585e41ea41d28fd59b2f30371126173b4d4d48a45502583b4e366001c500cd8b100db2d61bef95b3d14d0762144032fc7e2549bb2bd501a9c7ad56e441856cbf3aea546a7abb29e2f4fcca572e1e1ec157f894b387717d584be16e36187d5d2eb651bf0d9dde79695c8d8cffa49ee0e9d7364455f0b286e04611c0cf1ed7ca5c7162784bd7cb02738cdd236c4a7225ca67a5d60672259411c446f2b1035aed858f47d1670fffb85af94e3a00ce3ae01284acad1f2ce129c9d3bbfb485a36fd458c996d31b00ae803418e33b43b83a7f8191f1f3af93406379fd4af237a938352350dc79c820fdea73cb9d4c398e25ddf2b4ba8efdcf3c79c02c28d56e5319906ca857c14329bd6e4647d1a8d743c2df14068f0ce18b178963e81947ca68ca43da8d8257b2862432f52b0ed1ca898b53f593e0ca10d49d81540473895df1a25015193e0baa94c501c9bc5d6c5da9be70bba46f9d1a333d49424708eb27022b1bbcd5fd3bfca0593e6851eced64331d089a62f237d57e0e2809707c041debe743ee2cf993ba32260381a9e35f63dd00f9774fd5bf358cb88c6af7fc14d4248d5c3447013c661c7a0f90698b08e8cc45b199176b404d74ca8c12431fa1151f07627116163d831aa96f1ebe63eb43e32cf088b49650315f1c0923ac0f68d5beeb0a52a661b977ad45ccc6b450d9169841ea973191d7d8ab7f508948fa227190bd7f9346c3b97a7a9f2d2492a8d1af162d54469bcfde55b67defacac6757f2ac3323bc684627392e6aa656db23ae67d82dd1308964fe3e805641cfb4ded0ce419ab0a5d58e487bcad2095ea2b1fb1825b9ccfa765c82c160850761ddef2acae3f00e2f52d906855f82e99b266017b9302b4b6c288b4730f2eb02993de96ce033a4082bb4603787d27e6ea511db75db1db0b4569e18ff3314a3b460b4d4f34e37d8c638e8ff71d07e45eea29672407db40a3d40b7283dab027f9550d30b4007a6a90c3754711786e4973b85e84fe80805cb82cbc3c2f954e6d7f79f535fe2b514b354c36be7300d5d5011dddb0ce094a42f6cc5ffc7a1392c09967774513881c0d40484935a9b3ef243b3a8b8d22b1078b234d7b5e959a48a572fe1fb56ced2a6161b17e97e5ee3e632d7062341896bdbf8f0875baca40327ddd63069cc133448af21ba7200133a3166fd65d26f783ff1b01ab740a662dd12261f87874d270af7b1fdc10eec4086cb84909c80c372f21aeccd15d7559e68495369ad5a9309a4eb91f1379e6932d72331d3eae406d4125bd07ea434158d80734d4bcee547747b9e902eda8728db93557d14a42be1f4ee8c874325660a5857e550b77ca4d84fcdfa0cfd0db049408a71161e53cf47ef99c975b0b2430216807622479dfd7cf4a5c66fa573d911d6f71ba7b31f693060c9fa9b6cc77c8b46ab7ae4be655d3b3c343a8402047c57801c6afe782bc49f26ab98e2461eace10ce76ff366861f600e74deae5a1bf2611fd880f43b5655312e30c65f7db6f7065ef81952472bd7499144f4f69c2b8628c0587bfce4c1b7ae9ede59e140b432cde5403176349e8990667ce90f82cc372901858aedb5e85b34541c36bdfdc585069d6bbfa66f611807a188ceaa2f7ec47211db5eb14b52669717574ba0e881526dc1e127a884f83dc61c2d5c180f7dff319d7363bb2c5f21e7863e50ca6ac5ec1a6e8f3453b1b124389805254001dbed65622c93c627988af613df59f2011f9d27b5220b98080547c13a230fd4aa27290a3fbe725513aa52c303f73848b20ae1591f248743a9268e16eecd027dc0fd4b34dafe4ecdb95318a019871a5ead2a7045ea59e8598d5f8a9760d322b69899342e1fd74a19de3a51164af30761f3bfc0ceced4adde234626c6d463b23d13f579a9234249060ab153c9fd9ec04fa56197f303ce297c9301f81b9cbba7b3c549737abc05afd5550ff5364b839c7dd5cbc604dbedab922dcf39441968d383c323c24b92cc25a297476e2238f96e1cea6f07d4f396ccc970faa010e7ec101356904063478853df47be92cb3208ec8f6cd1543f8858a107bb6ee271badf62a0697724b7d6deeb3e8e86a82d1a4a3badbb1c0a5ca2585cebae284d1f390f51f1b509eafb0f14300067a1f00c7c5e60dce12e5a20ad4e4d08abfd0775b424a72c50627904a271ab0c2ff6985e3957215cbfdcfec7bff4cd65743c440dcf2664fc736d715a3c86b0affed9fec89b223e75fa26ac3ef39ba62970050e748ab752898d93e769b1061ee1048d799b14bd5bde156c7a920cd25d0b6ee4d8132d5be14c2d548607668a19fee7f8adc439cbb338466ec61267b65834d24a1f62749654d9446598f3a8f46059827e424c913b436fc2a7774197181e02cfc8a8d79e18f7f033df90277ae53447e21a90ea2654f971cd964c847a2fb7cba8cfa5afb7ee1a9e4c97c30f04db57756851f782123661e5b59c16363523ce68ff620d6c6ee0844709abefc0cb6cd917af289aa65f07f84bacef1a57b58a5aa202e5dcef62fc2ee97264bea367ae381ed437309080de3aba3f86e12d640784833db242a2f8d6be31f066507d0b369f734e25b8c5b7f53d9c4c1dfc5137f63ab2cba774b5f7590d0c4026b26ffd51ee6b8afa39256bc77659d19841d20dcefea6706f52829685185da7615fb862798c462a3989cd303f82aada3992a3a0723c05833f865f98b13bef4eb66511be3f073001bee413d7cc5abfc00fa8e89c52b224f67e92cda975c73a0e93ce39145f166225fd1448e824713350ccf5dd1b69a0577e6d0e9fb8cb459b53c774e709450e101192a354f0d7c9b21b9b8b291a71a61f7caf778e84b69b51d853396f6df018fe9f4ca72313be4fef984811aaca12f3071308b2e0584a4c5ed6cfe0825d854440b7af3a002109b0a3af7d1c3a5ed6a34d58b5d6b7ea3fcda364df8214c7ef4d92bf158d556d7a625e52f4f14a46f25971c3ef965b894994fe0017128d22efa302502802e8f70282edfcce6b80168eb8ce1b11d03de65525362012d68718d06d2a75b6c856e5837dfb3d2d15f4b065b72165a6ef99aaf6cd445b68166bea7a2b77f5f9c3bc4be40e5a82f02f175536f96a213e7935b51394d52cd616a90b081e9a496960ef1215bf5b46e01a251e548f7cb96ba7527d6859e5a79a3259c121e94db313199de51003ff9b546b675f7ecaf824c1e9b61563e86192b10e4151650276848634c8128b3863f44e3adfa1a2610dcafc24c95ba2bedb9510b787cc4452f2caf3a814e2335dd7340835b7be73de11670c874a652205eadf336f974f47b148d41b9c623a1095b0d934127fe0383d5dc146c37466825fd8cbb7ef108ee3ed9f3411718125f2d83599cd0edf211ffca75b440de3ff0f27ca654cbf512a7be8549441abdbc2f6e1a5b4bb8ad4b95e8d5d8fc4773e8192a6846f16b61a754e3c85ec27fa3a8ca6dc0eb2e92c871ea049e41e7a0eee9445acf48d45252f0594ea8c642a3880860ea8305773aea13ee1d2bc2a747c6409fc08771e295b8c063b576fa9cbd52c2c61abbb4152d5f7b76a59484e8b080ce7ab23468c8f1a181c1be57a173416c5efd851cc6c250e1f2a5a8f57f591f4eb71ef63e98358eb5faa53c7d4aeb39cacba26a87f4bfafea840e41cac1db630b77f5bad8d8b4af8d373f46e1c4f8f3346e65f544b10e54eab6478cb46c13c63258a54b5fa114fdb4bbaa6df9f67f93120623856c1efeae78c71dc77ba9aa440bb02f60c98ae8e629b259f6dc048a08e9aa02b229ffddc09099f6de631b50acf4a7cf4224a0c00b8927e960c4eb04bce202647ae357e31012b8799bf1fdf0567b79c8578564fa9fff3ed6b3132b6d76968fbc345599652c1442b308e475837c3eb64f7e9a39767fa2de11a8d81e266437ac595d2f1a0de6df93c79689c245f18d596014fb50f9d86f21f2e1c6149b4be0b99b38320ac96ae0929d49359f848362dadd77a01da6be316ac074492b6dd4fb10547585b1db9642cac7c08f93bbeec92ac76f38c385f9935939fa3a93a01a25b6fb8773b3e4db5c4c17821ab1d0359cc89fbe47be52da53f6af3cca1a33ba9d2d921d45460720608ca406de067453aa7860d9979f9c8ef641808ff07d055fbe53ebdf32a9293500cbf99f6f585f1a5e743d17553b5202f05c8e5dcfcc27f2a5cb5c43abf4f27a11dae87df5afc2ea09e1f49d48d55b80540bcd44127c30b0006cfca6a97d4a9122ac2130a568ab79376b3f06ab1e9e99c969417fc520afd3883b531810de98c498f55a0c67ea9f69f7da3ad444ca99e237cc3bfd81fee39c39434c488537516216a593e86e4ae6d85a9264c1e449f0e79a5dba0dc31f8c113577e84ea958d4eaf08c490db3fdc4ebe8d32d1de3c297ed658248af0083d1afffd2f07201eff80cac88c3a53e1aa7e4019475224c60692c61b070e7a134a8e2bcbacc5292faca619db76346288c65d5be2cedec9d1aa301fe12e49c0eefdb0bfa1a74750f38f978a11e5492b18516de8aa9fe29f13ff3a621b63d10634c30484f7a8405bb3dccac942452f99eee5aed514c54061d635f42771e1330e7bd5570e5060b0f8a375643318aadabf59985a5094ba6ee24e0f118766b7b90d68751980132491bdda8e8c91eb0b7590f69205fdfec35940612da890d51fef981487699edfd88bba4c5bb4bbaf78fbdabd57235c8c87689b3637054fc776e947c63ede2b9caace1f89b8d7b3e6986e176c83bce7a1f24c6b8210a2d58d17ac2d43200abd3054034ee4493b396f70c47584c27e1466b247790eb571b7ef0afaf388cf3ecc1dae17767850df1beb8bb75a619f34114f3cd675576f7f3e2714fc8892f5ec6be4917a6a5df7bf5bd4d2f2196c7ed7820255381ba0d65923dac8467c4211d80dacd84244afa2fb5580871f302f56c237e845da2b03e83091b70f403fcc30ae84e64983f349c87dd304a58b3495c2d2684f71ed9d68c86a697eaa01309bcc4ee98a4d4eff4a024b19d54e081e722c9149bf19fa1a3aa32aeb685c5a8e23461ff4aaec61e79955ad1aaf2401c35ff6cda3f78758a8560eb0132c2bbd0c8cc6aeaa8ef62f9fbf755c99963171c6bb36d436fe6a809ff6a0bcb3d0095ac09533ad74d4ec050a80a679e6b9ef7f1080b058431310ab74f317ed2f3c09630c0ead70c0869d08582a2e17469cdc8aa73331342784621198c961391a270864d05c1f8d0eb2b9fae4a3845a84df46bcca3b42034cd119f6fbe178b1ef247d7eed9b94296115052949d9064f7aedb23f1fcf4b9a9a3fe7fdfdd0a8775fdda9c47cbbd9fbbf4344a342b3a41657bd554d4fa908928179a2fafccd95ba768fe46c4457b56896a1767fcf2fffe1ac695839d21746a2e8b82682928dbafd77f88f3ed77d124f8302dec02a82b4df6c47b6f4473d23c83aa6d6581241b4c8c140dd5b775276363aac062c4d3fd4b800638aac907b38859ff0483e488d79c100be578bb2d9acb4c362fe76163370094540377f202d3ef08be2bfa9249645629494233c4459510073e051ef727778c8b386f5e867206e3488b7c125e47d6a38cfaa5fc8ba8806f62950bf586b3aa93c949d4a3627ea373fae0df5f216fc6bc299470314921f89571b26ae2ddf2a3d6534c5e234fa7698c5accab19b88851224026f94c16d19ab5256ca083343285049b7b5dc600a8484b7e29efd8d6a79ecbd2727bff969436733c0373c6b023477c1522aa5ed96063d72be06345a54f29b0e7f1aeeee10cc0607a625e0fd553eac233dbc2a2607402e07fc690619d3c88fc0274619ea4e182d05330f0a522661b8bcd6cc7197b40cc4d0697cc0bc33638f615845689d6cc41d821a1df54ddf4612260e312bae210b8237d504536277ae5e7a56866b07b6b9e015696e06591a04dbbb08dbe40fe572e0f04921fc456386694018e580c5e226c5c860a9b379b7762ec99e2e912b36b0775ee186750130c53e4147c0e698630819079c0de160309cb8470580e6fd287963e38c383771eb3bc19950a05b6cd48a94e88b792f47a327253426dd12a5ba1aa3f6e060a13e1a5b78b731f2c67324b58147f6cd89cd644e22f5f980c7222ce3b951da47656a25f5ad2731d972c21212b6839c67eba247a3b053404f261e42a609bedadbc2fa8d8f2527699fc6c614e93ed30120a47cb9d7cfa93809fe86d7f089d5089e635a3b82b7ca7611305f81a079a12a1442cf8a0b03ac720d543a203ecf15dee2d10cdad994642e4609e57a790e0573b9737d870cfe802c1516841d9f58b006559a96052b6b9c02e0b2465be55836744df6d1af979a5b33e9d02bc818e3f0b6796684b0af4ab4efd0d3d3073c3b689cc55ea9d32225817b64ee877a0dea5fc843a6f88b4162ee4d8c3c938138ab846874ec142e63ecf90dd48653f3332aaa405014ecf0e694efea623b537846a73b2f74ac5e91c77139031093bcbc931dcdeefda3ca50b8ee7525e277698b342ba5fabea2be63fe97f5cdb52a2826741e3aa65d47df97526c103815a251d961e7540d8700520d4604f71378b3ebef92662eac7f98171f1bfca1d30819a5b5066ab6748d61a5532b36861de0fb7b5505dedade469bcd41e75f197d583ad6de0bc5bf109e0585b17c96bfdcef602eb335b946a06bd4fb7782b3ea064f091671ec958b1d22784b5439944d41435eec44c33190e28510bbfab33176d9aaedb53d65e1044062aa2aa6e127b45d431260657b816678f4c1c41aa45b21691fa34f5c75349f3381002fb685f8cce1ad870056750a72606f0416a648a9f181764448276ec203df086e3ce236998c7da2ef18746e384be5d542d137fb8ddc56106efa4c682fe2ebd854998d1805b3c38b898a6b7502edf4ad55da3ed5a6d3bace491365e37f250aa517eb6ba0469dba9a68001dada21fb9a120b39921fb9b5a56c5a5a74dd0fc3d216af8900f838ca92fa53b82dfe3aa9cff1133048cf388402c77c5bf6f2fde32d9fa86ddbdd4ce2b7a93b679af8c76106737f0769684bed31a236101f4d46efbe972ab32d32a32a53be22c58ea3d826c62a9d28ee9158e7ab0a12e93e098bbc497016a2aae7a7886f5e4e44912b851153aeb3bb3449a015875a583903e36069448f67e33de719e281b0d33e35265c50b4c5faccb2d61b0eb6e5d7014b4ccf8b5707d6fc8d1535ba0bf9e70e8fdfc08801cf0fba33d5a48dd7b4ff320b6cb775a8ea02a9933c1f53468ae64babdddc87c16bf51aacb813a9047ed8d931c5b50fdf7143c44a2be914c9f632dafa09083f0f2593c54081f6f638384429d21039c059bf4042b483cc5ec3bc0fe468f18893cbd3b99a1b9bd108de539b57b3f64842bc110c820f8b2ba5afb19035060d87427c85d12727087a27012629ad85743ccdc9b2421fe80feb35236e3e84ac4c3c10c26d1aca1e1134c664b6e8d27ce336c1a42a23909f604adba2db368d191bdf89a6fc4553ec7df1610904efe8707e58da91f6319df50c5df676b2b1b88e2c071a67790d8eb40efec73e004845932cebeeaf6c00fc694ad998e3345895a8900af23ed89512c946284a0a37aa861a6ba4d8e3a0502724239e0df69310c9a605485d0fbbdbeda6856a64b64182803e8fe23541c3ce2e6587c9fc5732f1967f6928addd1ad274d3eda91af3b422066dc7dce07e2e207ec1668d5c3faf65af7a9c17409d8753c98cbe49c13fe41b565164e1374dc04f03c564ce9d2327ad259ee3978cc14767f1337901a15d088c662f3682502da5fd9c7341b2c1df6ec3b10023fc0b4e150331807f5387585af902b72edb9148fc454544d251fece1f2ec9d0c5a68ab224a0202ad667278718ba3529d5c35704209e373cdd9e411b29f5b46218484fc86884f5a369fb2028ed899bb73e0e1f8f2392883b19d1ec5980b4fc819572221032c9147c7372e34b5b63a8638fd21a62015f0c3242f0cb65c92a5f13fe0c984a9893f1afef1658460cf182ec7f754c6901df93da6f78c0b91f34e5aaa2086a3d7f68c6bf3a3d9f2ba7a9952ca8b30a09ad50817456f95c999b53249b0a21a98ac06b97eb6568551dc2c5893a07324cb7ba5db05900379758d50c2e6259010427d2eca169a4f669039c36782608f3ea52ccf350fc0d3676ce55557103cb263f0145c17736dc50651d29a11d4a5d3c031c95f4de4ff45565744dc9b701aa5c28e8d3b06be7418398d64d03aae5156018170c36160f7e4262588425eaf0f6bd805ea866e9b551b7b6c85e84c362b66df0776f81e98be28ee012ef55204cad476e9f202ee41e5e632d4171059b27e585579347aff6c1a17f858fac4efe2e2c790a46908c9fb545a0df3fea0679cc2d8616d5cf4e5176ace1ad94df243bc89020c1942f8088099927e2891b232b5127a8aedaefc5af53ace3f91b2f5b1d0bc020793df7f0ef78d3b563e58b3a7db77f948a817724cd6422da68e0c7d8c63d54cce409916e0dcb3bc1fbae8bc8ed9014e129950283b2c346a861a523b730a75d12495b29c937f5b6ddb6bd885a87f37dd922a3ad969138e6f1c229dbffeb77bb1f06df163d551b27942dfd2c52d4e6c74c93ad68dd2d95b174aa460ad98dac39161f14b218425d9fc36b545030e389c5f18ee960d249d617455fec262e2f6e750c92c80e65322bece8e79aa2812a3a2559c969e3ef16cf018e3f2178b3aa42b1d21a0d7d90c9f967f7f2d31b552175d0a12808f47304bf1ce2144b47b2b69554dbfa1e973c40e11e4fb56f70c5858ccf7967500cd940cbe696cb49437d2cc6d36a58a7ea530ee12420569c466cc334a28f0bc9a31817c4fe20c52bb94161c3443e78f58436c79653266f5198100446d555d07d4fca72f6b4ea470b090c8b7c0dc176c86d4c532ba7ae1b043e96df709a3d34abbc03835a6cfbd329287307d6f048ef63abadc23657216766f4c889e831acd50683c7326cd23cabf07840a0dc17c81ef59fa3d0775406fa972b5fb2fcdc61011bb6eb7708ee0075438f95f122ef3dff7bbabb67bf749af2df9dccddab5cc98fd0060c1c7e198a3d68afd5ecdc03fb8c34f4a84cfd6cd8d31dbcb2be7af61f1b307458cdd72aef74f0645eda7745ca31d04059721ef8cc9772e1c08e2078228f60e38f095c6dcb4fb9583db348bc770b5bc24169b47c6c736317b94a77678dba499fbf600178e70d03d328feb5a14cb5e1d3d207b9e0aba95fa8f56df0f7589e77b502fc2e9782b34e2b97a656514022fd1683a81a4c86bb6ebe27779a8d807d7294ceeb2b6558350a6b3a428576cdf2eec1d5c9792ef39c5a7310819895ffd9590c1874b049642df1ab786b60e678c4c4c6d87252ccfdf887cdc8b8958c0734dab06541edf0557de155cf0d6b2d944d5d247f314c7a3e04950cd0bee4de04d80f4af697e62d2e3b6d512111de5286b3ceb3d2ae984244f9cc22d6a227346bfb53e63b7c419606ffe5c5317a1adb2cd9101da3bdce268991c97eaee0d274949a46250737a47d7a3d94e7ebf873671f3c65b75babaa7c8cc2036d68ab9d7f5a0c3e6761c438b946190d553c2650b51d59590a7e49467663c00bfe7f2452e94cf3d133796aaade80897476b6d0ec29f8f2f1f9723806c6f799fdcb31c3dd4a9e83e8cb7d20062d57eb4531874b0123dd585dfd8a44ffe53d3bb60e415a91b4736bd94f107373f1d84d5a801235ab4bab0c88e5f1e8a14c12d32ea033957ed8de6b635c6deaa8c32889a6902c74afcebca23a9b07a2af35770c2e91c2b749e710f9da4dac8cc3555679a9009edb47e0391beb348b72dbac3c55d2fbcde14016fcec7eab959747516f5c7075fd00e52e3e550cc3a008a3e0d43ae7db7ee94c1ecc8b0f9918e122f4f31c297321276f20fc9074ffc38dd1ac6efa2f5a7ef217b2d5fbcc33711275f06444d228ab0fa5427de9895d92096f46bae07161422784ae791a1090c410f531ffaa2a17ee02bb4783f17c09afdefe1ae2714696ca66871a752303f7c9149cc85bddcc78e0debe1a35473414c56e89159dc72291f4d2a2529492322d680cf82b8057a646af5e0b245f1ab91ce13f259996378f37ffa3a14427ad8acba6435f4b3e41b5e7c6215b40559028f0267edcee710960d3287c30dcee3d819097e1972ad0431e7c5060d3cd11c3994d40d145196fc8419dc39b019311062c52c8d576b33069db11157b97276f310321827326e1ac1ff72acdf404ff0dcb2d9876f410056678531b280fe5a76ece8e45c54ea2167b467f240c92b288f3ebc80667f911c0148a5e86e5117ad03c4459b52edc2e95a9b218db5b5bd0f04bc62206c621745b7cd87e09f90b846112319fdd3a2e02798627e926bf1056faadaa495c5a0a1bfe34db218abab471c9f8ecb32c8b7a07a11becc4d7509788534aacac99ff35f4a3631970e53589745a4813ec197db065ee43ea14a3983c1cfabf5c32ec40d1c59e7e71ede7e76fb165e409417d2fec452b219c8eb1e6731a4850cbb1483759dd12e8417ea1fa8a08da05cb0a5cb3d2cb318dbde11c05973bab202c694402dc12b208d21c9ca158cd31eb29e2213e1063b31754e07e1d04e9e7e9685508cf5a579cee6a4255bd34f902d63e351bd5e4a2544a29c7b62997bb4e626a89a3b554d301143244c90c93f8a34ab8c509488af6a37acc7cfb95a933ba4b9ef08b96a0e795e4642df1678fd5ac0109cfce2f3dde005636b10340981eeaca272a0c79e94d55791ec76959de02bb73e2a1edbb6771559956ae5ebc45c197d94ba8f4b5ebc69a1c02d4588443aca101c7e3c427059d2ad519f59102ae42fb8e817f0377aea78ce938e0068757329d09b69111a82288504f4de20a0c75985dcb0047dff1ea73d66e3e818cd69be5d0fa2bb79ae801aeb756ec667f4a130b27f721fb685467bf73afc8b94282aa107a34ee248905ad514db6d4056889fe00b2f12df9dca11f032199ef65b3faa48fd62d0f4b422b955eaf62454c9878a6ec0eb6f28ed34fa087f8ffa614d9dfe042f3ad7621a33706c4a9563676421ed8b62bf54718a22a2d528650b482f1fa9fa383accdcc8b5d76c95ea407768aa6991ef10fdb445cd29c42c084775b72622fccdfb035c1dae8a9a33b9c74ca5ebe348fddff9dbf82a004dd9df97c912dc9bd69c2cd9949222c20c2d06fcbc4207e2a3996385a9101b78f6377d1d1cbb3d15255c1f66899379b18d1fca4de5bdab53cde1ca942c724e22ee5329d68162d5b742e643f310d21ef703505153e597ca2dfcfd888954ed3a0a50107507a0fd85fb5582d1ea4eac56b52d49b82e050eea50411df21cd66d580e1aacd4530d55f6b40d621fbfabf09456919dd0289547d8e3183d7f723daf72c4db26d8891bfc6b7ef79b222242e360f2175a41b850d8ab42c3fafb2666d4bd147fc98481894e20714af7d5c6652882b987b3005e42f2177ff2967dae6944fd2c84ecdfe1d324c96613336afe951c0a9baf56c8b15f5e6bd1d07e4a02a68cdd4c17cad10c8b78ffd07ae0758c37839080fd0bb280882cd3f451c168809ce6a9e89c626ec2941ee57111243408a041bed08b8c1fe0421a7372d97e6db6bb3f8c3d284eff44263d1b3cc1636924537fb60e82313d5840169059ac5da1c205f495bdfcec138ec7b44e2e3807c82f6af86a9f12580431f84c07c1cf459a8333b58921885ec59e343fda100672c24f98de8ff3f8e267aad255fa51a6f1ca5d2df55fdb4dd893cafb7b79f21893d2d5923dace17ee412bb2abdecfb3daa0d52fccc5efd274e8b2437c60f7f609477d3a6a2ecddae066d0486411069080befa1e5feb1284d0bbe0c39ed031da90566c97d64a8eab90c5e3795657bfa78891f4f22045abd567e73a010680d7d9ab3a92211fa1658d6706b2303252da69f3d4aec3521d73a67f40006c7e75ea47ff5c7aa67782b4ebb4652b6375370acf2c2ae2b9eadc3cef8eb0d8658338682c12cc3cbadd2e6e0b2ca26f01808197e15cf99fdf5fee0f65f0f875f324adb1b31339d451f4948483ca6cc38d3facec561cf4e37045c8088622822848defb905ee145a4d453f5b87492c5e8448466690e1b1ea481683ddba1d492b394e0341e72e775955cb0fc2e9ef587d71b9f252d5cfb4cf6e50d6c4f7a8db247cafb4f3d5a5f2b0a420225a189e937d606c7b239547164364932b55b1703d336951bbce26990cf1c927a994b9d1cb13d977cba9705eb36c50b2c5d8f8b6ed4cc27b0e9f916b5ea8efbeaf3dd2adcd14f5869fc093bdf914a223a8b1feaab5d505c53394efe4ce64dcdc74f07f4748374ac2bdb9f2d86e030269e4122e58447b6f334d0999e8c917297f1d02fc35d8b384f8baf6e7694bf42e6473d9753028a34e0407ca59ae3fe14763ef1ac4f0949ee0b5a1ee5997f71d6f4350cfcd1522c8336bed2a5eb30d6877185a896a9fc3510de763838a818dcb2bd38b0d0810aa4e892acf78b60cec57b489616de5aba7844f30b3cd2d2a19230fef9aedf6f57a1ee090afd8f1b8569ebea0e27eb1336753621eee7c461cacc1fe3bb48fbe9e06a08dfeec3288ed238ba5fdf083efc9cf1db13b7b588912bc1b60ebb843652571582d47e191aabf802436c7c70723738da6bc0e29f43353f269a17217239329db71e6fe27ca59db2962a9b7c5b880f58c5bf15e1034177708ee62644d37420042fd97d76c3d0500e86c3a7fdf8909222b289574cdb32f6c2fd347b3102a6206eee828e95cdcceba82a4ee2cdcb701f105425e400cf42aa9f1941d8c8d790316efe7e96432b06396a7b78e9ecfb2daee36e1344e330108f4c11c216e957f60fa8141c768b61e43abb0958f8e97aae8fb52eea2e6aa1da1d52409866b0dfc076eeaf2c26bfb1bb4e9bea35577e3cbd12dda78f6c91c5e1460853a46967f3572555010c5b5c175d3c9dcff552493fac10e057c88276d627a835b3d87757aeca610eb2150c746d5d80984723719ad8c5d1106853472e411e75c926f926cf1bc9929c08c3fb7b25caca2c667c4bbb1559388820a82d4945cc9a28996530b13e3d3df8e8d456037fc8878e3f0ae8b3d7cceccc6e3151d53f0f602eaa10af8cd80adbf83ddff4455af3e1c6c1b6d443de383eee7ba5ca0eed56fcf74b4d8b940d944409bcc1d1b4e1033791bc7f8aa6733312c00da89cfbb6ece656676bbffb9fc5c60a33e8fdfbfb295f8a154ba21ee054fe30814176dc9a7e30baf848e633ee6a0394cfbd78b467bb3484b07b56e17840ac6c5ae0007c6db58b75d418c2bfde976a72ba5ead63689bf913aa95b7e79339949dc2f5cae05cbdda84e268579734d89e8cb3359f0d74e4c784d63e4ca26da4822b472b55f1f6d5ea251ce571b008e247d4902f482f904479a10f70a368c7ec00061fee30382195a0d01d159db60f16ab0dc9360425a170900e1e56a1b269ec8e7a435786ccbf24b1cd1a282068298712a9ff48e27121b2590d266290140efc090d579aa81cf05880277e307782cfe27ddf587496bec6f22d57c72332b5eee2646f6a934f58886db28111f34e0675fb2118186652fc97691224883370e9e17d7a512159c46969404a5e056c5a718cb73443310d5d5f2a5103eddf113cbe1899922d1c9236a9505997317ffe77f7e61c75ade65e92ca097dff36dbbc516f8389c5e59b9a6f9b1bca2bbb679401d61b1c60ab87329413490280aac700ceed43d57a556e0073bfeb83504582d9bac89efdb13c5271c5a2dbad0607e39202194a1823a7e457581bfdb0f1abe3c7c474bfe1511a09d1e7e24d3ca859db05262adedc9dfe51813c2ea11ace4749ecafbb309942f81fb86defbf52bd7fbc12705fb8d6ae09d22623ceb655db1f22c22ce11582ebaf439918c88a04889339b3f3901f1f7683d62d213cdf6e65adeaf8fbf72007e9263ad335eb3b6b1823886c346d2c5ff24c3a2554aa9e3a42db77d684cc510b66eb416de8a200363add24e1eb84544a44f3330992ba1599da91f849a5973def74bce8d5cf2ac9ffbc0bceb2d6013f5c538fa299995d3d5dd3f3f0e53457e52e1f34b5baa27fba84d7a3ad83aedc4b7774a318ea152fc5fbafefd21c26df42036c5da18e681c619b96fdc9b73a1a257f4dfccc51a92d26de5b916f5215f3d5507b3f0815891b9e00367233e3c1fe943e900dfe1fb9e1cf371f1f4034e66e3e9dc83534ca2ce24be17d700e52256272822fd3f1bacd57d9105457e1be2cb21aae0eb65f5418312f8be1beddab4ce9789aa8b7f4f423eae143fb99217e25a0fe8a95e809b974bf5142fe19b690fa137aa55b394983d7f197153bd4c728cbff631b96bf336296a5cc284ef05daa3f7e14fb0f6a1f260960fd5032aac7c3f42214a347011bc04b39dd69cbc82288b1c8022f88e418f692dd0173d29c6f4491c15c8475fd6ebae393831de86d81caf5696432ead5ae1d50cfd54ec485b8ffc41c77b75308b73957dee4669a1abd370167e0f844a9d58fd73d2b9bde1334f9bd2abfc84833b49137db153eb86905aa2850513757574a6f658b1d053efd07a9f0003a734a51f02e60fb67149a51573fc8603e30b1d5ad4bbadacbbb3e7aa57f9c6f1fbf7790a924f6c789c7a07422bfa037dbd6922d05f17f77e9ccb88f2d4b12faf7888b71a78f982558e8e32bc53c402ea32afb84b12af1df586fc7d0d2279f4695cf01307cf595d5b9fad75d4e35aa2d4bf6958d104d8f1ff54455d79a1bcf9e970e14fa4369fc0eac9efda8bb0f96c3957c5e9c4698f794020b8697024768c10d9d5063fe68196a94d100d953601c40610d6e92cd4fd919f598bebef72c8f1d66094e423d99b21f07f1a6017ed3b09b444c796708b7272b4e83acd1fcd08f0c9c36917da641435f0d61744d60be92d5d292c00355a2d3f350050e6a12973893b15dff5c41703bcbd1b8dd4c92578b53a05607ad978ccc2c8a575e9c3489b1d2f3039692eebdc78ef80d2c697efd5e2f0263c8ea5355557c29cb0bde28c786771be6be46b6f3571f3722f56a18970448c2e7377015c15d6412715a09c9cb05e7030e127af9e7441875bbb992542862570bfbf4f32cfa7f5fa3ba4afeb24be5bc9710e99db347d059372fe37b12aec5b6287ffbe3e666b8433a47827b092e9dd4f78a9af18b8cb4f4343b2cc9a47df2843f0eec3f17a0498864c578ff08abf486f4fffc4522d00698146592a2ecbc915d7f1436207bb2d630de7d8bdfa53ebb1defc501e29af1ac6b73b7b6e502673e816731e4b8d0537f7a5fa918eb7e330e9dd625285580eb6b23f1e573f368dff441309f7435cfd79b3dc12278aa3785c362e4fb97474da5c6523aa4c6d5e618685b1868365455d58c998f85e40e5f168a8c1b102f030ef7cf1a4ce5b1f68a9536434d2b067ab3288103ed10b5bd7ea46452811f3e6967058df8b190d097cc92129d4ced55813d648a37e0ce89375c308a1b01a63b810c90e27a59057332d2ac261b5e0fc9ced3cdb76d7b8e80664193bb1202e176758c6c4febe3b88152f0502440c42d7c4885cf5e0b561d074540cc9fb406729639b817f41fb5df427020083020c3d3989170dea228561075ed80ed84698c107316fc50355a81d2cbae3b1045c5241d7ac9d27f9b112635a75285af51cd188212d77176162a2d77aff8b780b945c657ac1f96811568bcdea36215e05ca96e464e8ce9780b0b08f1871324cf5d9c9e995153ed2f9996578e7a967ebd8b93477ff934426df218fd0d1637cb4c7fc4f74c1941042878d3611723bde15446b62f1103272cf1f7857cd2c8dee5653f4a7c2c4bf781ad24b632bd8bd1f5c42f4964cc58485f3b060900137e8bd22c90c231e30080e04bc256b875bfe5eb16911e639d6ae384900721b81367255abbb9127f7d969cf957fbeb30c2a09419ddd71a754b305a4d6bd9e7d1de1104711f6dd3e6ae18ac17a5259abd4f2d54f5711ff875f306036b501b30202d47f4d13a1b689c702fbe710d65b4a09c828a7671229f9dfaae9d2b01398066b4253cc8d4242a01617bb709eab9e69dbb20f21acde00dd3b5401a0e4551e6960e3e9aebc6ed3d7dc3ad508d38e0a0547884556425129b52efb0de458225db177a9f8ecdbf18ab9ed2b92f003c83ae563b1029caac4bc4bfd674f3c591838e1f76fd09d45211b39d559aac3a48e5a60b88e6c3c7539c04b4a09e8c1bf8b69b955f8ad3140f0f4fefee560703b43dc282b6439e68b0f792ee4ef8e04e87658df7e18b8a43de9745674ef088dab9c4c5a0dbee4e401c98e919ffd99dcb1c8d379883ac115ed92f794c681f35c6aaaa9afbc5eef84675c059f262cf5294c50608b3243a25d2f40058ab7dca04fb10806579d233488116a90c2c2a1071b5a3afdc3bf793b62f1e69998eef3f3b892aba8dad3d712bdd36cd7fbe93ff0c2b704bf81ebe7c845dc89acb6e5f1a7f0766389fb009c162827979ddf9ee346f9287f1dcc1f1facef31e2e68934f937d40490d321f4c79be100f0d6de36a880d04c08e61a15aa3a311d1f2d30d0f7e67fc11070d3031f6369e6a48ffec636d72295332525c2de798032cc74d572c1f1adddf4cc76739310ea1a1b87fadda78510cc26a916c1126efba5d60e64ba0a8fa10605d0c744becb88cd1e297d929c01c70460968a924ec596cf2881e0722ba93b3634d934251707750f8a49474deef4945151b705669104fc8a75328eb871d21ca6bd439385286f95ae94b3f665f53d70b0215dc4f584c43a7ee09d701253844c3611824eab361d360064a73d468e01e744d7b5cec05f5946ebcaaf3b8263d2b3257966b82c70b98ca7bfd8bd7ebac0e13407a4aa00fb31d4bbedf8a0ec54a098ec7ff740e33b2b0d892a8c14dfd7051301ce7fdd5cc2e4e5c1d0aa542c6540ea2cc299f0bd99c8320b9351970f083faed1f34d6bacb7ed25c5fa373b346cc31314f395b97fa54d6253ecc0f0126725422a46cd48afce80801b35a864c36d54ae149e7d666b5b1937128c819527f4fc1a5aa6ba28f6ac740b0762aec62a9208d7f0216f39a9867ca353aa30cb7ef1471409bdf2c85f3779e052852085d17ace9e3b8d387632df31970620bb5d750cb4c723250c73033ffb18c629356fc676a9c692c19afdc5a41501fac3290d405addffc98b74463d6acba38d0fed74dd2f9e501483458325a326c698b85becb493aac8211a2f079432a226c2f4208f00c123093cd034ca93174297424a113e5a66d668b2a898c72d7b88d40f1eb2191d8efa243fc15784f2981901b02c4c1526506e3a7a2fecc3420c94ccdf250f8c44192d969df38ca1894984aca0a17e7689a2fbeca9fbe9f08c5c5ebccc26685eb91367b514cf586bb0ae94196ae0da7460305c12914cea5494ce6209f3e8987ed23e836acbc53aee6114395d97288e21c35f6c34dbd865b041fb65a580f8c3b40ebbf1f758cd3b2d45fd4eb409d9c309de426224c85fa999bed728146d83d29968670c664edb0bfb05a1ca92a8bf96537b2123796f5f9f6a622433e70a0c4f60d78aeeb3e3368b5e5a8e8e7df11137d12d833b62e1997f679b70d71629de6fde715fa0b1fdcdca22dc5c5ac19128a4bef31050b1a04604e08f8637e511805908a8faf100ffb4cda3d1588ea8c574a4dd300d3b7387bfb70e5f242cd8a615aade0d21363ef11d63ae6295993c2ac24bab27e32e6f104ad270ad7d0f67617fc6dbb4809df5b34f7d36aee7685593de3a6b35d049d67b3f8b0e6c77a5d0fc0ebbd73af0356c8cd31c6a4bb45e3c48610606038a477f0c29a8cbf5ea4b766b4248a99f9aaf856d517b9b7335d80afc6074c0bee403ecdb14a36ade7d4f7cf77ef7524cedf786fa8e696243f5e2bbad8f44fabfa8c9c6d850e5bce4cfa52fd0b4a56090de89fb11d768cb3b877da77f161e45bea4ba0b26967e54d1b5d5a221491bbc04fe84604411e85babe26bfb7d9907bf6531132542d3b10c666e7e007c850351a5337a11f1d4e91f1994e93ea9e6f5913841d7ffb54d3d9d504ac700e16c99014c25524c4dbbbacfe1686a334c80ae24badcf678916222eb0cff20c67c8c67727b8a221e4a5e33122271097d113c2a4c8becf50c4a9b78d7b34380add09e926c672c38947b12eeff0e031e2a6cf4f11a4bfbf4a25f484ad1c7993906200cc6af7916dad908a926d2d8b675d22e224aa4225d06556cdcc01db9a8527a7f96d0aa7829162a862dfc20d5ffb07545b05105392c0fd51aa9c0a30d2882fbca26ccf3c689cca6f0459974fea33a82a39605a997db8952353475c8824bcd2614c284371fe433c702929c74f89bb8ded171ad5cac0b3cbca4cf9332e01a75e11e10c66119a038bd08516c913e6bd06dc5e29726212d47f1ca0957829b738b0ef6027c5f3df8f2d8ccfcfc71e4571129b493a47dc825a12d539704af2d6c8e0d9de48f1b13b817193b41f18f5676a89ed79846230d86ddaba06137844c9e241d8b62bf03993f4a1d04d72b64f6fcc8d240c1689f397410e278f3926d3fa90fff06e6f0174c3eccb3644064d9ad8b21eb405e95eea6840c026f574883e56aa2f0be68cffb9f2f99dd614d8b66ccb6a5b3c3a8e88a9d01d91e965fd2cf85a7932b25db94a0f7dd287f2f389e4ff58639a0a19698ab878554cc48fd486c306f1cfd0a93be44faa8b7dce1feaea4a598b0062a9fe852cccd05c6542f078c1b0b7f399e6d53a67e2b887a0c548ce0b2f0fcea8d855e9b50758f15c6d0be62a6feac51c1cf065ff6392ebc9a67501a638603af3fb74f8b69395dd5ac6f26f868c03c646fdca9e975c7c20675b5655e8737de0ee485039d34d8642f12d5c9952eaa769800e9e17e93c12079693b320f2c962a3a4ffbe5413b98cdb1677802c99a887ac640289cecd2af154661fe8e04860166f21266b5d416c20ffdb63dded57f31c2025ae7f192355d0aae87d1742bae10203d79de833572e0c159d7ad443c8b140a7d1a7fafd7f979b011e45ca127f29803f8cc4ee83f4cfefca3e59f281bb92c48437994b8fb12fb8de9b01cd9f36ee21fc884feaac3cf509346957e0dd370feaafef07cf691f853e9083c70239ccb73895ec07c4f933f8164efc86ae76f14f67b276c7ed87fba8f03600ecb9e8811dd87ccce33702c9336a2f2a10503f571d5c87cee7c393a032b1dbe04e451b39d0695452b628908e3063a7e9a711f264a6fd4f64b93328851501c923d103fce995360ab6d7ff1d2eb5ab0fc5a31d4f13a8ca0b55d0474a3fc312b905977ca5514aa7f9cf37383cdc2da43c8fbd3efe918ea7ac3d3f16a2ebd3f5bbe10b445226fadb35b538bc886dcaafe38d0f30b212050bf3d974fc9b22adda7445258995ef16395879729e102440b3c0377df0c50bd6e03cc2e782b17503698fe575db8aac73901b6ec995246af649e4b6cb0bfab61007d2eb046aa7f27ac0f5e8d4e7091ef3fd41516aa997e7c480c90623c611564cf801bca414985b627219129d3a3cc3e276d777b6709c231bf41f41a0e50eb7d4973f61562bff0d5f8d881e96387439104063229e5747811e751375cc7701c9a0ca80a027197521851fa97184717ff2e97c41fe9d14472a7812ea80ab3cc156bd210c387f10994ca1721d196d44bfebc951e70e6d758ce17fe21ace04b82d3eb5ddf067b55da152a4617720ce590d4b69330d9ecb3fee8b1e5ffc2ff1ce824b9d546bc1ec91a4b0b9bd2495a1aecfe2b945673eea03d6bc2ee9f1af6559f260e1f9b938a3d95e1d9250e78054bbc8ee6c7948b1ee1407f0923fd1e5d637e5d1bb7c8abaeb8a885a2b2b7a868609eb24698981b5ae83c97e2682f6e8ded7a81a339c82dd303bd7a1a71a17041bd9140c62b66e28dcf29b969a5326a9e9ce0c325f0a266a00de71ee82017a83990200144583e69bdb7ec56692db5d65654d097428c232abf8ffa5175394a089aa7b55b65a5140875c77cbb59f5a62ef2930ddf9eb2ec21e2eb47efafc62b6e7ad73f1aa9e15158525603b865ef1bf2df43252b7e1fa008ba9f16e898912753e1dca4d559352f4a313b00dd70e9c31d8e606c4c53c61d8387621af4f17ded57919b2b37e83da354b53c74a906511c3455a167da3d4e8827d5000b0800ba339aa4bd7414e394b9f78c669518b386e656bd8e9f6cc01d94189fb72e86907de89d348dd61c9d99ff12bef200453e75e635df1784603f9f1f2f549ce4d5ebd08b9d402d58a83ec2271792f1d0636686af954cd91ff63b541a91cad6186c215300b984836adfedac9e6d5548318d2d1b668bd06e11e46ebb0e76f1facfc8d7b2f7e71f173e74fa7f307b5d315f38539ca2070386596a33e7ba46b3785a434c4094824bb08c97dd8ee3d96daeafd35758acbf6d18f0325599ee1be8d9cecb60714761924271062a6903f8ed507479bb5480451c61fd54edf79c7bff1199dd9ec2d4cdc8187eae816f11d959fa74a91a127a7370fb31d7cafcf33a61ab0479176f4fdd27781375ed5fe949e3b4118ce7f3c03d8a8027df6a25d81305914f80f1bb5cf430ee927544e4ab0cc1d40b9d12aeaa31f28b2fe9016c95b65ea1edb37970b91d430efc1c7395dc7e38acbf7e595b4377c8175c64ff898671d1d632eb610a1362edbc74e4109872c7361a37d8ccba3cd61869eab7156f32a1d8b253d3aea48f4ea802068154e9c9fdb62140affd9a99491953580dbb9428f47f8d1ab6c04c8d91e7b81c439fc0c266ff707d2a251149fe248a5f17f8cd01729b51405975de654b8e38b7ede2f7a8385d559e94cac08de4c21c87ae02a82973db7425cfb759ce32583f06e1cb5694e1d6f56c805b3ffb33e58e324a7d43dd9fa8e00cf24266972994a3e176698c8b1ddf031cb3da74f739299b946be6d5d6933acbdce7540839f2bcad42dd4fc7f180fd18b35bb6e739ae5ef47636ac6f4c7a817c547536fd5640a817a8a8ad8a965795a8109afa707387b29d2c61d9392d31414ba97913e0fac7a0a473ff9f4147e4a3c54319c2eb32e0b8eeb5f837994aeea738354d13722594c94b008c215601de7d8611a95bba6c858f9f6a00ec571a3e56e38ec9c9069d2741ea42d3215873e95b031d8c45eb3f3294ca2595ecef595807133022613bfbc8521993a74fa8d8fb9497f1166e6049bd3d607b1b50aee0906eb733084ad1a783e466a03440adb310087ac3bc3c81c806a5c9782642e603df74e0c0faf9657ec2313354a8ea8f0b2815879db3965cb69c17ad97dea2d762609c510f10bdf100e61006cad7fae9142212bca110eebb6246b960e20050476f7f6c7b8cc65adca650b7b912877aa0856ee4290e0f296bbbd5ba9bda82f82b9d75233e3e2767e573fa19f11e43a3063e9536a5fd47cde56567d764a5ad5066fe16d60f2fac6693a0b67d238607c2a1dcab285d2f8b0655e455518c7bf414bce8c87a1ebfecbd1256cdc2c9e4b87ad42b3b1454fae3013de50c19a2877d4fbd3999dac65de87f5052871fcf72f4f17145ff0417170de63bff9e86bcdaa7f28b2ce84471fc1cc6e7fea9eac3fe58d98a54d9640621b990df616bd7e71c500ec1b3ea9b75d27e1d5df68d4ba608644516084aba20ab161a74d717667ee5f5da71a683d8989beb993411b6804b9961011404690d2d2c17eb2c72dff811aaec67bcf23a8086bcd64c118449a885a2469e4b6bebe73f5ad77a910a72ac35d8ef9101c602abf7f78ea33c3bf80729420eb88a74c1e7fec0c983cc4a2d4d6b02447876223f7780eb073d5c7788ea61893669401c509d4bf055d4b0bf2ac143338e05d0ffd05a1ae6160ea2117a65f161a56434814ca5d26b2977120a717e8298de89fc738b5021236437fcf3fa696fbe5eb204fd700d77d695579546688ce031b0fd14da4a50e693394ed823065856110211614e27d0bdfad41fd3d8cc1429e182e0bcfdefdff036fbdc6669b82c5135abf84a5a371944b65da7ff83e97c2246a5205fda0408d5448800970a22a183eabccf28d7348269a4eb4a5d961e89bb811435d351158bbfac7bb9ac2d59cb4a49b3f8915b62f1680464024844f996b4b3aa4c64b54c5249bc86e0a9e9b5083c34dfeeca88ebb27e8884e9fa921ebd47f4a7d90b3270765bafa6c0deee2eb6446f2cd6647100fe1586a6716fe23e995c916d8a513f6afc338d57f257ce951e558f8ffba9450d7a475f631eed7bbcea32dc5fedf78953e77f4c33ebb2d1e7144fbbafaac483cc322437cd65dfd59180b9ca7bec30dd16752376c03f3af65c297bc795d734438ae1ebd089235283f8a78a6b08784208adf1b289fe843e2151e0fde559e656f598c4014a7eab2c88173008e5cd780c8497b71887972224b83fabe0b0b63576667a254d85e3a015926817ed86e5828b07dc40ab8f70914c81d4a46d7f19d1d92b58484866dae38adc3c8a6c2d002eaab0e8011c9742bc09235a73de5f678105151d1baadd249ab48a645c23d79c4beb644f6c2de9eb354d4e11d50074973e8bcb9ed196d2adfc3cb63fa2689c287345a2b5e39462a2078ffd02388f107290e9c155efbdfec25149e19a2418b27581bccf5a469154d827214e0ad55385446edb369938caea0cb40c7328a54bcff64569c3e7d2cc29551d9bfd3e3e1111f7adb925b186dbebae317949787e501a495b30849550980aed7dddd8feb2547ced6de453a571148cb1999ad1351d7c29a886afc641d16fed3a33eb51e9ee45eef61304a87a9eae8eb2ac5428fd4c80f36c97f4786a1dc36b8f8900e9b85988ace4808ec10f827f4e04d891c41f2744c8c5da995bd4ebeb941ac5cdba1f11f104be1ffc8cf00299107f459e296cb1010991cc98029bee682f40b7fc7ae00dd0cdbf539aeb6fc99a19ea7ee26b2adf4469da5d3260e602aedc8b5eab8f2d48d0d6679da89ca899a24170971500bf709bb3134028051e5d97b1f07d590c0d8ab71259818d9396beda0c1935d1809707569ddfc13c008cef41b546a4404f8c73ea9b3b01542bb0dbaf0038e92ad9eff054aa6a73cd8c9f7056b454977101e58161ac7325f2b05d568cc3fb0e32fa09c5fedbb4759dba33dd9d74b87d7bc64d615888c3c1077036d8e34245f0b25221c4308bf32879292eb51bb19f1a04bb7d63bcad49d46c8d73e69a923f3c328b6bbe8e64d4eaad0c492189ca6fbb6c27b6e37637eb2b4c395d54f99f5572648fa813ac89192a9cb763447eec944f79a69173b9ebdd99008edcbc36093eef4589cf93874ef335448677426a74c2126efb1e93575d410e58c7c46b066774858023000004c0fbe395dee24a2dbb0bd914e6d41d86736f32fed05fcb0ee40e0c68ee940269183bebcb361acc387c823c28662c1419daf95f245a408d02c192851bb10869de01832ac28cbe77502913b5167337be59955bd538bae688c6d98dc0976fd21a955ac4c099561d558509eea27bf9cb8872163d277c96651018352b5d90fca21ff677a49bb5f0873ec82c0265f7755bc824c8ba0cdfb0b605c7c91206177bcb0b55882fa0323aa7dca1c5598f3526735d5c349d85af8c9398fcfa8356e21874948de4b2c22f47091c83b361c4cfd38c123a05315a5659b59c2e9624b49aaa586b7c7dcd441d9f8423aef9acb07489c57433c72041a8904e564a50c38563c908642a75a0b6670797c8185c030679051d48751ea9e7a37cd3ace354141926a48722778014309e02a5c3f072b4bc5ca2135a684a9933442494b6ae5c12b7d1500c51457c8c4c3fa685c13887120976011959395c33361cc0628081905599b979b26e8fba9e1106ae25a10e23078aefa7395af10405557d7eb770047cc5ea9132a10154e7a223bc809b2891c8657063a32345283021e6da32ba656c155665e46a2816191a6690ba9e083a9668b69f5b2e75c67190a0335b0b48720090dc0973f2015182e35f754645c5f11a1ee5a0bfcbab8ea75077dbbbee2274cb9882463554d1d39af8753b577165a8432280335e331539002b95353607ab58679a715111cc4b4e738f9222b82fd0a133a9219b3829bb134cb0713a4a8637cc2a1a2463968f290b45437a04709260414e89b19254e48020c660774a601d50a3526963a437c16911ac3650c4ee10917d26b0e017cdd39ac4508bb6997a8649bb8fbb0cc8b50924c87750c6b2019595588b20c08d1c5bcbb99840965e2bca7434e91ccfb93a502607d9b783e31bad294b2148dc240f422f6b1879b4390e33b26d4c72b351414da3d93b01e4cb3d2c0f82fb58b8c27d1671735c820a31e176e2465f9bfa92d1d08dbfb94c8c2332855a03a826083ca615add83deab0bac1e4af9acbb6cd307654063a09f349f56abc0a5c5b3994973700421aea226eec530b591564e114f6707d7d2acaf7c85ba3bcc71b765b31a68b8a1c26c494c98a782580271cd69caa153acdbc052c0d72c5b79806d50bb955467dfff7153c44499e366862ab3a808589b4e8ba7aa3b031b67a4cb1c68dd452b573bc7f64449c6cc688a88aa2a16989336717914698c48171ba610898a7887b08cd353a193014cac1b2d999154198705268b578430bc0c1966a8a283ba8a5a06c45a7bb3d3f0a7271944ab96915d0448f2df78d43b6c8b5c68c360b2e9aa78b29f43de1c03a460bad530a4d746acc24d3bd10a550db01817e8465731b7d93a0cd8eb5bdb3822de51b2c103c0e5776a7908455f159b96e550dc8eb83346b1ed0860e80f14345207b16513d2258287df94ca335b751902104337610502f163a9fbd566418e01ea033339f41191bd3431f62b9440ac4c76488e8b1b4fce79451206553744983eccde6c83681994d63c9ce7553bd0ff909ba39ab9e9b18a667b1215b5510ba75b70c7bfeabc25359102a7c623b9a296c4c0874565ef4f440d99b09240b424540cdf3a55fe9a63aee6b91ab821cf983971031b234ec4bf9c5c87127962ac47cd1a23eb242785144ba3c6698bb0743fde7b27499eb0e630dca992f69825d210bf148e98067ee68f4b53e75028dacb2295818006336db2b7de6fc5658bc1f4edfbc68e54d905eac272b8759a192c956133a789bb1666164a9c829b8c28eee4c1ca86c4a8a6c3d8221b3edacb11a18fcbbc29df02ece86bcad1de7d4161daf1e0597bbfd208049c6b91d1ae4f2b4075fb0d208f1c2ff0000430b0618210c0000002c058267748580029b0c22a106d54e0307021169f7b88beb2b76e3aad0e114be1a8f982d74dba9ca51d03537f400000000519910200456ed30d46f85e8b4b79e09c3312a081c34186d74b971d18d16b04114362b26dd4042f89bf7fccbf2075bf5c4fa61c357afcd110e01bbc344c327a78e1b77d88b171c6e43531f7ac5419d5368a19a02c419f29935f2ef8ab53ab75a480b43e3f53a1f03d338ca291fa86ed4d67465a3bd7998e250f6cccc97582f24ec425fd8555b2a8c32ae92072d5923ecf00b18052e8b299eeab6023696334f32b2a31bb6697168aada57b9023c780804eadeb3b2c9603ef606969e48ae707c2c258827f5d599886002feb55e0f22457348fd30381a818c4aec72f06392e20088d227579c810c086080d97fb2ba963c102716fd7b25105398640649b32b133946144d39fe26ba70d05139f6da7da67f5e723d5838c53634d5c4c39682c63dca0654b4f89c7900da22181593cab8f3a6b148b99463abe05303756b84fa6420c874c8ba80a16f81cab48d2d1bf174d967a49dad9cb0862d002ff3183948f1af6e0839f1ca8434abf1c99c68b50a6214e4d4fbc225f87344caceba0319978bbbb2bb4506abd633b296015203a99ccfb085cdc25a6e7e97d392ef578756c57743c90a9f8dd191908d3498cd61e9b8b796403f0c37d5a39141002b16c4b46cd04a991ac59f030bebcb719a1e0fc6bcaf91a4dc6b414fbe09d3012b7806eb3080412045342926cf8559f7897d7a1940f0a6bf204763026cc031e65c564d421ba3af739f0dbeb54cb74800cc1ac9bd0c865d420ddace5b40d97156bfc1a5fd0df067166374a7f856e97df1be43d4415b8667b321c3f9675c5442a68f5aa5c65496128f61a58c23928ff4ab72a71eb5124a093edfec2082e49e3a5b0f343859643fc468067218c92fbdf2e693669fb0f63dcdd8b7fa345167bc55014a37f6f36f449cdcc4e313ebb28da2f2f92a2771fbdb3cec586335ea1e78356cea0f40607d705ab2d769819dcfa27ea18e619b281e3a9313badd6ce8fd37e6785cd98330f6e817e63c5f931c4fbe627d9ca41391991029b85e3ec7f8b60a71e0e73719e951b5aa3db4806776bc8030031c589d19cdfbad44946e7434d338034323b8feed908ed04cc2ef308bba978f34e1462ab1b79cf8d5e6e8a73dec0b56e123a719dfd5d07b94bd105bf04803d7e2aec725445ac2355543b56af299938e0207ec06a311abb43a8bc558692c8abed609bbad2a12d8ee262678272a1503d9b09f0a4646448a19b5aef4d4d7f04587f7bde894ec2282873de9c0183fd1bb30bffeeecc4a8dafecd674a455061950d4eb18c1229668a6cab4a8a1c660ddd6693bff6785bf4a7c62bf40dc05eea4f02e58f9bdd78873e0cda67e9edf9c341e93139020e63081a2e4fe338fd9bef05be57342846f05fadbb02eee59aa75eb88e1cf0328096c18f507c4a26727f047806ff0c1eb070e3e942ca5f643103644a23ad87103e83893328866deee40ec69e7d645552e4566dde3d5e7b06eb31094ec018903021e1f78efb2e3fc5c8757b98270b41fadca3607dc2af196e1253a691e3e16f5aa8d9febe31eb982ca6a0841870503f1f79838f241701c4ce95847ece532391d5bf1965452ff92282f5a8aec4a80c303f2274103e2d85c229f9c9ee2fbedd2138f4cb3f31c27716f323e2298c88ba0f46aaccfc2c5dd54d404060a055033afdcff2e975a474d4547c4b740dec1c22d52ce328dc0759722d8ae1e1cc2ead5b396be8c04b000ba7ec4883575692ae3531ec5c8f67dd498e1d6546a92f3ed241838d7a0c52c6080efac02875a8d8c5ab605c4c3c7025f7baf20615fa6401be8587bfd78e2f80f5a95d5636a75eb345f53e9c0742ece91683bdd32c2186dddf293d65a2acff1e2af1321cffa735f1cac31b39da9011a0be5e32b6600e1c26572437c8b6a5171e8b7379fc397a6027f9709e8b0b5a014f4df646453883509a5f40e930c6fe7e48db810ef0feddb62695726e9a7ec53d94fc718f251dbaa5cc98635c57ead4fb9207f4bd702ee00f2b78b13d9d650c9608dc90f2050baeb353dc9d5744e24c3a431ee6f99ff52fec898251665bf34a454abefa5af99c185b741bec7e034566588a5185d795c9a8039c1e5ba1bda17e6001e5f5e5980ba1b52106ed21f0dfee1ed7676450357a0a48d6d5b7d452413ea8430e585e2389b343cf28172bbf9c28ea63b992bd658d1633ffa84bb19738dbc82a3ea4904343c547dd1a9a037ab4fe61f0c2e5f1504ff977fe928fa85de891877e7302c95e131229fa24599a1777b501a5204897dffd9d77cb3d19f7212dd3c5d162ea32459a7afe94658f4b7d67aacfdce86e78adcf1e6742831faff1a6b1f29656b33124b364d37678025d4b2719af7e400cd26d85ce271f6642571a5beb001fe02a6b1bdbacc85f9ad87ea120f4ed36506de9a34306219175daf817cdc4a4a0b06f0db4280786f0510253acc54cd0cef3bb245bbfd2f54a417dc18f863eadf7b4c4592f0a9116122cb7636fb5266eaabb6b1342b504d371368f5f0ca6d572477fbf59947a624a70f032be0b591d9c1b6473476f66096730ddeb87526c17cd7c43a9745c1d4277b23549bfcb606c4ede1d4d5fc920252bf4ee17ad6bf35e08b2ac44d21705c533d120023c8536e78bc9f380352241333c69b5bdbbfdc930a8b2581f5567ba1151424092a1aba316a19a2747679e36f5eb3e4d6e13ba2e38a37f3121cb5d5d3ceccfb8ce41d19b19843c79ce83479a634206a8af9c555b007e020ca51258f1f2d0747c3293b75ca0325ea9401ec80d7e5834d1d7c602df37ad180ee89f05538085e64c82110825f8fb074ffe8002acd95889dc4a621a4a73958eac39ec9270850f385e00f34c01c170ae0904b13001088c127efcd3bacba4694be5b6034eb9ef71de220766f9c9703530dc6bb1c994bd0c0b76cf700f3ccf4278205d0633c6503c50e43cd554105aaea205b0c8b40f2e8f3843fd2866d0da10c74b0d76bde1fc5ee87bd5203f6a4d8513dc03629e60eb8859888b436810067566130c0da51fd70d967ed2c9395f7a6fa737ba49fd3a13632f03fe453d7243d7afb7105fa1ded865e6d1d88be43268faee36be04c3a1236bf868bc40f7c27f91d3ce9d4aeccd0b04ed871d6c0f83762da374e9e2de238e281f02aacc2dabcbd8632b09bd7974643bb543838458842265e7f84bc463221305d0b0e84fb89e79efc9261f91d45460ab6aa6c8c7ca0756407df15b849aa8dcf65a9b89afc0be4baadc82e822555991ba54948135ecb6864a5514a1f0c709306fdb54bf2f7a3fe984f811b5d9ffb44fcd69cdfb96b4cdfdbf499d6775af4f9c8903294ad4d878d4d00ac54e2b27e13067fbfae64b3ff0fbfbe341f0aae0eb7c3449ea3fa935be2b1c50e4879aab87157605442530bce27f46d72d9e42c30c8b8d90c76fa300143e74758588f66c093756a145e91368e8140d8894549ff8d5d84654850f9e9683cdaac9c3b2dd30b5cbdc1c9c6273e4d26c66bad4f0175e67497b2f5d196c2a719110e804a3f7ce4217feebc0f607c2e7248748c6907bf044af929f22ab5c0944333f5b9aed8e549624bab79bcdbf2a4a514e94268e7ee3bcce38cdcf48833ed7f1dabbd958a328cca9573c1fea82281fcdcadcb5b25e4e02b80d2fb24e600a67149cd0b3bfaef54a20031d189e3f20d19c813c279fe78244e6f15fb8a07438b5130635b35fe113b3a473cbf35b04744a87b895c17d2108ba2e20917318379b1530d9d5c882e1377d18f346e6160bb25e353ede5e44ec7bf1315338ad94dd885329b4fa1c69ea6d75c3c837e9db8d7e2ec2d97e84117b726a997ea37c6bab5d346db0a07ad49c3d4de030c16c9b511e73915eea13c51793f2e44789736bebf6cc5b4aa80ec1963406a7efc248464201135e4b3148ed0df0e320a5d4f7ea68995d139cdd53062169015fb17cbbc32df3dcd24515b0dcce4540d11d2525b52feef526e802af7291ab1b15ba1e95f6c505c03c40dbee28131163c8e4b41672f42f70222a7603c8978737e27984f87d0621209745b5fd38933b0b63ff0bad1de1a344927a90d85512447301fb5af9a2bbf9ec8c146cbcff7aa7d72f45bcbf86435b8412390a8e2cd3cad4bc33fcb795f3f99810cbedb63025455a87333f36c9c567ffed9bcdedef6f6d36d73f7a474fc3b3e8fef62edd8f7a6dbb7dd2f164944922ea09d0c0140f69faada00ee2b5d8fac33c6ee8306d2add438a1eef87e8ad4d977946c24f64d171caa54dce9cabcc84640ddfad99d3707b98127bc41f4a189934e201e174e77eed5b813f5bc35d518a038b6b96c709dfd3a82f975bae3252ee0c0361d4dd1a4856f05b70998e5618b40bd5f938e92bbbb1008a1b811755a9c8f7826927ae5d654254d581f77b8e8e3b837501d2237efb41741d788e3fc20c07be7241fecf6f5f773eb670a0d4bb6fabb219afc89e9c5bdd08e3fdd5a25299a48aa8128f0bc401d2a690024569a48c8fa118e74fe6d0fb1f0b43db6d85a287c4f6b31b62d3ebb4826f89686b6585f33e8fdd47a4534e8ef66cda156cf9ca79b533dc92cfc175bf2bc7c0862851b54a536aa21da54be54722a75567d9cceffdf4f7636665997fe21daeb24b58d582b34156feb8df4a8631aebe6adf90b67083f88245aa5fce7b69b5d9c251ae04be94f936a3ce8192dc38e5b17ff4e623e1be880945b4a96949a1832428594f9f647f3c99f21dfd5437453a87470286f8a25e03c3d2cfa5f5a3c23f38b1fc0256cc88aaa29746880c5e24bcee5ad0ee9b2e0bf316776ae2d7060d502d2d73057934f1c87a75b15c491329c41301d90799a4846154aed8d60bcfbe18c95028c189fb9e62dc346496b4cb9ccd5ea753218d066d867b05f3d92332af39955645ab299cb9bb0538e107f09d838aae46b2625f28293c742f625c94f3e615b08da5539320654a952844b9e17c0fa35d29e850354028c68ac300de300fe3dbcfb6a247070ded5881f60e3c89ee9ff7ac598c13b54c1644000f4a319957ef78fe38529916564f6abdffbf3e0af95e468ae2aff1e288fadf5802ad4ba6b25b36b8b236755250008da1b7530be2403dfc01ff798dc885e5d3d96f7982c766850fb184ccb55ab8dadf8a082eb647fb6a71476be87b08371a949a05607772f344323dc1938c61387b50ea517a1d135b45fb026e51d6dd76f55f8d729b5db11bf708d37975f086a0bdc0ebd5d846f26e4256f429383df246ca1022f6910c769df0c031c61aa8123acbb279b616f2d05df4a6ec73c67334864fa79ddb1426809fdcd161e566f4e1cf8329d9625a1f7dbe5987638f0708c4d5840b8a86062d026a1b992f45a56777ca5afc6be8b1adeab079adb2e231b55d46a74fe8c1c3ab2d85db59bcca25fd7d44e6aae6602930846dcf6de75e5f6a996344b2bd46e906952a2d7b58cf2157e01f3a9db52580a61216acb90969b4348e79f0a79e0c73faf481ea36aa7d2b2fe99e289555726ab4d84df5017f9a7977709dc287ed3de1d62effd6ebe91a4477342429f42df1a2fd956bd2e779fc996e49ef2f373fafb9f2240f9adfd51fcfb632cc4020ab6c9bbc94f62cbc18708f71ed2263233a2542e8b21e42a4ac71e9f6b1a789c09b192900cca6b1a6a45bf888a9795c066e450e2879536e91c3521b3fa7982c5e10301836ec68066d964786d32ccec8d90cf375a083367c26cd7f745f35b95b10fcbda54ccead1140f8370ca8d08e177bc1ec08076438a768c2dec816c5782dbed89527f7cc5eeea67379884cdf12050cc383115537504cb15da3de0207a09947d52da313e270a8b59a22c59cc1697d464acb07e34523f67a8fc601c9f590f8c03974fe04019a676cf06b8d97251fbcc07d1177124653f05d1010ef491544e9183d71a81aa08ec7dd11010285040a5739be4d55344f6c410c0fb859fe992cf04eee95f79db213be9c14c3dc070f818177565d568fb7f4f3bc7bfc81375743d36d2966928aacc70c2e7c70df68cec643e8a20f4cca198781a9662676d93f86eccc579c368f3e9a6130be918883c42953a038a07b5dc340146e6473dbc6e5e81ea6aaa49c0321aaca99dfdf73e46aa372c5c5d4fa48d9dab8ef249f545675fd3111c279c28b7ff3a7cfceddc08b6f02bb18b2c7a6e7f9dcad3343a952d5520de60a202068cd6803bedd7eaa6944974feae36d422e20091f75848d926c3afa8f150a72bbd012a85db10bf78b45f10c5561695f3598e59f80fed9104cfbe24647346145edef6acbb810ff067dc7e312fec80ce0da084a5334d1857a02256fb5e184a70457fb72788546fab8e501fd52e0ccec6c85c217a826b9fdb06accaa752babc263c41ba2d1822824ea37fc08828d2f26b358e2878e793309c64be7c7fe9821e9eddd9abdda48051d4546ea46ffa66d170c53105e6fbcda696c98a4c6665ba03209aac606a7abcd2970ca8b90eeba498e3b464321ca2d05b3c4284d5666d26bf693f73be23457da1fd84ae0bd35cf9c2279f17e73a2eb0d6920cc26dec9454ba73624dbf8d82b212246574d3f835811b34540633e05e66cd9030fcc5f52c3c602b2a3b07bdeb7c053e78ad2857e4ff3a0ada1352480d5fd1254566ccbd348db96b9fc88a6188e7afd91b7d02f9935a466298e80e37c0890b3137915649ec3e8321928561f92aa649b51086737bc07be839936c835b653b685e962ebf6f8de081de8e243df30b04e2cca737c972dfc0f6b81b4c76bfdee5d2c129a6bb1c5e91b6117113b877be00f578e327c56237dfd0f09461d68381f576011e3313cef755cf50012fc830379488aac4583c859d02d37646d24129a100298f353917d879daea041c596925b82fa364603e3684d99591a98373fb8df647c9d3d31a9375c50086ce8e59ff9a95d239c5f089d0e297c8704d79288e68d5b4ce918ea98bef12648255fcfb66e5c2b1edfa540de718cc9f6934b72e044748a193871596f262838177c4d2639e834e5e78d23e655bcc828aa7c22f3004c69d3151f3f05018de26d5f011626e793eae577b4d376f34769ee44c5f32fc36c7a83f7f1775e7daecc55538fa9cb637854f800800d5eec550c7c87cc7557fe5a73abb9ee99362e7eb8986eb9d958796ed0c568560fcab7bf36613d142b4e339582c1668f42b97efefdfee90162b37106df8785d22aee11d109a5db1951c053f0b689202e2e5c7a2e82d5e3e66d47c9201156972720cb7e209de2ea03528ffa864da7d8004eca0f4d578c6e32d922a49beba2f2b16c53593ea8b4bf343a03f812eec49a962fc6059c95437bd5c960eacd2de3707b40e4ab4e52f78dc32a4b0e6c5f31efea4850788314c1e68933496e7681e59f4b02f7fbdd4bfba0ac6b291834616088fc56162a912898fc25834bc228c97043d94c2a0a47192ac21f5619a06dadcbc71d036fc2c258249ad20b4d80ec728f5d74e49cd093b990cad4dba23498e1a5081adb80cf326131e4e79671937ca8de22ecffc7cff43ba2323a7ac35047d1d3235ef3de18f475fb4b0aa6254cda7e56764574f0cba41b969c4731e30c6ba74707d44566bb884de29b76ef926665670a7015ef99666f2037993d6c45a95e1bb8025c998695d6213991edf0c47d8dba47d6ba793c7b432816640261024ce60d4e39c5a67f13ce6ed66f6faf9b540da4fbfab0292c1fb29a31fb81d16c55cc40c7f9f0610dc64b7721eb437281c9a87695fe663c42d275df24078708c08fc8d733cfbdefe71e2b7e2c31146c9871c5d5cec54d19ee5a2c9f7d82d7e2cf090c99328d1efdc4ef5b33e988408e62fe1c6286b868b9485824ff02f20529d7b79d76baa2c321acfbf95e279d1394fe79ce253f227011afbbed7c9e8fd353eb3e0ce31971daa6c942520a1d5e5d482004f11d86bb0170c60d593a8d1b9b1e701a81b43e0cd98cd75b2cbd1ddbdedc1154fdd2167b923c34e597cfc33a65387c600e828e791ff4349cb100f1f1ea693feb03cbd00f3a527453d5870831a0fc2e95092aca97dbd72151985162b3ed060668a6cb54e292648d5cd6fedd8d6c247c03a1301bde931991cc4739f56226c9f3f4c414c7b2945e9056c57e98e99d6216c978e58edd41c096014db2973cf6818d2fee500369be19d1fa9da5dd6305d68ba623651120993fd0148e914a1909497e79e56753537ac0d53e12dafe47c8e372a49404479782f3b1e8cb54c0462fab76d99160bf8fca6a13f5524ed90c5b241cf4e6dfbf83f908b5df8a2ef9a478f9b991de5fef1d3cd888a41533b01f7842c098a3ef55879e7496be0dc0baeda23849eb439149b2b81e3279adc0ead35526331ed0d94c7ecf19091a2093522d183dee29068b9279cf74242ecc2c7848fcd88682ea2889c85e898c055d6beeff1ebaf6ce0dabbeffce3c95a1b8ec96508324566574b38deec50b33e09acc731b73d3e88dcdcbc1f8a0607f693b8709eda90bdc75c3acdc812c7f202ecf875fe2ed5592720737a40aefc73ade46ee0dd6f11748b1f9d17e4f63d27ae2fd0eb3ea434943b4cdcd1e44c0454115f61730d4c7a559b3150db514f715852c3fba13e7c544aba93ff191c40f8707c4ac924d236b9f0aa42030060ad447b5b7c0104afa192ef05a9bf23f80753c8f39a1503b34d28cd9e5feb83ca68f75b032d55a676b6e767a1aa8ad2a2327204b35abfbe7fbebea4b187273d81b00e5af68348865a0cdde82750a76c527bc308313775ab3d79fb78a28422f430001fe3cfe51e094f47c37522020d4ced66073cd53830c7ce6341b885ee9c380ea8287c584d12195350268281fd61a74d10e9b8c5e661ef59df09dcf9f1bc7602a526d28cac9fb21819959f1d5579ea2f19177c242f701e03ce5709d1be02bf416c204286114a5f836652df3f3e9ca2367f2c95e02f56488440f228343d6ce4cfd4f5571cdcd53c81d162da452012826a4040b52883371ef3fb7e3ccbf997adbd31413115dfcf8655ad6c7dc2dcb41c8913186d50faf9ee6a320231f1695db2f93a286725a5f65e8ecca43f73412e147eb1d78babe96f18199a6855331363f9bdb9909075291754554cbd1bc7a6997037d24f5df98f415c4428891f40dfa47a8cc371f64c6498a8dd7ac3ff0beef37ccb4a54d329370c3088ebf720a399d8b5100048d812b1e06adb6f6e8304e82a434d8d466fad45c25041cda4cd25ba45901c9640fcce2756406f16709a821b928225e61a2a6a7a6e1e2a7e540e88cc83d6c9deecde29260e2ec0ea1f3f1949b8794a7917753a83274ff831820a68a7d49d1b6b3b6083ef7742cf0dafe96abbac69d8b2d181e206edb6c59fa11dd3f8e47f6b8fa315ca25b8a1dd133e6398a7904edde81d03948294a4d26d9a9c96f03832a5bda45078e569fdf33a39bbac4f8f75e040e3ca72a766a1a98b4f1ed6bbc4b9f4c5aafb9324ff601ff74bae15456c4026f4921c34b6953d434e57da8849915e33dac71837a258d133f026d762d58ec15e49fc43bdc937fe6c73a41534359ec537eaa2d76c56d327f510cb77b1455697dee32aad0bac20ffe22f53682890bd114a06edc5d7d350dfc380cbf0ecb4b10ae8d83598e95173bb2b060356285d02480acc63d77a0b073fbf26a402c1d231855bca657fa1dfe610d75a9207def5c91dddca4b3a8396b4d8bde3efb592dafa32eb57cb70971159f20a2fec996375c79efd59a9d7cde4c079598d6af7ae29c81e30cb5d98c271f1dc295c80e9d346edaea4bee6aac8aaeecc89fffb40638ba581cbc8bdc18e912c20d9cd31aff1bc7a0106f87b860898d4fbdbe18294e6838c6a158fbf24a1f98c64ee5a5989031cf9bf7573508632d6be9502ecce7e987480fb85bd9569737f109a9b1df867a3aa94f9e50cba30e2e95ef30a4ca461d41ea1d1c8da4a9fd6eed215416cba3b92ec45d27ef52873000deec7ea8d6a8ceeeb4cb879ce151a76cce260aa49cfb658763557281b7e4274453425ee52b053d44f4425be0be7104101099d40d28f5171440ee0f7b7431f6d0dedaf2effe5503d025a5723f555ed409536e4255df7a2b455f04b080f7054a4e5dbca0f2b50c7ddd2a2b01317f9f6e19a8302bcd06429fe0b0e94bc9588f8ae1ac3d9f9cd34db33ecb61e3b44343fffd0687fd80c0259ff4a2e06b28add0ad815ae3e44ecf3952ac187ad26ec70d8812ff272999aa677f3bf9f1f3de7f0908a88a4f42b1f083efd66b5f7c80a888f399003c3c2f6c7bcd5979d18a1c1d4b4a259706ccd87b2b684c4753049f0aafd9aa505134f7a3b447a2eb08e6e47e9e6c8409ca6a976f7d3e9133e16ae2edde027c491ec23052344b179d4cee24015509a7a84c2e063434e7365748c365dac75821dede12b012840a15acda47e10aa57fab9f32c6edbdab5bcc9b7ed2315fff1c25753b6fee4a2f8c20e4e6ef3eb5686783451dbfc2f3f36d410b23edf6b4331a0fcee5ed2cc025bab82617ca58eb5193faeca155bb533722044e51120b3bb923cb7041fbbcffe488e4d613453b794ee8057c92cc8ef74792f3c594cf18c145c9c6b96137238045f557ea5f8ced63e008113017e73a6787679fbd07a6f5e7a264aa8078532a967a4da3274f95e312ddb837446012762294252a95ab613c57e34b7404da89a851434d0a35b1ac2ac55f5f132fe01509b923abc60f0911675828b2b65730f7eca5209e21b61091876575cf7533a6541b169106f4ba481d811727b307ccf8b64992312e707732a0e6cbf4d8952fcc2225403a546e94c97715ab9a75968ad20d62c6bc9ab552e717415f58ce11445ec07ebed82e1cc55eebdf11ac123d85734cb9280ae0e0687c452c6a10d9a0a2bdac7118490e7ee85e523e1192fb952e5240b732ec9be606f25feb56d81ffbbb0d33c3ddb37f007f1b7f4d9a1cae145c2582be72bf89ef59c9abe10d03ef9908fc602d9d8ba7a0d05add9fbfb6af6e11560d7cc64ea01ba9c83989f992a65cde6249cdeceac1f736b2593a303150715af3f8a4b26a71b6f05297fa85b374c9d3ad8f881926b56e41c2246bbf108b0ecf524580ca84293fb4e0ac89d3e29c577859d5883f5328b8189589e02fa41f5e40e123902ae33d36de376fdad170f4631babfefba6f5a600640196bf2988adc600928306654237ecb36fa1c7c4b4762d449cabd1af6d152e8abd36bd0a1fa6159a3b6b4bf58ffee539cf0adab458a43057eef94a02fa01d1b6ffa257de339e66b3eb53c019fff2d86ce3593fb877b3c14dba08fd2a2cb29ac1f56866e72f449a8a816dd083d4e896a8df4d9da248684e9c08e65016f4959ed651cb5e49e8ed46fbae8a222e7f11c9cbca6880f283906bbfcd8eacdb6659db00fa575b6545eb9615800d5b42a33147812aa5351738073b744fcaef57102f8355b7c26730d59e385e6dc1ff0dfa7d6fd185e21d4a58f6c55c25ae2a7a5b9813f30a43dff6e62a0514dd3e284cc64f0a94acf6dceaa39113d40204a5c5ec1aac1faede20e38caa9343291b2150428ec468d488db2f4da7d9246e4f52cb3de145f186aeec104d9e997e25d8bc8d2b6ed7c002ce302129f83d7fb406d524e18d72ee8a0952f1cce82edfcc82b343310f7703135e6ee3f5246d30c1b551a4704c55cb21c7bd8ece32356cdcf8c0758f2c19bd905a948c911993858ebc345c75f883b80c01a92722fa04d526758c81adc3e73a2697d45f6d60c971021f6b4dda2f5b092d44238617ea05a4f04d0a8eb20c11ebc1d4be788ee91baa18fcd4197d7382e86fdc73917358126347609e9b7510e63588f804efda76c98d85e31443450da18ee9c6f1a20163b7e954206168917c9a54be54c5a462c76bed8d9f364652d5f21f06722d3c1c09468a6304713c57d9c2e58d43b04819ce5363afbf51a45e0bcb5618ccc6e89827e5b0d33021507fee40e33e4b4d3813bde6692a739fda889b144085f0684141db884c0f38c936f114e6cdecfe296443e80ab058e35e3d0d027372a5a36d7608f165fa6ff4ece9b1dc68d880f3b2abf76e35201a5b57879308e775efc1a4d7b9774955ee228e9a36ae66ab4ddc76e6d30a3733797d74d5188f5106bf2a49d26829cb82fecaa3d4b8abe93608cd970cfdf07bfbfdcbbfbfc5ca5a77d8c167c6047fcf8fdebeea5f999c378bc6ff2fa5898291c03bcb84f147c85de70a999ed03dbf430d1a75c226e81d3fd2e1fd05792a31a5dde630a5a86642035348390202578fb52dc6c36b80cce3936dd7cd06b05a8f17863e3035d6d0cb226d5e8cd008961e11374115a23739eb215dff54b73e828fa3129b8779df15a5872970dcae8998713804c8ced30573c8bd32db5286eeff7bbb9ad2f179ec9e50410f796ae6a57dd148bf5527a93ac41cf72968a87163b9ee2fce27335bb65876d29a7f38970b4728c6351679b93752ab0e0171ae2ce993b204b6afe5b0ce0e3bd7500ad14ad337738c653e9194dd1afdda7ff2e7121004ee58e61b28ef7fb72180e7c1a356ca01fe8356e33fdceac536c021fd97f79a29a030bbd3721070342866d8f0d4393b3065309fb813f41767ed1a8d1fe0f8b510055dcc313ab08913e9d2a0b3eff39589ebfa6bda7c97b17d5c6aef2859d8c2cf0b1c7c465fb5db906e95a2bb74223c50525f44f5f99f057390b3ced83e6e914f8c91f03e44f2630e007c48a9c54db60facfd6d6f6164f45376413ba71d410ec768f711e44be239ab13ae0a8e7c1031b30d6462a2f488cd9dcfdaea487db40a49fd79af53ff3856f58bde889a73c08e8da82f01363cc80aae512ddff17c2b9c7987863cccc7f683f53b1343a4dd19d1dea70f3e035f670303ffd3a041b6bf423ffde014fe3f550dd5e0f9e29e5ad6ef25707a05d3f3879b1fd98b7f181b50efe82b63880d37221b383ea92181a45f7e4f964b3f07e45032900c0085dbbec1751eaefcf1921d1dcc75651a72b23034192a4d432a7177eb328e9b682aba0aed29a123bca5f35e3dd850fd6fe505e53cf4add6bdbfc2dbdac0bc324f47e56e8ec566ac6c3e90e973584a49eea19c99f6434a4ba48773a3ae1812066212501440ebd118a2175b925f7f454e423fda82b2094b958738440ea2143d8938a2233ad9b414dbeb8126ce5d0ada0c9ba905fc12477b4fc64b1d3db760ea81f6bfb47f92f326725d354c46a9b1b11dcab97a6413f2ced68b86284679d15209dbeba7e134c4a69add76515761bf5533ae421623fbf405bf90631acb593aa89df40bbc03df0dab238bd8d4fa0ea367d78c8b405278a228106af8dea209ed097d90867db3bf76ad10954706125cba1822f2f52742dfe55a98d5827c70019a08b1204271633e3c28a0f61fcebae1090c0262d030f77e809e14956cfb40522561c148fb1254ab8c089d3a7fc3c3620a8cd6346fdd3ac9ed61099907f1fada01eac792e76ef4c190d36efcfef0905552a5062e306cf53331b192c979c5149a72fa58426445210bb247ce0b5a740f4175a3a9104a6a531e045c10d83de6f5bd89ca8145bdc3485726e9d53bfa68c6883ed2bb2e4d167b9c6b5b71de90af81fbf4b201beb5b310a36b5c0d127ba96da2825adbfb4b73531539a427ea41924dd7a83fb364d9d4327d09f6f8c1d2cba87a88eb7256b2fd6c4e0a3f9416cb037f81be5ce2d16eec172e2916e4063507c8fc137d8842d209cf3acfe8eac793903b284fd9febf55274ad1864b85fdf35ee5024693724acbadbb1b8f9783493753749cb5f52bf893bb51fca73de0a4743b69343350743924ba08b2cac5d63954700df891cc677c2a6150134a26511fc788b7cb9d4a8180f4ae5e27f8539198fd2fbec3af11789b9f89b7905441fd123d00000e71148d4457b100eb1c92f39a09f25499c43fc902201860f5a0d949bb9ba71ad821d469c6e8a07a0666dac963638b17591af49d0dfe0a65cd048c3504a28f91df8c89e2c219b29724cae014ccf818d62252cf58b0d17177669df5c78c57e45034272cac5745b297741764626e4f6d0574dd9ddfff64ee8c306a31e97010c2ba288951bdbe669e54cf1fb969154d518078dff37c8a171de4d3dec589db331ae9f6523efc6e4dae0edf221948a141b266dd0b215dbf308450107362e4086e73e0a110be012f7cabf65a6f6c51d0f2f954acf713be4a58d983bdbdde3f24dfac3da888233d28caf69711e3ef711de392706fdedfe634328e745b7ecb90e3fc5b379bc5d012998459c05cee23ef9beb33b318d6de1ed300d9c04c8044cea6ff4c8976a469dd46f7bf6d02234ad6ef1a23bc81e010f384a5c5d8c628829413d154c17c9bbb9ac63c2932a43978dcece26bb20a4c9ba9e46e877813955ac326dde06390d6ad5d8e68b2c8be41f026c106545a39cc1e0b4aa2e811f3249ee3ce6e2f5f8ce0b0c4890b71d73bd9eb09a4c33ead91c9c4e521e448d9267fc11df6b6c3b194399846d62bbd91cc7ac72a33a679daa547b847ecce5b3011337211985ee54a23124d1bb156df4e13ec1988127421d12b29250f47f6a6ce47b5319735e6e46a1777b544b7b7caa116d5e269a2dee2e7f321df34b5d65e9719b73d138ebfe2925f4a126cfa325c9dac6fff3f860efca5e7edd038ffc98569dec3106a1bace2d03f3772c32b57d399fdb0e408112bce479a525b646eccff0eec9c78a687e7d574b3fa9cd433cb822bf4561fca71cd9c950b88ec65e1c3dee6aa2ca77d99b3e7276210ed85231e2b26ea145f4f515b41014000312435686c0498fcae7f0812507e12dceb3a56554819335c8d44804fc659f6bbf48ebc248364198eefa7669724aabe160c676b23d6c19194d76a2f7956133905ad1f538de6fb8cfdb99fd82d4853fb618e098b0936c3f39dba0031cd709eeeb226ca9c43ecf54044b48becc69519efad4621ab7a770653f67931d529bf26eeb2c58bb2074e76d915e2bfa3fa151081739185502137b9bc88ecd6cfb58411b8b769c9fecdc489c71345a46f371ece1ce73acbfefee3589c27e5a675f91e511244e843e23d1a80fb8e2fa5ea559ea4573bdd426b322a81a1014f4913319d3eb72f6e23f59ef359690922c635116f6b023f9a3ef7d4d3044f9baaceacc565b294bbb02258e36181360616d4018e2f0c84dfae690434546334deb5abc426f88056cca9d3b73e94cdaed812dee2c3075a93400566e22cdd1541ad74cb53a0f8cbaa876986dbfd94795471f1d21a82195c89e325278cd3bdf4ff1346c8c4426a971bfcb717e549042a35bd4e672473f13a6bf4bfddeb04d5f456d6e8cabb06c906afaddf419cf1ba1a6ec48b6a1d80ef295dd4e1030167e5e654449509f051ec0d4148d06e312c24359df77effc4e42b35bcb7bf51638909461aff465247ce6028bdfc21d159c8b9aeeb0d03d6ae00a39b30e9dec4e3523cc4c16ea4292825ce9eae68a1becf68bd46c1b73528dee594dbc2e0eb823aea1e02d16bc218979facefb1d7ef98b5411e514a1bd281edccc91e4db12a112bc0a9cb47936bfadfdb4a7e4341684439c1515950df8cff4c128fcef59d729bc28cf793f4729d520a006e592a7851511d7f59bb8123e71d1fe1a004659e05a589bebae8567bfd8926aff2e5c577f2148b3934dc40943bb18f8a3cb795c58f7ae5a377dbd05d2d00aab2faf6fecc08b1ed0b61283251298d389b9d84718c50a5f555db9a8a7eddf3569782a21ac69e5feb589c4dfcbc3f77d09c7c3008e88dd84812f729cd0fc947c91bc30981619b60b6b3e383d1d8ace7139aa86f75bc00461efc8527025b3241b276d4f7dfd29c0393cccc958217a77b4f5dfc247313eaa82951c4956279728e7b1e5101c530ff5f511b536eec122055150cd6d5dfd4632557f98ee449dcfaa651c578ee2c0bedbfa3e93c5f4f8f863ee1709936d5ec42dd11e03d406e6c2792cd4af9958a0e998a12aa61109f5660a98e184874e8c8d995070135190a5b7bf9ec4c4ef404bf223ddb93df26f371fbe633a802980e0daa84619869315fdf885f61d08aaf5577496abf8a393c836a973ce9c1c8863dbc8e73c2b5f1e318c934ebefa81cf4e7faede6d9c11283854b98d4dfc6a2ce2245dc45064e1bcd8bcf99a481c00e4c06e24f044c881bf6636ab8d39353e96a1ec80b5182515b32e045de6b63b0b39aec3a605f54eab706764ea85f96e7264234b7e22e988cc05645bed5bddd39abedde3fbd3b13021d9ea8e68767dc24825557c5e3e20d02c39248086243212b2bc7deebd676fe4bd4010d6cefc8ee81fbb702dc10ac6dcdc08e53f64395598d3c8eafc767fca5cf26e56b2195de5e2fc6d7dc40eeb888442cee99d46d82beb9ed4a562ee83082c93f3e37d8967604e211fa4a707d3023793972b876c1751fdabfd1e428c966f1169b46f90f24b30b67017ebc77b8549bd9adf7ea7ab9489887db13a4efdd48f731e39a55043e69937cc5b045e66ca04fcbf3cae635c78f28d8b2acb23467c648930d24b9d31b2aa08e79d338ee14a2358e0444626b9c211057be204a8d8f5e267d7ca83d15202fcfc53d050b47fdfc8fc55457251f02aeb118b61718efbcb8fe50db17e430374e3b1e148f407d26c80609b0dc07dc2a49b6c2114f6b6d71c63ea323da87b03406b63a09861677f4d9f59589208d3b7b1cedce13ceec6b5fb35b2cd27e6cc58222c2448d23f579639d6161d87c25a57eaf7c964e124e270e5eaeba4217056e3a084489fffc4da08f7e238d5ed07798181e556a2cfd750ac0bed4697f146bf34e6cb3f465812357c7180c73547192facc6a7b4bcc1015b869af1bb53cf34712294a623c907301231bb240b11f0452e77a869a234c73d0a87f9de75595093f6767f339874635d68e75629f3d159e19d68c19a8cbd86ea14203e0766f596340044374be559efb7f9d513eb68f004f86ec62e1fac393d75dd83d6a6efc4bd3052459b38bab2dac28aacb4b93341059252b88eb0f6d167076a78859c1904c45f3023be0cfa1b248f6aba378754055aefc1b9ac439d39589ef6b6af55027e370b105b68384009aa2f46146a57892d4299f1fdf0dfd2e28739c6c172f91e2646be72021b0824eff2b1b931b201a5b32de8e7f011bf8bbbf73ddd47a29df248aba43ca51da44c6761338e54b873a94483db9ad8a7c4678a1e50860d65df2dc2a6d69495351d1d3fbb8f53f402954ea061f515438dfbf22b2ff069787b3af4bb9b688a1ae2c7df50dbcd3c50d547b949160ec68ca12242ca229f066b5296390cc3380847fba72a15ecd203b58399ddc675f9b1b155e51b188876aa9c347d375852bf653ae1ed773be733feab0de436f3abc2b4c7f7baf77fc4d831b1fbe61a16a0061d4641c36668c4b9c891c037b90fbb6a2ac777d268c26727e7ee69eb4a9f5f37165e34a2d3ccc057cdd99fa9261e91d7fdb038c57756a8cf9d83342dc96811eec78e53cf160c6323ab479ed24b9a49ac6f81829eab63c22f78b5d145cde306847bc98d3994298236ee471f5c956689093c2ed6b14b70973b8771200f744eb41ca1733410e7d41e1d52756506203932e208c36d237b8f53db956fc84a48b0f427ad4c5b100e7901f207103d38db84827a5f5983bcec3ba867cc8b63044da6cc6451c8dac99f9aecee8bdb10fe1661bce7d4b3ebc5fafe55e27cc1282f5bf4934fdc5cf7e7808c2d4f85cfb21c5daff89aa94656baaef7982a445fd38d2a37cec776e943e1b6d9afea1885b661ed91763ee2b7307260df9cc841a8668087c778b00b5b9ffd7616fb9654247ac3eace7cb662e219ea89329545266e825cb243b833e16c30adb1bd1ed30cdecce6472538ec8ab15f432214084addef0c22c9090b738483e7d4da4ec62535908e2c50faa11f83c8eba472992117ec18f2652630aa5b54a9ef650f9099deebf3986b8618a8d091a00d47347cb81b31904471bb5f91b4447f54ef7cbc9c62474dee7aaf89f201a2d498a079a71e912e9f9bd3bd831e96a66bc776980b8f83ebcaedcb8f8a9544f3a16ac9a787c28e7cedc00504d5a23a671e3d5672a818bf6e76870503d0fef1904535481c04c7ee7ca6037a5c797508b6ec934e3b9e47c6e82ed501c2f81e4650f1bbc7c5a67c3ba5f8321215da7704d5d3d20fbb66a16c79dc4ab9f8ca55b0b25acd03f7e347cb9232f9338ed661aa28ce1a241769daba92157c8007d237fdb9524e88e0bb69a92748d2630619740c4d6066fd9f6cc21776c1215d9e230d8e718d9cc2e3f2dc3f4c9805296fe89cbfdb7f6f758cefc53a4f4f09fd5483c24ba1f72d6945d1cd97b1f3590e745ec6f7a9a1d60aee69efee61bed84af7efa4327058346937ea88e848723ec95fe15c8e5db7ffb0283c6f658d0d4ad5a146880080f962249c30ed5c4c9b986e41e7ba5f7bb526f52b784a8c085aafca7bff6ee44d620097f935703fc5563901290426be5240ca6bc2231a83f23b64f727059b36a5eef801d9efe0014fb083fff648320d53813d76f71ac9038a412c011d221ba5f079e5a155e529623a6e75292134070c30370e186d095dd4c1519dea2e31eaaaa1953b42c193d987abce9813a3b2445991d8bc9dabf6a385071a2ff8606edd4bbc9413ea869485faa9fd8c2ad5d6c63a929d1eb35a8ae293a6456d01d33b09cae1d090bb528efa06f886afc288b68498f34bfa0b0dedfc0569543a199f81748e6e845985bcd65924327b2bf258d8a499e4dac65f1a94e0aca8961dafdddfa08fc9e0e5fa3529b7a5c1d099b08f27686ffc1ed5f2059c67d09cb1cbf1c3facfa6cad4674507f37547daa5c7d1d69d7f890acaeda3d14e13e9b67b19018f0db018a3bfa52a8f4183ff3682b87b6727370f57d8e9fc4c60f094b35fc99ad884b431a24898faf38399f0efa70f2c5d693cf4c7a5ccc26b72974b291d6f0cd8d6435695e5e8ae6ab815850b86eb30ce17d897d6ab4bcfe5676e6cff87b4aa1e50f2d2abe6b60dd990615e694f87810ac58870c44a3bdc5ed172ee6e5eb61e72d5a16d5962142939301a559f54eff5c34d0b971bfda516e9e01e7d9db2781b386ebe3c51c42d7d11b45e06ec6344f0e4c51d6ca4d28d087f30418341d9927cf3a212d09d3c035d02cff56da506e781ac17ddc844291e5939ddf19ef7f400ef48fb6f2765e2fb922d1d13ba2917e1cc672fc5cd2abcafd3fd90c94e28a9cb13ed555b2a0adce4723bb41fa7083f0b423305aaa136bf2d4fbaea9d0ada395cbf1036bffb6b4d9a185246481fd11493d13a0b20f74174e2c20065969e4deadcb557e6f45fb275518e359e1f6ed9de01407c5e1a2724d57c899e0cf9ac2197c542ea0bde40e0d04f74a8105331dd8597829cddb16d56792f01c87e39348c4f3ac422fa605bd369466b68e6ec6d07c53c5c4b9b43da53388dfe18430f9735c3380fd51b4a23512dc43436a48e11a7c048f21f8634f16ba1994b1befb96a9fdd3238f417915a8c74c2ba769432c01c9a001710c194b595686c3c2073cb0afb3a5a6d5389cf116f7a65fa5b40059d8df7a9dc692bb93a39993f29bc4863faf534f4cba6e55dcbc5aff89b04953655ebb03798f138e6e716d208c954448e7c598431008dd6ac15c8fc09f3b5da21862d71df3eb45f16c63c478e67465e345f46d5eab78a3dc0da42f6a87ccc82fb933cbfba1a8d2656d69e64c189f19e552b8a5382219063bfb473aa228d1e850e7a0c99395a7418d55dc1c02520ff22ad09611f681b1ab5155e11ca24e64315d1b4b5c99fb9593058d65ae441f304309a24da9dae4ef842ebd3ad006502f9382f614fffe147245fa4b9b17e9dd020b348ad36ed4e522fa9108c763c68ac0c6648eb58c86ac33e1759064cec8fc5cd75567fa8b32f6ddb6af107668c79cad947f14458cbd9d5cbc9e8e769fe7c3442b6ee2374590ab9facc1d20f406fb3186c655f9b06a1d7ec7794a046eaec1bab1bcb3a5cdd7f2060f7e1536789c1ad854426da89315b9fdc04c445f76508b1612e1ec6be3bc5706d7012ad13f1b423ace57bab60074407ab27ecc184a24eb72e9593f243a6f54fc8b25fde37b756ac12e907ae3f70a7fbcd7fcb8a38749ecf87bb3374f7b5c31eb0cc4eb038b21ee14e34c958f00423a2c3e4dcca1ec78551719c829598d2e0f743587d1912d4cde656303cdeb9f9ad51c91591e4b0f2cab4eea498743fe237f95fa1e95e0bf9c92e6cb9a69d8c4234d87afccd74a710c90e02e989893504e6ea02d11544d799b5a5d36183edc3f0f093ae562dc80aa4556da8c4c9af7f1520e909058ad86a6cb2d9002a9ac5493be8dd4a499c2769eee51ee1e7825e9a34c037920a62d3dbb2d7edde7fb37f2573724543b000ed75e89c82f886205481e400eb5ffc8806e167334acfe7901571bb8fafe8498f56eace7e9671edd4c5a6080b2779c5ed1e9b95d2aadf1e72d12316c98799694ee402d7b86338aae3cfd76f3119bd876053d7d1e8fa72f9982056c6abc2f17a8cd3ae92b664915d75cfd5e8659abc5684501d880531fa5a5d98a7305e9609dbb7e77471901bacf6f2386ac9fb0be8731046d3940af5f56c9dd5a72beaff3f8c7919a405e373369e7aef303c3adfd0a7adbc14c37decc53cc4523d539755ed7ec117336d3bde1c0806ceda16528097572ac912a3479500768a7b88a6734b8048b9372bfd991973dee95d14494b9b31f397eb94ba8f20e93c3fe491840bc679c0d30873c128e7f93734ea641251a7f29c1f5905af9c61f17f2543899d9cc27bef65dc0c568382c564f625986cb4c270cc496a714206fdd57da330ebbcb7118fbd8fb776f71f846a86aadc5ed73d352f339c34cd1457a98e5e2a1091002b0f6074a33d435bc41f22baa9c8050b3aa11ccadac1d4f1606ff356734b247a1d3bf161d7c9de2a391a003b1efb4361fdedc20aedcb1346743d5b4e495bd7b82c4d0fc918a6924fa4cb165b0505ac035b403cc2a9fc57adcfb0feb1ab2104b3e7972f4dd04ef0dcb0a28994d9d58f39a5da07b9a811c0c2cb4ab107dfb3185232e37ff4dad86d459ea119bc5fc905912bd54795e3a750ee4af81d142c90558bdd93c609fc8c3db379f3fb4eefad5bca98be0d095372d56c77bbafdd3567d30b22b26d82c398f548b7155347be277348ca51334d3b1b425a9c30cd306499b7f04248815daa73b4a113a8a0174e96b490124c47c668b8401bfb486c9cffef5a9aa628491182bb1340a72bf4e8a3829f8fe0627183ab5c671b13e15c94493225815b1e8c43ca74617cde98af7940c417d44c8760e90d93039823f94884f680a9c73a8b5f3a540d31eeb542d9902829143606b19b9fddb8e3d80f1fd754126aceff9a117d6c9e439c612663b01090f2022b8cba46520b2c3cea463ab32ca2d4ec3894960acfa38245d6dce49dce7d9e6aa7935ae880a7b2ce160eb1bafccb81fdcc03c3734090f13ba42d4b826f73a6b9ed46a632fd12dd3bbc720302e6fade4d917651eb2898b6b0aac2e74f05754369d56d92e69a99d63bc39acaf2bff60da27eb3ec0d3c13ff902fab400695bce55f3cbef2f915fae22262608c0783b885b3c4faefae90a89800482af1ec150e7f93cdf0f83f3122993b4d71c344b9f85a90e5e2453f9a7d13895c547b9207359da485bae1050ae34a1dc2d2336d07d4747e18a6e46f1c7aecbe7cdacceab7b1166d49e7e1ae799fc79adcd368e52bf6c10ebc6824dca09bf3ead490a5c4d953652fd1c5148ec34780d6f93b0f0d678b0e8550378b4c936db6510b9f515aed8a78424cf030045c20ef321511e8047b309414832ff4e9138982b21d82da431f2c18b09d049fbe2240b5593948e295a37fae8e22f82f4e1c4bd3c3b45e4e6e64ca39abb4085f730ff05ea6bd5e4831780eeca3e3bbe8f32d0df0621f9758c2562e9052531fff0aca343fccd9b59e9a7dccae6880024cb1f5fd9b5197178cbf0d0716095d3dac2b461003251dca18f1c9ca64c11655142458fcf898db3448f6652e704564b4913f9c3f44ef7d0d3746c045acb933364c69c6b3339fe0189bf04baca24b2507d405c3c052d22a41950a653a5859f5e2950d54c2312b48cc9730cb897bd1f6b9b85b7ad810075e1ccafe20e1f44096ed7eb54bb19e49451f4cb55864123167d3a046373c9feb542f66f9858d905c97acd4b6aa6163cef643805a8f114e3ac2204adf5ca9b85f42fb6b3726b7f7d7752a04e254f7a179c78462af16807018aebb137b0fd937378cd74febb58d6426605ed8885331c4756cd28ea9c01159c3becc00c217eecc860773480749d7aec5018637278cafa06aea13275ed7f2d0a13f256215e2a97b5463d3798f2f84881a1808cb1f9758a617f74647260fb6e200243feba75476549c8bc60b6a49a9b8c62b50e2864156ea669982ca533abd7c2b19d3435beb6cd3a57b315d2edfbbdd527dce1bf58c804d425082bb4069cd8ac6781aec510537f728370684dfe5daf51252f17032a70a166e07adee1b9678933746c215e4651d1d6d2b061d3c161e516827ee71822bf58536d1e33f0a9c08891e8f53bafae114717884f7ea7f0d535ae142f5b06287b66e9bb39f1bd8c88b75ad7442ef6f1b51d8dcfeb934f4692aa18baf0b48e0ed8066f829e8dc1bea628469a0c336dde366002af9294e35a28bb4890e0651a8706d32dcfc40a7cf432d21cffa63275df306ce2a2177a65b1e4a391c6e4b7d0604f9707c3ce2f5eacc7de6dbe38f0a6a5bcef3bccae71533b63c34340f33b8fb460168293cfac30f99c616cf3aa3e0a5f6410d3bad7d40251406663914ddb3311dd235563d2bc13fff3a58fa1a3b5ec9b7efa05ca9cab2982c417053b8ed0e61a0bb29850d41b03866bd0804455750944f0485cfea0bb17337aaae17259e8a9b1de8417e5dcc7580bb905217bf2cae3b60ce794f3a3541b5c41386672768b8f00d89de814f2b9a138086bf0310ec1cfae3fd6fcd5862bad386db0710cb7e599d16b35bae7b78c73733bcfd804d444bbdfac589e5b6a3b669c99e23848661d6d7c8576f026ffe7bd02316ca8de15f644887b1019ced18d725383d20cb86067256827de7caf4bf974eef295ede39ce427d510956592c556b873d71da7e9cbb4f69d07fc553f49345128347094df159ea850a79bd85a2b3f5a3500785cf204ceca4bb82d127ca9226307ffd62c14a77b99bbaaab890ceb27772f7c6dc6d0ba7af595bcea40429c93c43b8574d3dd3ad98d08e2ce2493b764d0de333f121e9bcf31bf972a1dacabdb65dab2e4a9eee9f744b882da293296e2c836a6d8a138b78e90916dadda52f0f28ddaf860fac6e123dbb3a707345d3d504731533d98bed44bd3ae4b0508baecb4cce4fb6b86a62c6ec78d8b20cd2f790a3d37774959d000ec2202e52a9b14852975988705851fb3a7db53f05d328d23afdc04bcefbbe9f393d8b45bd608420c0534a48b4e127f5b27a6c9923811fdb30f5bdb688c1d49a79ba8ad47e20fc76dd05413037547377d390e4f8c2872c73cdf6fef2712a4a906de065b0c8fc0f871d44d9347ad3c4cd411c315aaf739f4548f48da8165dd0c51cee2af1130d6dfe10fa11e990463333d8a62990eed9b0e7e373ad35b84332870f61bb04f1ce1f941e21f34b8ca194866d96134f3d1348f4a91addbc2c70f1b4bfb07695812f80908b62e5b6c98893d61d89ac22620aab93c6cda2e4cfa42c0fdff09ea1b38a9c4d1858a3516a307b1b333960572ccd8f30d0ce9e89478709729795d8a58294432e06657e08d03706ff050c8ad07a50a84b2fcd06d03e89194adb15754ed52eee467f855b73047159ac422ef8d062702b59db9f1ae4255ec248dc48ee44d9af39c8a52fcb7438bbccb45af7cf99b0153102c243f693063ce5a439cede63c631143589ea789c1f2f2e626afdd862ca97372eb554b58ce18abb7346c5b858d39a2f8b21dc78ef859fd7e71d285f61e0e9dd5fd5e13fc9afbe2e1c5210be907624c8019ae2e063de6fd389b541416d2af1332a28353775c39155c4bb265ca45de83c11aca5b36c3065265fb90acabdd67baf267c0e049a69c0d46ea72c90c71b17adc3508c3b8083c6a51911b94a865ca8bf080d9fc0b597746acbb6031cfc5e9036cfabda88867b085994a1e6b3b84c9303e812e1c12ca0b326f0e2fd3c4650144e138f3a5b0ca14e6dfa34cdd8027cac4aa391d1bf3a944fd5ddbc8711321bf0d45effb7ee2b56eee4cdb44a9d850a79fe6f548d889227fa25da859d8fbab523eb6b6835000e32707e7e2e860a4a11386ed372d7186e061e7780523aab53e9ab35b5f016ca0" + +const v6Slhdsa256sMlkem1024X448PrivateHex = "c5c00b06677485802200000040266fa62166fcdb796f2230c02a425b54f546a79211653090cbc48f322841ea461066949d3dba8e3c0ea58857b18ebc95115abddf7eb033f1d29c1c8d25bf541500115728999788004cb8e387d4cdf54df39cb7572d7ab61e427fa68d61af6ad85bff3612b6a66a9edd89f1de9303451998a65ed0e1cd0928d4a2ea4202868208d1266fa62166fcdb796f2230c02a425b54f546a79211653090cbc48f322841ea461066949d3dba8e3c0ea58857b18ebc95115abddf7eb033f1d29c1c8d25bf5415c2ff000074d0061f220a00000041058267748580030b090704150a0c08021600029b03021e0922a10672fff84863aeba67f0d1d7691173247dd427533b9d7ee76011c6f77f2ce9fa7a052709020702000000009d352042915a30841c54aee368a700a5bbc46f844962c2a8f2f47c51e63f33c0a7886cec96c03f0825d9824c6397e3caf58f420822434391d468b2c95a5821a66f4f51ef7f25e7dc24da1bf42c36fd67306247f3ae41ef5d82142aadc65c87563d264728c29455923d841a73700890f8ecff97acd5de7efd27a67cd96972d245a449b8b3661af689242833094bbf9888b9f301fa2a9bf048cde957a79c46fbd6cd1b70f226820333e41470d0642f4b951ee01536e36ad33e23ef0a1109a4b4d98b2c6354dcb307885ef2fd0f694b9201ddf3328a065dd785d4046847c57794f972d66158fb5f6bccef3016fba9fe6c7fa3396f887eaa11ea04407b27710f28ad9487db318205cfd8a5e526a9b4b0017e1f0c16375cff27167ca73b84d7ef431da059962cc7c3636a8e5a9095702da49c7774c6425d5df940dbfac60018d123505fb7bd4929976af332587ea8336e06bdd2d696f0b53a7a3c665f2c08b32d5867e7c369b410bf1580a2efb534ddb66a32bce40d034d2cf8096581476bdd8620239c00beb4ee262605cc003b3e0bd4c71697d9969624bf7e2b428891992c8f5287f0534f4e27b975d8f24395b48af9a2fe89ca003b98be3a85259b9e6fdbd6add8c22ba07ca48bce3a7714b24f5c0b7f40fc5c589c09c344b195696200aff69e2e970898e06b33b407d18e61974e5260902a61ed1638a3835d3958390cff588d4292bf3e10f2cca9c33d1ca6deb7c52b1e8e519d682bc2cbd9869ebe2ba178ef106e136b8067ab7db2faced3cef03666d946d30eb22c6217241220d1b059420ecb865039ef9a52c6c909b70adf5f0ad0ea42e4a88b7264705950ff4ac0e13eab9bb62f7678339a2aec1a0ef27cec53bfd92af99dce12ff6f1a102a5ff78fc848f027f04eabb307b0b47465e08553bb1c46f3fb52c5077ff16b97fbdd1710e4ea2557ceb197182f2fc9986c84798bd5e89157e988ff8d73df9f35d937b289f943f3ca6455ab7a79781c23fa2e4c22ce089634144d6560d38824f80da7131d46894e049893af8df26f07f40cf2de357063b64c5f7f8c9a2688280bbb4765bcadcc93c3939d0a8452a8149c037d949ff61c463e5b2f1371307c7b2ca9b2d0f2023c19072a7f72aa5d28340e94b978c9b64f9cfc432706fcd0f4388232fa792ec6825a39aef571a2334974322a2659240f5ad81d2e09f4d0449cbf00efc8bde12602d1dbdba7097568adb948619602c78c2f0fe1bab8dd69e6eca003ca3bce169575626aecaaac107223e80608bd5ec65b624b2b30816e281a861c7393fa6db49c2b756476cef5b810b77d797e11fb4ae4e85957a157c200f872fae7caca25b6aa9bb279276705bba1f12006355edaacd9fbc6b89eef9220516c91db3d3125dbc6064d3ebaf2315d429cddecbfc576a2688c042f65d40d1248f4b70acae27f03f26b5c2daacc3db6bb4fc1ab3c0dc2d9ea45608db21cd6e806244c2d45a51fe176ebe037af946aea9674b9eb9aab7b4411a9fc3ff7cc9636c781ac6079cc415faaf6c45d8c10317b7a26e5f45c4bc01da1f70a3f3ab19bca21acde20cae4c13043d8a89c3d8fd8f69f5ee9f204a5bccf2abbe762ee7d008aeae4732353559e6ebd9f4b69e20f08a43a615dd0b1f30f490f118a2d47957aa430cdf916c5301dfeeb88259acdd717b46b54f88c6b53223fa3d613a6cfe4dde8427660e5e32db3863cc4a8f4d9e636a813837c37687a735554cad0ad0805140d006726e561554f0c5e4fcba6fc7431fb8bdf3f6a8acf077820d2f88249a34991128544d007f60cf801c9767f71c68a7b83cf839a21e139f31d0328d7f9db8591a2ac00c55da74985fd283b7d28e99444f74c80078445826e4e2dcf3005c92e23d402fb4f71a5b06829e106711e33b0e855a0aa1be6e24e7e564e9a9ac4b5025e44986bde1728a9fe5b1109175b2b1c9aa22b78c7c600c08f5a8decbe27a6d61677037aa02fab8e06f382e934a16adc6d5421997c130b4ac685b936bbd08f9edd201c09c8d20e2f99a698ba43715098539419b28de360c5d3f68c602eee367b5cb81f629b568d9b7ec2e864a9587af8dda060e8ffbcac85ae2aa17d1a6be234e809933e665daeeeac800a9cdd1720a1ada2a2fbc876cda7ca8e8ce2dc9b7e083f04e2601ef24113f86f6274dc43edae47942a32cf3de51489504700911b4de9757122dae04782b3263b4fdc9c235b01edd27452784c7b8c123a17a5faafd734228fa1376f4be994fe2e4850fd4d66a09b3c89eb9c484b4d94a4e24791c381e237ef5a5c0c87ff7fe1bcc72592a1d101b3a01f0210cd16add5b84cfa0e2fefa952c69d2b00d424ec1f9b45776fc81336d6bb947a06492c7c040bc26fd479f28a9f4e0c6e7732612411b975e48421252d269f09761f71c46a3ad262844c4ee0443eefbeed23a65360827198253e6227c575364db918a2b33f51db863c3bb56c2ec303c622c0de8aa180d30a7fe2a5b9d15e2b05490fae6ebcdfe7b712787599833056beec69c016947e320b80aaa8bc546639789cff24adda059b11a18be601b00e66ad20ef3f2a501c99e323aa1fb9a73d9f4aa500451b194345a28ecf537917717f005504dbe77dd6f6e9c2ecaf45945019a13884a6d95966e38b78eeeec0033f0783a751313ef23f7fe38d0b3823209b57989bda233c5b0a0451186318523a8c2fd861633e2ecdd80bd19f564f6f1bcfdaa48bd96586b88359a06e85dcc74f114f13ef1faab55e47bc2a42127b382a80dd069cc84489771485b2adf35d83ff6f1167bd5d9a04c1ec1d19fa9ea3d9b488f56633cc8fa33c40701d3bf29f2e01e95ecd709155cd12ee163c20eb5d81edb560ad9a33b666ccd22d96902bcef9eb8799fef57d8fa10c55cd1a1b01ce51d24404cb00650780223e33ee2424ea5a9d02c8b2c8eeae8f55495d4814d1f53654fe90ad397075ca957d9ff8795a6ce6f84a8f361508ddff97373b19cab74eb535e7e55a4166867195a735d09c213d16da73adb1071b765f008d3aff5e36f9514f725a5edd4e94f1bb4328252b08e070b1efcece42fed5b02ff93ec1b75442e0b1437a0399ac6f1b326bba603e6734cea1a65970006e7c54604479a190d44d83a1fc7157b6f75da97d6f037a42f389b44b06a28e6b22cb7e42c735fb12754b5f23c91520c8518bc7f7f0e3365d09c17724d14ce78fa8dfea4ed83cd9eb726fe9c49b20d90a54e88af097fa499c074cca69e267a0783b8a1346c3724e5e6bdb8262fad9642ffba5582486ab5c2631be8f5e8f81d78f7011678e6389fc1d2cca6b7a9f865178e8c330931689989fa4f67e0e8bf6d4d609a15cec7667fcda77777ac1fb499bc65a89d5ebf8bdde60fdd0f18ceed58f0e9a6989719c4591f179fd9e98060e137967563136d527bf4c3364170535a8c829c2dbdd8eeae5522caa7f5671df49398c341408a28524096b13494a2d8223b2b93da2e7117a2c84bd6308bf48db63b29c7fe49cb784c61e7ebf6ae9a8b583a54313c36992f17847ac53e5dd0aa00a65d22aae982693089cc6f87e47734ff9f8353eb2716ade2eafeeba2f66d0bd0a22c8ea12e9cf96f9aa07c0b8e5b44db41660b8a433a7b3cf5f88af769d38e2ac82235ca77dc849dbdebea60b1c575ea3594e1351ff59a7c57003bc4193b0b1d4868a0f0071ffd9304cd0bae8aa5b42bf3d852808be411b19cf8f0ed6ee5cf97c1dceba9376bce6e0afff58722972594cf183488bed9e068bb87dd7c049ac03b38d1b4bdba800cd0bd62b76a47abb90cfbf6be535739d95c2ea574d53dd5844afafb1cc58da1be217d0f9a29bb3e650d7d891006c9966c69b7adfcda7ae6c2e6ab43ac013d6b92538bdd096336ecbb5930d49194a66c32a798214cebd597f29fc70db48cad72c5fe4e222acaa9445864a5c8c9090c16ed394969c6b6eeb474e898f8328129cb79c0c07a771c67d882d6d288887bb2b2c183b601383072185e720bf297d3d0a836f098370da34dbe39b9ac3663ec0c1481359ac163075f2c3050439b5334e66fa5c0f6503aa2bc45366da5c040e446a73a51e23fa35823de29c0aff8ecfa969cb4373113438f1117a4053df17c937ddd494e2f528da0566ccee87036bf7ef29a5afd8e31a05df5ac9c6436e7d33b1031585603540e7f08ef8d2a2e38135f23eb1ff087900710cdcf3e824cc349dea58d12b7b43e85b0fffbcee6e49c6fd8ddfdbe167650b7071008c094ab33d7dece6416fb2e089546a655dca3bcf23d9bcd81fe0b55b25c0dcc4c2974cbcab8277b89e8b72e11f1c9c9b2f4daa67a4903e0d5a64675cdd3af8885c8b121c79139753c024bb3b3f3cf92141e852df66260c2b7ca2b6b9c6027379e2624a2cc2201e11b76ee2a620007c087111839978d0b994889b3d10f80a5d788626ea023d7b514a8f2cb3314cce0e2ee9272cc7e551361e1896e35f5fe178182eb9e08e7ca7a7d3cfdeeb9c391fb724b1ce57b8c609887db7aad8904160fe54fc8dd7bc039468c45dab9522b81eff69be3f70c1d1d6ee8e159d338606c37a1225941cc8792adba6f26829095bf07f23e0306f94508bf1ae0797fd135d72853107482855fdcba88ffb12babd2b717a70768f735ae9c89a6aaa6f23453d373a1898609b05b591c50822878430bdf37b5a3cc35cc8d5344d2ad1b42b53c6dc78e36b009443b22b84e64a7d1b18785b1d73091ade3d3c250ae1667a53bf9f91389a498bc98e59ff28063c20e9dfffae2f05521c3f1048439e5fd8017916465e7307db8894e3ade2f9ef285dcc59e0a1198d29d1f7e3f88af358b7828a901f5e9cab22fcc75b1eef077a6dcbf59360822abbb87b6cb47473c5290e3d3cb2db9485255f0ca71cd7d417eda80e6dc1c0c6eac8cb280605975e825ebc9cce60f2d41726d68341392c9089e630b5c141a9c508ce210846ac723f06bad222f1d2b98cd67deca532112518f9f88f583b3b27afe89ddcb0ff201085092ac05d6522c6124eafb1c2d2cd1fcdca3295bcfadf4073c6d1b86fa08b8800dce22ba7bd18e3933c49c8f32114b6d5e36d14360e382481cab4c82c6c1053cc0b19f6d72cbf293a7bdfe009315df00e7273cdcf06f50f4c81a3caf9f8ba7f3e9653fb7990efde1cbff6d3da7d9626fe420fc05edddd003e9f16d1271706d57c34a451681bebfd6642c51beda0d11fbe6cab57c43232acf93c804372f7a48308c2fdd227669dcfd5a8015442e7e015568164f911aecb6d1f2a2210788e6db815440b6f640386833f37ea33f0cb80d7aa61a6b78297369a712071d5fcc1451b19841ca4ea902fd1b5642d7c044c1febd00a99654592cf207fd897427add57b1686950d373fc38ec6a58bfb4c3f53700f9b2a407e6f69ca69c0d1c755721278c49e94de252046181992e94b351fcc7638618115f919d1e5db8d308cf0a0529555dec2457abd298c0255cc95bb8460fa47e57f2ff28fdeef2d9922528648fd2b2f4b82e7649898d34d6478729e27f4fc214bc34290204b57cb81639b882b2959e4ef948f8a0bfd9c3145370fb8742d017d8cac1466dee82fb2dfdd1c8750607932e8fdaab888d2cadcfc0d105d58d3b5a0ddf19d780d744f09575ac626a0975bf8fad3e08a3912c00da1cc445382950df5b9284ba7fe83c3f8fdc8d33d13da14c09ec1412f28c810dfd1f1351f452544fbca04019e859a4770feb2cedb15d1e55c0025d838a84519f85e25a4f4fb280209a671104acd2de0f35e6ec5db2809b6cd0531ff13cb5045c6678ada11a72650ad58bb1e9f7dd8104555159c9f83bc9bd2fa7a5705074d44adede41221a81116829d357696579b232fad337d3720ad4e0d317adcd7fcf82e116bdc85d6656880674fdfae1508b67d21d1c3a0c71994cb4541ebbe808510d4a44744142884b16f6a2ff3c383a634fd26c59f9b1ed8bef405fde4df529a90ded9eb57f6f073fe1547c5694ab228b89dd85dcfc9cf82ed840e4a00c37365897204f1d75991431961bba7c33b3350f353c0bf9fcfacf272eb9b5bc6f35802708288d00fc7f6e76d6db8c611a564075da14f5fd8ea529e87e11185463d7dcd5542248f8a70748b3d0f60cebad30721edc0a5c4ec1387f06999abd88842ff162b419c31a613bbf3d56d05e1326fb8ed91ba21702ee71c5325b5fdb3f3a14ac0037b4826c8fd5adcef56e8af8c5e488863ac55b05f32da94d9591ab0de44815ba28aef19a6df5d78b0636a0c5637326046bbc3beaa25ed927add3faaeb17ca750e82974766c2613a9175cc7bedd4b4a5dde171a6cecdcfbd801fd73fa3749d0bb98e2c5511e40c79b21b1055d36c1f2d68b9d914bc639cda3ae6dd9667332e95cd2ffaf93bf373164afa95dc211d31c421fa8bec2c9f7418672c50f82f2cf934722214b637361b87dd1a74c678bb2da260bd804dcdd0c669eb0e23f4aa0b682f425a22c8ac4a6836e8c11376b2f11f004cf87927cfc6a5d786bf67d44b4acf976a86e1437e9665eab254473fb0dded2bfa1189463c538506447710427a816289e5eacbe61e7e6eec4ca9f8532ee7c41db22fcb7429783d96b495c86fd5faeb250ffcdb6a7e476a0ab22b95f8d602700a9d7ccc6f2613413a7fbb8fc02f3345bd1fbc92b1e01d0ab3db11b47eeb4565ff5233a29449b91d1ff5b59035f12404e1f6d18792d543d970b24c69b37796ca962d2cfab57c8a878b805ce81f121821ae71f130ef26ecb0ef9a08376cc24782512e0471a3e124ebdbf4a0cc829c239161b3cca16327870fa7fb9c1109f7c2f028844b379fa7dc08e4f94cdf72a2a9ad0748574f31797bd93cb5174459e86234f810c7c10e8335e6b3940ad48836e5dce6a53a3ba5ed6d35e2de68fad8e8f0a0914e5c974e5de195cd0d36dc8a1fd364e37cff76ec29ddbf8da3347406925476c64ced6c35eae0e4f9811f6950c5d7dd697cc2562a1bd47e44c9afb18eb2388d2a656c834fa277f4439a0bb8bbff01a6d491a4c861ef778b2a9444a58282a3f434e92cd51e6fd9fa492582cad7ba6d0d4ee7da43fdee1ee59a2ceb6f3a4859fb6d4932e19f31d417fb1edcb6aaddd9fb42e6ab2de990274a370639c37a5da5ae17df9feac33f2b3cdaa2693f8c605acd5b993d433563cb8ffb47be6c10d4807708dd6d5b7e87ca5873f7641bb4f00164c8771d9f69fb3f5850f981c56847fc607196f9de6f2de3a379461aff68393eb95ab5acbb014f584afbbafb366a336f60304b74401d6cd2e114ed65ca77c2bfb8ff8170c18a7f264a6ea49a32f964dd58fccb420efc8fbb4af6d4e1aa65c6c18448d46d49510bcc43bade506c13cbd2af1cdd642b2d652c5dabea91b15dbe313efa0f9839e84fae0736518d2132a5f58b1eb672e3ecb8654aa5d6db1b812e5eab5098a1dbf3fd9ac851eaf3043f80d2e5e5ef795ccae25d3b62be46c498ac5b6c9f02f36c3e50bc7abcdae15ef7f78981b9ff9a19baea81175f5ec680a265e4383cf4959e0b5d34e31310ed66f83f82348311e6c4f995a732dd0730b9a0c3dd6c98fe0a0ca8c3686f4243c2eb41038be41b745a506923fe8ef18f7d4a300e8c9660724df5969e3bc39874c7c17a261392ed7d2813db115d4429726667b95cf9e406a8fefce75e91b6b064cfa5c1cbfce039a6767ab27120ba8020552b3d0432cbe7d54d78900899468df7a001200bcc29b708d51292c31492d5ea5975b1405cc1205820e8abb3a99cc3ba45fb87bdd9b54b7708d9f92f01a004a5f59aebf674098c9e3ff60023727bfde0a93d6a8746511f7ceea39fde82f6e8794f287080382fb3005cbde15d0043de85f91f8b2c8a2e233151a331bcf77a971d6d909cb1b6ea73d0cf98e01642de4c708f86dd62f9df15fc7547126f4f8b12f738842295bea9b253d83c45f5827cdfb73b71550d17e33abb4c3d52a7a0e42d3c96647bd721d8eafb3352108c153e59b7245cd27f6ac327bc16fc75a9f6c2325c8f30fc5a1deda5916833e8e030333f587b028bb4a6a7eab8a2afa91d7c2b23802d69c031a2ac9d5a2ed900ad33359e7bb6c5b3ae5d3e53118668b077d6f0487ab77a22c9dc9435057b8262e618925abb73b1d5795a31fe534054a310173eed95b44e478fc7fd654fd28c31873904c2fe900c48dd39dc043b619e7552973c3033f5c8535f7d438f0bcc1a74dc326a44655962690e8119f4848acb757ef85b49af71eb52a72e1e9d1362845dff8a66d107b2f403af24b0a8605317677421ce9193f9874f3ca143bd8f3364d9507bc2bc64da80ffb7f830a6a02385f950234e7d73e0f334ffad95393f51dd318e666030e9b034d5e731dd48ce3038a71d645441cef55e4d875cc6b4f92b441231026e7adb0a54e73a2ef4be7c262462cbcb3711d7ee60f673b9c3fb0a349c0db2164357e7524922d7d28a61a19c275338d67be5074cdcc415be69df16d62aa0c8f0a21e3c2e5521c72eba6b53256caf7e1dfdc2f45310d1ec775bbc617fa222c43439070222c531f5f3a82a394fcb3619b1720bd6d59a48beda3e7f86bb08229565ccfec0679bd6701a1c4c9e7194fdf44fb767106a4473fceea48ba458fa78bfa5ae9ff602935ca07c8434888d5535298a55fe77c87600b7d5560694ffd3d067b2095d90826516aa4229f5a806f44a0d5856628d9fecf2a84971d66ec93be7f289411c33301f3d82520b62dcf94de82494d91656e2f5cb33c3720d21179be5563ed49e41f9a6d62899a710cf6c9fd6b5e6594d4b40367ebd5ae1c2cb521ff85879d8d413dda6e812e873a63a52e187d6b31b8c8e0b4c11656e9da253d5a792f024a8eb5cc4ae099f60393bb31246470b5b47d87d1f51d01e4da4d0476817c4a0fb11311e82e7ea3183905c0dc196f8d44df9476bbe15b7e078c8d44de1f37c6ba4b27abd4f66f76bf6d022a56e9005d3330d1393fbc9c2978cc8c762bf8b5c1dafcadd6e4de4191b38919e33d2b0746bbcddafd731bf06c7df372929cf83aad2eaa70071ef57f9cbb4f1a4570a0d4870d67b8f31119f30c9edbfc9a371b7053bac57139a78fd4a37a4b0fc9aa08f0811482a75856df8f9a2f037eaa897237fa4421e7f03e042fba1f9f22427f1a02240f9eb49c73a407603ce3f830031ff3a5bc4b078c942de27587fe70b142644786a55c2c747d4bf545e7373a294e3173f787c05803195e0d41d42be0469613ff70faf3f708fecc95b51d532334a6304f3fbc03713e0cf3efa616adfce90c675630459c2eed394e15b8c3f290408bc71728c2fca0c8e06f33e795ae04fd878ac07d6874702c945538f9c81f0835a1ef9645f83c43244d222777d99a3cafc66a97b610789f84ecbe7e450e9077a05ff99bbe6dbd1cbdee020e85978493dbf92eb4ce2198fba993fd4ba4492806112867b031718c28f8fba6f243e8a2a0d010d928a0d07707f11fb68ad7f9a57348d65d77ce8d80073ff73328526c8940e934122eedb85be89854f9fec0be0cdebdc68a0e65b77af1f590e5e78a531d78a20edd28397272fae83df20d8eceecb33f5fcd3c14cd983d1a11738290b1765365e4f716cbe6efa473fe68f581c89e475f206af836d5ed313b0ebf851eed4d53011701b4f034225e3b28bbf49fa1b36c481719e5156317ed38886ae6943cc5f173cbcfdaa07e755c68614ce18e797d9105386e6c00310f3c70ede20b0861bdfc074df6edabfc1cb132b57f10896351f96f15726dc9864cc7d1749ce87e877cf9ddd9510f5e500132ca22fad936d049a83ffb92f11d0871fb09370679123ca76f32d902587e0d0d7c560b01162843c3f917051d1559a76d41a3c9fe41bbee3aad4761720e77d0206357f79c0673f936ba6a50c6e6d11e4f43fe10705d38efab2d28aa92cdf8fadef7d0d1a942b1408777b7b695965c8e3512575abde9ecbaa2aa830b20b8ebe5a6bc98a6b7251644897978c72fb43b412e1754e00b0dad96c94c9a10716189484386c68bf05656572c5d57db5eb6dc065c7ac5b6f42c8742e53dfe82e8ec08132abbf8e34e0e073da476681c111932e9e4273c8fb8c279bc12c98f00f058a13355ef9df839ff5d79a31310304eb64b8d0f7f9df42c81bbd20ef0797684f6bbfd4ff3a02d3af4cf96ffaeb42319a24cd7dac0433d171194fbd9b376152b5bdd6e916530e91549b5e5556880d8c8ed7a71c08b01942cd7ed157101931ea26738f769ee3f18f78d91314633892191b87c68e2deb5956e20f95fd5a52891a99ca08d83a1885b9d5ed7a611890b71307baf1840a159ebdb0c62ed070a0cb2ff9b4b090df6161ed004cc6f91ea18515865f938ba35cf5359bcf47cc81cadf4464ae17f55b73defc3caa759dcf86fb72d229d04f4ec2cf0f227eb5a030e59d11e0fdf15a2b3de71d2a577d4885fd34c3c4458e93abee70edd23dc2a450b90b106fd7c85e6cdf0aa3348e87ff497bdc4e92fa9ee9627465ddb31c1e99ebc1fc590f995adafc707558fca5155c97a31d408967a82b791ba9e3d109ae936f8add0242e3277b0c1ca8e5fbe061b161c37ebb2ed4f41e926b1f961ece43b22071e04425d204f60fddca8c80ce0ac953d018d1d8f6015fcbd91d42b00adba16e8bbb07426cedb0b58920fb7be5702620c9b25e10a7e122773a61c0fe54ca4851d8830191d6458d2d01e0eeeac6d4a530e0d74e68acdbbf7ae86808d9f93dbaad9b48abbe48a57592d32390c9103de1487761ad4230342568c2a9bc2e47fa98c751a8371bb9f4ef2b7d91e0407aaaf2efbd77103587744612eae78ef72060f1ae4f5a46afd6d1974c4748b8e1efc011c92bea3dcb6f3ab45551ae905ee89d82f63f0f291e2376a63e40e78301ad92643da39edd71f278b05e0ba76caacd58ea47f40f1f8627001a144cf782b0ea585ec4358b96009efdb73ff066d420b53fa26e971d4018cf2ae20f83ebd3b1bf8a9b7af3c8d4fca34039d12a58e7b61400b9f9d4a8d827e8516d4aa38af3e7a0138c73b8ddf120fb4d58a7851ee5e0441860bd9d57969b658f22fe5ad28bf0bf8b9d81e049a1b514f88fb0a6dd6a1c435eafcbd4f56a7bf24fd1f6726cf269c8afcdce8f31cf0fec0737af0be934a8281f9c64a8a6face85052c2df559e3fe5663f250ae074ef448bbd97ca72e79d466a79261d587c7af39a7fbd16932b372539b5f9e102abe3239801294f5243f30bcdc156b02e6a8de4c935bc97ec57ed387873ddd2d5a9708b0449de82d2fd3f39f4cc780179bef0b0aa723aef10484b2a0756dcff07b959033a0aa1107f3d18cb4a740cc8acdd0b4b6e07be5c49b21b56edfa5bcde8a38382953fa7992813b6529fc7f80c20350dc70dc8cdab3fb863e13fb064b384fb4f751a66345a2865d1cd0b4d3e337a23e0d7bf88dc456e7bd848bd614af5b931856c30943c8f3a2629e51d20c7c473356c9ce26e25e1f4b63baedf5242cf1561af5c8daaa370c25227087d082a4d188a6ff08d3e0551f4ec8371b5202ef2814301400c1d9441bacc99fa1c9a7b7d915971e56f7eb5dca068ef8983bf1d8909c1866bb0947919ec5259eeb8013ee3dbb37c571063d2192899189cc345f18b76194f4fdaf42e6759b359549295f4a1ac162becd69b671c69dccff10a81a219050c63e700daa7f64081a6430525cbfcfcccd4caa1baa3810e15a01714656b74dd58fe7a4dfae54b661172542068cf245904d2ea82f8ca9684d00698769c80693d2dc6ebc21a91180ad973db2c49319d821fc4c1c815c58f71411949eddc820e869f578df1da04626cfe3b58e4f55c6e4bbd98a890adaa49b4e53d5cec95f14708fbdac4cd5f2608cc488f0f689f7622b4f4715ab255bb92287371b19e1704b7cd1cc2391a6a506fb47f2f5041837588a7835a6175fe383ba5c01c4321579b3df1bbe77f6fb6f5c3781e4eb74d23375904b712f6a7723005eae68db8ce24dc80389214dd527226aa2e2e4b904672bb2d6465d86d206a7dca785ead00f6d593526541f0a47b2357b7fd5e6a707afeb49d6d19f8048ee76a5ee80a2c91dbd3a83c6b9afd2e702c87b92818032243c58efeb0151f672762301e5f147fb503c2b70adf0f55df608eb769f480c82bf5e02e9bd8375302969e6d0c2fd7577f669769bff56f00c1641849f5f9650d2816e02f31ceea9f0ea6f68f983b16a2e694fe6db7cd8ebfd821996a8a76ce3948819762fabf1702f409837b3101e52fdfd0bb9ff8c7a65b00424ae9fe9cefe32ec9b4f2c951fd4e6ea16c00f922269fb693633673de842870dd80da7b10de53dbe1098bbe96a34a1a898fccca5c61819f5557f55c7574ed770f8f1b3c284df1e85c6455a5482a9674456fb8386399d14b70ec19252c9175af3d368a47aaa40959d2efdb6c5cf49aec4d33913250f711fe8c1ebfadcbfd71c2dd9d072dbb3632487b8c45c1cd3d69ab472d9a00b15d8d576433862d296f1b4d4776c13c5e7e4fd10c7323494a9a32475a962e1b01fe496c9212a2d7fb7cdcf1932f39929b098255f9ed2d2a3f75928cc3d844d583fc4a1d5831da18996d10c8a84af6cc66fd19f44e3ada7cd7fae4429c2c0c2343794b9da80aeeb7d76777aa97c428136d031d32dd36959179efcb72de3976843c85072a2151e88b8912794966c50237e45beb30067587116c92a131ac6623127f757415f0ac10b94f1f7efa8eb513b85d1aeddd3ab47361a672efd73778b08614bda074b5f4d7156c5cfbbd2c2b2d98b046bbf3cb2ed98f8002ce394386e315652be23dfe50d74babcf154fe288f7bb9d26886e5da59172b7ba67aac0f5d989fca29e9a4346dd12612c79cccd09858350d7ec13fca136c2d6f9ff3179c4c47377b3bde5298c2c4934f7cb7227dc57d5683930434d76894c8d1d9829926e4e365881589bb469f06247d17612365ec352dc753828c00761f9c54e3fcda2931d36b593c3cedb41de11e01599e62913136e54092efe65fd4e2ee328706405689e00ac4a8b2ce84c5aeb4087fab6ef4b064ae0eb3d8c5e904e36af38947d5703ff5d556d86275298f16b0c95e97251d9a0305c4aef2945ed5a28a298c0a679e55a170d06ef8168b87c1d5c647562034f93184ead8549faed841f7fbd018d3c6d39de2aa5410d7af8e90e6648da103f9668e56ab89153621448245e28e231f03af0fae51c6a4f0351d4a701958f7bcb4f52fc68e66b60cd0ddd7500c51f41a9a3650c1a7289dee09d038fddcbb8e32302d7966d77f0fd9b2b556ce5a7480380a81937bcc536a8eff0bcd3f9766b1969d665e37033e61978c31c11c5b86dfdbad6861f0a4116c4b6f9abcdc5950b0036c8c5f74c6fa8497a017b141726846ba45995395f95f682d77ff30c8c8426f31e866ba302d86300418719644c2ed5601ccd9ab32277ce7b0ceb77aeeb48a739c08c0a2cf97bb178642e97cdcb956da3de13262ccc53b40ca2bf9199d208298125f0ce0708d3168662752c7829f6f15db346cb09b8ea9f27ef65deb2bd4e3992f8d09ad555e36799549971c30ed81f9ef37606126fc50a62e7439dbf7bcc69fc9a2db27ec762f8848c7285ba1da7b28516127745c7d854123331e8243f59fe149149d9c4ab260aa819081d7ad37f3e4556a9ebe418265bd2a436d872067bf42034978fc2ee01aafa567840c43b98299136fc67d1abf33d22541c6961031d9588fbe11a5d77ef045a72477ba2df0c683eff97da2f5f3174b18f10e8126fbd57b5d4fceff7d4d5b8d9c707388087006c0610792b36be34d6d94eb72e995c38edc87d778f57cd0c6d9e9af5982a283fab32585ad771182349f7a95dbe1d99ed488f646ca534c1293ed46f81b501df203932994c1cac058d13d69997296d92f3d32ae8eb22ac5abae2d7ceedac11169e97ee8fa4f77bcfe58704c9e7976a1633ca80aedc50c6af886c81daf8f0b443e4a26f7b9584f0b7fc240d3d04928d9dbcacdea3e6fcc234f6b05d44d656929d068bc85321a82067ae19ee3985389b75db4b29ace142e76a613b8af23432b66b103c076669d38b75b87aa1a737cb1b5b63d71ab4fa7c12dd7687f5aae2e8fd61b09e7f0a748c737162bd2f6ad5fc2981e79796643f91082c5389d8f9a2ef4992b529cf29bf9bb6eb781733c4d3076347ba9703d02c06957ff9430854611804ea15966ee0fbf84eff9bc381b2f166ead2a06b32bd8a270ba9e84bfb9f023348727ae56de5f7e29c6227f7a67a474645c23773103b72a62f27249baeebea51e3d50884b180dc47035437fca17850843bacb416dc987da66779dbec9b4280188067ce295076943fd69ceec4cdfbaceec48b7681434ba9ae3f8dd4263bc158fd608b9f6f388a43f4a9b1ada6a573dbc27b7250fb9e7198a181f6e2945cf6e2c96cd072db1cf7e92ce071e24bb3da72edb450991dab9125d16c20c140b428d7c6243ffbc3785c509ca0e296a2a58ea05ff2cfc340ca94c70bf7cf07d61a1933eeddfd7d129ddbf067b5deab6d3801124adcbe736930f693cef94d083c713ca06e72247a9b365c476385086982391427f2550e7402520a351111eb36fd6c02f1f01c1c4923a66fba05c9418a7a3fff90887963ed76e6a30c243e30762312b21464a4febd357113132cf3a694fc8d20689d5aef4fa3f097818b0bdb87e98d2240fc4e8dd845e17ce9fc552575f3d2f3d853055f56e79902f269d73917dab629b10293be4fa2e85619880c664f1bb9bcd29cf37ec792fc2f6a15e51229f52ff473079cd87198428047df712117c3b729ce2c9e48fab7a60907a8f0e343d5c8b21ac85dc3b182ef10b005aa1c6e1044c548aae5a31e6111d84ef7f3f8b5cc7caf03b0effeb4819a926c34117edf6f21f15af012e3c72553ae928cab95a227c48f3ac928fe0c886d60169d2cc1afc086a21e3e137bffe65477157961a9b3b174dc58fe9b8473d8b5f73f20f656cb6a6c5e668fd61dfbcf0d8fd12341a54484fb5154b5732ee507c4540202fc53203499c8c016e8b7e8057a196e0d564fa3bd7ca05cf36d611dccb3187225e177f97b5c7c6ce3270260458c89cb3109af83631ed263d4b7a21c90093edbad93066842ec7b8649e18c2764869dc335df0029e0fb4f970bb5a3242850a72205e73dafb583f6943673f0981a88036bf1431434e062116c7c43ae9ea05f66e6338275cd93f7ad3ee558d36eeea4950f57933e46ced2db14e8f60f310eb5a1deafd1c9bd74166bbbf8aa4318850aae4b4e7fa7e1c1c6019af87ce30c8c44ae52963234f6fdb2023f0690cb8cd3742dba92d34cb9599bba646c55f309fa55e53da5381860c097bc5d43e0d76bb02ad004f5f0f43651bf348edf5f5c3f48f246a0f1c18a1ba715b2cb69313de50291d21b00b810e8f4b3d300413193ec1749a0a608ee317d93cd8e31ff06f912a9c1ac205a6715cb3ea3222d2a62e7ac5dd28935d6e5bf73c69d455b0961ae764f1fa11f2f85a93589d34a1f9960973c22b7fa2c069870941947bf6a30032f88a1ff40a9b851a022020f32e8b2e8fe6cfb1898b6319cb8d35be96cfc8c81b85c6c5bc1481f7ac2add3a5d8e1ff0679f6ac5cb58afa5227d356d72871d5842fb7a003f6827dcc3bca3a4383bd4a8af5cbd8bec31445b7929364e84da87471ac06d4097c6cf165d3541f766488aebaf0426728519511c0c9b008015dc40cbfa1b3d20af797b363e6d198d80873d0a6b5c56400ddbbddb81114a1c8c06942257f8735605b13262a5e327412758b87814986b7df53c555b3d7e438596a93a38b8aa6826aa250219425b44ac8afd42466779a1baf38006fe0476af7bad0fbdd2c2c51bfda2f66e86640da3f162586e3c21bdf66190917aea61eff0e79300e5759960b6a9904975b049b1c18e8e9e45d7fdcb4613dfca336b0e3cf2797d8cfc5a8b454d02bee5483da8a5d5072daac1aaa6f7a706f23b005417076a4107242b7b6019be81b9894a7ec991035e633e553918b1842664f5b65975c62bab7a294c276d790ca3cf62fdb261f1951581a8c285868b5b03eaed4c448dfaf796c945137def734820a2cdd17b6e3619edba39d03e79c9d5677119fd5474d93d7c2ece1c4f5cdc3385d5fdf6cdf80788a193104c4bcc4f95322271173e1626576a3e9bbebb9e8d549e2ee9d52db61f3d1ec99a260e79bff34af101e975980895cc6d60785bbcfd7b0cfe2686d2e4d7e0ddccb2ca09c24dba8520ed10f7732698d951b987f4d13626dd7e43f8cedd5bdadac5087edbc0fad4c6a1345cad7d7ca1940bb91623cf646050ea37ed96e58123e1174b698f6d96c2b2940d7816efd2e457ae6edd0a83d50fa4990cb049993f78ccab1c6b12b0f72888247e12076367a4532d0b9dcc048b196a4f465519d0ab7286e91b8358f565080ee45f38b9146cb6f3c16c392b47b47f4d0b3442fdfe9f00d6a2b5b66b95e1fabf4d11442325228c1da885f1fcecca8ca4072cc88ce6a39c200d20e3d51a7d509128ecffee946b8d61b037ecf09099161c0e3a4657147169f762cf902a7a542ae35a69e2f08ce953a1c38e00c0aa5680b0e1520902009b8f6ae11d60edc2f8e77d4a3c68b9bf49378fc4499d0fb9a800a30ac82d8d64cdba72263295136e651c09d255fdafc42aa3434b4e1b31ea70b2a7ad599c910352f39109625cbca90189eaf3ddf143f0c23519d46f1a3555c3ab8657200a7f149ec0728fe3c38c143719a7d6acb730e17d8846ee76312678bd741c2d1d09e2eb562fe8e77381f06837df03f51e3045f3b2c8f0444d3dcb8d022a48a7efcdc03ab90d15fd71615799fb0f154d795c0ba891026d65d16644e224a0e8048d6ac24561efba6f966460867fe443c7cf08ac5eac8b6f939c611b8e8f8c83d22daf80b40c7d0e7e5d4fc22108293e17d75baafc6b50842898125dc6ac770dc0d9d30afe1e43d435c1e8a2769054785398b6e468c3cf75e5d692ff116c2780617603d2b77ea753988f3cf901b21c1da6ad91b0348ccd032886a860837074bde5c377e4aead8a16254179fa454a0e7bf81b1f860f8fc154a84457e8d2fc496492eecc1786846f44e2ecab8c6be7c2bbf93c3fda39958d7eb11a53586d98281d2a1eee229ddaa0edd96ac4bf213ddbfbd6f398a886bcd82e07b9207c78a4a86abc15b650635a3f860a8a4252dc79ee0f45f99695c9cec46c3bc0d94ac0580a4def4cf7d69ecad3856c517883bf535d5b5ab4dd5f57afb150c5397f6b42dc1f31d6b98d8b0e47afbe4d6c5348f3d0b0de1bbe6a7b103ae5267ea1e7c1b4e7eb55138e1644d29f96cc83afb3dfa191601568c6d61e71a93c1d210e2d2e5d60eefdbbd6f1e790f2dd96f6b992f2a90c7135346ab047e339c9a3b346e385bd2238449fc9b56a546291fbd045c6b18a100c08950e4cb0579602474a37d43f71cb82c1cfd79152442abebd05645c449aead3f44d6eae34b9c25c66eac56bd4def5470cde54dab269343d0b79e2a7d4f5ce9314a916526abb24cffe1963cba691b4888b1f02779965406979a644739979bcda8603446075306921c413e9ebebf806960075398995d93b7b568ac6e890a2d96b2392d507329afc7d95ed0456e12e5a708f4f216a89250ec2ef887136ececd3911dd984adbd26f807e2bd8486849b120035d5a541c6313b85604c0ba5165e78ef600f307b54a9fe4b4959a24efc231294a6f8b324ad5095ea0e601e5cc3da67c26fa3369e2110ef1cba09709d9657486f47af47b6d363ed4791ff977571ba70ce6623e5a29f9648c1895aeddc2a81cdbb3e0ebea1118e09ec98bd99514e783b882b65dc363e0512207c845a044f7a95017029a8c36c81a24964004695c5fb655bba63a27d1f660d9d76975fa44126cc824a8cc14aadc23392585a78a24ab356677aa01d51e2289b1828f4f449d5f092208a9490b3d28b81694700456a6872e52a4fb94f2177514a2fb862f6c4fd9c6630b5f4682c135c92dae8dfd01e62e7f3971edd5588b9d2bae7a30fcff252d79f61cf9a243bef4a210deb47fd3192b23ea138d8b7c9cf5d64d2cfd68f72504f530402941d52a98083abae2bd2dc3c63e5798956847c93edc72ea7a8d29257119733a3927cbbf28a7f1aa88379be9ec1f07750ab797d6346b5cc59850541c260d3cf2916d6713276e6e30c443d0e5d3a5af72551d1f57bfa7b84746469a7376b99291579dde382766edff7f3964d62d3115f0e8e2aa690378cc4ec2e0ec9da63b925f1e3110264ccafdc2a491a2ea95269225d725c3ad9c7e60982eb38834a070217975ec447e0fe0cf809e3775a85e3762c3c4325c26a423254d388542cd57b6bab4fe6f2da54cf1435b54ba4846a873f965575de454a12c53c72c1671b5b306b9cb5f2b816ccea46e092706d3fa0cbdbf99ea63f303d6a5eb940ce3d320b5b8ccb0a54ad4c87e12f2f2dc884f7d4bfddbaf97389ef175734f385bb1b1ac66b95d64958db3420abd58f639eb58672bfbddd750de7ad1675ff014b841c1415c5753383526eeeff0566c4a0e25192640752c9f487d5e1f116737e83344d8817448dd18d570bdfe9b6671472d26863a28b8bf4f103425ee20bea74de42b7c8f25a554760140a4ad2413f1663f294515d2eb5b1860e3c78903c6b2e83f919197650b2434d88de37e52d77a88819d936d2d79da2b405a7ff28f5cca224fa06ec7ef41a219f67462160ebe9d0ab3d272bf95032c771b224c450307e90ec6ec8fb628ff6833033d1291f9f5cd822772499a4e69076a8ba2da3860249b1c3351c8c6dc6ef725a0b542048fefde0f725721c3c1cdb65f36103ef86ea7017dd59616d84a52c430a603dfbb943d57d00a5acc44d4816b5d1d355631cccb0003a3f557ac5af987b9ae7ba99fe1f933670bb4a38cb916eb1c0335cb7d092969e9965f1dadd0453a1bea8c88ec027349e06b0f7a4b7274a22d53da359e5bafc01a238c89f1f11334af1dd67367ba8b226d24e6180c0366a66a7d3daf744a845e9d074d561212a84958d187f3b31de8bde5f0f78ea191bddd634006802989d81b4f1d9b0a74a3c6700f834ec111b308c3e2b1c31f5653b9783cf55c45db75675a6c0f6b2b0b5377558f4fe55b39e31258c5016a3e0b223e592959f20a086655e08680817f5d7b84c7eed93ca8ceb02c60aacf5d4b3a574fbc32cdbc434aa4f095fce4ca9a10e532a03d39a62b6377a8e97e44500ffc01c00aba5f1d429cb9c6637684586e5da4d277ba1c0f4f2aa084abdebbf65bcc2a864cfaba3f34552b9c557a206f51011869a80793989861cf697a82c390ad12d25846dfae9745c92356213413abd3e125c58544ae1983c1dc3f2989e9684d0ca2b7c311a8c99b4caaab8d24b210f6a4cc227be19d90028e2c8e4705479bb5b47b1e9506c25f1d2f42b6661f0f0c0d21bfd6d8156a5b95f36b20bc3bc683fee8a6b7d1e55ce1443e7a4702674e9ae2692d433390ca7711cb407dc3e12bdf391a3b21f615849dad25ea44376610a50a861bd75db8d53c375ecbc17689e1db58aa97e799aac7c27a79c5d6a4c3fadaec68f5b4a23dec4f572d470d280432ded8c5dae654788e9e602fb549effaf534a08c6504e0c5e303d5a1278e447309c5ece014c6addfc5721f624348d545e8e24400419844676e81b2eede36d6472a37ba93502d9ad1223b52f028e980a150f4f7ba79451d7a95a852448c28f53bd4af832ac31463a14fd6d43b38d4419ce8501179abde486c882d2a0fb0ef8b7c4771dc7b4c9060f20cf6abc5c6af77e6b6dbc79714cdcedfd1e41ca88549a664d3dd57021c0d2ba52ed63af5cf91e729b6873e5c66987e1bf120d2652826845c03faa7692c049675430624b26dbfe3486d83bf287a01217839e733e35fb4e2484652537c48a6838ca49bb5604dbbbe72a09cc46bee25fe09106de34dd66d65240f728bc153aba34a0dd8ab8085d11443a6f23b1aeaa71a157b47e73b40c2fdff265a772432c2aef4459c155422f8f1c0c9349ec195450fbbf2b2fd6eb286c60f698a84a1ed5c80706b7a9a385630bbfa4d1aea6a4cbe82041a84f383d365134903518fac5b3a3271ce4521a19cb4378162f6e7f115dda122e314db8d122a1b9b9dc74d784222f6c1052ef4e7666f817ae13fdbaca6efa7dfc63cbece61fe6b70eadafd2385ce869a191b3e76ef5759a251743343a340764d3574e340d232c8ac149ac7831ed70ea886c7aa01dcc1b357a47cf8789891331e8183c12c04b6e513cc67f6b737d2bad6893006a23c8a4b0552f65dfba9d449b071df177d3098038d859acdc1f91995e29ed58aca2af82f1d4abbbb7e282666bc2fda0812d2a47ae6595211fa16f5099e441704c7b6eb594ccc324a002ac26aca629205328a70d111479e8d3189432cdadbfa6a30b4aa592ef3c7c41ac636bae88133f22735b5c1d6bc66cbf032bd3e40bf1899a80a0115ae2928dc0c59ff1bf2f660acd82ce937e587b1d2234a0b7d823a36f0a24ec606cc639023d9f1c11dd08c393b27efa95c507b1022d16847137cae64625043d8376bec88d0a593419aaa0511cca29fb5bbcb0472d05b7aa3627e4d0965daf4142ee0abd9401c42bac45a65e2d7ac171022654f3d3e00bca6d0ffaa285f738fa74ff45d973fdceea3870088224341dd63d07b6b178bd902ccb8d683601046438a222ab6a2e2963d241c783d1bb4e9268a3a11909f0a52132d68b77b80afaadb957940aacef79273a4616ab16a5f22c276dc76a9a809ddb85b32a9a9be1e613e221f35f1bd0ad7ee52e31c00f0ea6197488aa2a7b7fbafc6d58ab6495e16c574948e8aec59e7b1fbd086628615fa58a4219b5823bbbcda100d0c393f1610026062a5c82d2ec20d27fbb0716fe661557cdbb90a4e6104fe93514e7302f9e55ba257c683b236527d9248555d05bfef8c8dbe18c642a866a92f920b89a972f3db47aebe6a431b3108f60171682abc3c12897a8a82aaf6b3366f1f87f3d723760d4f94672fcb2e5966def133bf46789af6c57e77d1f3793621d60e7544c74293df71fc5fe74cb230135b19ff209df3d5924e19ba9e1a5afc93dcbe3513a33cd9517ade5b196ab0df4e5632ba7051acace078d1487050bf5ca69198ef047430e5596c3efe4e060b0c61be36e24564ef1a11b04ba2a444d117eb9c06b6f06bd3b21b41f67a328704b7398012c65698e23372c63e9fa45bb9f42a26d1791f41fd0b73f089e02ff58dbe0cdde7e935edb0e1dd180755851bb301ed59205d877a40622207f3ec2591b9ce6f2461f6c52a28f0c6551220ddd493df8a293891075b7de8bfa94bdb59a42b6354d8d5f73516ba0b0528732f7108a0ae966330ea295ef4cc895369d8d2a40df907830e5be35d902fd5564bc9a48d2475fe7f39688070312d5a7c722dc6ac3d16a0f5b7dfaa2c0f2fb4e48a7405d7a8ef3f5708eef0872aac0de3c701c7dc8056643b3f6ecd4bff165dcdd694790232fb061cd2a0d1ca000ffa8ba06e83b74c94cf1ba10220a1d49500fb93e45c38d41518ba8f220ca71f0add91236ac5fabdeec1d156b5afac723a076b73bead00f42ca3a7bd8556b13494a17533e9bfcb423a152e6e4e96d5d55b332a299349b0e826dce374c246d63a53932e68c74c85eb643cc3b199e4db8ba06912843ae1ecac83ca9a3d7d7c2c4ce7469914e551b2c7772d7fcaad7ccae4b60540c757bceddf8652b5a5969e5401c5a0fbe7340d8f5e9193047a43c0f78ef850f68946000dd93c94d6e367823c9921476eaa7521f5756b289d94492e22b9922ad94d562738117f66f90d3c3bab6bfc12a9fdfb86a13904a984ebb6ced926142bc3082cd6c8b49a75647bbdf5d879d2180aeaf28eb7c3199a4efbe3e7e195f64b0f9dd77277d39f7449455073d1ec876f1b63b6c180ac7831bb30336de1e15301cf7d0f88ab1f58e0f331dfd8315920a9f4efa48d689a7230298f1245e238e6af419191da9ec5c9217810b114ce6b159466f2e94e94e252a8b9077965c9fd17078a0e5146eacea651bd02a2cc484ad7227b5327d8d515dfc8fc226f18b43493ccf9da249bc33cf753d6f4046543cdaf6eb77eeb27045247a0cd317bc0a1785b89ffd26970a797214986bff787bb774eefe653204dc566e066e0fa5e0c17eafc30239e8d2bba3be7f771d0bb23f0139e26dc94465ebbef7630556d8a65cd96a4b3a61724dcae20dd19ccc25638592fa9dd3a5c3f4ff9582f39ea6a0056dbe957ab2e1f477c1097da6e4576fa3625c8d175ad587287be6c2c2cd0da731a09bbd092383f92ed20a55a42c3b8182cf10a987dd90c84a366913ded30186b753776b5007f1d17c345b452b1599a96ec688a8e87832ef3c2fa7c5f2caf23cf6d57b9496357bc297fcc10730abda140b25343a1d44e7a44997458091b9dcfea835b581b6d4e0ce97c4ac2c010c6956ca7071733e6b07d1394fc0cb91fc2e43028b9c1dbeef924e3965c50cc6769bca0920d5da27f52e74fd7dfae174786a89734339808b56ceaf0b1878284187d4c695d48bdc935bddb0ee257d05f8ef25f124f9238e39a1ec01b0a50531579e4af2058bf8b2c7f2d1c6e44de5532b1c439f2bbd77f267b2cd1307532097684bc8a061d05a5d2d5593e97d1a5461015e32a3010a82e42ff4441e2e777837b93b7579ba93ae7aea64214d8c7e14f0b827e7aea88cf55f365e0964293a755a0a37763074a4dc1c4bc653ac05b6f5b51d16381ed274d003ba20cc82d0b49406dc96a8fbb0712f24fde12a9c2bab6859ddda295cf4a2db2b421d8939df8bbb1276cd87df44908d41d47bf713d4d802f8805d718f223933bb4428a49b0c5fb5e55c7eaeac89ed772d344de46f9a541a626b80dc272fc7704083671eff7cebf9244b9f52dc0af662ad294ab3cf8565637e449418950700837f165385719e75d24d07d955dded0daffde07018d1d707137c2c5393f1512803a9f6f492f138ff2a6617bd47d67a76075445e316eddf4c6127fb92b66543a6e7995112ce0a01db0dbe5d3a063a1329bad9cfb9228726ce7109c9900b57be97981c21c25bc3607a73a7f25b5d2487b45bc19621ba7bcc249787da03daaaa98a2ea0cb3f37a40e47097e8e37f6eaad1883970adb6ffad2d29396dd165f5eea2460962ab2317b1fcbd11642a0fac916137711a9a0ed6e6c34634229e375e3c8d6bae0691078c2f9e6a34cac05e764739eb1196010c7b67f2b442a27d00768e83eb789b134c15f9125707451d3d65064e568a9c424d83531da790385a902304d116d421f411777577df8ca3023ce22d1a8e9b54f315b5b430df1f452dbb74669ac308a41dd7a999e34bb50b4bc60a7b8038d27c3f22a329d6b8250050babd3c6dbe335d3120a49a2f650029727fb279fb8e5507b647c96d43efa3fef2a919168bc87d8643067481c28fe67f1fc1e68a8ce8496e4f11f3e90b2654c0028e19c1fc859bfa650645e6b38c2eafcdc14a4575683acd725db236d162afe43cc38376924e693597acf4836114c96d14ab21388a284b942e3005945b2dca2964bfb401a66d13d9d60550a5b92179262060fa54934504ecddf21f15427a3b2e35908efba32b651634665743685827708321ce5383266af841053e0489e0b280677ee0c195ed8fa6bf2eb01cac62d7f318962fa25d3c8f7c950bf25bbe420f5b346fc74e49fcf401d949aa37507e57f5db8c5d138c899f59b5f086233705abd29b76dd0bc36bafcddccf5709d6a47eeb7a6acc0826e9f3e0884c544fe2cd21e4439a925057364a21aa68b7144f6421df1dff2d817032b5e960f13e328f75ba0b9f2c9656a03323e240478779d45f39255210e8cfba74a4d21e967464f45d6b0ca0451458470e53daa1b305ba046e79893be5104140fd0526b8686c393386e71201c1fe2a7d4fc827e1ea320e175d8b62570611f5754c64fd687b0d223d6cf2cb59863381be510ff096cb690b2cd6fc5d73bb0b2462d8ca89fcc6368768a55376bddf052ad550a6ca30424deeb2134a6c6da2804397c83a0d519b38338ec434157321f381a29b1cccbf798f6a76e49b4c44d7a7e982f9ecaef82e7393263cd420025dc9d4f6962eff0462c7debd444a6051a915c018a89bd75bbb7a006a9cdd870df4da52e180216afcaae75922097ab6b0183374ba247be4c037cfe6222295ab7cd6e2c41d965595afd01bdc5d294d84bc5017d499004a65fa130a4fbf2488f8310cda7b84b625ed4227314fd57c59d5775ff7f5f71236f096341269f940226523cdc051b6fd68d7bdfb556492105e138bd9bb1c4c8f17846d9aa92bc717b9056b6f645b03195ef900f00c9f963216a9b277f386838be3cf20330b90a765460ff27e929317f3904dbc5f92176ba067a70e1d8a491e637d9eab52ffa0b11fa88f7402fd6c75a802bb6ec907574d219c690be1a2a498e9cf428989b409c643a355a4560dc8d1836b84029f668a0f243d7ee0ab7d64cfdcc0ca2d42072c7669ae12023a68ab2ad072b6ce4a94f1373122d7032a542ff4690b2bc3fbd17f876dc23e5c06f3f33ef70f1b4c533abdcf2f54d4765d392f014c0adc345efe2c27a3559081904d574d57a1014d84b31b03e0c9b91b3a1dd207ccb16bc32cea2344286df249e91b36cd69420bc7c83abe5266a01275fce67eafb848ab7c8a266d2114fec4a1335a51f9c848d5760f644b128db9bb949dc99937b3d52bb86d46aa87dfb2af4373d6aa5601fe45b4d90f619c644591c20ef8d7daf061683b9e0580eeaa89d0429e21e3c153676e9ea043b4966d41221a6fa62ce0bfbf56e33a9b969c48c70fdc8d3e3df8f6a55f44f248b98e785b892cfd0f6545d028e9be1970cf1d405dbcc23537568f55b8efc69eeb7eb963199938bc1a80ba7ed7d3f98e0128aaadcf03cef08de9ca3b3c57ba0fa1386667c44e10f1d070fd15673d1cc60c1eaafd68f858de1745322f0592115494deaeda40aa8142e692fd6315e19a70edf7661391d0fa51728d6742a3026f4e26c1ed2cf71afe4a46ea1ae308bf9b99c1585e464667f63b22ea06651f397f7c7e8c4a65e8c07400ff40f83cecfbd8210a71cf8c05743252ac0c1d3af373c1802c19ec070e48afc9a0f8a65fc122bc866461784ea5b465f551af6ebc81fd99bd83e9147b150a194e0ff2d49561c962487e3234aa3e350f692eaeb6578fe861092f0c9be650a33efe392bafcc81adb6c20de36528219a4f5648baa47ab5bc82e7c81bd96e39079363dd65acfb29b48ffd547c0d785c28e2ebdd43ead571ef9a0ba37985c5631e395229970f569e7442a3a8cf1ea7d613cabdbf435edcfee3e44d5f648ba6887fee111aeee3d81e5c334cf197c01de014c80734b12ef985a64f005702886fb53e919ae83067a5cc6e8244e048d592bd67f342619b74ccc9d8b7bf5157d4bc13c6315445538b1374e29169b1f2e379dadae0c7db7f0d9253825ac276efa84b1c40e0f0abfe51c6ccd73eeb7853cb493e9e5ece87ec55f69e1b1fe5db2be741bdce17b5d30f0048e5ed952d393b7fd4fcd1de231026cd81f9584b188caf8db979f3ae92e26d268a8abce787abc5a6f3e9f076b34daf1f4e47d325ec2cdfecf8b05aa0ca720a6501721f527af59908887a2ef06e9c47898918402b4854a8bd9dfb00cda5a694514fbf26eab31de6c346127f39d605af2120da9ef54b2c9c14260c15912c53676d94617908c4858a4ec04ecd0fb47f823ec5efbf77d664662e9cf50e59fc66aabdbb90b6df4a7fef438b3235b5711824852e3e2a0f794f3af9887933c59a87a509b29010278a438a594cdba4628e0f0f2958b170a829341f1eb96079dcdf7f48147cbf99f6b80592b416e6e87f0f9f19c7dc1113c1e698864022efd7d90cbd2ab45e1524cd27343420175627f4ad39ac8b73924d3a4297ab68f249174cc5e41e81d1aa11808299f543dd3f77e9e3274d99d359e9c162813e6ce6fee07a2154f5ce5b42eaa22bcdca3b80f05f06235abc99dc5a25a7c852cc07425b424501f3accecd48bb781106cec4de7cd2cf31bd684e353f1268c6624bfa654060d4d3397476f33403f2b61b4196e7445641a6d19ae4114cda4fbfca36a3e813e917f8dc0901c26453b1d0109977275689a9835e77bfbad00111987b612697fc7fc58fc707f457f54b969bc7e45160f1a8a5eacf6817c34bc25120d05befb0429624aac9b79aa80bc0c61eb4a3eb7854baa509b6a314c8de71e79a11541922153a43b59ba2af324397c6abae2f58d1d0fd67f889926b51d2b12a09f35851f4678662b89c701da60aff1501e634e2fa3e36cdf9d35adef8696881430c8d33a38466310cf3d601aa3bdb5149a2f991dd8b3fd76b3ffb5d894c1732c3eebb76769fcc853e89a6d05220debceb12ee3c66f004055507e4443158e45f94a2ab345c753c581959c6584f8b0695cdeff3d5f3d3f54708f8f95d0a6a99849fdeaac4758377791da1c5a6b51406e28654e3ba6988ad3fc85c4fe74800d8e4b08b24428ea3d7b414197a704c65e58f9a70b49692fe70c1d02445e9ff63ab01502b1d1924744700ece2c4d1f695a5692d36b33dac71c60cf72450a185ca6067eab3340a01c646e85cfa6a742396db2d81011f7aaf73c2d2cb84f9b2f4447efa38a45792e7f8216e98140b9c8b6da274f460bbc165118900c57707f8d3366ac2412fe70913299c9bba62b327c79b8d31df4674d1c5002ba3410e64da5c66f2becd28cf58f193fcdd6d29dca1d1bddee949986dab9eb0fa6874fb31990bba60bd371316f3a0f0e138f0c16b43fe6a19f01d368bc8b712c04b98d3e04e4cd290bc3671c21267801a6718cc01ca76894610dd5faf7e8af455c3d0929e57c892c72c7f3578041dfbd0d1bc866be1d243cdea89f1c9df1eb2453982f69d2fe4b3ccd468bdf02b8c2be5fe1fee5bce9f60623364b04bbb7d92f08489d9b754266336b7a2397443906b2017b05288252dc981b041ef5b3aa9ed1860f202d1b26ae2f3a608c957b1a2b863a94343730eb5e5e9488cd5b7b847b95c73b127f0bbdb66e5f7cea586fe0d544519bf3b009b751b15bd4d0aec81008987599efa0a5ac4068d3dac961feb52b983ff94d25f27a66c5052732c880bc5e6ad0657616d27b6b0a9de45a15978a10f3d4811f18de107a65129372b25f199c037562162fd1da7bb715ab5d891ac4bc776c318bf3998502bd36218dea77d144fba07fe18dbf22371395b6e0c890736d294b396c44421f60414ef315343be2c66a582154de53f17b821bd75486bbafcb8e676d57edbb79c437313b688a8d6f83ba01b79d9adae4278b6ffdaf089c074056feb24c922d3311f4f198af4a1910af2ae4779cc7f545dfea7d9e604b0fdae1b1dc41da583eb815a42f954dd4c512f80e01ecd01a46e8dc1257d9e70318b1149d7e1d669d9980848b9330d14d6dbdc6f7ad81ad6178f299c0d2806e0ecb0ddb5d53856468cdcc3db05177e0ea585220c34755d24c78fab22bb2108e0635d7e1966e5bd3eda5168a023cd7d123e80ce4f9f7cf80f2a366363f174fbdbe72bf868a3c87dc58b7a18786490389b70dc8e519cc5b345fa40213e4e8744976ac1cf35bf78334f6141632accc73428b69d2ddb6a8471293469cfbf3656da5819dbba6fdcdaba79c4a7aa758d673d0397ba10386d99adeb4b469e9d1dd048b9c72fed2646b0749686e69e98996fe79df08a332a137bf4e989f71a079e99e528fecabc3c4819a845f9ccde57453e86f9c78f2fb35d09b980b1800115e32d5c420309d82989ced94392db3bbd237187fbd986bea87140764a61d6191986b5067371d5b8b112886a9d88b80dab1768985e8e79bb0286b11264c0df6aa491dac9ab9e33c27df4ec3335e72138a3d7b1fdd3621e6385ce39c65e7e553a089dabaa86fdb6fab197b6ac56715bf1cfd7f90b8cc24ba2856d63291cf0c0e158ccb53747915ae8b59f6efe863b24fb77496e5bfbfe83535f2d440b2217c08ce4fc7247e1006628de79a7cb00c9e3ef15757956c829f447ada4740a87d0524a2cdbeb23c454f3b834ccd37a3cc43ec1218a072df85fb037e0106d8888bcd0141920e2f7337fb3fea8d734160504dc496c9bac391228452162e1ed6819eb2374fbd31f546e1ac1e1e9c0f3a33c030a842e95930994ec9caac05b920d504a2aa56bf3b4218b27fdd3010dc939494c525fd99db4c12d35f497931c54f40c3b2fdcef3cf5b4ab3042da081fa48a9602237b367f02668e023e2dfc15d9028e0b3d7e115c1a554149becf7a5c2e5a93940f9ff9910ac8c649f7ef45c934dfba9f41ed365afdecedc76e1340515500d6a640ede3363a02f6084563ae64c465c8db346f37dead912465f37e2a69ae87e008521695b91f5547ca595e36217ca3236842df5a963b946fbcff65a2cf5a3beff8ad77128d10910bc52fd17a002f1962ca323003f3fdff350fb179caed3c923c66e531de22e9067873587232e00edbdbe72810332e549faa4f96a9ef7180dc8e13a334c94466206542e57f7036adab7955cf92fa2754d9ceb9e4213c56920233246433cfe473ad4c43cbd4c54173fd65435d2596adbf39096c277c208ce7a11360671d3db38789016f887fb10df0f28b62184a0c3fb3985be9d80051a359b2c069d73807fb95e6b1385d6259dccf481725469c2d1fdb4210bd70e27c52a74e8352251255d8c5f947f100f449fa8e07ac129d94fb6d6dd415a17e0ac049b3a9d77cc66696a222ca83bd71978d284305ec63e4bc94bf9dc4ff9720bd209b19be68b6a5ea583a6a2a6e086be43500d2eadef965486174705b9f272f23930532323d7ff39f75989c044ec9cb3b9d23d18c26d1e2a3a9fd837dd46060a31d16ae56494aa472699a7dd4e1d616110c77b01caa7a67d108d2d6343a480a7afc62c8996cad04a516ed915a1df9eece9c0d09a0ba1bec0995f446e683372e9600991a673a9064180f3df1cf8c35285c8c2e0fb635c1bc3d23e23942534fb894d2b8154f25db66ca2af26f0739a8a9348afea40b1c0e9f5e138a4aec7413ce125d64be0fdcd286d4f2dae07c7a6b5a34176db83aac86c337c25e4a4f3a4722f463164df24d3d020e2dd6a72ff27e66446edea923b3e6a6c633639dd65ac25d0dc32dd1c0bb5cf914da1dd595855d887e87a869667e751762c80d901f17ddc62e1f578fe8f720f0d76d29d3331cfe17019bc084c71069acb765c3be458b43c0c6e37a987b96bd3d42eec56f8a3e705df8b673793f888678b53f4b941682e3f3dd509cb41d9e4aadba6ff02a290e894c494809876a524871fff66dea55b0315e47fcbffaa261c100c92684fa9716d35af636eeba0d09f7a4f72ce5d50983d9acd6d9cc415b31efe3db1c4fc98467b77f108df1c5af8dd2eef3cee3fd47a8c4c2853a2908ac80ef76dfb385e73fbc06626ba80eb78958af02514d051b0065c8c4c3f59fe2df490f6f5f19c9350cc486089fad588a844a48654ab67aeca5caba9fc6b217cd4eff90b2fe153246119ce648e7a3f4aa8b4be8cabdf46c8faa73f348a377cf8a2b413035a20241029065622c1cd5b9435e5bb081ef42989384ca22e5baf50acb62939f69c82853645b818ce3c347dce4f07516f10d6cc3dedcb42be722030d26f9fdc4334133fe631beda7c9f9baa790fdc44752add6bb91dfa8dd6a1e71a4c74e7a1d6cff5c010cc978f7d785cba354e13cd9cbb4e21e18f3318ce341dcfdfde78d550ab677688e40ab48d2473eb90a3a4454da7bb4eac2180e26e30d8a68593f9315b55e42da32ce54406a93e129ed806ef67d91e91712b5bcbd19769e8b1104470c43f9f0995db872b4a653e83eaf34a1b12a8a91c27e78897ad1563cd2b49e2255a7e0f14ea3e118c8dc16a61e4ecf2e87ac086ca14822e5c4fc17c0374bf1bd70c9ada76dabd4b13752d533d2e86feb30e5cdd6b5abde6cd62e18a8c9dfb0f14533a2113891044b1128d3187718e01e71c08a8466e2bce36976708001e499e55eefcde34048f538bd844f19cde1a50d4f6f1296584f00e88372604cc07060a241579f7d9dd8908a5e862611413193ce1a5f2ac2ea89391eb7bb8060835601628cc66ff823cabac2128892cf1a4d0b6e67daa99b1f481ec3b3dd64153ad4d5d6b361a6e3658bafed720f958e0c948fcc7b1ea4c5cff268b7c4f1836d8fe5163392c4a9747e5c549d887f8cddd86d133b040056dacd39ca6906607bcae4812b6d5ee4c6d7b69743bd096fc0d214276ca6da22d68ddda5289eac2a0090db3aece1199155746572fa569efcbfac104cd3aae453f43c0c1ee3b95a55853c8a0337a4a11cb0d1056c73881f0b4b525d78e9fc4c4054d2cf9f9dec0fd21fe7a435e8d96aa97c0bac93a268cccb9c126bed8d10e35e66a64da5ed0e687ed5cbf95313902aa97236be3882442acb72cceb6f52e2052e1007f696453a6dc5d3a8505dda487b47f2373f2c1551e0361a57d7c0ef7876ab0d5e54901a4993ea5552a9def54d625e9b7cdcf08a851102e8933aa4921f2382a4d0cdae1852c524b935a6aa6ac008983dbe2cd1314d71f8a739c811558b6dd7043392a5e26f1b8ad180f647e82b8ba058b6deceebd69173347daca8a4e3007cbc796363fa5416c0a3b4aba295ede185c018c97726eb8e70ede3eb50f44a1ac78cc06c4118cce7995cb8a3df872dd8f57c70af20fd4baa3df4ae900291b6d5884bc70c988ef1f40d342a440f584700ae22dfc5057a8bf7c9998c8db733591ea81228f3a87efed311188c176712ad3594586d7ceb5e7fb522680b5e1fb6be18bed1aaabec5450409ff0ff27e7891b66fd45d0c0e8a67f5635c93d521c22120d89291c179b4bf08c1f6fb69af29ee6c45968d674e5fee14e658f227d56963e3d3f67131c757092fe032288d743ca4f78d4e167d49899f5bdaba4757d4eb115c82f99969f4846aab519ff2406dd615ca122c711d6176e701e07951a9b4eea02eb2e65bfe5c044daf9343e1b848a0bc1900d1edbbaaa86611c1979e128d9c4c6c9eeb1f469a7cf2a3b582c12f83300b63335b0603353be504e06279045a52853e4c39727a1481ad7b13065d7fb9e27652a383acf50ce265b6c6ac9b07b5587458af7f31b7ee80e075ba915c70c2592a411e2cba1f0e1aa95d553f8e98e480de41ac0a767d89a49cb03c2fb0bb0cb64a95e3132e64d9740c26d84a6a5648527aa7200394bc79612d0ecf2bbcff948e18eef5c0041b3a6b78e3c4cf120d9f01afb4939ba55283312dec0f1ac2b1ff515688e115f5534afd269f000e3a84f20829d2897bbd53d87e551f5c85bb8ce73a4e2833d1089a524e5187546e2d9eab5181bb90ef376b559dd72e9aad1f51ac683a312ba7af37e83958cc9dfac434f7ace8bae717598aefbc38449edd790c9fd8fa31d4f9670a5e7ee7640b834e9d3946fd8fe9cbc2e8634114cd7e396dd58a15dcda4af851069b0e57eb5f54af378a2029f9b738ff5a23a7ed3ddecda4ab1363a348ba6abc610a268aa1023b56ffb1ec2261375b2f02d51e1e84f7c533a65a94c7a647856bef88bf3615c67e8fb89ebc28318df3a1815a0967f0f1996cb4db611e25ef4f33a4269a4ac0f2f7398dc9112896d9175b83da71a871379ef51ed341b84fdb7465f855d29514cf0a0bf44d9c72eea577451311146c414196730f90915dd4068c8532b4c91b5635e82cfdcf686a1a4c1facd028133b69e1fcde7eb9e9918713828f9f681a5a8081d2664e697ab13a08ad1f36b492fb7ed59a0aff71162e82fb2e04f78f1659e6b8a5eee671eeaa9a2957714faecc6a4c411204e7bc27fb51803259b452b22a61e951cf7394d77632c97e1d85066263c45f5859dba3c596146458c1f55dad93f35203a956a55fa37ce94f38db1b257a705afe432f9b33b471da88f0a002531cacb3e5b473406ab1ea2902e836325b263270551d47160a6b57a1a77a614e9e406a03a2411c07e436dff79b67bae7a9cad1cee38fdba50ffd34491399a0aea4827ffdcf0ca37a099ea74edb338f6104603beecec0ccfdc5be7dc002b9ba3fa099af5b1930a050c4ba54ea43a020d10e4ea496a6a475c875b2c24b293421a8aa76ad46b3d0f364f47b19d670a0fbc860429931ab00413f98dabaa0696d40d7f8045c6c98709c211a10f2997f36a2381b0ed43a27d2c434e90ce80ad8e59db37ca2bf3117cbb06d8627a1fd6001878f28663440806c02c63f690feebbcb0df156b291ff0ee15525846afdbdbd7d71d36123881957c34f6ddcc4276bb86df78871010acedea5566c168abc5a32893bd717fd88cf2cb42a8010cd8feb46eac1bfec57b69ab71f99a54451cbb9bf1eb676818ac2b9080ad1722ab2d3d4ba1c9d50b232903b8d8a51f3465a8d4fe2a5c9df1e17b3fff258d4a0f1a152c72f5bc49627247902946ea6c3b2f66058b9f06ae6161779dfa86498c979ba723342a9d78d1affcd1f6b31f94b8bf4bcdd0a820e5bd384e7b6a27ffdfe55a432bc0b353e4de5cd1f6bb592056f70832dc1ad2c4f94b1c9d63dc6b08ab60a3db7eda1d1c57d90b9282fdc0dcc0958a87f070799622525c111328e8933d2da1e85fd018118d9541bff658c418b4bf46442b87cfcfbd48a1dfb6ba8994243b7bdd75e83ad8459e779c42c3bfd38c4bbc97ab0aaaf3723e874974e90b7592c5f0227e21891bc89818868563c002184c4a0c288542f74cff3621a161008848602c8d3e6f2cbead2f32641788fecaaf0d46af27c3bd15c54e8e0e5ebe39bd5f26be7995264f6a2bdb667bc409e2948c097d2b2118ff6a8c0d9e7cf14ccf614b9c1b11ca9133bdbcb39cb40d13e98e27d6a3a58473b70d6607e731077f8b24522974a0d5342b992cc999c154f909c6ce557313324ef2123db312d6ce80bbc095f7ce0d59c669a74f89b36cda8a1a3df68019c738690fb8e4bfcf86b2c1f63420a8b5f273cb6b65ab29cf9920af079a1e4a8b26ac1a7605e271d8a08ca95c067eb8977628cf3a55ed4491d8eb48d32ccf7b97c4f1e4bcf7dead29bf0a8d408526b4f7935a2c4013b3dc7540d605e4ac52089242eeb5d574e981da7e2e9303a679ad5240642ea9b82dc1584c6bd07b02316f78ef31efe4d4be0c157f7c6d486e62588c40045249b3e565d19ad9e2847be6a1c73ae4aaf221af243951e9279955a3032b4c2512f65c19d4a8b14e2ed9b57c41c1098a919bd350c9a4c9d4ad12713fbd246cdb1816de6d05aaef44de5890fa2810d5af912062419094114dc71ae11e0c1471faf50db68ec73bc5261e7ec66408acfee3bc71cefd02daee519639de6a87c63f0ef2e8ecb997014f7d57054fd99066c295b70507831b2d816ec55883a6596889d846ec10be29c3685f62a49747af5e618bfe8bee8a7ae3094bdf28e5c3b1e90639a5245b5b9543f31d56032fab245b7a60d5ef86a10adf84086bf618e5721bfe69ee04b9c9cc7d63a11268f8683ced88258da8c47ca069e472fd05346a813bf3f757528f068e005fe2b4bb25133686d55b1a2fbd750d5b4d87791e6f3d5ee3947967e73e503550336ffecd45e04a13c1792e6f5d18d74ad7ae619f161713d0fd3fccd11550d15baff5333c3b97cb821c10a2351b5b50d18df204a6242587e8d73ae55bcb43fde66797dc87e60610c119bdfeabbf4e4e53e7bff24b76ae6404bdf41ca25f036bd7df8bab619b103ba1806cfa687e78383cf2f1406798e41119113970fa4ffedf99f8b26f02de9643981c296c58f06a5edac46fec5bc0b9d5796f06011e2055c3a9f1f47db64cfadd61d70bae39236548c369d19779b03c2b18fab0860beec297e8459c8c91c1ba3e75beecaa22b9719646e75801378c3f90cf9227e174a2553a6178a4c1a8af3fea84d9baeee5b84cd18dac17d2f92b55bf1139032c5930d572fdf1217752ce31fe55bad6ff4ea4e3e0f97c49c3baaba888862ef9986af0ccfe2cf2b9b81a3109bfb149f2f664a80d11434920244f39d45c665fab207a5b95f0c69ad02480e340dad7fa12277deff8beb636f878522b7cf4f8e5d281653c625b0d7e1990c8334e51871836bef80169a72dfd2ba481771c6f56124aa2fa46ad385c6c1e01347b80dadb30fd34465f9a5c1fa7a699518a6a5b668ced87b3f0595f1e60dbc8508f38e84221b71b7fc31af827cbc7e12762a7d31d8db7171bfc355142bc69efb0ca37d18d9a764e9eafb292074eb149221b0ae18b2d21c463c4231b16674f463a3c6198c936ebf1e85a0bd79eb0710bc0e7f6aba37cba52d93a93bb63eb1542f06f998d49b2489be23374349254a9d5ef162bf19adc32279033805695a66ea1b8944395a5610c35001e3b59e74f4ac2a37ad81cdc270d23875c06c7aec5a78295c3b67c861a058a5379c1159e1ddb1b15f9e261005c50c4519016b6932a4a87a2f275f4dc4fee2241aecedb78fb678a02ad2ba10b1e2268445a63e306637145ef470fe76765b47a5a23f1c051e4007547cc00f7b5cb18f1008ba367bd98a181c89ba9bd324a9cd36220c5977fe3ea608acece644a85a393b83c315304040ce6ac06b9700cfdc89aa4748c614147180bc465f546560c3a9ed5f6b2bd2095b82215dfb5143fb90aa14bf18e44583f154535f0ccc65c9560a11c93ef285a1d58d00fbbcce40b0b5f9fd87b24fbea8e1321bb293b67960011b3060b1db0f1f5841354afea3d50633c6ed3e948ff35af5b2b1f6b8a77ad532211071de32a0e1e2755aae4456384e346ccec476d2a6062aa216ad898e4d3d41951efcd22db605385ec8e2fee61b4a39ef42063a9e86450aadb425ceb59b31bb469f35e2d3588bcdecb2bdd518ebc3a69c13cad6fc59a594f53b94dd5baecdde7f25148d650fe643037ded6b87c95a88a8cf2f881cafa37d5fcd7dd0162130aea38acbfd053cd171f75b56d50d499d991bb9f549e16cbebc2589e5201eb726a7fc67543f04eec7daa59389e51ca817ee3fe2aacf13b5a003b68e7bbd747e79a35ddb85385501026cf342ae9b777e65617e6d865c41df82eb28424b397b956ce97ff0fc5c2bddd86048e9cf5c362222b01a01028028879bf5128fd9e1e147b6c9c3288fccbd8c95aadc715f438689cf0d2f4a9d31300b9fdfbc4992d2242b601a10360c1f859084ccf61b0b81caa7e2aa08f41bed936d92b53a74485bed871479995476b6642f3c610bf0252a89b8d6a9dd65e90ab9c4b8820c9c33dee32dbeabac6a41d709fc8c1d79fe844f5460ce75eb2583c49bedb4834cff52964c4bb2a8ccb4b9e49caa78c33ae7347fdd2036388f1505b639b417a338bbb37b50bf83b894723397958473c7ba7590ab9c36814be24772ee84420d84f6e85101ff5dc8ea26c7d15f8160797ab1dd1375e86949910d218c828541a41d1d2f7d5f252beec5d54332038640a6a85558ea4b794a153f041e965233069cd6de11b3c5b59c0fb2a1d40c17f119101d6a9b605593bfd6d24b30bf1e7abc68a5d1f10cc328efb72a0fe46e9dff31c3be6f9ce27813b0497598019035ef66f57d7adbf44a4df1b7e06bdb8f01bee651f1e33c9071bee3d6d43cf40db875e8cb107b1795c81602464271b6d03a99f6aa941dc6d531028a0625e4f19a26cea0c18da5ba8680ff3eded44754a4496912b4fdfa1c35a4a88a92b1139b9301f0c9ccb26f1d0551be346337cb7e6f8508e060769b0c46c8d5f01b4a82eae588bd388e205447957a1cfd0240b4ebc359027cacf16f944475b6b0690b2f5d83ad55383d34dd70527466e8f21dad467810b3884cfaea1d732c4d70a6e334dcabe2df629e1713392ac1f9bb64661607f465bb25144a54ef7c76c44d9db23e51fa6009ce08215f0ab3a4da1936ca55a6a65a630992dcb0eafbe7e621abf6563b6810116bd44bfc0c3b015e0adce3215a13a891ba50d82dee89d2871af8300c14851cda909def58ff54bb8eff7ed8ec9bf0c02d3b00aef0b5a4757156e1bfb65e977064dc679ed78dc318f7f474989d257f9498cbae2ef17b378358ec2e4417d845a3ac9f83105c10c299dc6533c9ef4cf0ca9c5f84ab7b4cc64933a0e5e1596c0878980cbf1ee108c58bcd7a5a1eeacb23bf3ef2ce9c428019c9ada9e680b710b1413611597f1e3628e41437a6977b6639c82cd2e5be86e5463cd63d1219d885f765f4849a18f3baf4ac07dc8f62c0e2c653941430832da555ff4692812ce013f1d374d0dd8693c20810a083212693ebbd469c61893e51dcffdbcfd1d9be1f7c0812aa71cd606b07197957cf773fcef4b43fe6e91ef7d1f3e21f0e0a0ef8b7ed0eb8e156fe0c7583a146c64b72bad52fafd2daa441d74505292e7bd92e8aa22596e3200218a214c47f31cc520f4ed2a510e2c143e92ccf7e9215b065228827e6972d4941e7955bd98c1aa637503bac454dc5626ed655477a626b9c0335574be0449430949b85b0e10d5b5b4dcecdcc42c00ea67bdcad4c4a3b8b3facfc82829427b88ce6a8b2f68fe165612ded42d6e1a1523a450f57803cdd40c19592fc0ec0cb37047b187fb9dbe57f20c2cdfa7f6c064d8237e37962645d44b549cf54ca3789baf830e84d78d4ff5077dd9520e35f27dbff61e5a259133e9f8900487b597ecaaef690ee0d8a7b601c0a689c37150d19e84f971ffcd1543a5d16dc1fff85767adb9f5923d36f10070f5d5d7475cdae4367a64c6e70cf9da27c9876aa688e181bc2d7dd0bd63604c8f92f1365c1e113ee153a7e6c800bf98fa989e10ec1819a97d0f51bb4d312e9e1602c36e6c636714d830ac0c1c8a0bc39c446b765c86231cdd2b14c8c8b9ae4d1da9fd3b6647174e36502257203ebabe5ade434cabce2ddec270bff2470e43269ab416e96af5fa084ca7504a5716f58a88ab84d1fafd998f5d73ddc585ec65950dc80996a161421498041391c3e724fdb88f5866dafadd602e782d046ec083756d147ec7062e59477ec36362ab0d07738948a8d3caad81f0a846f989f21227b244a3ec5fd43fdf495f6a54001d97f178dd4412b0f7730575692391c5d439606768f2989e3260eb9ea0d7cc9296bd5684eac573408f1c053465f35b14f9fa413b5b8684a9a61c26aca14c26472d7f49980eebe1edf802f0c2bd5f13b0ed167bb573b700572ec6f4a046e74d0883860580bfd313a18d0d9b56ef33e6fe50dcc0c1bbcaf17e2b5d5829fc8d69a0936150f0a635f5bb99e421ab2b77e8d552c3d4943fba0520e5896dfd7aa89748d93483ef13aff90475036536f53d3fb5387bdc9cf4ce086765dcffb6acef7b366b537ac0a8595633b1bff732c7f46a32538b835e4be8a27b6a41a8f0126368acdd187651b48bfca6d58cbeb7ca2aef9ae36662d2a475a18bef96220d9d1aae15a79529a9ac3ee9b75333eca1beaa8ff6cbc4d9d0c7b1218711bf0ec2a97e267ba0846f74166464c14edba27623a52a8e453bc219b29a4f77a5ab24a8ac56c3acaab4106ca5722a1d0d94d947cefb528e199455394f9293ab04676d22a8d62769633829994b82208665087aa2706394c9049396041906a60b20e54940375815539db39bdb2ca835f24dd474291ce1c7142bca5c819acd0fb01b8949b7ee6a795bef5d586ef2bac4403318a5522b8780e7305a0f24cb5ef1202f8b0c6eedbad391e81886fe5ebc4f59f9ba3eab94e863e5559f98b3e15715d627478ca5bb27dfaa0ee85b7472cb3ba21dc2ecb39b5d329d4147cc086a592b36ba80c90227e67400e35049a305c87a86607369b524f2eef6a6a42b74ecc4797a0ae96307fe8ed6a9bbc0a0353ba0a686bf882d24e88810e395f61d9ee0b22b5682027391d0d7f3c8d8e245c0ef969a8abd594bc088e8dd7368565fc1955bc4b4f770226c748f0648783d7536c60c4c1bdd3c99e03bddb384ae0009556f65df99055442a53553744c5a17acfc394d6132672a7d7f0f80e55bec30f447bf84c0bbbf61dc7b1012c2867310a7156df5987970cf696f8ae96a4d3f09afde18f0c92629cbaad597edebb8e86c3d2940b61a4b0839cfc098ad89b3281d48e65c0e0fbf9b2657e62846dddb442a468fadd6386b064ddd98f6fc995d1d6e30f2fec6d607a4be52e310d83746ee1f0624de885df50e2c13ca60876d764354b96c4677c820261f25609dfe3e15dbf500315439e1fe4bc2b47c93132fd0bd854f61326992320f0a25e8637b47f20a293f1927f6298f126f3217d1cc18316ad10ea7b5f03e45fb7b9c4aec6fa0092fd2a89c7788b78385f9c76565999511853eaf7795c659156d57987b8aee54b57706d7f3cfb8d67686dd7f98f9a3c94309c352d71c309bb73d9b0d5cb23ce421d5108500a26acbbc36d33dcc39a36e3cd768e743e998b76cd68a95ad357fdee8686437d3bcc782fcfca0cd2adf104767fe2aedd0b30f8afd22b704d5db638e4fa441ddd58352ab93f504a0528ca09370edbf9716a9cc0016cd08b75e03cd228c031c25d025f89cf540a693df820a4b13e8dbb131757fe0513caf83fcf17cdc5d7f046c764aee60eea4d9d0ddda828d80c8331b6737577c6f1810d283057d5c2ac2fa37c04784220c53d6f214a5df849b94652267054930bccd442e4f5cccf2081da37ab42c8196cd8819ac22d3c426df8aadb630a9405e3630bce9887aa0467c13bb66684f11a9642f32577c51559f644ac8dd66c118c61708bb31fe0fc37701f08902b6172f0d1f80fdd5c7a2672a7cebcd3b4850e32465891994587ed48050eb81e7e0802902818dffaa3833c7a63bcf109d4e4a889ebe0e958e765c9d0b5397c6f0116181fac01de62ce91a1f7582b2224b4faa4ab995b6ac3fce728ddc1c9825745e9b64246d50cffdd40d4b5f6cc8904306bad27ba7d5e2ce2ccb161402ee0178f782a3ef3ae2061546442b6ba6c2f1498432ec3b1c69cf0de66cb78c1a13e2b2cf33a5c8cee70a53c72f0473ec55c14b6576f9103fb9562ccce6a59e03785462853e35d39d4946117f75f2beb5321bb6278c2bf683331b134c6d0dbf398d33a8d8dd98cf7bfd926f59b52a029c396fd359ea7a1a5d50c6e4afbcaab05464e7cf2fd95a30ddef610dfae4be4bbcbbdb85f53fcd891be5e977f18e0102aecf53b4c88da39039989ebb1cf2607d53a0e7bc3bad35e70dbf2875a5a3c1c54f3f10d252cbb0b4086c7aa9ac9457136245631d93c16859176045f9128c5e8cfcb9ffca75c2d6a64aa16b7a33396bb484a00c78ff046bc27bed71b1578f2b8fc0555f674d84eb37736e82dee09396460d192d31fcf1bd8ed54e69324e3dd25dcfec4bc0356394e76ecd05a6b922938f4cd8bffec5eca881bb8635520afa4909da6150a77283687a49de59148a70436d485d59af699e2f991dee38b119051dfe1c78f7c558a892e72a08551ce7dd9c8ad55bd44a9d2f4fe4e5090668f4e9fe6dd08466f0d9abb0a68640f8515a56c0de60f6608c1e83066d0f78f02d50bf4f5faeaca1aabcb763267eb6e918b95ca9fe3bbaaa82f7cb814482bfd311981151cbe1fa05f06b6cd690056cca71a9e685489f0eeebf35b14b9249c2e6d057cc59412cd4bbc6a570beb83601c7c5a7f3cb55a32d6307151e6458d68d53f5a921ce6862e3de9ae2fcf52b1478047f8a767f30db29ead86f2c603cded236178a6c14b9727547e0bd0a4b877f1c4bd81e615c2f0076e23857b9aeed69d2d00510c157de20725eccb8dbc06cff7ae01d7bca3f9ff7aad3cb8d4a348166042d0745e46b251585a19a49b10fbf26d25662b41bdc3909d11357dc1752b26b0a11df3c339da66beb962980d3de71949fd4d0a0d0e4345119eb30eed4c6cd9f3597804671bb6d164e06aea2cb0972e110c0bb2f8052f7e2f50613f03ad32cb19dcb21bed1e81fdaf4481ab0bd8645055caacb8a418d6f8d95c953e1ede6718c9a688b7f8a43b3e2b22fa767b1245edc69ecec7f928c4cb76d44a4274c7f898309529b82fd3152c187fa5ce62dc9588565d2ee7393451fb5f037286b291d45d8b7def18f20fb171678e46650f19df030fba3014bf43f16244e133a78ca4c200fa4c8077919b391566e049de2534aa50a01bfd227d356bc4360b6cd1f270038ab1a54e2bec2ce2946fa90039f41ad943e56ffa76176e4c0b1a035d892af9644a4908f5a82069400ea413e4f7d99582f1d086d1ef1d2089316f9e01d8ad27745c50d8cb302e7a272929234de0d50ef667f5dbb3c1a8180364437b2c89fcd10a7e3a7cff3e518775a7d222e5c5899d2cfe340899f3a5a507061ac1191eaedfacc0146eed1263f25e931a010a848b1496d80d2993d4222bfec9c9f9e45140a9ae9463fba18efff6d968af1784b6d7a1e6359194bf6c73f7f9a631d1985c59d3fac26878833dfc820115ecccbeb77edede2ae9c7989a83860d909eb6e0c77ddae02d8301a31b5c3f36b194699ffd1abf2d039f6d65c8520306832791b7b01bf69d7e34fcbe8a9cb0b5b975c0fff48b68bec771e185a6a42ea78c372d3adf8f56ee7fe2cbf77f1416790e98d4d5ccc1c2d4f6e459ba41e3c933f2c989d03afdb1928087b9de0819733cde3d78f8734e62aa756c8711c1a816a02cbde1631e633e5c113ba9366b1bb2893a8c4db722e90b4008d747b3bda7cfb088d0c0ea6a4d3695219e1249cd821c2b48e42bbff2be3b7ba7fd55aa134d64ee42ab933c7641833698c4fba9db6304166414a88e7d0d871bd311ddacf23f97acb295ec1d6bfbd34ce59bb8278d73e99573f994c6c91822092fa932f0d2d1b9bc69f01fc18078f69f36332ebc94f50d7c64e8c2b42dc5b9beeac1acc6d1b43efc82876f8a5dd2e3499bbca445287880bfa04a4d8985f36d2bf128d8bdb2a75d53766cc48620a804ed81115b17e902cd2871bf0b26dd5b186f619e70f568fa26cef3a0752104bab588500eb95d075fed9d213d59d3b48da8236667d81a0d2cae31d5db66e3a49c50c01821f156bf2a64fd1117505762c16c402016800e4d3b7db37b2bb0561ec947732ff2c30ecde9cae81cbe79ec62e5c3b1a7d36e1d3bdd1fc484e2ee3457f482720162a5e15f750c8b20094ab8f6daa481d994707972132660f8421884e44fc2fd5da8fa57d051a9e00242b814b7905e263f68aee8533f165b76a58b37571e0cfaf90f92a59fae6d06e972e509ce720f79387e658dd0d31643a4a064fbf853481e0de5e8ab3a58ce9ae69001a253b3c7e3eab6d7718759808cecc972c9f610800d13a32e5358a5451b60259ee29d831347e35b281e34fb2ea0664bdc4e1781535f03780fa0c4b275e74de0dddf1de663d632332115a7be3332bc5e0b45d1e92954c26c29aae8f0a6d2ac2edaffc9da53478b838f5360d807e7c152e426e4c7bd71e90ef8d0ab2f54af960e2bdcf8a38a54abdee01df281f415719bd6cb83913d5bf15db5f354f799455a9fc76c4b9fc6f4899c2a31d45d91a3a826c9e50fd437cc51e999e2624d51430ad7f425f97a01c592f0f13b7b8cf7a946f82ed5f249777323a3c26a75b32f80984115cad4a4b9129b9b3de5943ce8b3b5038828abc852be8974442675619c3f0e945923ccec54bcacb6ec0374bcdab9ffad033deddad54587ee86c346f340aa4105dc3b71a482eecc19d3cfd5b43e61d6e6132f3d290182c42459ffc140ce2af2b9dd348541c937364808650cd45fe542ad30c8d384155381d09b93ff0b1ef9a2121a71007a8bf85d1e6ceadfa5f36b97108db23c8685ffd4f18d94c7b30bc52e858c4c8498a34c7639abe2aa70ceae8a23f3a41fc5dfc7dc859383a637604717cf2fbef595b49a33c08a53639f9fc2bcf299301934ecd80c05d3c32485a80ff3496fc3d8dc86d678f9bfda813843da82b6954cd4ff7a561e1ffa9277cf0518bd2c042cc16f10198f3b1ba2054012235d9f1968a6ffa0f7727d8ca710deb052113a533ae842d203082de8f288c08019dbba3f0290f4370c936bd02266cb01ab2df9b0a0e1921bc4e590020502d8ac7ef296ddf1aa04f46a69445d0af1070a409228067c41324cfdbef7ec32c142599ea76c403137ad081e28dd1f0a8fe26d4b2d886b9afa664467b91db2b5cb89dd897ebd9c3a9215214c21ba5c10fcd5e91da576d5a70976712c769180f0a95017ddb3ef9cb50c233c9be65fe84ae8d78ea57aecbb4586d3514562dd2dd116e806197a2611f32f307e73607fbc7e355ba3c7d6de4ecd0814587a630ed64edc528e84a40f409f0406ddc8cd60c7dde021067f50bb7367956308d9a361b33f0b89ba60dceea37345191782eb33aba37e291cf4eb1c439626d8c8a6a7acd938dbe9eca6b473362f0dcfc207c2d211e4cb2f74ccd2e5051432075736572202854657374204b657929203c7071632d746573742d6b6579406578616d706c652e636f6d3ec2ff000074bb0613220a0000002c05826774858002190122a10672fff84863aeba67f0d1d7691173247dd427533b9d7ee76011c6f77f2ce9fa7a0000000055a02014be1ba8eff894fbebad10f32a3bdad645f4f8fec86a383e6f2b628c2a1c5573c4b01f6c4c0206b188ba5987cf1d4816b98b78f2cc6a409e6842a1c567fcaccb8bbf5f5f1c6ce19304b1594e275787b53f33e7aa137508faa2645f9ec462f4870ab7b5e2ea55c63b9a86465e9f5790edb30bad216daca7ebcceb644f6fb7d93de647d1e62a2cd8a4973df828c300f6c8c0502fde26576943d0a14344da5088a9d65b0b4f05489af28ea9320dab7c5a0dea8d7a88aefa26fad81b27e412d40b15ae82388bfa9d5bc36e33de8faeb004c3aab30361106b7ae9366aaeb68b77b37568512fd186c16e9b78a2b726a2a7e2447e2d32eb755dc73cdf0dfe0381199a163b235f454773b19430513443c2655621ef64b85c7473f39478d5ee9379a6be5b7e28160b72fb6fd3a6168ac6bc648435fe17368918bddb948a13e7bff116ede130fb8570b66fcc97b9c81aa537729a3a3266367b7d79c59b5d2ff1bbf0351c25ddacb586e072e182ff0cbd2c0534b77aaade3a4c5f262e8d1eb8f873327377605568a98a90b770529adadedb99c47efffd24d9070bc7ef0051924361d121d7be1340ad1a8f8796f3026d6bd55b857843797e06f6240e5dc51f10482004c24c3e9c4c40694daa177def4acd5f0c5236c2f9e663238207ee84f046e25c7178cc26b4bd9a6becef64c5e6b6d1b2eb5e5216f6afd841ef0eb72a11664b77f1265099eb7bfcff04da5109987d574767d0fdd57dea95ace7b29b5ac14d71d432f85e3a1bdac74781d58a30517def9b1caba52d09132375fcae991242e12f515904d0e794d4b15f4c1c3ddaaa62fb0e52b8e511c662099ed785acf46d5adfa9498aa13c914c59139c05fe87a41a5dbd529c08e0e2dd271c75ec60314c5a2a6ee19f8b59ac7304d2394e50ecf7cfa3e0f85ebe4ac6e086d32f4611a1834afea43d0089eeb0cf0739a63af0ebe549243a65e0e50e636809722d819e1d74c9c1e96016aef7394050eb3a806607d00330f4cefe6eb567c2ad7046c2d0d043ba4d3209f9689167f158abe1547b30680f1f13c430efaa7dc75191c61b43830cd5247ee982272aeee087562f97c9bb6ba79950d9f4c32e3eb418efae2941ff1dfd364c5005ac00343bd8fb34400ec64f4ceb0d5ef2420c790fb19f3f7ad0ab5b40e05a37c4704d1c07e8b5bee2fbb76936de8c81fdc3b4dfda4d6444b0305050a73229a3c91b0aaabf83bc8c53169a653bb7cf1453c322b0a748735114a4aeac999acd1ed55856ea0466f563f47b28111638c0e8c3094b3aa4aa16b83c64fcba4a964549a45ca93845700bf47415214cb551fb9923732a3b2d0c543e84ec74227ff89c11f684092228816ca2376521a7505dcf6f364503f63e17426feceef5b014440ab0ad982ba17cfee994971b635ccbcaf7e9c291f82fd0fbc05e4fbc25f28d965067a7ebd7b4c6b31df7900cd6e481c46ceec0e39fbf47c21cd1e0690a78cd544e7a02c684082704d1c3b97c6b0e5b92f99c7533002cbd572d3a3822c2c7d7e77992d7b5ea6399531f3cad90ab931f8415ebdbf01c5ff6200ec42f721f3103f5df7fea2dfe989e6b96a8771552fbd8b14e5ce893d34d188388c16b247643b1576bb695f616a5ad5754467d7ba77b006b1fa53893bb1ff1d573055b6bee38e2160a1e1b4c409d9e74a9cf27d95cba216963ad34a9f36d4b7e0a210b94224caba2689393e2f0cb988e0f1c455bcce05050dbb79d58765d3400a8a500bfdb3514a0b0c031477e8a8cd0f9ff81bd5eb7a17cdeffbba40a59a008ac08c754aaef6fc372157138ef3cc4d2518b692c35c9b46474866133f0ba9a87408aa464dfa91538fd0e2d687873aabdb29ead56c1161288506f1a6a04644c3e3cf7cf0cb7cc9d4f5e3c5a6dc6ab30f03762a30a4b49664a21d383063a1aea9fdb98180c01c433724755d193a536d3721247d02a0dcb1490544bc9986a50ca6973e7d5251d850ebc67eeea0f4ea2f955af0cd94f92a06a55c5690ed667e001499121fe8ef8cb04e5de63e02e721781af574349493d5841354cc69b77e69abfddbb3aa6696aab8e812adb5b831a49e0973c571afcfd1e5fb8dd971805cd5b3d9d193d267f77e3b8c2888a6f237d63e7ceafa8a2bd99163237d4ab98cdc94fab1fff6c3e6584466ce1a2837b7676f6bb2050029fe71c8011790adaa2b1d2466aa9adb631b0a8237ff69f4b4220fce7f678c2d87ad8a089fdac933ed497b5ceb0c65ad14c657b263008593e15c80d6c9e34991d60eed0a537b4efb996d142120022d766f991a94e587bca005b78011ee19cdc7dc562a3923f13aa4e8d089bcaf7196a0820bda73128a60479e7c74237cb6dd83460f1353889ff5b61afe9ff7c7ed1a0f2094e97899e91402d30fbfb93074d652d3db1609818579dfc469ea281a0dcffb3be7043eed3d3baad1f14fb96e58e7a5f2b202393fff45461b1635a04e0aa51e131989fc9b7323fbc589aadece5de5d70c6c13e903624813a0645adcf36cc136dba4c67242c17787b9d9442c091bc1e8a091ae99a16cbede8568843286765786f3d0445ca2cba17f84911768c0261184f38964d67b34bad18790b125564ef1cc79282a7a89946ffe83564c1c8f78531a6c62ed4958b567900f8255654c2c213489543baac82be1415f19d578c12fb4427dd1d5f6a4888499581e8ba9813a645b9e1c909a9c14a610e80248a931edfce0c644e1316ecf31699c20bc5517f736c4bb7785369dc49fa755a831c94ff00a5a5c6c3bdc58b5574d36efde369c5126ebaeccb5c1f7dd89199b4c45761d257bd63e8b56004519c96b6fe8a487fe0fba870e1a1a7e1904615f69fb8ebd0ef813683522858f8e182d7eb35901af7f141a3ff9390e494f8056a75049d0a8b97c8f9742f5e91718840c5177669a8399596cd06366006974513497e614218115b74592857c583028144131986c87366e8e47f5386488b6350102a5166d0184d4ed0373988639688867790656bd5071302bd551f83ec4c6ce29caa1e4eff4b657e874b3575f87d8bc0c9d855919a8adf98fd5ac4ee43dd984437bc6fc3cf08d175ea56e338674475930713d9f454b2cec9d930a0bcd91107c0fe37544146c054a74b9d904e70a34cda220e6607a46575629e331016b4b42959a09f13e312f1ae75380c1fc01097aad5cb8ef6750f9ba7869ce624b55996f8e65dc747e519624c34f285ebed1076ac2e253c5d90bf1f73cb6d93a90002f4361b5fd6eb731c34b365dc5bdd5abc75dfc7224c6ccaef9dcc10c6aeb1766fc1e4b3be00e3eef93ee8abcfad8ffe795b784ae7f16b3df3ee70e591c913c64dbecc58fd2a17e6e63380e5b15229ec17c20c3bdc4a5b0be2ce4869b45292560fea1de1febfce1963279d78f378aaa977e25c5ad6d9dfca121c854be7c63503d3645ccebfb0adee58fee69973ca2a5feddcb547a6b2539a7eaebb58321afe929ed3a075b6e08962242ed63397eb5e8461f7aa2c99944019b4911edcb4ac9ae3cc57a88eb1e0948f06c2d671cb82adf408ea7b01bb4e45c5e23bf37b4df5c40dd90b38512cdcf3e9ca6d5835c053325098f19aa5ba788e5f091d82bea8f863e11dc0764833cd2cd0407daaadc99da788faa32dfceb2eed49783c83c9da0564b5c968843ecb5573b017d39bd674b7b5af5a77e24828edb4077fd573c47b821644f20782832bcdedbf3312ed003db775c6cdfdd5558440ebb06bfb1916bdd20fd9f1920cc91a8dd2b85201615eba5d641288e7898b3627f4439c95139d5df15057e0e6852895c12526f02cff562a839b2b42f8a2689a3513c76805634d0f0a64b965ba95cf6b86d40ebfd700170c5795f5c7208c7d31e39b0480a7390372e8b37e46d3bb424617d2fb3c510103cbdeea4ddbc29cd01f034db4e5c0258e96bd21374164cb30634dd47b01ac68a9d36baef7457cb9130109498b55550ed4ed926583c783248b81975d2218f43107bf1d2d35954655262f15433703ff59723c05cdfb063531a7ea0117d12e249b55edb04bb09ab21f1cfbda472cafa8208f53df55ace6dbb7a6dfbee49d07fd580fb98fc6153e138bebf21a9c934e56ca03e547e8169e0293c02515dc6f369f2c9bce4ed6e0b13830c2be0ceca82e9b93b13c414682438f31fa5fdcaf1d994c9274af33e1dd45488eec9498940c96f94956804d4b38745a14fa5e4b8c414069c077ef11609f75d62533227d7b716d8a950f7dbe50b9c80628c2b070702dca84e330a6f4e2916f9a6a24dd049db0b8b2773d866750c7a27c5a1ec38c8c4743824b23224815e833d6caa9431d5c7059e0a1eea6845eac28b70952dc0361e019d1874295bacc20c9245b672585629ee725f94141893348a3d559949a90551a57db71a875a4914ba96f4fa5eb0fcfc328aba48cdab70f6abc54bac36f10cceec5bb7b2656112bb143a8d1b242bd3fff5e1a8d1e65aaf8afd5f7e0327a9b37dd4126f750e6cb85c31a8dab9f7793f332587913595cae49c3e58ffcfee3a650c3343e68615338b4bbf09013ebb3f914b611f3b5a361d2dc7f269d14801d3c2d4640763128b9acfdfb735e423eed9f06068d16b0557cda73f50968bcfd8b7094020adf3cee24dadeffd921b736d80c3931a966aa7657d408357e73ee3355bdfe51006f16cf3a33e8036ba1259d612d579359b42421cbd9d3953101dd6b3bf2e7b4dcc8396beb03cf7a9f4d1d14bd48a0d73ac7d0d84875a41f4616e54cb0027a53ebfa576fe03b8161c2d85e3fab08471446384963dc7f00179c4b6ea190aaa69149d6d8769b7382ead2cd96a511cccfb39b20f0520c98f7600a5b20117a9c9a7e79922ce2898fdfbf6e5ce9d5e2cd5309ae02bf69e8418063f1faf8373bf60a11e1b48c1e561b5203db198c3488ed8da54ce2b337542c6d9189604ba69792217553baf1e2cb636d2a0a3f892e196dce069a26964e17c951538408567457a256ef82052965712c5f9a8b44c846ab9c2b80169f9dfc0214e873a862c998d5f64e93858ec923db71c5e96c902046d1ffa46f4b22858113e8839dd1b43c8158000595c59e34f9a4176c59fc91ff4df305f4e368fcbf4ffdeae466f680a4bac13e415e427225ec7a09ea50fcd5f7ccada74f3bf4c6d5c8c409f5520307109a4247be13f379f69c8530a12ee9fdd146b917255ac6ca8fa90d64d4ce44414b1e177a88e47a5a1a61bf53981bc18b34341a0ef31c755e3c00e98be444bed3709fecb62169814603da225cc8fc32da49da35e42bc1ac7d618f7b81a4d0d6b767de4e9c943b0943137e4bc5cc3cc0e44104f2afc639ebb7c411bd1ecd61afcc63114668a64a980078ba495e1ee3017d44e907a08508acafbb616ce6632cabcb2b073072414b25deff7c4c0cda0bf245b6e324095a567f4beaa166b125420eb1a656a8e7785f5e5c46b310b7a71d11cee08df8e579363ab44b1e20cd533d0ceed6ee10e0a16e38c0a0b9cd224e0fe3bdc0b95af998fc751c05141c3c6f6ef300e3633fe9d8874819fb66378af8063af1f522ce9e9e78acc0d5a7dd27bc32191eaf98ac4be806a34dc05514a66548793722ce2be94a8ab4f1c1a18ad615d2a90e16ee202a0a31fb503dd472806b28ad084bc63b8601f6b943a745a10af88f2a3263229d22a24a4737da589e4a1506bf2af17d63cadfd94567be1a032234b4e56646854749e1482cf9183adda7c11f6c08ce7fa78ab5da59def2489ff3d6a6e3af3f5d6ff2f7f2f0c9bc10d64eaf50cea684888f09191079f17ced82c93a3f2b6894d22f3b9065d2c313d98d566ef067af974f925a1506829cf252fbefb447f14f1d85ac85b0fb13cbfd3f8446adb1e006cbfc365ceac1970eaaeea55ec734c3d99bf406da2f89c034ba0c3f1e82dc80d9fa33c619114ef48a2b275d92f0379df31ab85f949d6934b021fb1524f43219560e68822308cc30125a0f73ff1a085c16ead7596404c418d5786ffe4b7bb98fac7e60c6632293570bb05c294029b7641a25124d66f7def18f032fd958529ee7fb45aef7fad4e7815e13eeed80432abc1a10513ca7c4678adc1e32eb6027636909b4e7ddb4fc27c1d6aea164300f7742b9283a99fa6e549f39edb2778d1c2ba2fe4ebc9aa69eca6a2f6d48f7e9c057c9dba1cb458b9cc8a79145f8e2ea898b44d85f98a4e9df68cf55a6ea887c3c93989c76f6fb80236dd9000783a5928719f425b1022830da80c5277b62d2ef9bc1a2a1ed3df422e90df78e87826619f2b9ba94fd74c5e753fcac695d6f526dbde93fece02feea9b1f375af9b1f57825c047627c06ca18974988abb5af882e7cce125d683f1beed1341236b65650192956ac09e484b8d481869f94c13f73753d0054aafa7a15c90c3ed1f2a445f08ea39f3689e8555a6ecf5c140824655f85a5798916fcddf1e275d02547492fa2e4ea331bbc0ed5844f7eb578a3f0419bc31ddb8b41bb7b8d18532b9da35aff308eea7ca7f79b60dd94c5d186ab8deb4cd7d5e57f5bdfe8b349f32b58b295427c27f34a0dfac2ba6bc4bd7f1eba5f83555b252c633757d2f66769dd6db38d2c100ba11a3b643cbc77e8d89737f709d43be6cfd65039dfaea4b4774d084102ebf3ccbfaa6b892372a404af1ed6c3904abe7020fe4f92123365825edab7a4a8da99f26eefb85fc5c61d9a6e43f0bf218af0915989684ea6fc235d53c84eec4a2d4aea510559c17f8417f03280e098946cfba0b0fc7ec1983a3bfb21f227e5400ec8268585aed3d96060f59669e1a94c32d4a282615cba5105114db5b3ae3d1c091ff974bedaa7cadff939c2e14757a2cd0cbe1b9d4239e8ad133b8aa39672da4a4845193cb3d57bbbe0c6d1e0500d1568f49568664bf8e90ef52ebe9f046c5962f9eb1b732d3d6edda5c59d49349c96b8fc183e1bf5cc9f458f356cdf0ae002287ec2f5ce4d55a6a98ede539339be4f60032062b6cb855da5f076e073fca27b7d50718de3b0cb9704891b916e48a234695960d72d2fe28a2cf0eb11251f37950540d57b62967ebf7f3431807ae43b89c9ec673d509f7f86af012be35c34cff46e1249683b34a8f7b59340535e59bbf18370fc6511a01d03194261514c9330a2afe8edfbfa9a0153c84a22bea17e936deb521b675ac074fc1fd263efaf6b5ff16771d8c78166627accf93281be801ecd2135c8afbfe008645db8faf852ccb2000de39eec946c916600528b0a5976e0449cd4565806b1b2d007762a2caeb1312aa2e0d486f9465efb2d28f20638d82b7ffb864cc0b613adf28129d835fad4c3e05fcaf8cabe503a76b390ffb906786d95aa10bfe939885f498a24bb6a97afc22d675cf961af9e0320aec5816d67b9d8bcef3a9583cc4fe5d6347cdc590d704e4e815cba4fcb08c3e7bb485a8c9ff93b3728eb2b36db08086a6862abe8113597572f2e7f5af3a004eef323c808d9272be9b27d8bcce5c9cfe47d5055225102fff781e4347e32922d857abf4669b1ae77eebdf0b8c4da52c38eff17791d2f746a1f25b22dcaf7d13f610c6493018c93e16d5938aea29456528844015df70be1072e4b4bab05e4a0d771b646f3072fbd4d69c9ffef5865a8d9de60853f225377c370fa9ee2d3906acbd04623940855d8db62e936ad104c9b7f08751d2f391d726deb75b16a5b9f61beafb19f0102f7d5e419b95181c8d82b141740c0888e91c37ba6a591b1e0005a142e50e0b1942d4fe582b22a51c9dec7645d5d83a09f37eb07dfe28aafc1d506cf47c4cc788e3974e0bfdd2697c4fd9950e521fedc533ef4083bf8557b6a081598aa53966209ab3bff8a208e79f0ff91f04f28c348027157989ea89f2a851d0a9714cd66394c7411db8f0df1134b44630a11da9cef034fd64348cd083fc9d9a61c1d13975cd3074a20614ab4c0132a0af507cc02c272f2661c128b41c490bf10ce668c594c505153a755c21d3ab96736e31b903c502821413b4329feefea9770b79ef9f4fd86dadee0176d51717a0961ec08213ba97a8f0b694c4e74f5bd6084a2d15a4209f684749902b33cfd9d93bc8477b0fedf574aa75642b2b5e1405a5c11c33d0d7f7828b041912bcaa4145ac21170cbce48087184b2ee00c1c5bcc990d9e158afc290a80e4eb97ac5c80ea12a5996f6856b0e7d9ab5aaf4ccedc7c243d8042f32787ac9d12c2511c744d07b263dd4f10096703c3dea6bc629f50d956bb3d9f29a524a0e96f21ddc39a29390e3bc4e1cfc87996229ae594d595b54b297c050ca8fd4315827f88ae7ba44111026d047f8748c370436ed02ab784121841590b57f1455416189e9ac53a3385bc41594d0c60a37ea73f6fb0097c438bb8a7e7c48793a8d2adcb85ddedf11023034884bc97c4679fe1b5f70d43694df0a63a5c74b01318aa6cc48511a1770c7f1c622a36e9f45c088ace1f1e84217433595c87065f696ce1cd1ad07f72948184602dec7cb44bab85a0bf0e54ff7a3973736996a03fe0a0e48a637323c63e8bc586a7ed95e1f8202fea39515b324412027bd27af77ae172ffafeee52d81e6ce0fb6686b7de77a67a1148c9c0c60aa022b7ea9f4c4f993a5441baa3e44ba777fc8044392218bc78a1226019b6d206e25cd0b2adca5586301343e7be5ee6b5e8b3bb144b1af6438c794ed8e9c093b586ec0281d0b02a865eabb1f4394333084c6eec2d81a1cc4a75bcd684c5f95c0b3ff960668cc18cecddab5f4062099515a25292f8dcba99ebaaf210ef906e615edc57c90b20b76c68da7292fafecaeb0b1b7c9ac28e7ed44781e39337082c47623a82eb074882559e154565f23e288592a225a5a7d80d6bbfd7b689f59c8482612c183ee2eb18269ccde4602f36eb9a856218e6ef16c7e35c607155420559fa24bcddff1ab1068865f1a8690f4e9e92ab4d7a68e24785bae8b33f0138de3ee11c1412b3b2b8e8381d3eada2a02a18cd5cf55f62769c40fffc012eb502eccf3f1a74fae5ed857426eeb23fb50aab71aa368ba9fe530cff80300c1ae80ad0ee5021e15f92c56b36e13516015034ec15c806a2675b2880d28925eba912581369b58f82b1cfd58d9d052862212722ba00e7daa8d0f1f9299edb6056585accc5e3148a3a102ab34d75b7c2616604df1e92b6eb6a34bf2fc2cfd5f191e8560502f7ca5402467489c8c55d7ad7e37529503284620f48c292b5ce4c1791e9469db9f1895e7e259ec046529e0c9783004b9bbceddff365c299a938a10a03769783dafac6d3ddd1e9ac1c374fe4d36aa06f8b306817bad0d56283a191120190c923d46f6672c9d32b0ad82e6b74b2affd308211cae341054b394d72cd38511607ddffa27b8f337f316a8b8f93db20bbeb6c0812b10d15a8489d49b75ea54a850ea4d09616079f0b34c62a6565f40aaa1c70ce3bf8d97c79d129f6db55ee11227c7517540117b8b0f96d2416d612270e915a63c3b48e3685ef4e54112de8e79c3b1ddac6e3975faf43ca283be9f381a09bee04b147ed199ff878e84068505f607770d9fefdadc275003aaaa5cc98d47bc93db6d6ada8e110e8e5e534fdaab22f90f3b82fab5d4ce566af73d640550c5a7c2b303cc0b254fed5b04b056bc2137fd496068a36866b51746b8fadb3bd0024ee97c1dbee0b4b9075ed06850e9f9f8b4107313d67e1afa2f3b18df6e0f799fe89486657d8fc79b91335de3e1dbe0430ffe208a8d3e0fe9d565d117c7e6db3e975dc17a2cae24a60628d01c72ef18d9ff86791953242241895b9aade6fa07a86db22147b97668a56308f4396e434234653d30752e63d13f86d93cf6b01009a3ee107450ada81c65e20e0a098d8fe7d80f006754b470c09edc661ef40ec79fbda2d459ec72fc51154e45bd180e8128cf65e1b689ada0e6223f264b037c08e9b1ac33c76a86453cba11b41710ed830e082707ad02d7486b58e4d80f7a566c8bffd073751212d7650a38802ffba0d679caa5d906c27da43708a6a013628e111df9884f228a8deed8ce8fef2d01c9a49e4c4721db34ce36d9cfbd81c8558e9a1cf30e855d3f89420c31b10dcf417d541b12ac83e71085e270695e0a7db45fb9e6f925d74dd2df9ef23247d99cbfe88cad2be9b85157a2f9f56103719e25dde8e6c03167a9e643f4bc29f5c4fcf1169f530bb7a9b7f6c67154cf9b99a3223a8e2f1c43354a1cc193a5dd6a20289233c818d5cf70567bbfa60396d2d99c479f8aa2c0a6621aad06d8ba2dc31c5c0e7ca893539a3c8ea48bc951ebcae1707e0a0bf2071c953ecad18b15cb972357b1e7f6e95ca1ec927e36f31eee3d2175bdb19512c094faf3ce8816847d27d259a6dcf53b7147db3a9088ddb5f36b99a0eae03efd51073c97321df1f28be8a0a6199e4ab9fd2bde0b96b7a3949ce270de6e567a1077ac2498992b7ba440387bfc99c56ed68de28405c1e7a4f378d82d9b2708a3df92c7a3ccdd882ed9aeccc6ee05079c0da2e642b687d51c79135d8e08cd4becadb96e2fa254000933c50725e84fcd67926271799defb013e84762e50f90d4d57a46a8b369ce41f9a2932303e8da3d52823d5e769e684e0ca15e4e1f09df19d40aa3be48724518ebf3d0851c59294f3238d9128a2439d2e98b1df3c76115679c095e80b6e2cffa7136e3fc8955b84432e2e3f569c79a089722e183baa85a2cb9524dacf17eda30ee8f20bf25b14f5240d55ce29d6b3bf61f8287ef806e75f55a2983c1773223b93e680a418e4db2ae7e277696685acebf977d13a29a897073863df269f48aaccd7f66daeae9d1f3df040d736bd4e2403a047e2a60ca7c6000b681d2384a1ba92eef3c3a1d396529b5834953a93010ade339d3bce6d441b300c634e5101c203bec5e70a39df81248adccec4fc97b4aa118119cf02dbda031bbd1c6716c7ec8c379e824e9abb65bc28247e2bf67200ce577868ba19e6e46f93b91535f6e3489c33c76eb4e04159cd875e4c710d4c48c650f627a6e285e03f586e4bdd2de70dabe19cb1151c066d6ed081a16b34644db06a96f2dc6974b37b1b601e39199ad885b6fa91d1486ccbc264be72cfef714bc33e1a3511e680182f89ac828e15174425ebb01d3049cda71ab591b463670e6f3bd9a1048b9e68ae0771ddd8676fb8190127e59bece03ace4c7d3c4571067d30bef3ae26f9c47b988a120071b10aa40ab763c550e6b573fa703299ac72a50364a8cd7a4fcfbd3a254dee908bbedc432c57b323198d4329c1401c1f00e1ba5ec43e71d0e648a045c22b5bbf0580ec7856878080385b4c6eab9e6146f222636db0613a0114f84771dd0a453d25f29cf5b98f20fa4129ff2bdd0c0cfbf41d3ded5aee64a6cae2c7a495093e897284a49bd670ed8bc246e301ae830e364ace66cfa7e5e02a2d9a94e1b56afa488991dbb04b58482e0a4a6a326ff34dc82e741dcd888ef00db2f6cc0e56bf68704c43bc7f513f3b4447a929653affd770dde0a51d3054d7e00107b87d68525c3cd850c90cd4bbc487b6d4144e31d5d6cadb462376ddf68fce660704de8e2a25b1731ac4e3f76d33779bb316bc734a7ee0ea64fc4c0fd88b2540f5f88b980c9a0c274a4ce6c3c47dc999115fbe69fa7941a2c0fdb1e3aad3e57856b4b996d3b623b498d84eb5de674c318200031937d583c3c434860f59d3b3af9a4022b93f8d4bd7edd29af849319f0404790950e174ca47a0a7f82469a4ab26a6eeecb03838eecdbff34183cee53d747cbab9ea9d23ca4826f8921c99a164d5c0976955dcf68cbb535cf1506f63f2feb6d2916f76e738324f56b46a1919769afa420760c79c17aff346e5030dff4bdda94d3e1850cb5480bc175e6db40959fc3b8db549f7eb5be272e5e70e131e26637a617242a70cece380444fbc60f31daca94cd78c3377fc0f6f46c3603096255f6639a42156669941c724b46f0672a6e37bf77344453c96483209366a66749aabe7bd1d7a76ff210b0c9960f5b50485bbb3b7e311610d2080f27be11d37590eb0d2263148cd3c35fecca3b84b991bfeb13009dae4e8eb2fb32de886603f25a524cfa34880f5b83a931bb0f762da6f982f48085fbd5a19e019acf98a9496ab66329ccdeedfcd94bdfb6bd9f5ec2e8f5ff52365600d0e7917fc163bff591c392dcf5494b6e5976a1d39648fe2e7ac62f0613c76c43d0d17ed376b780a569e6b90e6ca473b8b940a0afc4ab2154209035eaefb2abc47c0079ad853fc6bb9bde4048af0300d4d2d8c237d811ebe434078c5f7328f025887657a7809340218e28de820c0eecf356336f10f3d9c213089ac4b5f8a12b88b25c386db82b53eadb7e6df9609fc69d2861e8be4327599f77762660364bb2ea2eeb92148d57fc9f41272b37f4ef929a193b39ff76bfa164835e3b4cd7ebb8ac5f8037e1e1086b5628c3543ed19deeeda0b532e2227321d8a5b21fcfe29ce41a06047a281a45a24c1b8a17d9517fec38f591d12b3af837e8781086f6be11bd6160aee0d8f510694da67a9cf3248d7e36baad8770267d6bc330e375eb6320e809e360965c2d137746912b5ccb9ee954689cbb050dbf32790a1990995069db97aaee6aa1b2207f7fd52726c386bb1fc03248e0883e5374b62c565e343e3b078c7596fefaa20b89cee04cef7ba62e70dbcedf5f3dbc1f8bb1cadacc7d1bda575430a192370fc41844fc2c04748b042842e7c4e1185417ce396da47a1e25379c740324f4842eb4095f560e551b3654a49db042a27dcd56cd3761552c17dd3efa5eec3c9be4642be036d54cf4d30ac99775d7bb7e9ccb4e1769f97ce7785b0263be5dd561f988c5c55dbba86d44fad1e052f3044970a839c398b97222a38ebaf941590b46b2a1327e33ef8d3d138a357cac90e439d977e8077e6b2fdd0176c4539c52dad6835df0424b2ce4d42e3781b28456b5da8ecf016f5b5cf7275ae21b362183fbd11548065e13edeb636ebfac6c537272053a3d0fb8d4e1ffb8762ebd90d69c56e4a930385ab8815b039a553dc01c1678803d02ba4e8f30f0d715618cabe9078f018f7c98c2e11f47b7af7583cd4c2aade420a1ead9c27552a91fb5d50a65c9bc641217bc2519dd6eca9a0023f4a27b09d278ec91529667a46ce56b2fccc83fad20eb33b100160f6febda5a81bef70d01c562cc108e02937b2de93792eb1fb9701c7f7b73ecf4bf087cc0bc8bfa370d895a94c9288f3ed6ccb8dfbf6fc9ee371fb84933d8db006516bbc6a52b9a130d39ee74e37fc6f945c24e95165aaf8c95c97f05b649aa78d701d75cd1be3bb43b8d56b8ced265113c7257eea53e152acea91871825cffb968f0628ece5143956098d6c72d4322f5278faa5df536fc566acbbae885fb54d6a15898f4acb2b2e2296205e0bd066916100ed096812cd6cd0aceb4740baf1c0d0ed719bdd8e57c43c571d160b966c85e6a53ffb760f044af3827e1ed88b3a5ce489a60cb32874294bfa976cf6628cd7ad8b26b5886e32871b88e60cacf227979307b7bac7d77089e44690bf53427c08a53d9322350be90f0ae72c85640f991ddd0407790aa34cd2cb505f1dc8fad5ea10865d6ee4a484ff0e20e5e630137ff21f20adb2ebd13295db3ea1d7b3cdaaf54090b27b0a48553be4fff692c7ae46ab57244d40b37d91620aa1786347cb1869e6aaf4cba53642bccec8908ade6ba01d80c2901be50f1d226d21a827a9ef13dedd681963f2d38566b527842698c749bf90f5bb74c4b1d553080b59245f098557d6c464d8df9dbcbc5dfb80a7842f25087f58fc63ebb4d1d617d1c01a32708f987a8b586bfedc19bbaeb47103ec67c85cb415b26215be8a50cd54bf3fcc5d70be2db30b7a6d5fbed9f7e0db252c39f81ed54cabb6518304a49e630a6070024c7b71ab2bdbf6b178bef3930554813f2b4e5594d3de6e4677593dc01c19fd12fa7b368eb30d483c3875de449e1d1a9a831cf2ed4dbbea77bb67ba457bc452c686cdfb5c8f30b386033bd20a70412bcca6e3afe8a280ab79c6f0267eab108aed8c6457d3a1f7f9138dfd8d85f350be06775a26daa0aa1cf3f5bd5f1e58b585bd510226cd6bda0b760dc87f0c7f1646a54e6bcd85c2f8ad905b81e3a9c2462d85f5095c62b1f85acdef16996953f60f07437fd75ab33f850a094c0c02bf046368de850615e1cff2973c521da2338a1fc97c1672abaab71d593611b7e45edc8895c4c6e7700f51197f5a8b9f4b6b822b559743f77fe3fdf92de8efe7c2bdc31c293141961aee6920c3bfc3bffe001dfac63995a57fbea43ed1d6298ddf6c57a3072fadced2a4a35d2f68e831ddeaaae197e6f281bd3300970b65e261c900471581fc3389fcd2c348fd2c60c1f3b56d1345e94ef9001002cb658190840701292745f3576419af4e3d23f205b917a16e47a7c3d68eebfe549d790b71cff8023127a97e2d1e157e141a397429247cd301da575ac670c0349afe8a030e16fcd3e303901f7761190cc95eb213b1ed4ec77cffc9f9c903773a8c9a08377347f96cea12e478e917b45e1240eeed8504a2ee7a5d20ddec937923289c1248c1e2a642e09906e689c0f0c12f379fbeca8df170a2cedc797e3adfb1e6709d677a9ee84dd0a6d129ce98d7d6428b54872260b72f4511ea2ef76ad699bba00fc12b74b5f3b3c7bce0a2ba526d00f1085bd198808467ea9963a51c2d84a4989343007d5407c2a294c53a563044d4c7468dc2554e9b6575fa9e876bed7cf1084ede409af01052dfeaf6d51d35ddde19b234ed9c0d47b48429760411a1bf35a137390fcf99989aaf874687db59e2a680d0db64789eeff37b1465d5ad7a5220fa57cd96d44a6cb5321b890c18f8a5bbdf63b6392aa59aa020ab70c15b88792b28411db09a1b6c006e4da9f8124597171264a59488d0813f78c69db80b727339415c322e77de5c3a1d71a3e37c3448a0153ec0eddfa410c981ad2499e7dfebd3043743c11511d57a2b211ae0ed86c441db86729ab78cee901c102c4027e9e3742a4280c64611606a76c1daaec77f44bb9b52486e19318be029e4fe58048590e477c0950955e915f9d120965166e15236ff7a10871c9c76fdcd04365c6038e09c2fecfab210a935d6335978156ca58c75541111e860e74ad10dd88810a464575022d2c0c604b162ee34691cd17214c2e1707ab599d96dce9a0e7a81a548c02bef97309ffb20f9f5a469c0d58f71275fd27570762c9ce490561b9faab5d3483d79128b61b12d4f2e44356d30735a09391188b40439f04fdc9b8c359ea9140e0e074e188a9390d21337b09473ebcc29cd5edef90842276485316c9e9763ac1ba1466a23486512d976ea7c414792fb2a2afe6c9a49853d5fca5990ad1067a85488ce08a41b588d6ac64b31fb368e0714e89a3e5d96e31e35833edfc6f6ab6aa1a80f0b1e0d2f13779e1cc7a5eea578cc27f7584c247824b64bd6dffad9a559b3d0ca914f182f385c873abbc58939414b1589237e1c3f3fb700a723c7d15b723f684769048f9eddbf52fd48fe09ba36e7cf470c26b4c80cc12266acd9c9e00635a35d8791f8400aedf78447bdaf1b80ee49ffef35f601ae4afc54e1d74d84d2d8b14e8d5eab5bb286bca6f67e31178108fbf735818842bad5c97152678ae13de2ed1fbe0334eb0d710db7de4b0044ddb9c89c8b91639b2d91fa656d38c3e1ba048859b1c8ebc68a3ff94454e840ee394d72406453db0cd94f7e2de0fdd571c11e05612fdd662fd1e84c867448354be60ab46c01f692d6b29fffdd4cc2226888a21cb34b719d916c70512701544dac841bed82ca2e59a6db8143034dc00df6cb053ee0653d4efd0a8a37295dcb5a20a51c7f0362099b3bd3f6a1f3028e2720a08af6f115b6131184623fee9c8f8907dc9fa5eeb7faee75823c2aecdca0b4ad8aba10233a709dcf0b31d3ac482d185a0f42b72b4116948d1f169e9b14e718746a1c2857e2e0db8376760f487dfeddfeba2f405ad11e4639d6ba874a5d59eea7e1aeb4c72625697b6da6f9a07b6ba65c51e684ecbc80858b114af224489506c225bd33b28f214d3d5e32ad190b46ad640ab7852da5426456e2dba539a9cc6b8545e47bb0c794c48c516ff4d591ae10b045528eeb0ae0ab2faae2c8d8d9cc9fce865fa9b4f982d6b591adb79d05141ea3228098385c907481df4f7ed6b1915193816319f06f54f7a39931760cb993bacc908dcc8182524917c3e8448bb178b94718c68547799e638cb3b3e4fd35a94cd32981176eacc02c67d81bf3552f365f929dc19bca4ba445ce09a0dea7a5203e0a26c985a26d2749504d44b12c41fa10a7c2bf807817a7bb87aa45096480197f7c47c8027191c654bd3e2384f41f92dc64fd6217b8f4ac3c752d37e3930125e855f28e2f7678c7d625865da165086c93249a1934611ca749fdc8240ab035fb9a2c735f2991636ed7d75b7012cc6c975e769505cc09300cac19aca57c601ea3b038173cc4c2053ae6f73d3202e40cbc4d275059190284e169dd7fcc9b235ad25d7ec80131d96d43a16c94f4dfa486cb789a70531fcc6ad58c35eb7d3376101f66606fea730928df666c7f46abbf527eda0df8082d5234c5a01b6af9ae3554e74a175da3d7873a4cd4ff5cc7ba0cf82b3cc4c441ff1302e25024035402f5dc0e38761fcfc82b52c42608df8cdba64f705e113db7e8f89f336af9ca4ab9de80922cae734bc7ba2769187c7dc9d67de417062c5720b90c90aa597cf4d0226bdf02e9a3fc0237d7db4cfb4d75977111a325f3f94b9099ab75fbbc79d79347df87fa2712fd6bf8971083f40ce032fac36658468d221b1216160bbec8bda2e9eb56360b226cb270d1e277d68da7679718087a8882de8510de55c60f67c4c13a41034a5f5ca7e1f8ebc197643a8b4d9abcc7c9d55223923fd199e4f19436142f1db9d1276ec0dec7fc312afd8d0a684127b6acaa35212404f6482ce0caad7c1eff7dd95e28331a3d4c3aabd2fc787f6ea0a2a0dab0864e8b8ace482fa1e41b7ca3288ba6e831f8bae8186842c006be24c8ffcc9ee92d0039370fbf9fc51002d7386cac643be7aea2b47ff71c114c4cbe6b77a062bcbea7f6a7a4c2d169ed2b40cf826acd1678e14e005ad3567a4c1722eef26a5177ea144748315d3c848ae33a4ca6f6a76de3de4269cd6b296185556489eaa34f1143907deb79a9aaf9ea0f02e1cf134fecba7fd15fced19c2753fdd0e5f3f15ced3e28a94b4fa94f759bbf792d45b954a045045e2023753d05f9b0e3619b33c62df212f8271e4f53d33eabbd3c591fbcddf33e2274296b5ae753f3c3d6d7facb905d8255918c53f010f7dfd040cdb84366dc56d7d7fc5495e13e49fc39289bc9a24505fee562d307deea17f30f1a7453444a73aad6dfaf88c9bb4d79b142c966c5bfbfc90e533d931d96c4d8770609bd4f705aa8b156dc0e20ecf43ce263b9b7b3a5e124ccf38853324a410b8c98a93d54416658d08186aa93c78c6a1b3c6ac44a98220592478a912dd13555a1c5f00e2bc2df5b4f140c65d30cd47c27952c8ed75f120de42f6641afedaf8faa79a4e3112737b0e0b7ec81f32be49f26a6a2d09786f05c234ce940fa1029d4328a7e3d55c771446d6ce69078d203d9b6f4cc893d9708f1b781c17efeca85fef4416281cf2977888f14405a4b8aa70cd4cf38d84147b68951343d3819d824e5300a6338f52ca7e0f0b75a1b00ef499ce649b9c493c625de2e949d251bb92eed5fe312d83c7ce417c817a0188bca5116852bdf4c9bcec21babea5c3aa6823131eee8be2b37c53de7b746f91dffc8c6cf1affd22dcb1c69cbf14f725bb44883655ea5bc8f3808f3c0b593435021aa075e607ef2097c7bb53cdec274bd81535150d74cbf749e09632b688883f9b2d1ab723fe7e5cb821825cfa00e57343807b8d9561d6cbf92ee3545fbb01aa77f74a323354db63127f242aec538b5fbd0ee0aded92c4b551c772aaeb53597f1d5b5a28fdf7472c082cbeb55ce35f34452c037890a1cd0fbd002f52fbb92e33ecf8ce4177330e5d6d00a000dc4f5f1711a96f7b3a2ea4ea7622595dd493f6eb1aac607573c7c5dbb423f1594af6778d0c8acfcbc409f24040f30f1f7a7748e025174d5785b986accd00183006cf38b3f9a4384a91e6f9f8ac1dea4c9bcfb4e90fb355835fce7eb5404c9a4cccbefa0e0a3bb5493bee2883eabc1df85f6db939185834cb6e692bf7aa956548358d14692ea4e3361dead602e80337dcffcadb578b2300fe42269b721ff284b130021c946e546d773e0575a0b6d7e65a92eeb736517c94f4bb563a44e7f657ceedaa830b13de3646100ddc639af21e6f6d81d7f5da31f3f2697ed1d004eebb2dc80a34a6dcf607b96fc2a19843b44df1de7672d880e498bb58f928fda158a775ac8ceebf4f415e3b61735ba3681531f7a4cf8c9367129912773ca6f7e1781a54ecc835b0b37379ecaaccbb9027c8c116f53557b32363edd2448cafa3ea574e84440c158c7d864168c12cf183c018973a36ade6e3fb8c065ebe2d478b3158de4f3188eaa5e491ad1dcd5a9e0e336c7d613061e9b04d67a62740332305143767159fcdd74aa4526004262894ed980b6ee6c2c27f938055661a09747c38ddd7f71a9bdf4149a5c7b519a0baca5fbda5619cb9f4468f206f14d777333632e3fe68b1493b55ce834ef73962a3fe46c9a76c3d7bd124c54ae514c5a2006bf496ab0595fa3ba1271d004abcd0ec780579849600ed1a2b8e1120736e3ec5ace25a520d51256c70da02113fa7bf4db0b55e7d45f44a903a8c491183f29b72a6c819e7d66d0e25c9255360f4d564e57b9e3b6243aa05d5e7ff6f5668c829b115fcaaa151dbf752fd11fcb3d87465f46dba423e276a2a5adb311c3210798461f02c856e51c80e71f319e8bcf1723aafc1e61f15eb3890e4900fa58848963a841f4c9739ee823da5da64c0339a93bfc4ed190b692d348ebde711eea86430af809594a019baaa9bdfe343fb3d05c421b377904d0c78f3191fde14f6e8eaf5e44a25a3b14cfa4241ef1dce358adf8e88407e4aec760e6e8c4723a99e63edd080407d2e661caeb1e8ddd4d350c299a2238c5db09d4b1b0524e5b2cd9f7398d2f6f78df8883d1485326556e07dbdfb8994da721657870d4ec3b48966e104de74a67005090000abf81bd7984f5a4ca88039aa1c7d72dacce25a95b8e0c10066b76f797ebe492eb70c808e486a31f3a45786f5b60fc7870abdcdf1489fb21c5caee6173ed5afec7c9145d2da4ee5b5d5596cdf8b31017d034751968014484abf5b49b0d1017c53117b54b097111252ba9a28a6760f53e3c5b810eb215af281ce2bdf817d12b208340921cb14891582587a3df67949dc97bda93821a016c9c3d7360fd127bd82da3bb67f1937d7f5e767097351f3bc7a250dcc30ab2ce65426a1561c12c7efe86e5e4b58807fd1736f644138240fa630c9033b1a6bb31d719e7508ca8e99d6c95ee208be628ee162ba4c1fa862514d3ea6b79b08234c8ae2002c2db178f5f9082adaac95c88892ac7644f5546f4ae2c059024a8e6e560137af58e82e674c021d0b0c1ed68cd8ef188b7583764ead6c31cdd3c7526d5d6c36199250febcd90a68f3e1998d8ee8db74d705d2959f7f47b9d146f16469d58bd9db79731691097bcc36b79c9a5094ec239dd8f0a7ef4ca559cbad89e21ee56042acc64288fc7d751035584d8f54a4296ddcb93e3ae5c572dfd37cac502a9a92d951c59a261e57c4e37d95fb61a7a98d91a428cc3e3525941d6490d98e5fb1859843715ed0d1749f5b0e2d5c4a5414fd454d19d0627b15ab5d8c3590804138c3ed6c4e9b3063f0dc18bd5690dc56ba2fa5d06c467d20f767582787c68b13ec3df9f7e7a11a07923d997eefc80ce877c795c881c26963f54c5964251c0ca29ca0730a6a3803a1eea37040e044fef626951402a6c71bcd3efc3725e87249b800f7017186702ef7d3b34d196ebdf7b2ff691e61501f0102e1e73814b8666053bd3cfa8867a0c82fc632d991b318981560219c7b365c4ed07e3f99bd9f5ffef59e4e6338d8543170fa0a8b8960cc236cbb7e02fb7a9bf631405092db8e4e9bc1ee07144aca5532ea8e4e40963be6a9e3cffeea811b195dd155328b1ea27ec8866376645cc2128e67c580262a3a72af8f4a8bffd8f3a5f757accaed78192e371ec7c9b62b3eb4286984535169e9b0ebc81e2a4fa2733f7205d73bccb1ba4ea79284918e2ba857957e6b35eb4689622e7f1a8b6d1c5935e0d157f0de55b94c3c19ce701fe21d19a56b0903ad7143d92bf7c25d1d7fa49ccec4cd1f9fd3f9b5e95f189256df592b787067fc565db78bd767591d9ecc395f3ecbbd0a053fcd3e5216d04a8daf5f7f7e596c9a61eda8e6c865fa971c45d43fdf9782b20f65a433500b7bee914de195337eb47d633d3792aa9270ca2e2969b24142133ebc1fc98223756c746fb6b9b038b585f8c854a8e4632329cb2d4d3239da04a6838aa40c344915f5fb9332de658e84f590b2407e3f19a1c2b257f482190c67d67399a772df5a32767ef6608fa8d46c3c235df0fd397c87b878109a3f69a543c19ae4e353df0ac18f8d86c20a7d5422301c80be95dafd712dc53b3910a32bce6f44009a931384b8fd59365d8d57c55fa1affe2f8370ef292abc83c6311141196b61cfeb10c72161267af30d88b8144eaa26f9169846ed80f6b2dde61d7778e702b1adb6b61edd4fd17bcfa2633160171a7c280d4f38fd458aafc20cd7a8d0d9b1a378e310250513ae735baef79eb505d31172c2ab0a0e39ad3934cad33a36162ce404a2431ee07881b06bee73b3e0f6ff79fb6bdfa15efde14eee6872122539b3dd7ab79ca5c209a050e725399300720d8d6480bbe858f1e9103fcb5cdac1e8c13366c69071b37d871612b0b754ae762161b5526b39980dda68bd8852f15d3c6775a12c07fb6ec9c9464e4a648a5dcd98680c777a851fa2408964b522a7f665c5c9fed86a5e8b7982a7033e36dac16afd581cac7aa7fc4e3546fecd1f4a7fe10764aa867a7823e2f479592e9d7b02210d77c2333583482f5d7681ce97dc3081535d14f4052604294769e6c2637406cf917a8b8be54f4562db527a49823ab3db98baba79e4cf8661f560465f814ff77ac786d3545cbf172d7333d4a6ec083dbc0f8f982c6fa193cf674af17d9e1a0d75f8a75f196761e24bc9570501c8529a6add971bb920db572083541f422cf21e4483aa042d8364953e629fedffbbea41baee9219cae951d6c21c708ea859575b01dcfed28742f60de188924d6c1bf605e7dbd905bda72975c0ceb119f63172a1e07536375f1cad6a49d496993a9e96ba5ba38daf1abfb44b5bf62e08b7e9567231ccdd5567eb319a2d838819c263b9ab106d3879f7c8593d7fb5841e1dbb12151b956f9b6b3f0e5c56d065f2a5fe024e68b11ad807fc9af4e3ffd92d863783cf891ef3736857966a33062ad14e06b7f875202d9716a7905de3a7bf2c29c3fa9f228684d6a49784e32ab5c5aec9d4bf19683aac106f5a7c0a99c530fdbeff6786970badfc9d30480f3dbec1dd6d0bb2b205d8b71b1ba7194f0d36b12c8fbef5b1e526c343cede14f00a2759ffd0ac43fdf615e4f53c54770005852a25d6946fc59a67267d8904e4ff814a974c7ca2f38f5fb7299283ed661c00558188f29879e2c1797f017da73193ad4498e7963fe1a797d56b97d643b123c442a8e8a14818c6c6a632969add9d3fa3d6ce620c07df7f1fbac578d6787a3a8be4e578fe640716a174a69225a43e7b3020ac921b363d781a782d2fa23f5f9396e73d58aec9a3e0ab01c30518f8ae9e17377d4e697c6d726fe6af8b74ad0914bab746683d85d4a2ac8ccd11359030eb1fbe348f106493ec3acc4506646503c25c904ca198b76f00b4e806a4771a1c29effbf4b5416e4c2a4995ce173601acbafbe323cc06acb7e792f2327f7125fb95ee8ce60ed5154571c9261410289b9665d529ed9642249958af95e0f3b7d1b5e276b26325952b40a08dbb0e1570a8a2fd43b52800437fe18180315aaa62e4e1528b0753eb4d61949ea2834646b1f00560def8317bb9bece20d9166c410cf885cb5000df9a08c6fc6a999a89b0c0cab71842f6fdf4e629c48a0b7c926734d635b7c9bce5000fa4fb2338a87d6b1cfadba853f410c63a0b52987052bfa7a413b5130e176245ec8d8e902e582c24d52ea62a5af9c3cc38107e6e6387f089c6e2cbb3caa9cf8f5d0159383d9a630361bc50c95c62bc1864a8ac2f45c7f6410e8194da003ee14f216966bcd82d06e8fc427aef6cccd9b255c6b67d30294c5e73ef8055d72fab89e0e332fe2b3d70bbf23f9e305890c1a4f4b792d8504a3f6462e22f88b1b558bebd02f6a607854aeddd840ec05e259a3f7bfb5581b7a76b37c9b9cf6451ffc9bc8bab69a162c0e8f25faec7ab96f4b55e2060a9ef9ba000df96eda9205edaa416b3f699708851fbd5c6345a929fd0ff277bc3fd5d330753ad7de4560d15fc8c7285ff7d97c33948b252165df7b392ea7ddc15daf8e63a05cf4f8fcaab872defdeb1bfc8536e4ca2ea54da597f08824920878f69dba8acece5157c223a773f4f5a9e03a34ed4b103691b26ba5ba9cf944f1e90b0f3e7cb33efacd0a8e3bf663e081fb32b4a18cddcac21aabb1c4718ced9c0543825efebc98eefdf02def9ba4473eb7c23077f0840e530d6a72d12f302a0095436b775b44d09464442236bd2852f3eb02acc23ef7937d2d90f63fbd9f75db261c876d65d5bd4ec92aa4a36ca74507d667c39a3201b3fda71353eaff1f5c6002b244afbc37bb9a2761a829a89bc5a5b10769e68801c798b8b038a69541cf973d76894069b5a58c106cb8dc2ad4b152a505ac2e2a840663ddac5c403c15581733721e0dc7628b0df39e4a057124c1e0e88a569de5148b2e2359bb0cd50cab68436f60988835b8cf55ef6a3d1c9f62b05485c5b070f64aceef5b2c3f9bc3b198f0f76008aac3332ece2a61c466bf9885aabfda67cba0d5c119b08b1e20e2772e781c7aec6986c5bfa236c0dd75fdd9eb9778f39f955263e190709dca059a3d356931b37c053f10c15727c53344dee090f5ddad06131eabd70110cc09deaacfb17ed3b09f98e283dfa09389ee46346ac613c828004b5b3ad0ccc70a0ce6b092303de8edb32dd3ffc59783dfb627b850cf81f1a1af21c1cb4f13a4548a29fda6f3c95697dc4b36c0073dcb6240620e5e506feb2c187b2ad99a418b16b782280543b1a9a4575ab17221c02539531a298aa8850c21797c76bcb7826345d0961f77488b10cb338e001aeea78bfbc82fb70fcffe74be0730e4a328936e7cbc985cbb0222693b522713d03a20d0af69686d653f37a62c4cec6d78fb4ddcd51927b66fe23e6d3efebce60cb612ced9f51110267b6418927fff85152f69b33fc607291a6aa9486a69d1ec5caba2bad7ed02167a84a7687a83b033565254fb5cc13ade36e222b3d77bdf417f5ea4baa10a786f5cdf387965694e827e429acad8213ab7950fab0f7e76ec7bfeb037f6bf0e6789620915d8bf9e20dc3d79d6f4628eba08c43cf0cfdd2e379ffe67e769c6c946d3a77ba792269b79a47c0152beff70fbbd210b5b1320a0a8a613aa30329cd32ff3e05631d5e51e1ef5ba543ded7e2bf04e2401e298606e109f85f85e4e86938e3fce3f1a60f8fbfeaa0dab9be4c1fef93a12fcafcc2090c2b6c74b6d648b1ccc7e9aaba191ae78c99131cab443d05b146d6a7b83355a0a0ced0d5b3b8dec9a3ba792f3587b5853590a75d2609dfdcde9faf6b8176f6595d7e40edb6f730104a481f33976ac6520fc7368bab6fa1f657fbefb843a7b244fe1676c3c2622d3f27aa757a7afa20603b90eba60154a32f9afd25a82c875f608626b830f9310585f58dd0b04ea1683be3afb721624b41ebd753528cf5d8b37ffd66cdca0d570f5d6b6b6f261b166cab05bc128510cef92e8500f0450410284c6bd8f2210d27514bbd05640e647da6e6e9778830c7626aec7007c495d4baef0e203ef51207053990a4920cce100492c61c759341348016162c39e4035b799c808b8454c2f591570b972c84a1fe98118c07a7a95df43bb2cf6e32765f8a1032326301380ae9b216ca86ce2e6afc6c3d9c265bd12b039201f65dfe61f3880f31a57e77a115b32afecdca3a109013032bdf89c624df180281142ca5db2ebe51eda8bcd33d2ba193e9b72fbc6d7a711e238aead754e21d9a0bf6c9e104b8384c624bebe85b946a77ad327ab7acaefa072662ae6fbefa8ce63d42e9eec4a65011c3a7409bc2d90ed88137ca3b5b48ca5269c2690a9659f4e02b2c44641a660a3b018d865a0188f63a4da31d44efffd36e39faee94c3f0e7460e6808d339f06d2f6bae4be0492cee01036e82afca55733f7c0c7052b5e2096c5819dfdbb5b553b27b05e580b26bfaaec5f021befdbe3a68eefdc23bccb94af2ddea2a00fea62ac3093de8c2d046fe6d5b2ab89996e2431cbbba47ff5b5767fdae147d96e3571c6b678df4c00066dee4c99ef7dbf9610e1658acdd7d0710cbeffa09c557459a46bfbb93b8b0c5e335340cf4688c4f816d9cfeceb18a627e8a418b1ee1b3cd8b3a7f719bb02d0de5dc19808a43d3515378b03ba5a912a1ab37912e8ab07c7bf28de392feecf48532ba11649e17eb538320513f7be753d03d8940c7b8e1c41816b59de475dbe58b2bcd5d5c36e6b13eb4b83f3226b17063a944298b93fc1e96dfe1ccb524011d2db6797053bd50700047059cf294ef2f5c4b10f251239d4698db3a0f11ff17ce93e4c1d7c58c5bf2b51a60c25748e5e0ee8f8dc408452c8891d95fbf21ef4b4116e78450e23715f7cb99e2a6be1c40b57cfa602069e3e1845478f9577d21316f91577cf595609757af71de2427c4e52115a75a5a3c26dedd8e26c5a872cc09ab43a61b2ea777e55faad2182df0833a9a6b34a369a10280a7bb96096157a8a333ada01e7339bc7eafde5cb4a7d2acf21cdca0514f75fe07b1035cae98af55c33e7fe8d2e292521b18763becbd0640b1e8f2a071e9a5d3be74107a4bbaf7cbd1a90709d43d2ebf6e2a627291fff6ee125758882bedb6bd784dc1fbb80a942f14edd2fd2c4d9523caaf161bb77ec35f398e919f3004a5c9e9a109fd74b458c4350594b56cd95158c7e80200cc090826f7024d3a4cbcc22a99530c31a5ea7dd7cd59dcd5f9a2adab159ef2505b7a41eba5ecfe4dc6acdf1af9ef11f021141275b3f03d77b10762f9bd8922c4b4a3ea3af519eaad5654ac4575a11d3d10d9fcb3dbf4275eb6899cf407dfaecdb2e3d7bc0672050fef6c877167c6de3af72ff5a1e30ca116d6569ec3ddaad32dcbb8b3d5c6db2485d37dd6c63252ccc192727373a3edecc677e21fd02adb806ae0529d05c9db4507f9ced211195a68b43a5f7cada555a99b0389943a213c90e3257e8361252c6435cbcfb2356f678b0456cde5add3f7b0dae62d206739f7af623392dd560a90ebb3fa13c493bbf105ce4edb8c270b9e582582df9889cc459d012f7cb31836f0f6fe7e4a446eb57beed9714002b610cdafea2a8b2fd97ee84bf26609f7bd46ba66fffd548082439e1670c3c1a7bf4007ee32ad32d95a769fe0aaf484295f3e3c9cf9ac9276687ef263632e637b007f4bee27ad0dbcd5ed3f851bb6c152692a97a791248087a3084469a75eec11e0a3bbce787c8c5c626b743249200b662f7f3d0fa53c5350307e46d7f5c7a15d54a3aeeeedc80279f46df87ff24e12a1ee79c6e82895aaf2942c448dd3c323e6cb1444e1fab1bdd9b30b28f0c63dfc53d704a3c7143b1ea04b5f3b2f5dcdef46a24a2373b62f084ca01b391ca767c59173a4208f9726b9fe00a2650592a737a241aa4838b80eb1b36283db71427c4f5cc63d3478a9f34ccb4a85fe25a3c0d8e704bb2388addcc057302add4c4cf36f9367de6fd408b421d748562f99ea707d83ab0f1b3d67d074c8b9d5548649790d7464c436f9b86a2f35bc90675d081aace973aa97928aa1b4cc66c353cc3b93a1a6e163c7820595a8089541bd01bfba8032881d8bda1643af4fc7016775a9b901887c3ccc20bbd53d988167d72dc6b6a2a5f9ee5b628bdbfa6745809f9273ea19b130e8a82203d76f07fc1073ed8ac3bb868b22b713e6652a157f757816a39c99febe1a87bce440b373f936eca22eb6d2ad5e3f79d67e3bfa69b95661b444248254021e0dcb9f2788134204efdabdcea5cbaaa077b2d35ff5fecf8b9eeef26cc8242dcabb18ca93e85f2856b7c52b7bf27b455d2c9426e4bb5eb7ee0b9f12eb67dae3530b727fde31ddb9aa55a4a785c5bbd97678d8a8e398cf388d026d19925b55add650d0047183c253a7d2ce8825cf42668f199330e8ca866501481f73b106aad79ea5e6f1cce31aab488946a898725bfefec53203cdff03114be22a4b725c3a69b08258ac72d7ccf144f6bd148975322328771608cd9e71d477ef55cfcab6c94b8618ea4be5108d6debe00cd25e5a064fa58817b5cb79bc55598f0a8eea02e3a2047a5407326826b08a2c6a6b954ad390f636a652b9b7dec2e640ad293af75d9660b600149db2786e33bad0a551e2d0a659324bfeb8f3bb148c8adbf60cd70f0aefe90c862a2cf7d7589ce34f06cb77e5d110e8d21e50ff30069ffd94219fc0535794ac40aef88c5edeacd0bc7b1b69c11d02becdad8dded6c379cec144541ffb58ddd32bdf053e80e2f44af58c5cae7bbdf5efcbdeb09b542504481e81a87db5eb0704ad6399f32442d3c7609050a9c14c03dec8110d8c9f853af9b8cbe5650be23472fa328ec98d3b44d07fe78ed0127ec2a38937c842ad5a5c9ffb89fcc8f64a9116afb92308fe3aacf1ba453106ea4294ef8ec85a6b54ce139746247fbfc8ec71958c19a26c6380d6c12a8792516ef32942e485d3af85025d05dd87792fb46d8be4db50308055dc6828d986c2b5eef360fc3fbd04e2663787c9770bb4f67c06c27dab4418f5019dc3149187fa16ad02f673dac0a9e89e0ad064d8e58111e2eecc0ad3a9ea330a740484916d68166a616ced6d752f2f367ab9b1b91f8431588da39b3904861098b191bdc35b16fcfc15f2a7e7f2bdde0d3df09c55ac526a69a0ed56a0296dc9844eef41ad02ca187e93be455bacdc7a88ad0df497e599a9bd306fdc240c579783994697785a1f7cabbd0a2c5944c43290927b8ffdbdb2dc135239daac9c46c9e1ffe7346aa71e8ddf22142e21fc484fde795f643f1a10c3dce3864ba1ac16ba724aa1beaf3bed7d583ac7c66a67904cdbc872202bde336d46e1f6f8ac9e84f00baa4c3a525a199c07a0fcc1dca0320e72f45487861025c0fd79260d237f5f25301dd4dd02bfcb947b2eedb9a351599de8e308a90e52c4b940169b85fe13b03e5d5ddf52e91cee732350b7b063e5497e5cb6a61969ff7daf88a113e723822d85d1e3bb06d7ad467e5ad8f9b35f7e01d1701048c5699af1a03c49443451d3e904adf3b46fcb71e0ff16d75d43c2ecd3260879e31fcb7d8592361f86f45d0e6bad48a06d9d863a05c6592482512335604b4bd64ba2774b69c7b2e94e831f1161b38d62c32018f995b98994d9d5ea1ec2facff68867b1f5215bf466c40016f76c21b6084889dac7e86ab909284c0bea02504bfe88cfe31cfe6589e60f7e33188589475619c1e1cb44200dc67eb0320d4d5c72bd26620d307240e41129b0d9ccf4bd62c5b960fa34cd3e4d88cddf0b02a17f816698af2da339365dca3c618f9943c6199bf0150b77cabce43dc112ad1cf9558f43c456c0d017edafeb19bc4065e0965748516a442765c35cc89ea0f5023550ddd1ce48cd6392a6da031bd84c1e5e1129a761be1cba5a55c299106994eb9e2de5d63db13eb0f4c9fec9fb44536c6977a17351c6aebc4329701cfeb8a909cc3bd09a93b07536e06b20d4ccb9b4bfb6827a77c924ac453c4a4a9422076630b76ba3454297b43770860d212a125b4f174cae843494a5e4374d25da767120ed813ad582cf95e8235dc99949b795c083a5cc7421ce50033f1bf3247426ceb8d889745fc224e3955e3a3e0dd497ae8a5d27f5acca8cda83a43b6fe77e939754bac4d00f09e034108e429022ef09149e3e665668bee0db6449672bf89e1222c703208da7a8d196ace99fb69955f6807a42c698b080a767aac2d80c65ea7959002f45356b97b41079ffd88ffa00d9bdded58744710e199e71c40f1e66529b079a61e352560b69b8c0ff1730ffcd4c643742ad44539ba988f7776560750c50fc7b34143f4bb2c7746c1927d2fdece7837ebf711ca6ece04a510c62a62066a5a4227b21078283cce7a8a1bc0c2c5e4794f901aa481b0215df7d3651a87595354cb7dc7c683e0dc5ea208b8bb32af01465f441c970ff3f8d627186a77580d316497a54d38275ea9cc5475eb7830f3a1e0b52516bbfda776b73791cfb64dccc3bc2188ed164a718fd8ae34a97acd52865fe3900be540e59a29fcd13b16d47a892ac87043ed1fdaa605e5cd24a392edba7302f4655ae793ee2dd95a441e07cf6720dbda025f1a66267a6d2798e620b5c8163dd799a5c2c90eeb738c73cbe8dfb55d86fd313008df557b54d463b06979fa416542c57cfabfb56dc012cf8aa2f2962ce11db5e276ec4afd8c1c151f53ea8483413592b9eb6369d0d0dd37ae0e4fb57b0fe9f447e29122d2946c2e64d3c8d4ed9bfe69b8e9a7fabad5a93c1832befdcac409431e5781e0e361d09b0b60347ad0ec800d5dd16f3674410bea6b553436a1d6523963270e9298069d5bef8460d7730ae35f8461a43f37492158d2c5f8833521cdf23e7a6ec3b5be82be36af005765549483fcfc532a6b5825c4434668d9d5f24bf273b4659760eeaf758e7615055e6567799a3b83d22dd97a79c532a6fec700b43509e9fcc21d1f95ffa3c994358b1a3a2aaae7c018af1efef4e44db0c5436128b843f323d33c4013ba512625f3708c682306264946105456ef22b206f6d16a04f80cc4dda6b109a666bb73cb3e43067e82c4ee57d164c9eddc721781feedbbfc2fa078b9def78d0e9848b5df532341a6cb2c60c5a68e5505eefb8461618774d902b48153df02ad7f5226ae8b2d94129c1a950054c309b758a585361a4ebcb18001ac87a9a048d67bb379be42cd4633d52c8559e6ecf5101abfeea429b2b80ef82263ed980168f80e8df8766f82367ca7b90b6f0354dd1554faaa280a34d91ddaee2736b8c13f47b30fa2cf064d28cd2a5a47f2438705e5ce066a807bed2f137fc915d8fc61d95997464bdbeadd150eb8a170d7dc82873d72e2796bb419f8b853a34f95dc95040f451f1e30412a324b45d8ae3fe11b56dea6472bb8626c75a66c75eb440c0c75dae28056495d2b785d95bee99325033437fab25eeed45b323bc8feec89c2912abcd069d7038ef4778b468c44eeb832a854bceaa6f5d2728c195b8cb209ed0ce52ff06c72a1456d1402fb88dec05c6edacd597cd927b45483397364cdad74aeeefcd6100b6414562a298d470420c8375bd468c12e99133c8e6b13df8daff8867afe94b2bef7429bb9e056ccfe4fd8f045f855963c92f92cc72974c9594064c1a9328a1add3f55313141261a5db7862536465c0fd51a67ad39d63accfe1279498179800939a4d414b642ab646b1cc910efdf68113b7ff1e87320fe3b41f49418d2013c268237037e7c296112ef8baebac3a73640bd574c4119086a4d959b560264d0237828ebb4c5a7875debfc5f1fb7b2d02625a6e3d2ff4f55b1abe88620b4eacec8f9ea8e3cb47999a9a42d863773ed08831257c82c0d8d170755a5e63c1b2f7c364c7fa82533bffea7121ae52538eb91138c1b1b2e66ed8581759378f35106bff7fad9ba1769b61a8307c60e9c33baf2cc43371f6d844a383ea393fa3710fc08c03ab154ea049c55e54b4009cafec9fd0478203481f75d4463aeda6017d5f58cb7758984d1b1d19b8445080d19be7bc02eadca472c5c99735ff51b40f9dbb1870de1cd08a4a0761ceb636a299e249d9ebe5593be717bf07a1366ca32f25fa5c3e49fbf3bfabbd425a44aaa24795e0240d3b516f3ae019af65eb75687d8a2922995c660755742d7c940069de3825c932490ae6cc661ff2102b8f5a2d1995bb878dce2d6af9b5916513fd5d0920b3a0b38ddee0bec3c098229192eb446b5015e918ab9e86cde633ee4c6b6363a480b4250ce75265cda48cdaa4740f0975308873b5445e9429dd3c2f3e400d6bf9c0ee93f594a9790329004083f8b0eb451d627358a55c047ef11080ad6de50449e8e1fcf1ba456dfd7b9c8864a993e5f4f759778de72ad7667d56fd87088451d6c61c02145153c04e07a569739a8e6f8dfaa7820c1df52676d0662c18c3005e15863a362cc7d9fd48a813f747cc9982d98205642b4fa773173fe7fc94dfa7a556b354fece7c315b613cfc5bd0c59c55f93562a3bc3d4888b71dd3ffc61a5ecf343d9db68cc71a70e74cdb7d138a32c7a14826cc9d3b7470a6db3957360435f4b1929d92866b97d36279b3aee6d762df6be02a45e96f4d75cf38d7f775f05e63e7db38ef1468d7ca44b019e9f35c789eb97dd3ecedd22947cd731f7bb4be1566d8e5118cc2b3186312d1bb58d04a45a78fc1577f2af7c33360456187da46914ae6fd2bc97a62c77f8274b54a1485b5f89726339e91d587476248d80754b188489b12c792f64b01b02cecba1da7d6ae0ff314408e2c68d3e3d3b7e777cf0580eb8f2590c08a51eb65ccb96d1e3577277098dd97d5277a1ecd9b0df2c1fd0b56e031931d1219101329c2e507a74a8a09db43477c5602dbe58a7d94e4a8d629359d7dc8ab75145497491b3503a76f186f4d0af5875e78998e9950ecb2e680f9da9b86ef903440300cbc041f99bfd4a9e5bbd8083ca58a75c306c944994b57fe12f87f35e8e3364e065fe251176833e85916dd1d20480ca3a96de0a48f12a2298c2b2b9d7071aecdbe8c3e7257c53e9b70639b40e65cef1908fb63bc66a5e5058be6c28af951727889a3210fdcfeaf2f44b87e0ff6fa10d366e2ea43301767eea5fa8672ea010b6c869c6d03463be6f2ca278ca9e5abcd98d92e49d3a40e121e84b1d1e40fd08684fd822c2cf0122d8ac31edad303da9ca4bbc0db5167f721e9bb4632a6ae86636d41a597da168173fde8bd76b0971ead45423936ae2a89a29c5e4c290fae800b3bf956028d98b73a73f48cd5dc594f9dddf31ecf1b5b15581171e5c2aae89a971626b7051b2f7913abcad28756429dc5b10d1cc6ffe5c504063b6e5c82cbb109cf63865d4c5dcfa1e0b798be57ef522743332a59a0f9d5f8e0eaf6ad50e22550fadf82f5f27b7fdd0a2226db246572aa76b4538cba3fd86d1428be36c3c4f7d5ece8cf7d162c5ed597d4e219a88900d8076ab9930a7019776884e729a341ce714c4d5f5128f97b56b763baba0ef68f533d87486ba1ccff16d954b417666aecc2b9424dc2c5c07c0e083c6746350c5364805aeb2965964d9e14e10f2772a5ba151fc3d5d7929c14a99f1a36db4677fabe770cc2f6cb269def443c42bf0fd21f59d22400b32a7524fcac34f3d2e618a5536f49515be3e51eebf3f06be94f0e6884be3520933122a1f5f3bcfd1f0eb8b579e869e014d97d717b370c0781329b6113b7d21cbac1a61d474810f0c84463c5e8413f32dc4bf8f1babad9ad10b4271f61dfc8e05dd6a8908c90c95e39348c1505453ff78bb7f9899c333999ca5929127b5e8761ab23a2c54eda5105f860051c3b45d7e96dca57064b9f43d8278fda0b6597347fdace1097d024119dad74e5a6eb4e982b11e50ff75eeb2e20d51c4874741b00913449ffff936b504281a069af6e70d79af5696cb1baefc1491a788b80a9f824ac09cbcac7eb53eafc925d5946952be407a69d62568698dc2da7dfd7519a8db7d1dd50a7835e13f162a2da9eb0cb701c83345856df88c8b794e90ac45420fe0377f8ec2137cb64ec6d807e3fd473d4562b774e7bf5d583765e326bb36afd1aee067a0ba89a740e2d30bbaafe4df72781e0d853fef697d376723267334b46cc87135fa87561457c1f90e0bb989d6ab83f87be8651b9778bb2b2fb50b74fcf34a5bbdebf3ce72ba03937033df8ec3469df0ddd1facb119a38f8e25093688449efc54ac9cd93d4c3980e640d6275e84d3167f48d06c8c549809a23e02e902bff692ad9ee96e09678dab9ea504341e90a04d5b07dacdf6309e1bf214e3d8a70300b37ac51b86f7703a3ba09c6847e3ca53e35b02bca133fe3f82a7bbbc604a4b260082d8175224eb8f4e0a1f7509dca5351aba191a0f49791e46ec9232e6ebc7fc5096188bd6eff5cf241fc78e937c21e8b5fcc461e1d2cc6f5916c0b4d99ac20425e9282102b8e970829a6887cef1df00beb479b386465cebe4f3fcdb16f6256c7021cd6c0f2e3c6564d897a7e73c40e95082e3a2d1abd3ce06943bd244c3cd1f4d9ec570a8d1f9d225822b665ffb76f7bf4386e19347af1e00ffe085827da42ff572827a60fc61c2127a4e62b297bfee46eadf0f8014c2cbb1a03ef1bb7ac380cbfed429848250acb15d22ede1bc5becadbc3404393208456c0b7b7d291436f98d45f81a3d44b9fc8174fcf1b9a48b365f5b21dc7ae3e1197cb71d4fbc514e1ebe30dcad6d3749e082101bc67e343c7e1d31f974e480592fa980435413fd68c07f594d9707d110c2af51203eb02550a8d714fc990e49ffa91eb18d734f2586c9a14e1d3985a19c1cd19872daea7e872b57dce067071086920fbd5f71a8a02b851133c5c5caf07325f102bca573021e18a3a9537047c83a034b5603ac0422f6517031ddbb0c23966bfb16d8e06188323101e720c11c56a56d0facaa058d38544643b8ea9be13758c7d78086c9e0f6c345ffccf19a5aef5b36820d8894ac039c7d74b056961c722551fa129af3a2ba740146563d2b6b774491b714b2ba7eb057cb20214053feb39ed871f0958defcf977ecf2c9bcd424b3771918ed14479c097238dc09a8720c2723bef2156bd4af9b0d5e6f013191e6b0824d609b24856b419ed305b425f6c3b2be5e4844077f27d3e0b572954a1e85aef878174c90af38d190b514463ab573bdc7455d70d2af311934687f9a2b8aeb4810587c51327969fed2ca6c639687f68bbcb1408938439550b94ce51b65dad7418e2d99a734fdef88d39188d4aba1cf2a5f0240c5c4f2660deabb04124bf6adf9f99121003e1b89e2cca9a0907b91fedcd002a784d283b6da669e2f932b474bff7d24c746c81b2d79e5477de7d4c929b760012c0ef78845658d3f2c11b76931778a3ec5820482fe6171732c08b62a4b5b3cf360480b95a24ef976d327f42f5a75d8a09191ccfa3b842104d437baf78dc53f2c2b7e2080ea7949b530491301920c2cb9adba0cd2b8428ed60574810fa68a41df2567d5bd3c1ef8a4789aea3b5b9d18998ecd37c4642556819b4e1aa298c1fa53c71ad47f465b92cecbe2a23cf440d3a48af56fabdb844f244051b05ca69a15e77b4cbf251df487a2096fc9f7b11a1fb2a5a93fb94981031816d70e81837ad4206448836cb1495260d4cc0f26a7589bdb1414e9d5d0b9d193f867979dc0e89a6039bf5734547dd5dbbb460a6c1ddaeae77f308371a94787da836436e1f27e277aee3c2fbfad96f9089e5fb5adbb25dd52e1dfb19d9d3cf4d44a71fe92b1d10f0d48771ee530bccc5ad28318509dc71e4eaa3eab46f817fcfb94233e17ccaf12de68f44162aaab1fc3e8bc0107834acbb6d474d3b5446ced57345e4fcb0218d129e3d0d3a83b61d987d50cede08d025adab91cc97c9216bf97b3a0873091803b85a2cc2ad336c797fd78d820a4e431feaaca01a681b7bdcb385af40f452317625e5871ccfb357526ece8fea4d15fb46c2a8c5ae21f9f66cca8de98c8fa442f3e799355807003e61d13137f9ebef2db919638086b0731bc250330368a90e07714262fc661867e4754a0b57f849fb6d4e49158250a7c378b1aacb01674f58686d063f45f35e6bb3202f917abe4a0f34b1ab00a8ecdd2acdc21889a836bc0e43fed31ee7ff14ee915b74ea733350a8484da5b989eb94bff487c1041f8ad7b915e991eba58e0a862ab2b65fb7e2f21bea73331f8a60ba039a6b94b1615fa5e9147a9831aca90d96277633f6cddee9df7b35fd219759fdd0efe94658f20da2989b9229c7d5a87ff7c5bdbc53cf8ef5a098270229968d8276b05916ae6c30b0a82a3bb38b91ac2091f636d40e7c517bc4719e86d99c7424ce1080f4619868b9e405a2003ecdfde6eba0f33522a860daa52919019d109eef42189a92fa1ca4c8545df32acd044d069b76a3e955513ce7545ccbb6ddaeb6ac2c517551104fef6af506ff7e2ca74db9e8759c704b035d5171eaade6bf4c9d84eed7f3c540fbb06157f8e3e10ebdec6d4818bfbee8b9243514b266070d0efcb18808ec2696911d85b52733216597c193d9c3fb83594e2159643bbcba8b3484a736b2f8db3e28803f977acb18c55478071456adf447b0cb00db4fbd2d990c22f340deaa93ddce5b52e46f0f1bc474227774774a1b5bb8e737c3f77d09ddfc1aab48892f7832fa18ed3785f9e5b64d9971debf077a2387b73889fcccc230b0b93461353557b033d5a87b02be558cce61801dcbdc5c5396839977601f6e8e26ac1bad6d835e193d7aaeb2d0884f88f2659bb39033113a47f1e26f4bcf58e467dcdb3c3a455cc292272c1348d565ab85a07289a1a3c32ca8a80da7a6e8bc641d9bcc18006144dc74239b55a93df09847515d3e0326dcec34df5817e9c9ac8fa472e9e4b339538844cf3614b6f779c1ac21a50c9568c10e6466186d1e54434291fa9bf5dc71b9fd203d6b6c1c94053255a731fd23aa0784a7ba6c1ba809a57ec50998925b97a71320db6f3573dcea41b849a57f5a129ec26f67d5618c5809ff3d0f0ba84f8cce7c4b0f5e547df85abdd461ec1465e700b07c7b96593ce122647260a2e9330debbf9c03784c3ab980dde6184971accb6902e3a33cc6245a3bb5b67aee19d5946b91848037a04cd6feec32e2170cb961a806f66156e69a4738fb8f955665cec7eb951e41f7da17d5c5eb4b00c0e4e8b50dc24281bfc91c4ae428a27bf7f516933bca45727d805ec5b37e9f3a38ab3cc3702dab806cd4bcbaa7c9e57ae24b2ff214770a6866747c671e67badacf7cbf8055082ab84bd7112312ba349c1f54101d42c4f66e59d7c4b0fd3e952ea1499c4b873f58ce5504efab43d318e3deab65457b64a98e33a7060cedc3e2ec55e8c50e7da35d62e20c3a4a1437623004fa788564fa97c11d4adfb57082bf8ed662b4918aca2fe998d3377c750bac7713cf54e35e3734c1a550cb15ad297a83e752d1756df1311d4e296c268a6a115806bc2f6c0d3ca53dec563b9a7095e354a3c2ab1fe4479c04d7f4380f0c93db03b8ebe46d3782a151e4874ad427e182c17f2a6e8e7420a7331622d30181252246628a235d83bc4899ec741079def3506a8f20bb8ba17f6262ec4ffc663eeb5e2ad4ae6cbd30b4b46a205c1b9d6c901b6de4ca6d493c30e581c4105a1c8869ce782a77b7c97c3dfc37c0a5174b4841c232806999877639c9a3f73580904df0fc72469ed61f430f87628cbce262a04222e9b6e83635291b7a3c5919720f5225e00bc72b8a5889c0605115929f8873904ce743e2f00fc892effecb9aa4f1ba7913323c6848041f5bf0ff3ce2a2a4ebe663dea6d525922a578a0d91628d555e7f677814b1cbec72340a944994b8694450ef315fafd42a9f2fe7fa5e11ca1d6e01398c193ba436dd9afa1d37553d1223a7742610c50b2f82c05c92abfa3646f47da995b218022fd05eb4037927f2a86294c4b70081aa576f4780841f336d730252dd25362d05045705c261f5346a066ea7d929db029357542213e2d2c9141d9f91eed0072b63016ca8650d0cef922945d25b909104d90181bba6ad8e3a179f71c2f67780fc1efed823a573a1467f6a7efdad4c4d0b53e2ede5f0ade92274a68e0291fd88bf3172f7cac852717314aef4bef8f5e4eca435be5779da6c4f998c8c5ef70d42a5e7c33fa352c7f8e41596d6fbb5b85e0206240e0c7dc487e0f6e3bf191ae4817c0d71113e63be56fa041f23a53f946a00dc28d999d2043b1a6859beb0c6a1633992a667fee8bd670ecdccfcf2de1b734162eb4bffd11be87f91ed7d4dd31fb57baaa6ba0b47806991ab19c36318745cf1bc6fb0637f82ef8d30d93baefadaa1352c0ae902716fc72d5b42581cab1b2596ec2540b6ce54c25bf3eb617362d5926c92f2ab7a740b28aa7b309c7aaa66c286ca8e0aca6f578bc3d7f0613421b26b24bbcc1b307ebef32a0ba02942a650d48eaeca79e10c22086ff26c3ea3e4138ff4b7fe43e05e2f2995270e6435b822ce35b072a803c2034af68844adef172a3314fd33defe8d993d0632c64468b557c3644cf27d4446f3ed8e44ba11be239ec3a21f0efcb846ff05db261662b432d73fbe8033d659433fefc7340a1fa46226d7595b86159403bc7db1daff82ae4414b557c33616772dcb4362e1f7c35b57295ccd9182cff2700f81d2075a99fc1a8cbdca9714e91c91b6a1a816ba5c8971c9bef328933cad1e136bc602633a288cbf5a68f89f4ecf4b9be728a1fb58f63a438dfb847f831a907f702ebabbdeac25008b5169645b504396b9cb191472497ad76fe683ad4ab29b0aa7225cf0a8b410f6b5d2085d9fdba64de463aae9b5918750177d2ff29973dd8d2a03e2947d2517184e33301110ba4e94bb40e8af144082266b5918b3efc750a9de756e7e931a1b37b97e118d36cebcbd5f27a4ef7c5873d5ef5a1649984a742e37a5b577612ca942621fb4013017b09de343124a11cbe9b7e0109cf4fc21395e7613c5f3ec1b16a2f01f2fe703104675e0b3c5d555745813c66bf13aeb27ef5338a2b02ffc205f6e118bc92bc27407ff0316e58c8a1ad3ebe6d672820daecdd2448e732e87bba76b5170b3054bcf4a6c28242a7cc0fb8b9b191191c457449346f8e884e93f7b31052d8d1aa3ff034b8183723be7ece62cb35ed58a3ce5b8ce0d5486517c1e12351c8957de7af49816a259e1a43423be4f92190ab664d6c81a10f1025389f85eddbdcb0bad47ac43a339ba1c105a36a200af9457ed397252f2bc80d3fdb176dd2237ea8621009b245f8c91b8c05c197a4948ca9d9658235a5544bdbdf22e6ec5854135b879b38c0391cca9048dcfd8b2c2d197d78a08e391f78f3a9cf550c9d4e86affcee888825875a44ad88ddf820e496331aa47a18eff7439ffbd833df155973f8a148bee4f108fc054318c745722d53bc3a2c7cf9264d20101fc89a9c992bfc7de2946b08cd7583f492073b02b3228380eafd7bb752134968f21748a4840fc8695ccbfa6bd725c2eacfedf2cf791364c5f3a0a8b4041247394efd473417ed8a2a0930e4f7397e478517c645398389f77e1e0c40c04af40ce53f3d46d2dfa78ebab7ea56029e2ba2b151aab8dbde642bcbf0543c8b8c1f9647f6bff66fa69922e8a24d8c53ea0edb79edd3221981c77c8f8cf8412beef29e22d56b45057fbbd224ff40102539828bdde6f5b99f720de262cb0d920a332d016a0f28a277fa00adda40598d2bf7d323c21a300ff03f586965c17c738c6be29712ed2f7caa5a324ba6c9dbef37f05c39c054861058b6b271e2b5414d55eab939aadf59aa588cc2d419f12aad749dd7b57c8a1c1d40a7cb3a432849765df3ab5b690794e07e802e0b749c2a1af012c50dac198d3895f3e1a97ba31ff71988207cb1d158724d38b232d06919916cb4562f42687a298292a9cfc26f9dab2631b69084ef556f3947ec54517b71d092b26471d8ebb79f706bca30311a68a672cb1718fabfd1261eef2011a42eaa55c38daf49bb745d55fd0d94c98c271e2bc7218b82eb489ce42b24e99c6435f4b0702e8fa4394a6778436510d78e372c73b2ded099b02048a4deb2568031631d654004ea76d3681a1ed35e75ab1ae513e979ee7aa4331b5cf42dd84e3695746d1a3b18103bbdf208103b43f2fa4afb35831501c5e24cef614edb7a6a4bcb1a0290cb21a39b9210d86882f74e583afe9c422f55ea860b885c93dab2f626a7d678c9d873c6f3482875845274f37d35c0c5e3d4cfcc7f3bee16a935eb8e8b90e322907bfc967273a6022842c3f8a43de1d5713ccf6e0b3e25567e69867b1724e0b4ee8bdf6260a9e009acc005978c9b5fef3ab05825f5b69326cf09ad70c0799aec13ce5f5dc6f1a26709e6f5672c6822764ef8a020cbd55634cf085290b50e6771d006e1871704cdcd270812f4c667a6a889cc85300ffee042afda39abe5c085475e65257e468d8bcb7db6d64a552fd46f3dfdfc1b51f2c881d23d322b06a699b61ac09cb80ba2e8cd3454ff65083cc1347e146ac07896c12efe174c4d7c645b07fc76ff727c35652398314dd9349558612eb3432603d64b3c52de27fe6a5a01bce3e067cf9b5bbda58d95fa89d18d6f488d036253006c147ee31309ef7bff7a63a3e47a6126862fbc2a73f33ed1e2bf7408e818bb33d8b3af45469f05903079620c7781317c73a2b74c24b1d7942b5eee795fe0f570fff148de034b15bc52e43610e00e567adcc3354e9ac091eebaedb3d97ca496b18ce66e0d5691c3d5cc09664f9e08064571b6aa2d78c8614fe666b0c8dd413fce3f4ffb9ef2da247c74812e4874bda4c75abf357b489aaf10c0e4daaa148ec84ecd6c8a990188c9d647f078188a8287105ad9733526d221f68266ca00891fb1996e95253ad1e2c997fe953b42310b419f7582c3d9f2e95769fbcf46d6ec1313bb01b1cccccae9dbdc2872589a266106111383956d397e4b54ec8531b31b949590f0b1323c4ec0389a35afd827bf54f44e1c49ecf9da9d263b084d8eba404f2e8ec9cf78f933be451d648b18f368a9de32b293f3294716b44f8e3df31f28a1c9d357ad32390974c534696890b55eb96d4ad0802a2ae5df2ba275198b0c7639ea2ed76d18f8509161ad41dca75ac184cd8fe3f351bf10d6a865d164e0d8e52c85eb91643e17c5360c247536a7854d5e8369db4168a64fe423818e2a014a5f45a60193a8867333e98aa8fb74369a59a249ec73fb85e04b7e481de9442fece31bb46f437f6ae5da15c876e4ea5aed1705b090c4521d6323d0c90f9e40414113daeeeedeba06ea0f822089b6e905bf9da3f521b358598739949b5f2f4a3179b43fb9a82a202ab731fa3f0ccb304d1d9146bf992687a08aff5a7c9c1c33b39aff83d72d08811e927434316e61077d1bc9a9359980e27bdf1070a5ae44cb48667cdc15673084fd4cf5698a25d7c630a44755b35681ea93ff3390f6ad78c41ae361d265321e3d8ec35062c4923c320416997bf35b3e79c443502b7b23e54c1ce32f1fe5a20d03d1706dc4d29851031e6b6c5320829db8bbfad3d741e7307647cb6c4b2026b371d64840da40ed08e0a807a565074138fb817f4be3878221d12fe9f4222d45466906fa933ba6886b8eff29a2afd82abc6885a1a76b13600853e3753c28c672bf51dc97201762ac3ee99395f43b88be0f467357b950a147cf15014c78d34955867786aa504d64dd6ebbef2880fb17c22a6822b756a807614d8d7c3c0c3ded668fd55cdaa5e05f8481d3c0d0d4d605d04fcb6beaf3f24d254506372d71feae318f7692e59b01eee5d4c599f0767e949838f98fa8025702690404e084371838dcc5c15e996770768c5938a543146d66fea174c8f322d6e5e1d0c141e25edba19e74f08988b41b3acdac1d0f5345ed99d1bfc0a518951cd5c4ef6a4992e8fc5f3a419924f9fa4d2f21012fd5354d35cef1124b33f94deafa1b493a9d869c740e9b799fa45a3e7f5632eb18c852683466d213226bdaff22ee1d878c680fe741d8757d84b8871e6d1add813eba2947bb0bf75a22589dd47b9f47b960d8808b78df752f6d649af75b7e75d48afafd2fd067af7e5c3b9eabcfbb8a6379899a20505565fcae951849599ad6c545c7f9e7a3c6d08bb3dc9cb1d815cba95332724209fc9e18d90a75413fbb9a5fed3a7516021338e3351fd70231e3acde4bc180b42f452e911c4cbfcdc4ce745a0181b62b1b822978d8eaa24f091684fd3092bae3aedb17c732236e54784718b9d1436cacad5bc0a432336686622b3f9b7b43ba07527823aa7665bd14128cc66dfb07a65a4f127180d42f1fd900583e423840ddf436cae75aa791270aff0ddf246b667b6cc90e63ee366bbab7d39b6261c6f89a5140a82378724f0ae3be4ced11565becf65816e636cedf2b3b0f4d6dde55675a5efc3bc9ec8969e9ba7c69a5d78a16ff37a6a342ea4d94e8f6efa4ff9b2772a1f24f5b9eca7e39e100bc8d57705f59d0bc4d246ee7bca91c071187e94e33ff831b4f75ef78bbd9c2f1bedef01e3b899b4dfffae639a5eef880a76c7bfaa048ba7e19f7ad3dd62fa1010f4d3362bfa7863f2fa5aa6ec80f9ee113654e173f9a7cad15a07250cdcb27209cb562645eac9644c45cd1f14d0712a06ad38e34b3e25d4464de73d24b0122442f05c95e02acee56f53e0927ef29191ec00a9cd120c4b403eb2e44643172cfcd83fcdac20ba5ff4a6bea84376f44ab21fe119a918670283644f62ffebf84fe5c6007b946eac6a0c7a6d72063d064d30969f373332a59b34fc3e3a5b6ae3dbd5037b9c0f1327f64297853aaf5fa2871c6643eaec7626e3f98b98da2e2d245959109759e1d2aaaa3904b5022aa170e4acfaaeb9b59efdddb22f771e16031a5ff48ed607af5aeb96fc002a8b61ecb692b6138fbcb35b6d49acd0f4832c588a19e1bf10fb8184866bdb2991a1d25e8a8d8179d806855ed46e1a04aa55ab8d9e7b6477346b32e1730a0f4d4e966d8c5c46902424d873412079eee23bfc5b08e1a8c468c54a65f8cd7a027b7606c497b6ea8105a6e74cb53a81927d6014cf81da405241e1283561032bf91b68031821eb6ebb433e57a5c7ba5e388ec9ad53eb038747d63325dddd212d132f6cc9fc04071fd0268877e21183e5c2a4aa3107eacbc108f222854ccadb3425199793e2a77c45142c101e7077da3f52268ce1def85c51e567af82fab131ce5197672e822a2ebf39652c3565a5654b42c160b3df1686de9b22e48bc0c7bc4249696530a9af3b0b596add533c03c6dfd9b1fec9b67ca2806821343d466e135ab56d9da8be2765d4264c7c0224b2bde8029bcef1129cbf4caf1738f5d90c63aa6674edf1ad13030c70cb046bc58eebe8b08dea9acdab2adbd70a12d9425abc69f30af8e8e1c283c2c4195b2a83f4115358b4d911c9d5ef2347f56e8837eda68c7a8e7ce92c6b8fdbe2715ef20750be354b19b1239e6bf4b51b1cdc875b4a4838505784e66e2f8fe1ba7166b527d0c2df9e13cbb98fd40957575ad6d3a0e8870089ae721daeebd22367e657f721806c00795144001bcb1f9563c68c3aea3f84f4830185dbb213fa64eac7be0e7c2610da28cb6d5073ea60d488c58738ea19604138348be3a004fd55860a6160f75fd562587601258c7e028a66d0e51862c44651732a3eec21afcaaf0ecae10ade9e3428c710b35fc07c4466ebb06720e197689ea404a84666a7384d83a61021d7e4ef53d731ce1f5b1e6f533d9996be1debfd441b1a1099c268284df756535f87265ae1c4d0379b8067a6f395fc11b9290e34c20e47077e77d39eaf0023092d7b9b907bd735840a1dc527fb6c42ebbcdba1501a0a0deb3f8e4a2093e5694e10650b65ae6c162b2ad1747bb7bb353a83f2bee9ccb200907865f1212b59f331b92908ea123413e0002ad06785da70ea9a38eca2afb8b12577b75ed840ccfeb4383ffde1cb0a0b58e316052fd6638f26926e6b550ed03d5712fdf0ae94bf62abfcffc004d8ca3344d8d9d07cebe211a1c435e5461efa2222137146ee98914fb4bcb2002fdf9433722f33644756bd03634ab172db243b7d589434cf54f250186c92a2600cf870e7ca7d8cba5a6406da4852c42de6c6858ff0db36fbb1a413bff74dd288cd63e82d6ab8c788c34a9dedce6bfe98c285d3bb93f1d68f5cbc05ca41ae1442a363c5d6ee5cf07dbf219052480cd0481c6fa5232fa054da9a655abf54c7c63d879ed1116dbc0ede959ff9abea0f3a722c1ac141a25bb04e89ed10e2c63bb53ec7c61b06677485802400000658a1f34049ea57f8c5ef20e2fc712272addf8cd738efd527f3e7a69e75a1a1622af0078e06586050ae39cc5219e20130f4762080bff67d8b68815384b9eb43ef248e9770a6e910c4671a0530046180e02e728a58b788517ab057c48ccb5b5c6862215dc3f5b096a613ea102101823d3de54756e97ed7f55c043b4dc8e00077337182243557c03aef566b0c9208b4384914406890705a2427074329aaac80a114c1091ca6206409044d299ef126bb62f7948144ca7f3157e1f81c0661980ba5595c81a8280c020a512e8aaa0b6f522fda1252468b6a795ab6dc2c930f815fbc55c8ccb176502bc02fba906e84851c2516530603513c433d0b192c913290d84199851ec95b57bd00b1729346a3d7ae9b12634b810397c65069f8cfbf726f3b666f40033a72bb7a16da09a78aba7a0aae01649b90c75da8f121fadabd58458d7b6742333218cca3166fcc4a1357cf308832d750aa4df9a8b8059642f91793575073d48b84f1499d731ecbd50e87ea009f4aa0cb4436760a9832f016a447c692722160e334bf459afac59213330377aa95af52bfe30ccb7d492fc0358516c6188eca7f66e169c59129cac1c752dac85f8b4c582107d61a2fe12c0022530371199adff560d20c8d99729e47375d170816371b464905a1a9e4be4c266b75c0554edca51e787525603c4cf3b779b6a11ee13ac979b90c41035d2a233196178d416b05e09f0d772ab88b0692051a5104bba1408cc6698483ac6ab66362709a48ce51476464292032bfecda970762901ef4991e357ca001339b160e43ea6b9862a1f241b90b104400508802e375b5f926ad1721cdc080dbfcbf4bfa7b46bab603000f79b10d0de46386033ba3c4bd42daad3fa8263e3ca25f634dfd338d38a1cfa53b3d2df07c35a146e54c7eef822bbf6614b8d06167426454810ff3215bd7704326c89193a751a413b9e300ab8b95266f52952b71a46e9755eec5c4b9c5abb0ab44b3d70062332c87703cd5313214386c3393474afc225cfa3df0fa50fe0850b7388f26f81d70f117658314593b5ec6f4435f1561a87b009ddb77b5966d6e0b12f205b5064615a201729302609a9779bda802bccb76abd1ba98d8a7b2ebc2a4906f20b088f006019f3b9ea41144c97ab6857683f5036e64c96076130bca4b890fdac3f1f78dbdd12903986d6d2b2818f4b77f1c36405184d9b2cb64a3597b7ca003864c3f100d3c24954adb41c0a271ec6c53b784aacec2c157b70f5ec2240ca67d80422cfff01676241ceba83c8cb3247872b84b51cc697b476e7b692e6c19a26bb67bdbb16b6cc23ee69c02234a8837b90fd232c8e56aa568ccd9d95ee1a57e4867279679398bb5b342975fe04824d9432248128c0073ced5871a0ab00cbc32c25b19375e0944bf6780a7402deccc3c06494bb6c8a02894296e3027a4008dec899f6a97894ad11ceb5816735cb01ff69fb1e937e4c613e8f6c86cc1cf8106c66698353712a3416725d20a4e1d85853208aa16566aa0629c7cb2c5dcf93577083995cb55c25a4c5cf8b7e8dcaa70b21c589482e31a29e830bdd9196e61db8937341be3775cf796012ed553173c9a07056444551ddc827c68b798b5c45e600775be607a61bb2ba73614230b806b039d822936b8d50114d15abe31cfba787410061d9c17a1a411688f695c6db8445fc64d810b5bd5a4102e3738f2892c2bc30d6d6b7808844338f845437b3f1cd43f3e82a4c326533fc25fffc165b6c192e220b35990b14cacb4eb12595414987d69207f706892b46685ec0f6ec42b8307117ba1c56f06cbec345757285ad0a907d637c0e8b156c7935d888a93fee0034e966638ec23242c8dcb9935fe23b50243087af179e093949f984b63b2c1b7da99a3dc3d2c28a944e564feab75c4033492fa557d0b098e14c61b9137a6c131cc7c60af712c925c93c7682d78641195349c7cd7bef064603ca7abba6b618056c840923d64e1b1ea54b080b66b396c72f5109564429b7fa97b2cc1a5ad89269f3112e4f583f8102c09641e1443131c509974c9b5b574444aa504420754c4f561579c92b16575e7201f2d1a1c97f536ad3600045905db04590f050d4672419b97ac8b633d62d8c28241cf11c845a892cc018209361ab2e9fa2ce05940b8885f4e8270d911cca1590d68d190c0017091658e12e0930a316ce17caea83000a2f587883c4155d54c0af8c3df5110deea25e7769ab175484997435480896101aac0f25db669fb8414516f178060267eeab8de0976a6ceb8cf76dcb82abe9bf65f75b23c007676f13bddb7c449bfaddf5c799d4d04bfadc853de3d65598786db062223e759293dc2f7af9323c60b78abff7676dccab38af576e03d539c0d76b4b40dc3b14b692be113eea9a2ef33faa42f99a3326ca1a2bd1aa4eea1ff3c0ea75020d17f0379f6ffa2813fc9e1993333000a6f4406ea989c951a3d31d4c2ff000074bb0618220a0000002c058267748580029b0c22a10672fff84863aeba67f0d1d7691173247dd427533b9d7ee76011c6f77f2ce9fa7a00000000c26620b26625789f995601a61700391ceb750c1145ad6584aa71c7baf8ab020edc8ec6d88d040ef6bdda45c5e2e1fe0235919396d79537b60632486ff2d871d60eb8aa1cdb3eb1489e0f81fa569deeb6f7e36f8123e42b918a9e7392407da7ee5a9260774a25b454e156114e8fc28b8b88427b51a22e040d7a56f743fc70aee8a78f36d2068a2133ea2c5c9740e1184f1b4a1274afc057be2e02d5c1a7a5b172d732d74dea8629e480c9c4de0f0d836d6a05cf1f13d2d8d8ef15d8e6801464d875c264514ca79bc15ada08590d56efac3979c8286a37da03fc45b96db51f05bef8cd050d71b5767001c99598d5901552fbd7810671ddb6a0563294907aac7fbdd237f3db025e9fa990c1bfbfc926336e8b1b58ecaab5a0ffdc8d3b78be505d467114b4cdfc95ca4df56c20ffa56ae9357adcd0abfe971e62da6a972f78b883f5f6c40b8b270334ec971e9ca656163965f2e13f5f74bc29aa087576d0e209e44a386817e8938c4e18d5ec5dc237f5448d9b93ce4661fd04f6b9ac224184b3b1d2eb9f38f0f36c8241e8388a7c90fe7e5b75f6d49b30ddb69b2f0b3ebeab9ac826e81682aed100214f594f03b7196b76ef916893feb4eb677cb953b2d5f8705c89c33a8a3f49b5d9afb45d809c2a2aa04c900ca9cc101e675a7550b460a6cdfe3ebd07023b23e0ba884ea8307268ff0e38585861d38d4c24bfcf293e0872bff98190c6002d4c901704520721962de54f89a6b1f2c40f255d89c23e9d67cde98eb484c43a8632b154af21b0f168174c0fd7aa361c904951da52eb0ad6dc5ccc73d3f5550cca4c3064cd0fdfe66c3e4681637c8aa169d4ed119bceb8799c0e133c34291d3991e330118b6865df27c1f87e1194406ced142e9a59c086eea30ba4bce7784f77882f3e59507742d8dd1760236bed3c64692d699be9328336ac81a4e144f2f5b40ab11d21113d18dab89fb5ef5ee933a94b8e0b0c2f05a369622b45dd9a29ddaebbc1f96eae6eeaa1ae31d38dacf289c46696a81297dcd1783b0323dcdc3b5be343911a2bc7682c8d2aba1089f3ebad965244ec127a6b827d30c625c46aee84a68360a1964749a02dad00bffb74e7f129877eac456e469b31f6120ba4b161f77afc57d1e88540d0b68ea2f4c4bf1fe7d95b5ada1c532dafd32aad5d3bbd733f822b9b72bd146596d5b31c52e450f9dab97aaf77ff4f7175398e12826964d035fc3760842800493c9d5c5b3cca1710f82b704bdd29ba176975ff9ad14eb92d15bc3ff6b31557a3a0fbe05c6e897041edc5df0dbdfde8ead4d1a819d8a9157ede7c1fa4f09ee0a444fd32dd3f1bf92825dcdddb737b518387e4632bc64eae745d0c95c2544d4f609cf356caa8a6ed395e6316dd39b2346b26c84243fbda3a9ae05c194bd1f76e49d2e21b3ab864f1b2547119dc6b1649f35c470c83df48b19e876d77a4ae5d070db803d922451186245453f517b2ea2179930ede813a1f4ebe7f592a6feb3e60facdfe59dd6bb183ace95d7154a63cf024385783a52d314856719900ddaabd43474a2201e72c925ca82fb3163dea26f69e4906a4c611d2adbd4cb2a4a03837c28d81dfdd5f1469322e617396242c8a8aad1ff6de067488c90aa92c18c8586902bf52990d28ae697dd13860fbb2466d853360e39e796f2726285c7b88cdccb9a4ed41f2c9d2642e4ef7b108e4b4df49ea7ba4650fc7ee98ad9ccb03dcd7c821c297c17b1a8146f69982d8392931096197b2441a13c37c626e904d8e600493d2d84c084617d8c30394251e5f8001f72b4275f81e1c938b67f5ffd841a70a54b3616d8a5f413355cdab7f691027c158e71d12a5a0093ddbee6e926cfdc33f7de04ba0b3307fa39384d5c2301ca30ff802ba4f3b2cfd872d4dc79bf1ef51eead73105f3d240b326a9ca4375a4a021d4386b45845694c9e6adca6135bfe5e03288dc27db954521bb5c8e38eae957b6530d791f330a595b4b197a3504994a02fb02cac925dccf0a5cad53b43c628cf8c543fb2b082a14f11a3b71a7e03b0b1ca40ccd9b4abef509cd88925cc0974e97b6333fccc29d9f39449c87554b83e0a9896e535886290c9a5de1e34df603856b6d784a38ab30783dd488690e956faa6d84ddd5bb4340f974656cbf2584942bac631a240efa278d2172fc3885096276ccff465c7652d9163454ec9198286137929236ed7a8c54c9f44c82e6a208e386b555ff506a04164728a63725328cdcd182441a7adfc6b2fe2b4cb2e8752d3f90e9bd83de271ac60a0dcb5006c8421e33e7b1e197d67cc7285c50a120d96e19cd8743c4dda518b8a0f26d707e106f9cd2883cd94480bd59991b5caac43dc4201749aa7042e903c9517133313bb4eeca95ab8b6d5216f8e03894f201e98d56a78452827b947170ed3e8bbe0144defa24d9c9dac8bfee1e614012b7570e4bc899c5092fe09f636706dee312b3246864be03d9ed9077066310d6ad1f6815f90f7ba37134c80c720a3f9ccaaf9b8e2a5d47bdb54719b5be9a2aed41e5571e9d656b3a4bfa3d7cdc325215e97bb1c787b2f594daa7797895099932fc3c19dde4aaf58da11242b7d07d1adbfe070a1e4aebff04b6ce9a98b931f1a7675b64707944d31f036970739edc995e659719b58685438ad9df7ec1f7b6e9bc1ce73e2234902820c690d62a5d99bb4bcbea7765eeafdacfbd69507b98008ff346be61832af1d04f33769931e581a8f2daa46198d30b8ca16fec718a97046b61d98e1dad8aac0ac3692f32668cc8f04629e68dce6d5937333f8ea15c94f402433498f63cf08478f855454eaba1dc591dc1c7c157ea3159d0ba09c76168b47e33581103854cd60df27e34294b13ef72bbc6a2478840ed839fe28370cf034e8fe9136f9dc6aace98bf8128680af8eb577eeffdc4699bf26ea5da0e583de98bd738cd6405efc6a12f374ecfe5fa74a8d73d4b2adb3c6dcbd2ff27a3d83e153e7d31d39326c9fc44f34cfc3f39ee62bbd21fbdffffedb746978b826dab913dc331f2f741cfe26d607545806ebdc2e0fa13f7de4d234903fc2a7c3658defed3304529361b31911b6320240ca7edf2047f3f57acf9c2b17a38ba7ff116318286db5b05c2a8978ad98034c498d03a8540e33c162e052dddde40b8e42d60974a45168d81884735744b350fc858e0ed2e0f1536386cfa46bd81263767892dd23ec9cbc6cc696ff0ec67e842d7f3c16751bb1d15d7d93fcf1fe9bf074c8564c9182ad33d72906b05e89c3003a3ec06211026330908e92c28f62feba6eb0826c04ecb1dba48801f9e5ee145c372caf3ab8da0fe7a3f1bc01c2c4cccdefb67ccf29bf5681ed0939628be29dcdcccc071a5190fb91bbd0342735b82568d191b2af97de0ae7f01035a7ba46582ff270db3ab0f26e4f360282177fa5fedf9c1c7c16df0d26e68d0cb9c1e1eb60905b21c6749007cee6df12b06e747e5a80fe2c84cccf460fddf3f47b6d9c855ce119547eec70ac2ff03ba534568296b6a061a28650a8e6aec6e6a4c0a8a274b9c76fb53b884ced627ce05adf731a66dd0096e8c2544324914743c043b92038bdf1b3072e47d1fb35dec5c4142c90ee418a5da8d94a64c108c4dbee37b2afaa43302047c63ab0b1dbbf0968f9256ad5bd28461c061d281f603b8cc7d767e91f7801844857d69c79bde58c9cd1b236d5d74c0bb65975076dd1db27baf21ffa248b83889f2ce5674fabacc6491b4c86d015314ee79e09f50e5a621b39ccbd226d44c2649eeee462abfeeb5660ab07c1216b7564c81a3ca2ae6a26be31c5d164010ab04dd8491d3c7b331c4c04e9ad49779f2dacc9ef5e4c6930334c7321d5d455b1d50624f135f0ce1034b278d80d7401e88fed7c4a502ea7da701cf4c34438d9403b6e1974114b335985ba4e81f1b3af517fe482cf87751af9cf901f23713556e44d90ee089b74cc03fe7b2920d00179fcc2696b7461de6a7be044fc324a5b0975254c272cb74e81ce1e10e7227e4fcb1c5ecc9c7dcbae3cd1c981af116e95585651585f6db6c6f04613a7c1dd1ee9282715271c933b779b99a5c32432ebcfb2d6a88c40e5f433ac9b0f968cd6fea45972495e085c2b6845c0cb03639d36bd69a22805d80c2dd9499efbcdc71c92f2efa5ede2ea2a032dd8c9ed9eb3ccc9f46627e4b33123b77ec08fb0b7ed72c0e33698c62422761de075d6e1dfd645c746f32425d7857cfd7b51259f0ae5eb48b6a74fae2744dcea24005adcf16e410b0b734611b72f1fddf01ed1fbf5350d931db8922c4b778fbc20ecba3e09f92a0c0a9e578ac57b413a0c87cb9d5620674cb1772b341efcd789fba5f5bf2ed4309596bb3a2432f1cb05a849ffc86f5fa9ddfa30a1f94d01909edd31e0e9469fba51f34a3d98c37f6a7137943ce8ee281ac3a03a6853bfe84e28cabe8654082ecb97c7e592aaf38c2cc81014e3c40625df544485b368333c79b77e59901bec8c04fb1fe567dbd87dc5b0129ef559c97fdf3832a8a215a085feaebd3f3ae03af99698ea07fff20d5bd1c4f971125057b40461b492e5d68f092afdd9adc1adec55765fd52aa6c0e2fe84c5a7e357af06b8e51fecfbab53b27629826bd810c6e1eb911ba2e207dcfe3ff6d1bbcf72b67af902fa4ae4ca55fa087752e09e938b4e5dc7732226d282d1b83f4877e480ace0b5608a51d0363bb0dfface1b347dc0b1e4446b7a10b942984b73d6a0469aac827802f7fd2684ab098b1910cdbebe4611355872d4c581bbb23482a5543f4fd794c73f5945e3c9aed935d17ff0565dc50e007687a5f4d2712e72de976cf8705481b4005ecb58638d2eebdb27a303377c3b24102b67de485c5d996d1c39744cf5643939829ead939f94c8d21dc66d6326dddeff84b14c722736efca8a5670b97708b875d8ec8e5ddb32886f3282a33afa16a38312a944dfc206a7b3380ca836ed3636c54c2d9111427dad9f37e977b91b6744b8bf9b4afb9d85a1abc39ea667fe6864f3a9a97ba50803c1c117ade9dc681d6aa5f7898a9911b3cccd46c454e980ce49abe31bff1b8ae7ba7a4c5f706d262723d8fc1c03dd59cc0940b38435ecb9ed74d2ac28eadaeeea9f4e63be1618f327090f998416080cbc3e0f5e5d30e6f9ba4d34c560ad2e78c2af5f5a37e115732992797fc2dbaa7b16e6278f7ebd2a57436d342e216d9b06c1edf936d349222d4e59ab960b89998755e1832801e296607240cd6706cd507f8cb0d30ae5041ddebc596f8a0008138ffaa148736a476d6dfb0bf1c40e3a4241ad7ae944115e4ce0659fe1a154c958ed4d0be27fb44332911732cd4763db6f2c00349646ade9a19d2c05c760f6732ee775fa152bd8f7b90a062ff40905955618e0c1ef52f27d40a94f28c3760d495be75041e73b53aa16595c4c61e1a9e513249825dcebd08c2fc4b9e687054f559cfab3144ec0804d8d869cdab739fef8b97bc0115065e4e2f26dd555525bff4a118ba5b7b6dcdd33c35c9ddf481c03404e3e3f88ad45aa1a457c28e3f46168ead91fd1140f26b603c05f70fa284d9db5ab1ee0ac41f0583c197bd71dbc39f842628c34b35f27366e91388f95821cbfc0b80e92bcfb9e8544c2e0ea775f7d91c4b7d0e661022f1a87d0ae0f63d3f41401ab9d22a0c91ba6f690a00ba2771374c11488efd64277cdc90ca9876c1fdf28ba21c18bfff9311e223d6c3283bd494cd5a83b5ef4ca1827a2764121bc6493dff0d16ab002d425ffde2f3a8de49565e79cfde614c05093fb4288b95520b8331b00345fd6caa498718dfe09d575a845539eba74d20354a281f1316ca25602abefc14a0d4b92b218479ebb8d3933a71d79f8f656a81d27589c63261ff139bce8c982c5e9bdea8dad9ea62a01bba53087d70b99588a33c4761f6d7b64751301bfa5254c3d72054b05c28aa021a45ef847a74c50b34130564b1b99523824e3d5d24e021a1cc2376ea9f5d1afd7cf07325996f5162bcc9892dabd3e84f428f8577c74eca23b0d926e5b4332577215d45f14e5eac3aacaadf7faf1986d9a5bd42e3e1e78711b87b878cab6419537a24bbff25428cfc83a09f617bfd7824a1a620cad633f3447edcaff0276f7826884152c09f7fb7d366f46b7a064c3f3be73f0851c4ac2ba819193628d55f258dd212a56afb10acaa27d124983a64fc7beab2dd95e3d60be79024db9aa50728cff9ebcbfefa0b79c1036bd11952472f45a554cd52d3307e6334b8c7fba24a2389e20c016b9f25968336e268f5b73ee4cdcc62d509e850db8843f188792d86dc432143f737f6d03b103316022e278f94c1ddf3cbe2cb759c999db7571fdbe6b0e874405775e48779d44f77b5ca28733b674527411ff3d98b8529ad988e88701dc7bd6f0e17a6d44727baadbe132779d0bc695e64eba6c0911b12e69614277f994bf02ffb8ff01b7bf48357990b33b1fdb90be028552bde400b86199f65d670f398dd1f22be6ff7a1dc2d599e082a51e6607301525b3c45665df4419d15e85306e8da98f4e6c887ae84d9ff6881858e16248707932bf2d7cfe963738d4e81e51a2285cdcc22b0ff18dbda8c335f098444b6fcbd3279942c5835e436ff87d14b65d6335197f61167b986f28887f1eec68fe7accc1361fad47f624d96dd4c484fca137e848d8071e8a28fe8a98670fe6331f8062ca95479afa361d42338eb87e9ff1bcc39b80bd337c569be6a052e4c9611658bdcc122900cb1eefa57bd936891ebf65435931714ec1df080cd389d26bdfc55cf2cce1793a79ea00aa7e4433df94df38669049f9b87188e38c49f77676c51f8ad4d888ff28c41c50c9321041d4be80b72002e0884c32fd3c25a1f1359241198f8a6081643c667b119e9dcdf7b51c0cd0a9d9125457c3d2e6eea3be23bf24eb633c740d66ad4edacedf3988e6676a257803ea208eb8b66ccedf656eb833b6b31ffe695f9a33482b6e2b99d3fa6ddf872be0825024754b2b131e38cba1e81db250e42c54b0c3c312834c1832bfcae7ade6770a33013d7c51dca1732478cb8948b73592cab3fd71adabe76e16a129d2ff29c3e67f33f2b86dabda6417e2f649d7c66081f7e6932fefe4d9ead419ff93b3021d03e3e953de67d2e6d3b7c7bba71ce6bd33ea4a0feccfe2af996f3aebb78e1e75714bec5c9e6c0d9efeee6b055fc0807b8c6b5005a54ed70788cfba5d6af78a82c8a408acc542e2e944d76c105b0eb21a0c79804cd054c286b0fbfd1c8a9aeca072458d323bf3c00b401fd742a20520cb8af48d916feb69b831ce6c17648faf9d3cb5dfa63ac2d3370bd12009ec4f65fb87cdbfaea1f0946cad574cad16e23e44ac3cdb284130aeb5a5566f3a42ef281c391ff6735e33ac8785af9d8163562b438de2180b4122c393f1bde490f26e9dee98e4e7083341d1ba229921735c603fc2c61e24a876003bc056265aa3d35638a2b07db784a245c569b3b6dd02722696775496340d9d8a27ff0bbe9435cb9018931a36eb8435b0502e404fd2c2a04cc4412b3e880d77b167636ccf114804c70e5966c4d47dcc05f93e141d5789ff55ab572bcd5a1f50206664437df2e21aff73f5cbdee030f6ec9f5f082a2c9d48cfe0df89125b15b916688a63b2e4fe075693a7a69e6d10d7c27dca8eeb5aad5be18f99084d0e94b2f1abb26247564dd0c91ac2b87a3ce4174e733850e39d6e1a1ed35bfb90e9bc061edb377a434dec2bc8c351bb3a9cdccdbebc1fd66680b4a672e8db144d93e3407fc47bbbac2e76c85e07dbe238b0dba0790b3c477d6f246a13ed8c111730e297ae73c1a4366f653a627feb61d21045f659953d991fcd7accb8cc5985118f1605a531619cd1c133fc25693ee3753367ceeb721c240b61cf54ee851c663bcae118a0ae868fecac434b6c5e91f922eaf9e16910122a77a970e8b98c1f9a9b725a666db9aee3d5995d5412b7dae303ba5b5ddf12a34e5ff2e6d19469fcacc9b4f1c51ff4c09ac3ac7f06020c9ae1f5c008ea6200ee7659e1690a79fded779f7f27361fa81a7b829a5480c4fe7a868b1eff2a789c231f00ef61901d5d202837c82f8fb28fe27c7d353072b5b2046aa0f0450830fee3673ef18ee925dc5cef223b65a783339568f8b44c9d8dc2c5163e63061978a52e092ed1423ee6434141880aa53a7214cd9a47dfb487711e4e6dbb3958f1bff63175585b98fb24551c7eaaa1400a9432909722fa7c7c05c199a59d26694e573ed5b40f8a44647de440b22abafcc11a0bbfe4619707a87a1493b0fe2c7e47d7c1095407f0f90afa953288027856fa17f6c01c70eb4fe8d60886543f3682d02d914a1eb251d8ca790b508770ec2e32d9a4326138b2e1edc9faadb8c7796030e7f55361e4b6f64ae345645b9bf4969e5ffd447da009d835505d2e07b4f920c0b339b6fca3acc97a555ce50510a8678f0b5858e83ee3d9099fc858a70887f9a794769d32d0852bda1c384b7fc1fabd5ec195a3edf0d1b8dbfe9c46c59f5c5db10807da43f24f04c043ce0de643c5d5587d7e85d2f51d6d21a3249a2726ec8beb5b74d25287b5653b4da0eeaa9544fb8729081d94f6f36944d23bdc1658d75ecfeca1fc7a5cadc727ce0daa54ff3a4495775343e2a1361578bce8380570497a2b95c5d5d933039d2341861ddddc7f1a7a4e637d397a872ed39b35b94d49cdc668389083dea25f5c123736b6605e497392b1c95cc677303ba745236551698201a4a1b2c6bde917d0dcb23bdd5487324b85074178f1771422fd1c85dcdfd421d91acb51c778b4a36c931da494c2b46a618f7b4a1604053a83411baeeae43a1fdfe7925f06c5cc33079ac33cc51bc0765c70f44aac837824107cec35ac1c6f00492ebcf50ae90745881cd3a6e3a156cde4ab7b60394586aec18ae31e3012ab2f8867636d5542ed3f2379a0f374f9845ba30440ab71de8e6ed8a125562fd01d44d8852c5787f3a13c712af45dce79f9bc8e6e473dfba17e033ddc2f9de28f97ce4de029eb6c74a8aa5ea6038cb8de1b87051094b28a1cb7094cfd37f136c2dd4e27131a3933366ee2f52fda67a0b76dac5e0c274a04503a66f1fce9c059d56d55a992675e7821e8e26c491edbadbe1873161b70b0ba183c8943e9c9bbc83e325704d4ffd8d97933901012d49822d95b4653c07329fb5c1df226569fc909f2aa4bacc65af11f47c9d062a3640eeefe618146bd98c78286515c50cf60feae92e2384253be8226bf9688ba9465d79e453535e9d462f5ed363118708d6fcdce94def555f4d5a741051e3ec7f6f26a0a2509e5d6b3f531125258bac047891541116f53c202b2c5ffe1245546cb6ed832ed8fa8d9643853070f9446321a457be9fa2b26728e371d457fe5d5f1959f705cbcf006a1c4ba37519c6984cdd5341a61e45a12705866f9017518675e2bb58989f85b8042720631dc66cf7b44b87d3651278a6bf27574b92b7750b5556b3119c9c9444e40b09e6502b1c85adb3c75fefa2754f800edf63b1d8ca7b516250585a60dda549c143740576d221585a72d5c577a10bba784a3d0d472f4870c8ab39c0687ae5a0b3a69185f5be6c493a46451708b9977f2b830355da816a8d4168df7bba32930d9ce6f8dd38f27641a2ada83ae202db8445c64b1c06ab000eb06120e92fe8bceaf1321a5193900801b3f1bf1cd5a01b23e4083cb94bf75b6aea97badfcc74a2fef27421ae108cff22eab59c6673770b816957bef092fd5cc7f358483057671a2cda399c91465d37a026b1e3cab44c22a5c7db8237372b1665a5b063d6b380de2ac56ad02e3d24d746d698ee1757b29a8c8f7dd5a5bf2438292ff615ce9c24fbd44a60094a6ed4ab99cc126f08b53e9d27f1999c944455a04f7e90a6cf8e91cce627cf0700afe377ecc57ffc12ed4d23f3b3232d87a6067e4b680571769c16178917d7d08f79b323b8de5ff988f67bb82abb884a1521813e47613722d4b191b9673a2d1b5434ee01a7e03a5830110023a29a4fc45016c68751ef38f248dd4496dadd6cecd3b977f210924968de0e528ae031845cd0c231de7858167241af4048285e6a53c978db9227a4e6f293fbc48b2ebb3c28bad4fe145f9c3775b9adbd5cfd3155ee4fd1d39c7702a008ccf18a5a88bb44e5b85df1e9b244f59c2efcbfaf674d0d0f35dd94f55c075827fe645115655644e436521ca35c039df3542ccae6aa94ce2ceb4268de10bca8b7a2b93302f9066ad7cc26abad51b3723c0824273a2124b3eab8a7bc8b4d0adca26da352e895ea24771433ea433cba33d43f5c73b508cb435ede68abf345a544a53db7c63c37ec95b2d9e02bfc614f581ab07de8d56d5cbdeaf8514d9e38730419a1289efae745b551cfff33071ffcaad172ba1051ffe642ca2e466b524c41aaa7f89eed79a8e5a3c287d307a4cfed1eb70e74256e2c972a5c13a4ad5596750825b7bb9dbfb8439793b8108faf02776a7b7979ac33bf74e46976de87210e070ecf2568bffc409d2620d2a11fd798a56c0e1ce84d3f8e43ee1501eaf7f655364618750715aba33d8cdeed452765d3fef8a1ad09cd05a3449ba11a2df6f572daf9d9c6eb811631c974fa598b482ef134e1156fa3a3cea82f9b709bd8a4bbb7c10c2509f1db502db5b392c1ab92238cfbb867c43f2ab9b42dfd7ed02c87fb8ea43cfecf5a2e2fc464727c08d525fc2d2a5c62a561bcd3f63c1120b8b2185d6238b7639930991730f9549b93c9c403485340f59c7c771782697ce9033129a14a62836bacbecc83869e5118340495c24fc431f68654bcb4044d70dbdcc220ecc7e04c1647f13323d889b580fea1b29c85c09e8bc4e67b734f17b46728ba1f68378f1574a4e3ee0cdbed9a059225c4da32be2443c4396f5b9099ed5a85eea7bf2482005fbbe162167359cce0b2f8dedac850f2a3c7b7c7aff08fc7fafb367e866edf5f221199606527610134d34debf059bee25e9d27e0e7196f94c987d1ada838a1219c2b20bfdf9fcd856fda1d6e77f40bb338b790ecce1d32d9cb9ce5974d4feae9ee7ee845408e9071307b68809c136a50797ea510d475ce0331d91ae9f88a9d283eb44703d4385094f48fc7523dd5a294fbadbae89130bd9a09341c6078e567098afa8c3d9e40737296da52ec1b0ebd5ca9c0b0132c4938d66a58e869e5e2b2b71372f8fa77ea65faa1edf25b13ef3fe5b91a4b0af836e2db84720bcc7c3f177616097963753b37c4cef6a172408953a04e97ed513d37451cc5e4cc9a415413e15c8ba593499b60f087f2f9971031c838be7fe4e654ecfa6b9b61bc5d0626ccb9d65eadeaf79e7f4384255807d15ed5fc2d8ab90b32a5faabf59c42a60191cc02ffe12f00abd3bc95184f62f70cd62464831de9580ea81d435886eb7d11c2358f751c9a59387ce828c8714350556c97ee3625fee1373aeebe040a8c9db813192c6f294dbbe092d7d355259eb8fb5c247a5fc3b110d4c4b28777c8a94c737f02d4dbb9f1274454172f78d5cf85e706acd314a1b899a73b5e77840c8a0d45e39021fd7697abadc86d8cf2bd9abea50d916538b72ad954a8aeee88d202731620d67cd3b9e3251376227b3b14d7a90fd65c168fe6bce9fabae1aff3df1fe7e3dca1d2eae567f16d907044618bbad01daecc2c628263500822376dc92eb261377a64948697861f5ab46780e431a7fe2ea188222d26708bb42d1025736b153788976d8a7569e4aea8e5b0beb2fac17eb1a303d405619670073d35f0e93495575eddc80d2979b770c80d5f77675c8cc72a88e72372bcdf3909661b27a94c24f1c35b3bd6f42f8729c13b50b97683f198c8aa5298749373df1e12468ec5ae85c75fc53639cd17ecf521388a96570ecfd508bdca0d19da9bca8bf32007eeb44e4ef1b36e52ee955be77e98d8974f4af32f6dd22913756dbcb16f71fef191c794b0c76c49e91685c1ffc5e472ae31dce64598cdf4cf247d27c31115f604e1a3137ae2293ef7830fce66fe09fd262bc5e65d12f60771c3d99a132edb7afe024587d8e278990107e3c3a4022a1b43c9e9da716f55acf0aa4ff76cac93270fbaf75f35ee07e6937b6f71504c487db432bbaa0eb514f3634f693a9d6d19f377a998a17ba57ba87c17cfafd724eb3a07719c1a48021ca34a0a57cbf92bec2e15568cb24474caa6d982f7b8676415a54beb3e212348b7af9d8f2c397a5e0773be3269a6088a36879e8d9f8d860024ad4bd4bddaa09c4388d4c15af4a436853f5da846c0d5b34c9bcb628fa630d643a47a0b9de0f88835d99bf41d8828dc6abc2735db4c11f6c84b24e36821deae9356b26245289919e0ce6f435d6a1eb246e7accadf1618bed34284efb02206b10658cbaa7f291165e21ad0bb513aad4dc0943d6cf0b175392bf5f0f4ae43d508318b20877cb92a43e4a86c705382a3c3762147752e735f4a47ddbe264a28887d5da63a0505f052a47e68c133a5c0e05581fa0d00656a89ca8d85bebac0eb2cdf3df25a6b03ce784fc31b86e00825b6767b3928f391a14cdba4aed7e083a3d7b82759d371c5fd4f7d02b1cb763e4c54f82be714d6308620bd5a12963c116d1b854167fb63344bebb785a85c30bf5056563bcdd5999bbad7214c0a8027db1e2dc9b9e097f92aa6dfbe8109597eb5f956be4ac5f316ce29458f8334b5331534b88e1a9290b72bace60cff59ff38c051d3f2a43e19fc7d33c6f30e9167c8c7adf061d4a1ad52396a3894a136e136c08e6823442b2118ec542ad7966e68007555b3fa115ab27a63c9a8f59b23fb657d3343bb667642d51e087041310acf8c9e738494a4c8d87f6ed6a8fb20323ad5ba211538273df9e97dcf4506e5cd4dd98086fadc1d300e55814869a678637e8c907a2f62c74200669cf7a35f9e44e7d3a564d3e76402474d7713cc30de0fd28e45e0f7515400cfcd354b5981f663f5d4ab59755b70a73fd97a02af9b6157e2db7c3c1b2502450dbbae386139511ca428e29391f98ef5a277df3ff58e85a0c61aa133d1b4f83d0d14e7cf9cfddcb3f123a4acff0cd45be94289d9393e49a58cc1aab50a5e188d8e36c22b033a93647c536f3b7b3c18b107c0b27a479e1e29217fc18f5206f31da32028d2e3817324128b716679766a4ff8d61f00178382b3cb81e2fbd28f425405afb82fd2280f96e514b4a199b8be9f1544d21fa17302c44db9883f7b358664add777e0e6486ceed1260bf056f289c4a53aa9c2713a67a0e127c8d949adb36c68459d6009ad83b0ffdd1939d0bc31b6757e3516d8d170ee6db8eee276d2f9fc8cc452c082565cfffc8f3bb6fa9ae46060e2e560621765788b3f52de82357308fa989fe55087a35b1ea293a9389a21e6a5a38d57a157aa843e95c19b39dcca2937481dc8d5301e4671e76d58c6854e5b4d0cd2a362f3e0fc05f07ae6596fd112345896ebaff63a13352e139b53a78f432b6def4fcec160093145990af48cfd2c9c2e8a4b94760834450e6ff38a5a31c825b205ff7abd772bbb0e3b1fd73e28688733936030f064993410976d3814007c8870b651ecf8198ee9435e912e2065eda6322cdb543c0d3acd057e62a75d849daf80f7171f6481fbeb9b33984d91b12df8bf7ae59b718490d00ca548b3c68e2ebe65739247b20198e5eb3f2588f6f8f26f02d43692a489fd667bccd0ef8e6e5e44425ebebc64610f7254564851c8db6f0132a24b02ff1bf591f5e28398d38d3ed3d0fb462db62dc71b8f68881090bad7e559550520370c84d0ad3ad3dd0ff377af43a4e8ca3e666537bf36480ae4bdb7338cb19ca619dc6914418717b5e9f0b45acccf9dc5bd5b339f39aac49679f5cbac7067bb2d3263fc7547a76f3d61c04d13d6e829032c760a7009efe8247fd27d42450c0a38d30d9af09184547351490c8510278cf86c71533cefe81b9b36a7a651bd78709fb94848b311a6bf16a9cbe3fe72f3d81ef5ae414f449df1b778d0f71d830a20bc0a88d864f32e4f9a5cbeb1244673b2595ebc7fc31c17e197e1ea8d1e43bbf38da63d7403bf5784084f15a6a2fa1df2a9a46b1914e9642d9bef2491c54eb4d61003a34f8c59cd85bc1b089d3d5d088f9603ed71b736c7a1649f26f1fda2c156750b649322b7adeb2e41b3bb98dee1cc57d49940294b8a88915a957b6ab5051f531074c293c1c5890366a2f37d997e4cb28724f5daff5bfc629d6fe26ef7d6031197391dbbdfc6094245a5d2f3e2c8f85132c1fa4217dc79372ceca6031b3ed05fb7f8381ef134f922b25d5bd5e26acedfb205ecde2153ff287eae8034f2388664d8bcc9154b170fcf33b208784f44b2019641972607679e4179e9a0e1cfa7ed532f75c246ff0b0a98b3756ab02a169938075c3ebeb59242fab97b9e4d9c7764311c42a2a3c7d84a1473ef9326e7b07c0b1f48fe9f5407a75e21f4b80f3a49740b6bc4a61acaef6bc934ee5633cbfde39f26450c0973288bb1c0a43d7502cf18a333bb4b4edbbf1485e11ab1c30f92b9a76418ebd0c4d212312f06aa0073d191f5ba31a2c0a057db1c98a6ed403a25342458431e0e21f6d3d3d6ccbd36a41b166992459d242536738d0e91e9f8e645985919ddad085b6006d14caa488d1582aa9d9f29ff7abe0b5d5c776a9cf3446f407f31568e886eb3c1587846e815d274ebeb571204eb940a1bd1793772d027ce7d29271fb79f07f7813c797de1e0cb61d36c1768b45d64ee395ded3ceb13b39297c37e5b5e3eea29feac818d19620fe4c6c16e6584d06128e5437f9273cadd6f6408819a36428fd938156bd7c757879448814ac707030f0d96c8ee0b6b37b112e8e69a89f05497ac3449c44b85210f12d7a3037525b48d150d5c3ced835944c53b16848a7af8b3550b649882ed9a56d832a27f253c929a05a5b2491417e09aa5eaf9d970c0fe8e1fa6d9d5b74b9b1898dabd9cbeacfb011919716e26afcdbd93c595f8ae29c183433134e1c750b560713d580f376cf080e33f98dad6c3f4e90398df68971d3eb4dbf6c2b2a83130aabefd1fe7cb9016f7749fafa9371fc3840810144485dcb25bd0a9457ca7f21be0b7e0726d7040f5e9b08a2775d0463ffdbdd5c203f47013509ae21d01fbf16cd14d962966f830f157c842a058b464cfa0c1326ad5d9325e08e9ffe403cc9bcf40847621aa8105978cfcfec0cc71d9d8dac2e92ae6b35cf894b08061a0d2083d588b90b0b03269512a3939e982524041c150b195ea97d6f9af8bc49a0b354eba669490b6e20e60ca78d0edb243ee3908b826783eef4497a4ed0977107e056191f8a07df8ae9d16420e72bd7740fce724c02b64510c5d5a32722248e25c0b384f00504adcab25ee845ef54c12bc4eab62248232793d48d7fe1a5a54772fb35332085944d6decddc5de9f783d15d96657cef91c912a33c471a179ad29a225e910d0768a5a3efcf770d7f139a3b4bd5d4cd62e699ba65e622d25cbb334adfabe7b437455886d9dc199dd441ae085331dac6ad969174090c7e116627007594a039438c016556003d30a74742d4e3e071aa9034f94fc85c85807ec0e161fa61727cdc02d1dcd3111778e0b81746d37229925a6e473ec96c6dd0c3c85ac2b1b3f8a1e43bc379d8fac1ef9eab0f11a22149e0b9355a01065fa7026c67814741d8c9f3a5636e262a05fd6defcfd4d04486fe2da1aa84f96e5b22fc925295297bfaeafe4e43d8fb1180f47d7a8e5f97a93d35fe307243568459666687cf6003b30c04f3c98124dc1ff1d44d286174396fe23e03d76d50a3544a410497c466525c4178e7bca2d3517c1e193645ecca4d846f9974892347a237f48cc47d417b7541e6bdf7a14751b463e6087cdd78587aaaa72d0b5c18f4ffbe65fb38cc7b71f6cbc5e95790a1c8f9628d45d2e48219729fee56c387f918cda33d4a1d9bdaef1b9d9bb2af50a8a60a66f7f66968ebd6195a1bff83e74ebcd5965f6c069791c9d848fdc03b0431d38db8982fa31ae1db21145d457ba95dd82f686edbffa2a316ae181bc6d814445c4bc261665c037e23947aae28c084d9cd6120947598549f0d6c01b649eeebe9226121e5137ec2b3b1fc3febb977f8b696e7adbb27ba77b34d152d9f8ee0b9c101242316a73296848f84ad7a6a7334a22e0ee7b077143d9a63635d2a7216d0c954b65fd997997bda16c8767e08266cce0d9a5e4912a52db26c58e1d1aaa73042246fa51a8594e8575e3b7a9e45877f15d9c29a1f8042c0a849066d74d7174174267f30c62ccd2e8c4c5eb272254e498b872588ec329f5462906d47e97d6008da09ea61a2c7a513c5180b762f43f80a39ce5becc831163b5dc1001eb29459053f626e000c6eea89644f1e3b989da6c7371e118e263b3522d849fe592edb4ac1d3816d9f7065e1e6cf06043c6889d5b41fddce19742f02ee022ff1e97f1aa6c8ccd68f1ea1cff44ec0dc88b24a42cbaadea70c30d92c56415ef38f7b727e4676bdaa1ac67228b77e30fde883fb5faa41e83167a1e19f5a152836edb3869227679507a0f0949d579e3ee9453dabe62552b430925eb9334c2c195543923523f634462faff0e2188a9c0a3c3e615e90d70ae2501c0b14f5fe222f220704d13da1079ae317e97868156aff824b0aea8b9f407853cce2e301396da139216e477262d3a4871c9440fe1a923bf6d0738f2e57b47147737b5fdf030e6762f89a748dd4cdad495648e3ebd8550a67c393f23d4f081827a4f8de22944fea458009b3dfe9e430592fb9ca5c9ca2d3a1cd4fefea18aeeae3ef6163e5ef1c3ae8008ddc054aca2bccf19a238bec8c19a024bcac24caee3ef2c393d03cf0e6580e4b1d6b58bc4ecb48fee885ced4c8cc1c983d1e066053ddff18826cce26c1554d6d5f2965d61a989ac44a349f3b25e849e5dcd8299595f28ff2e0281ce6330b7d68f952e77af8dd44ab3a7ab3a7fce9ba2ac7bf22d61269a745461de802a40c4af0b3481794ae6a3705929cabfa5d1300e745f3de4f49d3b0d4ac906b3b6fd6e3bf1cc028d67583377b9e35e1296314d32d54cf1d8fde466b9c81932d0d85a6057b153d839af2dc01e59342ef0c6ba23c3446a0dd727b4105520c0c3b4048102a12a99275e9ba3192ab8e05f52add56e5dba344c10e9c320e84cee17cfc3b622312289eca3479034e0bee293d286081ed344dbab6fb4426762a16e86d96c52859a83670cacb66dee3bfaf0b3e34ef4dea2167683ea1a0ed2d20257344d855ff81a285b089e5efb6d2fb53da309cfde31d2ccc0d7090ccfcf0a1857f28efb47b3720eef51415e8baafb4ca2d19ace81885d540b4339aa430e676dd6c23ef5cbc09f6e624d707e90b0b6bd5cf224b9ec1b5fd44ed5d49974c6478cdb21cacfec236d6e071d4f4d3a1c845d7b986d96479e3e60036cb89729287f9e149113f472d88d8e25c55cd1e67801e27c95811e88915a6960552b78e0d0d4769c8350d6197b04f1c52441c4e33fb684f4d211c31a25643c7fa4aa4b87d89f92ab8447c68a22b7c9eee5f1710109bdd9e10f992ec8845412a795040676315744424886801b2a3cfe18a2d7f60cc17bdadba28cd1dbe3a47ae6c702f050c83892ae8ba9c147847eb52ac434ad3d42a3d0103a83ef1e42516f5a7a3b65efbc20295adfb08c2ee85e30e7259e99291704d952682c93e264f77770aa7e2d7438c3347369521c14b96d8da268d77bbf26a60ac4f9247c3b15267d3da140eb284c8ba6d843cf018c96962697b2ff868162b50354b0d60d7b420214d2e701dd85101b7210b1c33027d7480ff5481991a20f9d304f8023455a545e7cf91f3d5d46fd54ca3b93e8eed4d7794b6262f8760fd3a9604c0bff920b748dc07a134d9dac7d23dd8ac394841f36977c286f51f9de2ce14aa1d29744bf4e15eb1aed85a703cec123f5effe1787b9bb0e768f983c17d0f7261a1e03ee121379a33925736910838e3076770b4538265152210ae776511e21a4f9e51babbc2fb26f4748fb5db3e7caf6a58b70f75204a1f1a1cbdd613566329e238c0cced2ca659b733786533d1fef7d116c4cda1b8fee06db6e24a34024f2382902b924c60ffe5d583c707a12691b309f6ab183beb11dc04ae4baf3a5ab17e8c6021e7536d7e5973ee3aad14f9a77cf376fb8e766ada1158f165a24ce406242381db45aa8846fc41e313146deee8d54d1d27740d5c26f0f5c5d3848f1d0765b9a632868cd9b025153592fec91c511691c42480accb149bdfef72bb6eab53e34372a5916dc37fa48d2beb880dac77f6557a7ca98aa574d4aa457348b893f75d6310106faafdd854863e69a6f1080652cc2ab4c7e75486049e6e89e63d5b185533dcf4f90c18da277dce6e896c64c9382dcd0e3bf637e02433cfe2ad663d4460064e60db21c03da9b38de131bedc34032baee9ba3353f6bf42e97ee48173bac24fcde61e17812b9a34793873c1bc4c5161edbb8629b460f6aaf7bff0e67ba5c13ce52ba34863dae35921dabda9710c5dc15e9644c135837d454208059c5c1f2cc0b3883012182861c6fcfdd6b705a5fa974e8d0f9b717c9bfcb05b69cf52ad1998ab02a58597ef689a9e6bd2ab37c988684f659f377d3d1872c29ee3ea2788fa76124b34cf5a4d83cf7e716298f726e79d99954a208d93f64ad1c5a1052c079a656a8cfab8eec112622a6119249160fbd98ff781c76e74361402ac7a710037f5780dd59929dbb47d78edc0314b595e694cae6b85bde67af256859e6d47f306d060a5b4730ecaac7816b9c8452c91e26ee449dc7d19bfd0a6c38be5a677c6bc8f6908339f69f168999395ce1bc303aa6739ee207672edbd9e9b30d1fd39e877196d711e8f23d8f86e8d8c406afbafde8f7c53dfbc34037cd62f7978e70563ffcb122e1f7bbad41c0dbdaccc9017592d0d8f4b86895494de98a59bc3962eae886b72312f65c6cd33a4d9b390b46d603cb035a4a912834b6a950c8ea348c6ae0d9560876d0d2f26582f589e5711fcde2e179797e2693adc41021da81a93a903a35867a274e39844439650309714bb714f5cccad57166ba94c741fd18e36d2028a7123d4ea7986fd6e901f152b12e818de9fc5207195a55c9cf603a6b32dbb25a408be37f5956b5a871b556fea486a7a1796bc3e5e59e93d78f2c42fed6ae81e0089515d83b7a349a5756c394edaa125792b47070588ce591abb01f7365685b448d254962730721b2976959a35047523ba482985a51b6019d57f4bcf8a7baba518a6dc1915ad8e5f4dd62fe300607ac0a1681fb6515f7f11164d8f454a09dcecaf8bad2a346d091fffb7250a82fa24983a49d671f7ff1179485c281dfbc3817526b0a473791220382846237f9b5a1273aaea0844234d1433e48d8d6914447850fa2e199d293374569f02a37000ff7a9da83ea72d87d2b4760a3d313b557cdcba770496bfc310782278e520052f0f1adb48cf3e88a24ebb3e0574a2fc51f865787d4121300ee3246d04fb0936fed224c8f9809ee35e131ce305f0f113f050b5eedee212ea44db505efeaed3edb1b901b8b8d99a17eb55f7d850b584880016b4d95cbd574ce798971c28087c2144e167f2f44800ca60c969df0e4fa3426c8bb57c9455b5b63bc4700ffaccea9f069e5d0089fbdb63f75147922fa6e09c89f0585c22ab0daeb2e8e09a533acece7754c28f6d82f8c80bcad59572f4513713502cf1621e6b588daedabfbc51dd0079332f047ac6e8322423da88118451e18d90cad1ce57c6a8c60fcf9a85c498b1f316ad9b524491b4664f2d1ec6fcbe8b1759bd3c2f80785ebe1fa1589134de2c33e1c83f131c9396be1cb546206ecd92a7f23f75a3dcfa4f844569eedc0fd04f03c6d77b8f49aae06772a1dd0ffc5b4962f98978e3e9c38227cb29c78a6995eaa492e42095ab1ce0c09252866884d6edff53b8bc01dab37a07c5abf65da8ecbfee5f97a5add7bda5c91242c8676d68ef8732aeed05bb073225a0183e5b999422b0c08ba17521d132bf90a1726ed677633fdfa77209adc0b467695afb530c51636128f87d7f43bd875bcb54122ed357c9ed612ec75cf1e30d330c9cc7b5be1b0f9d14364dd99961ea60506fbcb1110931c361d72b641031fde0bf25eb2c996a49bc67e43d5d44a0109404dfb14a49f49c3444852d416f531705124a763b4b018f229f7e2f4facee02e9b9822534e7cfd716fa9806a7046d3707100c4958f234004671d62d79547eeadfb32972ba0c95a06fb94c81835f3541d8f3a1c82c263d2b655573789228283f9192a846eba02516846659f3c691a16d819ec117e49032640a6cf7ec4f9385c280d875d7592a00a1106deb036a4cfe6c8b5ff859cdf884c59ac48ffc94c2712d67bd2e70fd526c70826c0fcd50d879a5de92adc2823444ee1da4fe4b6affb078a0fca43effe964dc36e9ab57b11cfdc09f6a21dbaae2481805e738320cd19f1082989f5501274ab4f39ca61ee9fd92f79d686d68909acd2b02058b465226f9e0631be61e9e474463888b3180982d75d53ed9979becf5e61eaeb7a688be074453043b0c8f1aa89608f387cbd0d653cd4c80394cdf92c59d16452553f082e5d63e4ab2d7cddce37d2b8e7ba8f058b0210ace2f1dee7a55d3c05f9faf9021845349f91c931fb55145f7e6f28abd743f8c7b357e4380fd9f79819fa9f04aaa77b75590061bcdfd3809b2e7d2b2fe9cbaf85f9d94bf3efa52614fbdfedec7ce6ac060c9a7d05da64649bb351bc0e84bace18e28009af393b2b65fc0d52aa4d7c63aebb2b4b4d70a87b5d2a93e22918eec8f888db2348f91d804e85b6d9e1a8027ee2be8b76090fad0477c3219710c8d98871d9e348eb27b6be594f8dea479ce2e78164ea797b21812d9f204bbdf4c0d5b8f0541134f22de573d027db46257d5958ce71a5a4a1d0e7666e49009f0e4abddd498b79e75542667398afd6e9477ecc78f6ff726b28052848c60c725290b507f6d80547b679f590c72f80da040563a0e356b5ed7619d545bb06176125632a1158c5d4f25866e42896835f994e40d21ec1f1123bbb61bb87256677531c01adca6141d73ac6fc43498e7a734e3e7b2c1d4da3688208767c233b6f8e1072a0e8f6c0a6f9e8c99f950df08f1eca75d674d548e7c8c952767fea9281ffe4c7c19a44191a0015a2a477bba36bb9f9c3f2f8c0c3c39f5be60ec5e5d5cb48bd14fbd2c36e93d4568a7882a0971e6d10153dacb7abf7f6d7ad674bff18b07ce8278eb779d7334796d9f1a5f636bf3e1d10d3c1a1b0320575de65556e1adda3a2359849afd24bb6962634b29bcc17d11e1fd035785d14c0052fb76054c0ef4a021a714d9b5093de767ad314bccb827209242ce89c35f598a51c0ddbf0d59f1f290fda22b9189cfe7fb8a95fec81dbed22cc0d57f036c8f899694dc7ae40233a9531eb9116c66a975005eacf1b218157fab9309e701301e9ae82ebc763474db6495898fa368b91e3c2ee99bfad8b68e0e35bb8397cc272547c36588f0977e0a2c23171e47bf71da7c28f292afb0d94e8cb644a3122b57c79abc818e96835456788241b9d318b512237a93a89ebd45d6159792399603918b890a8aeea2005d76c493e22b76505c202e1906f58bbc092ea680df6ba856ae74bde26d2f89b73b83ff9802ae6713d3361e57665755eb259753efffcf392d9587479a45093a8d1f0e649ebac6cc810e0e76fa8e0c2a1224276421f2a5ce441c60fa27af38916d4e5f31df538afd4597703ffc8f061f90792e128149ce0609698eef470edc3efd218f8a67028033f6ab26ec4d2b34e680b7e1733bc7cab5506fb0f2bf7466f80474702edb970f54a9dadcfafa003234aa6c64dfc3a6d7c001cb18fbf7ee1cd1437173943eb3705b5af5752a4091d0bbe94748d6ddb8067d4aa582b5d310a3cfbbc825cd27fd686a50fde1308c9885da3df7df25413708a16c48c20edcbff82f17092b8dea4a1b0716b12a5e72223a280e0944fcf7fb8a60c5381efb8ea8c76c70adc02aa4446ce6c49960b5101adbed7e7ec8a36c903a2216bac74726aae193011898b57a5f9cc49b5dd1724bb673867e99cd0fbce00ddbd44fecffafe831734cacc55e56f79cacc07501fc017926b9148decd9cb23a46d1898839ce20449147adaf793314d0517b58943c988f7b904c2e356dec6e5ec2d986d2cb61450876cb38d3617982e69e002c7961e7b8d0be6d2aeb7d9bf93c7c06174786f810c47963ef3f10422ac9b35baa445de4e020c0321793a3e63e1f89a79c66908bd6096d64583c963066d150bc5699a4ea20f292ba587c9c1bab1a30f86ea37a5abbae17b8941022055239acdbab8173188cd969b3cbc770325c72c087257a3762bedb4a1082f5364a4a11d61bddb8d7dae612815ecea0d5c2309ac527e856479583c3c319e9e9e819120f8bbeb1ad3e215aaa206a71b04bb4eb6d895424e539705449b27f687c5a3219e2b4373db1b8f6ba6244fa325e81665339b23d25151ebb459f636ee1109d7a7e97d21b18d450f4cd4260b8973b64a5ce3eefadc3e926b2c091356cc17801b126cf8b68a2994ad61664f6e988183db4c389d7f4715b4d6610d865bee900ac3052979a5af3ffa2c2e88052e93d44f7f3ed815a80e47ca5a4bd437ec6a2c10d175839b8e41f30a104e3cc6aa57f849ca3317a9d8f779da5181037aba8350e87c54080351180282764ed291728e913011e083dbef63634d706b2eda0fa6bdd05bab8ae72086d607def8b28793aa8597c2658e6a2d40868fe5a1c70108421d51fee21fa601678e3b66d33b6f3dff0fd0b1423bade710b62e30269f4e4a32e7100b0d21feb5589a6be2e73d0afe1ed6020697cf36a28aa349f1f1ac8a68d65c514c7a209e1eba63a689ab15036af0caefcb5b721dfd944b9ec1fca28d7daa6acd710c091aa9674fa08b62447050d1717077f68a289321fd1dd11e48f79674e74ac494ebbb6badf4867ff60377064b17f39168381bd52b42fb89aeca53d74ac0e893de1d50f3a8519bb830860aafe5fab7df2fd0cabc1616f9c469bb39b3b7442b6e97f73f508c3217571623ebbfdde98fcd8ba0735bb5d67febae7c2bfde0a1dbc83e291cf71c74a7e5301ce177d75a7fd6d19a434d21021cfd69933b2566999ac98bfad55f78d6c1eba2bf18658b41b562701ae1ec83d5709bf05da4d6fb367dbd49ff9a10f00efab0354936aa4c6fdf994fa8e889a8f13143fc91dba75815a3f75191ad8a5db9266e708a628e2526a65d5c60858e8790585b5c7e73e5633906e6d52f918a30c9cb9e5e1493cfbe1cd6b0552dcf99d69ef12b1b1217bd9c7d9b8bbbb45951e3e3e06b1bdb2b1a4f2c53232fa449ff06989f293f051aa5605889e768653b1fc5f18f703b968c0f2d887e7a10d4f6f0a72b26e2fd073c1834eb579af13372b06a63700e7f012cb6fd6f548ab886165b3f08e095da17542cbfd689bd03d924a19088657ea0bac89b42a371b87f5a8c105b78d20a9d3aa8dcf8efac4e4cf36bce72f23e46119fddfd229d0636b76e5f72e2d0f8746e5079d3608f988e0b157276fba86f3b93950f352c6b9ca3334b3d1d78ddd1c31804ed3c9eff066f53debaa422e30b9b644f042faaca9b4fdd19dc4af5c236f03d4ffad5d3de7cecc810e5477065fdb6654a4710369f7843b3b8c2a26992dd2e0244ff2afe98149166ef1f2b7f97cd3be2cb552e44dc0c9bfc5ccd98eafb96392e3a9ab43d45a730d96e930bbc58cb7a04d217a64717a23f3ecd0ec43ff952747d21967486bc4ab229d455cdef8d3b6b4d9264f2a002dd5426e433a1cc1d903d22cc89535a2ad2895c6ed6a1aaa4248498d4672c4ee59986c79667c00530247252904577e79dcecef009a3160f73e96efe5c282722c1ec542ba58659553b43f07fc568602d7072b59c7cc5bc08a60f66e3d8d0a82c5e5c9bc027d7fd7279edf7a7a241e34dffdeb342caf0106563ad1635743b5c29ba6974f5d2c01d631a562dbaeed2fa37b652052b6cdb41433020c67c38c1716ed3a7b5d86eed61c76a9f3745f5508f8772f5f523c2ec64cf9c33d86f51c72c06503c578baf3f2e0a899622d7baae42e7cad629f6497167b5c85aa299f641822a9d039d74739fcc1fa79197c579b8f77a07adf7db542925ec7c88d2d33480d49cd35ed6bfdcb965f351585634df3e48b4dab17631fb7b9e123e6649647025c6df4e570c63628d8988d32fbea7f8379ab952d0a9e5c88ea8b06486108de4f1bb76fb7ad89cdd40c81d1ab88c13e96e9421454609ec083afbc589ac90b0b7e442f044167bbc6c0ea56a11d4354ced62afb9d45eab7a790724ec1a79b9f34d252add3ec84f2d80c7dc567a1bc6031f3411ef819da961bec9d14144ca6041c2ee767fbe414d81273bd7d03222faaf30ced07190b80ceaf86cf56ce6b53a218843a6136250b2fad41e0b859fc85d23ff990470199cfb2959e756293c383eef8b072e2181ff7a20ec5a852313f4ff3c5718e833cf5d2f61e4584ba4700d4b5548a99f3703e573425a8a0cb11c883f8bb1dc9635cf420a731c60291d0108301241f978ec18f8357d5534486ff84f444afa523b856d511ed6933f4c9bf564ce66010e3ca8e2cb46befa6503b06898b1a3863e43e34c02718bef628442dc27eb891f595da09357026eee5190a64fddcee19ce345a2b94edb761fd8a3dd6b5d773f5e476a6a4e84646813a08ebc5056150eb02efde645c62428c9ed7ebb132cf161128ce99fa5c7e1460683051968295352e285e80b691879eecaafc4dbfa45de02f71f8ca93c2d5547a0655044e95edd8ea85487aa042654c05af44f1288983f804ab821723018e8e23cbb8f575e00abe26a9866a046134dacbfa25cf86b177068152d4be575cb4e800011430813be9ae0e9a73a52c5abcaf3eadfc422831ba71212a76e87c93d222712b2a7f47641a1b1d057e8bf0a74346694189833843d26bbe8287e584ac1d50925a3b3643abfca29d8a00ad40e17f80f944104ec7257f922ab502a35d96379c1835c02969ec3b2c7578cc6ea1e8b3caeb11c2941ab1bd974cca53c4cde8829b2f867dd87755620a107ebe3478d6b962e287442aff7c0de35454935c14bdd3fd9bb26629bdc8a2c00725ab736d06e77a6791e88015c435b33cd411f844be1875c411e062eaa6f689660de1379adc638c33224f486211f7e7e4e39855f9b641b2a9cbb28bc86da61ee5dab06ce922f343736ecd6bd13f0a56ba49b555e7a379e4092cf608ef33e251990e8645b41f8f55dcde707e2dcb19b366b57a7424d2e5a743934c087aa4d2bbc99eff0c060608432a90c53194c57b92811047eb23e39cbd87d23da5366ab5ae2045a70c7c425986ca17fff6c3e9a2994f0de61223573349eca1b8ee33cb5dff73422bfaabba270955fd77e84d137f16fa41173b9ba3bf7e7cecdb94197ae9cc56ba85bbc749d31fb0dfa98e27efcfc24773083da5ae5dd88eb1a062c872860853314a1db969116db346254f2d8e49e0df11f30f5dfeea313409c99a0f2c79646e5339af6aa28e37b55be8a6d69544c3ab8ac6894325a6ef0c508a8773eaf07abd2df93d63009cb69e7aafaa13ca5f41fad3481c3cb199364b99a2a6f3499d666c3597fa701b6a0cf31f5230012d88d30fe550a4536deaed0a0b2cd9cfb8c5fd4f7da5cf8765c04c253b934f0d930f6127b3435e191d74cff657c499bcabc1cab9ab5d161e95744738fd7160425c656bf1598b3ae1b6af4bd3b13188a6715dc5b87501dc50c75dffeeba3a8751a94ad8d8741fb4a82ada32df96783dd6ce4ec006f67c988325440663e3683079b7ff375cae666ce3605b374f75fd8b52db02e63f72b159abfb64413f0fcdaa639b3217aa759aec16b8e9985b3bf8f8de5d423d78f89f6570cd48e233a2a67c53b01d5af2979755c5144f30777f77b76efbc6c76bc93181c2335c1cfa5d34b9c7f4ecb18a99ee05a91f8063492396fce6f171e97bfe2b15239be1c21d03f312de7d0dea9fbd40039eaf7a4c3f8ea2089acf6210f01467e8e199610ca88ceea19986036323d43a9774812106d38fc923121021bbf8aa607657a09cabd8a37bbfd97547efa9fb1b819193aea397cc7366a939fed97cef5b21eb2648b85b4881139416eef966238c59f3a84ac0c0239ad6d184ac722bd71afdad7a7632e9231c582671874d87eb77fcc3801372901a1b0434c40c218a61b112531f9852411d1da34a90656133a87e7961690316b1e33347cce4f436b21a25da7d1c2349a30b895f589c4209aea7b1cc8268c010541a87aa11663642deacd1200b13589fc8add22bcab6fac4530ee0ba2d759bf46660c60f4722990327deb8130d51e45327341de6ed7c53e01b77fdef7c61d62476f5492862f179d37cf376f2e589bb7944afb0b991d682df0ea827c6d8442b6fd38ed89cc1e06c544c51e1a304bcec3242cbb5ef995a2a3c55ebc7aa142632451e90670a451240583e1195e22053644d5d5d452f3968ed4b7d1c43913222e84cabf96c60be47e1c02716846cd730f3ce800a9d48fd8ce811170e84354382aa7fcb5904812f094b1ffb0b52a00d431064eb4e806e92086c173c4f24cbf34d9ce1fa465e0d7458e56fa2585e035d2adfeb7ab14f21436474c1c07c8bf893d34b7a163537f658c1a0e7108b33cab95da5927b7f839506fd9db8dc699ebbfc26e28a4e5265bf075ca2754efe41cb386cf6cfb837a7aeb82687c44f32ff2fb3d4bbcef984bd538af9643ad41887dfcaf95184f58cdbf75b1e9226815a6db7e3dfc8b83fc9fab26adeeac8cdfd4d1efa5bcf42c57ca00d118884017d318db4cef28bc2f77f0f568a3dd3bba33a76297ceabf9e7495311183de437bea924f64f4e204dcbc71960fdd5871b08cbbd557a770ac6aabc28be980e5eb81a69a16bd33415878e951e1aafc6b02e6ad01afe52440135e9892f03562b8a48c8cec9cd10afd183fad336ddb6e36f21280cfa41e2f16bd5277143c035f4306cbbb07de8de5aaa70f1e2b11e32357118fac315be7e7db1da0bf15be87ed7357bf2728a071a93fbee3b128dc6800d1daf833576f867372a2eb7f251d8b464a6fc099d316b4b70f79de89607550f37b36aaf94bb3d115e2dbfb446e8d8a66941613f95a711f92d6ecef6dfb424231b5c735efdad16b604f6bb72b2e81f3a9217ebb79573fba064ddce2b313d626a700aee826ecba90609f208815d47c0819f19330606b9ce52ad2e20b95a82e0dfdbb104a4203dd0660d1db615ddd1655c85f7fff6e8c1577dc0ccceed54c9f3b7185ebf63302338e6e756b42656925244b21ab5e81adf667aa83bb57c36f5bd4a0cf779508cb19caeea22edb40fa08cd7754298c17095dd616bcaa1f690b40f1e3269003bf7b8c08918015584e7ff6230ca14e02ba9dc5d5bbc2c99ba387a15a2e8dd7ed656524560e1a45594a3c88a8ba9ae6770b5cd2ac6265b715d9dbdcd61b0f507979b5076f4a3df3cae44b4570ee51bdcab24d94ce03d947a1f8e7059128854d39f650985adb36a54a9373ad5044ab27aad14f08ad8c9638e03db2a80dd7340854396bb6e88e199d4ebc61076bb031d4dab37f3c4a65b39030dd99f2ba38946ff16df08044483136547c7a6b358a20664104083b8bef356b2135f978c04fa4e2abc339f0b9356521a2d32ad9dd6e6ed6fc320cfadf64e9f1c79c7c916c1d4318b4e921c88a5f03be332a18c335a1269c70e8300622fec415026f0d922c43808bf2a93e81eb75d2b39fc3c78b6844ab6b18e5695d1f99a656ac71225feb9fc8aeb8a058279de331350e9bd86bf78bb9a62ab12bc7e41201cd292f91c3cf013e89ff3c46c913169f4435b3fbb5012dbb1b74c213d94a5e2c9deeb1fa0a44606b08a26c401eb09ce9c87af42adc9b26426d324002b6841641ec7e01051950b84dcf89041e06d1530c4a9c725ec1dcee14bd5c889cc1033fe4cb54c9ed2739657697c31807ebb49d420c72625161e3af7358d40c4491812358ca5e7ab61d35153cef2bf28d5540ed2ad88b3426235f64f4d7034a42d364ae3c6e45d13a385508411475d4fb1715688f658293de5624a2c70de025efa41a9daf73d4656659e731d31a08038b1a82b355d0d361dce7277f2371e6b795e24e3096edc3710c900530b6e436d8eef182d623ead1b8fa7cce42af87755003b75fb65a5daa694ac016ebeb53469ab2c4a73093652b05f262a4f54a848d1cb99e3fd139ea59746a78d9818c0664f0cb3125dcb26d0afb711dbb7f51013ab7f1d10cd42f1b315ad9640da46ff579adbee7d3154690c0d0a5a320390ccdee6dfd9e4ddb7a91cc113489affb1a4d1db7d7f0b365f2a56267c9c62405d3a237436039eba818a4ae8a8a7fcc411f856d9bd646d9503783989b9f67bb00d12e4e87ac7c959431c1516effa510a6ce40990cf533fb31e7a75682b5438e925076091d695cf9e5e06b09323f347e40b5e304f12d46302567be6fe008c61a9acb1bf3e64c6c374526f8506ab293ee03a616be14016c6f6bfa7c3a42df183a492447b72c68190592a79de0919669f60ab84c988bf1eab228a171d726817f1b7338660dbd380910258057501e6d36b74d3a4ce9bc521eceeb5096b6169d53c52be7d5075ae8d1b7e158ba51116780531d3ce6b2293dbae4daf3dde8c723b189e7b0e1cadf99c332fdc1c19aaa73469005755c27688fd1d929b12826950626a2188343a5487787488fea9cf07d373177c652f14e4a6582eb21274d486dafbf0055279e11cfc6005edad15579427062969304cc882a9b3e01509e5b4c0010835de13d90ecec070b2883a762d2f3047ca0b30faef0bf74faf7c0f9728799a059caf27be90286caa3482a7c751c64429da61adf9fe08abcb400465e9a51f095ed20046937e980e6dfd1262063f1606b928b54ebf9c5ac0ebc4b3debd2089f460d7c569fd5e2cc34fc111f229df409f5e3833afc6d803c27068e8dfb59109e9cb7d7ebe4b489772362a29129abb15873cebf0d4025bae733f7fcf4860de21cea21dfde91bb29fb18aa930cb683a1c7160e355f611925c8811c55cb543584a65d3f6f6784f60481c04c7c3de22843c28ef3939dbdcc7a381ad43ea9d2ec01a458daf7108d338bca95e83de3b5733f98d27426b05f572588a84066039fdfadfdc9cde4714d4d5cad307c2e9009ae83f4df8b6b27dc793e58781a2967a9f40b629b6b65d3cea0d7bde37b3db8cbffd71a3ca8d9d8b986b6323aa11bb5ad3a67bbcbb851c6544d3a5bf15af488fdda3438627750d87902cf19363ab3ba47d2d31aacc22b5292aac4917708d4c52849dd79eca6a10a62d2d89fa48df72b173aad7304ab84d6e916538576a87b6f0c116d721db01370acf93770ba19fd0979161a6ef27aab79143c36925634210bd93c1073245ffae627d3d85f1ee7408f7fb0e96b8da4b839aa894188cd07443b5e7741eb59e225bfed98990b153b387132c7765e62a4b7b8a575875d3d7e113628406bde246f051366032d26c6d8e15b25de95cc04ae5a452e7be9476e6e2e32df4b5e90f4821ff47f6a4bb48015aa4d67e88803980c8d2c1d0ca9855a2097939e19a9389fd2a6552519dfedbb94fcfc9be8f1c694c92f9224f0c58a58a191be467fe6216859efb228f9fac0997d3baa07b48ea2c53dffdc3561461f3bd56f3d9565ce8a9fec353e6dcb29d9291ae903854b6261a2232481d30dcac433e3c0f4448074a981e3f1c4d03753883b13d15794c2d8854a4769d36c48dc94f4d631d2392848440ea2b1406f294ee7926ba0b128def4334b0c4bf61f79aad36e75319b7f50a0ad226c298c1812c1f28ae26283b5e157c4561f25795bc1bad1789072f23dcf392dbbbbbf63b3f51d41e949c695d8350a0b7d8518a9393b08fa7e61f88c93459a2d5a03b784919c6d8d7713d80172a3f98b2c51d9bfa3b3d547c648e49b78fa3af1555c09910a3dbade2427352fd23f1c63b30e29f107d262af0420243c90a9ed942360e165f97e106677e21a39f1102390ad53b98cd9819ad4b1b7cf7239f6792fdc6b0a51a0a1944620c4e0928864142dd935a78f7f8fbaa10991e006f08b652f635408e6c8e22aa35010384c2fb56a5bb476ea75fad2524a4e6832beb337efc4b7d4b9a9b0d5b60e426a04905e7d2892db48dddd2b58d720779656cb903ad02fb3d467443301fcdd1d0a6f7548bd1e67f8e3a14529600026d16f78106045fe013b0b729ff71cd8a6396b64f0bbeed8b6459ab3a6e7426b1598e22d4e44446cbbc016793c43c51ce42edbc9feba4653188ecc2bc844ff43e4e58285e184cad0d35da51e9abf5bbadfea4d3b26f3be457904e16ec60bf6ff67e1a3fd9a2a37cd5403dd48ee25ab074867bbb099d34838dbf891b33031d5f9445863d89cd76002035644a5dfc0a872da15c0f5315a11e3c76675efdbe6519da3cbd08c7f7ff92a9068352d0b234436c0c955d12db2fb5eb3a0f106b246fcf7b4bb2ce4eb523828e72059b3d080125cbace52141080d57d30745b8299f27c3af7feaff2fd85cdd7b14946e26951f90f501b3f126e962d14a5a651ff8aebf7862ff5c2d441c62feed330e4ecd17310425887711fc5ecbb607e983d955eef14402e06d891747b668416856a847e6deaa4ac225e2eae0fd9aa7ef8ac4ef5bf67ddb4b5e45cbecafea4201b5429cb58df375e551c6042add766de5c5d7aa6cc445e8fc1bdcf1691e1dca27d26f8a3e538bb0542ef4e3b8d6ed7918e1fc3f0d9a4bc92f26299390a1f0a4a86a232b3482355461a3e1195db69be0661f273aa77cf3e55f7d5d2182fe53c2129c3a620ab5f8acd93ccfb9546b96da79ee5bafd3010540cdb302946c7a6668092c1ec161e8802292e7e2e4f9034a9ebf8a165a176cb225b501f7aaca055ae8714c288677b8ff62e656d9abe242638df9c1d018a18579a1eb74a207f01e0bb7964e68e04c91d7b1a0b47205d66c113f55ac309379b8ba99c44f0de22a5bd3ca88683fe57830a2420bd256ccf73684e4502a793266151a6c2baf2929a6f9700d92705af63c129cd7be38b69f324219d38e6525759e4d6104385ed74842c1da0671871130734b951e1aa65e1c93d5e95385b3e5ef4a04b3ff4ee1b2a0f770e1a80837351d99d467d8ce198cabde5e6a9c70ea29b21759234c1db52011ad104c9f06b9c1f0b09c808f3c174b509fd1e0021b693b5feeb61742bb199681585a4501eca3b2d5b90f87ab0a0d902fb3ff92334d5e596b7adfa873abd3619100fe4b116b350a7183318dbcfdf0b267498ca04a39f075fdf8c1cde0413fe2d1bb70df5b47efd094044ac94bc5341710dfce10c44a0d621050301d3aceec52daa45fe86c5b6299c574dbecf75962745d06b4f8fd9a4af9dbf38438dbe35f4186f681474fd3eeddf6ddf58b028957736839d2353695a199495c1142eb9d119004088911a6ef95392d2894ab1fb51ad23e31679b5c74b98afa53b6f92f702df1af52d56db083b211b2ccfc2f0e8957153e04669c258a33fd6e5edce33fc39a5e5c1b74e23e20c5765b0f10d4ca507d22b8e0b647d17fbcbf44f92f380040ccf5e466e77e60cc3b9a1df555707d2d4e7f1bce275388980e6a03610e7437434afd15c519b92c94113175428c94011a29473b0f71614d66e000cd21df5c735872ecf80b651c72919b6e813eb40a7dacf0aefd683ec7a008197f652f385ec94f81a2c33abfb665481addac8bcbca9852fb9e77c3f62d5f588446a135d00bb306c16810ad3df2f1a9a9402dad035835b0e24f7983087c35bed94d218f4848a76f84d2797d453b704700a7fe3042138d45cf17b14174f929a5e2316deb33299dd8f004e17d63fde1cbe9e82ab7b70a038997326d178ca16ffba6f79986a945ab5c48d99c77f136b3fda669da42b31fe895c08bc3299e5c749b9dc8d8a7979b12e94e9e85b4e6f164ecd82936ff3bda3f6f9980de25fd32aaf02ac3011552a4ca8823f4284e10d98d02e8712cabb4d28f76a114042013ccb56a07846f59b78bc18425dd72c2cc53444d1da0f65650b2b628141075409017463edd13ed31f19cc29259cd7adb4b929552d583535dd4ebfe44b8a0836cb461c91797175f28c318a8f86fb142dae8004176523594556c985f23f70709102a83e912a23868c4b9ec7f663d38776d02d6e9a6aa3c03b3fb1434802819f1a2b0c56f2c5cc8e611c7a6a0f7192160403d0331c001a389522ab3ac043632b0be4563d296a07dc48e25b4eeaed9806deb0d080f5f451bc8299674fcf543adfb704c9cd140d50a3b23f61e05c0e66f00b776d6d591a4bb40843e867c19eab69cd3eb3bf191a2c5b8ce43246b8b37649ea7281bc1dcc73720699766a4bc1d4e1e3a8ee2378932cc446d816a502dc4905634b06fdc2bd07ce8c172ff4aa94f6b9ec19de8c4291202cb0b1be093e209ee7cdd64a46c383eae6f2356890dba0b69c5bb932a9872a530314dc847a18a186e334a856f42188fdf7f8cb4dd3a4cce262edb554fdf077e50d39534d7fe923bde148f145add1a0748650d525c741bef14f707ad114e1d0df4ea9f071ae0e8a891167b83bf43ec0f828affee7044528a91fb7de7266d9097f026437cb58c9db7f0f29774a25c070a89304e5c265ab4322ae22bb4eb3bec880c7ee782e5bf202369dd63090fec0c4d13e7902ad740b4a57791c9ea56a6c253a50ac00bbb35f51bfbc78ea73d9d53c6eb4dbdd566a04524a7e8fedfefd1fe4768a14fc32ebf8770780f853fa5c0dce3bda9773efe3db7d54bb69570738903e777139911b84268c7835ab1eab4b143066459b6f21c734aa39366e6bb672ac1e512aeed0a54d2cb0da1e84bd3a05ba073997669b48b6737ac7a0728b38ae4ab4ff1ec3325224ad13a98ac75232071d1e2844af365a3fff9a93295c547dda45f61f3ac0877462364117e9eb4d260fbb9c19cae6c175f0c12e81d81e832dae66a47916e08ebe1122dbd79f389d2afe5a3348060a6f8adb62a2c5c80ea8acc6421ec864f402f59bdba853c5dcbddf49cf57813620e28f03b08862eaae1c77a6bcc9083eb2cb943160d24457089524b75e68b5eb2e9eb2880c97732a793147b3d06990496ea51fb0aeaa9d6dd27f55f283a634f4d4c2accbd2657b9e93aea130843289c7e0af4a0dd07d94f5456a4ffa5234a801e2cf03cf65f0b6207a7654ac3216b085824d5e2b8ab2b1e45193d2d2c6b5801dc23be6a119a269165b8a7fab5b8d43d54715c94ed266f66d55675cbf60ab9b58ff151de0f6572c40fcb479b0bc1d770524b376d2d097797c013992cba275dc990c80bf04ce8be17fed292a5d8446e2b1a99bc9f471e00d1764794c990c221df4d563b47f1d3fbe3d24ce93a51784f31ac895a614d8723ee921ee758818458cffd595aec2bfc5f53bc42d7232a41e0165dc7b63ae185fbe277a37bcb80c8d6f774ece7dc55fa195c0324cf020f48ff4a6072392ec0f1d2519943c8010afb3220d84bbfdde67ab0e50fde3964d58c656c00b5ef8d008c1d45563542e0da227a099af6586948087067e6489eb2367779c8a9975f98721c097b7c512e3fbf36c28d8780a3893c0222b553e9b8fe8b0b08d2c60f457b08298569cf79431e03ecad1394c04affcc20fdd206381ba9f075895157dcf03d8693dd1719a29be0fe90ea0ca0a64c4844348c5c6da7a5c7e6da386f55e075406c442f7d272633dc1473f60102a865de9a2350e534acba2e783186bba88f1bf4f0164c37470aa57fc19476f3fa50a17dde95c5ae71be3b963ba3c74f0397e812dd16fcf9bfe15a64cdc011785b36ca2937ee7c212c01b16dc46c49505115f276af726afa04ef46cad19c80d57ff49417224e1c94e2f1cc60e6ae897241ae6341e5550e4e6f7ccca5d65e21ca3c0e1fb13eec288fbfb713606278c119a1fd2bcb2eb6f0138ccaefde8bfe9a1bec1d995da2d582ef628ff25ae51a43ea92cbe06e2cb97212612822b2e82ca75e3b974d2212c2011b7e250332633868d5bd426c1411661448587fe4b83110711344d82e4b51d52888b15a6610546981f24c0d8bf9237cdca202d633a45f9e1585673b42694a7a5774bc2086939ed97f16f31200d235867bab7fdb805c0e69ca992d90e724a654dd59ab4bc329eeb6904275f54df5b740322447cab4c371217dbac154385f08be138b9ae9d720104eaac7b931825fb6b796954d717ef996ae90ffde388d2a4284ed606d2e8eee07d75497ee7cc38c7b9d7d133f490d2bca2bcf305a434ec7ab4e1e92cbd787ade02dc4da9194911ebb6ee0a190e23c7d1168a11d2e700c5faae344e4554b0c88aabb3e496c4e93ac0cdebde8f82ea7d42986460b8690216f1ffa7e9fde02a7ce70bb2e8f8ae0fa3bc39550f3b923b5f0872db1fb1796fd0dddc937a94f8c7974bac6425853936cae06d99996a05e2d08f0e0a0d1d59d07be3d1542bd9330ef95dbfd691df589a1ca019c514553b12a623242a84c869c7ecc787e77458c70d359b0936f16af029ec4a36a9722426d1d3810dc0cc39b70fb199ca1b297a5538cc33a3d3ed6a3f15d09df30df45b18f2eb4976f10c0cd7fa3ca5c31a4d91219ea0cc52e739d88cbd3fa707edaa023115da65f06bc35c447f8fd8edc1d009e32feacf8f45d140f1484f9494a49006c7f99e93c2243f516bafeb84506bdcca07f8347730318f4834e8c80ae2a611263eea7e43314cb95152cd7c57d2612f1136f9a6dd28ad7834934c48d21875865c3827a18dd04eb75b06d63cea478a2dac2e268e1d2ef48b2f6e1d3c0ab9fed31b386dee23d066fc959d849ad11d6e9eab45534de5fa059e7a165f0d0b452d438c525f2d9afd4c8c8b878a49cec7470c76c3e676588a4e5b2c1b43e246432e05fbc493ef86f243c41c23d981062c798bd1b33d5cbdab58d52c627cdc8049f9229132fa8e79d35a9d95c7a500b47ec5838274159de16e64f3558ed8622db704a92ba94abd825071f0e48853936cc1342ef2f1b113b5c3a22ffe3136d9160076f82a467ff3a3d4bd03923b78cdba61cb7a9da834df73249ef66df02014daae93ee3a4ba1d38ef9cfd54af64f2a1401f0891c4bf8322908eca7ac18ee1ec24fac125e5338bbc6e90dc2d2607fb580db67b8f0eac74d5b662a401a0970acc5ffd2834f56afcef85b54a0e7c135e2f9dad0181c45d49f69ef3ee2dac3337bc9f5952859734245bdd38ff4fc4ce9f8365ff0ee81ab84815be21a19ecb52fecd9262ce804c02edb81af07f1eb6fb5fdadbc6078e9f4d5e5efe6ee4e630aea30a9a4a56761fb604d3f8474d79d8ee9f323aafd7ab24a89fd9b969fe7726e733f0b00db8c55790174cca463a17228946f43f68dc16ebd0ca268e64b4bcf40f341500e36daa8f83bfa7b4f61cc22319a01b8d6b42be3eaf02f2b4a378e1b7b124fa1d83b706e8c7bf449d03ffaaa1a8b75e37ebf4c411ae5751f7d3847992a3dbce5d42efd3620d8456be5e9aef79b4a9db102ad4917fc4e1d701d96aac332b975739d296474cfea1760e4476b1118e4eb61a16192eeca1e09417450b6fbc5e0fac587ac43e35600557972cdd0b498b5a29df49abe83e2bab3b79f7f08a0b519bf3c5baf363a30f57e085b2af7bcf1f1ad373b132b594df9f9a831e718125061ccc58b06dedc2668e8515c7ff47ecc0c5e584121ee31c3e3b83dad04fb02a50a78519a193bcb699a7bc3ae01f089e120cc87882a6bcda3a235edc757503be576597ebb0390684dfcd70bf746e0dcc55cc3680dfaffd7394d421cf215ec44815f2d788b6d9e63e8c0bebe012700a666ab12a5334b46d50743493826a02e1b92f81e21f360f131aa2896ebbbcde7b6406c5e77f1f5993c85771c5e755b215c70c7e3306ecb0d2c0d20f671af3dc6bcde045198045222ef2195065e3ed8e3c401b92cad42da2ef5109fe7e9b3bbc6015cadfb7a8ea54e397cce542519fb8a28af2d7f39b4b03f9cb1dc9a1d5f9c1adf4c2be0c638e79b0060ad707a60d1c536001f4cd06dd5759e87f17dcb1ed0bf92e285f82acd83043eb377766bddbeb83d8fcdf91f7bb6e59d4bd6097bc2f713973339cca7b816c1e4cf1a7d420bd2f43ab0792ff50753c9599ead11682a7738e41866d8d08e273094792b0c79585190a05d6dcfc98317515c26406135a63f11cedc35be53e47a1b30acb2bfd9bc4b3df3a83bac90e7350440b645d4f5eec943545ac768a360b0d6d945d8ea6f7e24f966c57af1692d87e48cc44b33944ca062d45c9d402abde288b8105576352fb19eb54f4e7f416e3b77ef099b3209105e9384930d71014e3abde46b3238e52d1b66d4e266ac9af614093972aa5b2ef977eeb8a1bf3983df463e6a7d3b633c2c7cf4d3ba40f7c7d234626d3039dbd092c3c4549be8f2e0dce43393a1d3ec61885a8252c2a6f18fd12dfaabfdbce15f3157c4a57fcc2bf739c78802248d636621ff584348b0f2a14a38ddadeadf7e9b6a22203b519a0bf15e492c1583a555b30c1552fde0cbdccc9022d7b21bbcfa7cd71d8269c403cfaa461f1668175e2bcb33b19378b23e32b5cc882c308aad672143d464960c5c821d02110b6204fd3ca23b8ed3157888734f3b332fabe1de23305f84d6a3c106b586ae0158160a541d6217bdd0df77c8c0559a22acf85735ebf536a25b0cec508953aaac3e836117adf8bc388d9877e16818b1c4af638559e9cefacf032bf61fa5e295c57515ccc9949bfc25f2f34f670e49abd1efc1d8e98fd8748609e133ebb0fabda30a4d749c3c8100b840af089d60b7565f58659e872c6001454816f38b84939f2a90cc0f686b85c685d17b61b2fe40d7763a8e22e90dd2e5322517501363be58f96b01b080b203217112785741e6d788b79d00ba9fc96beb697d70a4766a145b292b33e17a8294034926cf34293afc96205e89d45e53a79e937588002d616d7e8bd206e826de78885576589460158f1418ec6f1f0d41e85a5010852b1e362edcaf2734dc91f804c8518b271a0b7e743606ad44d99d959126dc80ee83383986a373c71aa8564aec775f1254e3e4a4aa79b4775971b23199704fc16ecfc77d90f1c622128b5be7432c786195e989faf3e01aaedc1f4d9ed7d1afb4479f20e103c89fe74ce6d64af3e75e0181c444fbdf4b13781336bf9ca52fd8e584df66cdca96bb4b610ef955e1ab6498843197f9fd2deb2cd90459ec6b9ca6eb3f939eaa0841ca153b156409a54e83f8e1022a0a46fd6083d3a93a0694ce82e1459d7a4a37f622410583bcfc52ce7b459ae153df77a22acffc1ce2d1ce6a0fb068dc20a16d487441ac9daea060a25c5108f1ba86c40aecb7f94daa587c72059098c7399f775ed49fc014961bfad8f04ae7c6586ff69d2bfe6a0a5eab9596cd78cef423c5c2b5ed7b2739715b655c2f5f342fddb9794428f390a22e0374238dff7099f4c92bb0ab1b5fce09774dffef519a3a5be1f70912ea407e501287738daf72820853d85dd064e20d65bc8a7262d39b853fa976e6fdd3605d1135d3c470ef4477370d592a540936881b06123810253220866c4f0585bcc5256afc55ec335584d8aa06af9a471344a17664d6fe2257419dc0c7559e211c74599b506f0ec5cf0ae7a13d322c1425ff48914c3c357fdc41bb0312d56fcb1645fb9ceeb54f76e57c914bd3db758a56908d78f528b47263ad2010353fe92edbc076e72f261690c3851c843a031c5c5aa7ed8c0810b57c725868c42ff26c2a72c69e64d513d3a175f207e27b3824c38e7d00b93772ec136a1f81f30affc94a94c71b0a1bc30691455e32c3f5ca4d6942049decfce8bfd3710af0e15d1e3afabe2a83823e6caf282b72789849557116ff08867d4863ea9da14d1373d15fb9fdd7dc3677be3929444b38ad7266aa632d45e3736d9fe9100e14a1bbe1626492c60329917e46e289d0b01d883bc2ea96d3620b54f12fafb85ed5c49f48877fc5b53092381dd9e6858fc08f915351a1ce9e30057a10252af64971a03571b602d239febf593148e8e0759bd6209bb468f969c6eec7167313325de17e302becdd0c00f65566dd76c978b22ddc7af176c6288c64f82d280706b359933cc44dc2d05c40cca5cc05d7548df5facbc04a580fc4ba1b9d142f79cebf46294de0dc896d440333dba4e91a6a146f1249947f3cccd7433e08017e1a5329ae73887069761b933f737e245301d2459ecdbebbb5bc4b1983fda2a719d2674c7f21b2c5fe966cbbe25a4c1d5ddf58749620b9e4c45311d75be73b7f8f614217f0b9b4d3187f384046b0656d4d17ce8dfb67c5626bf5c550831928fcbbfb9221542d588a307d5c0e60a9cada9f9da791f7effc0fa8902f7c7ef40ba1680217910a7fe1e2559598aaf06b993653d4c41e205f785afaa1bce4484ef36c17f689889ed7357b6cd7711926c8ad073ae438f8cf1a6c2332113b79934179b671aab68ebda89934fb5419a31165f758941aa406f1bc279a9b77259dcb23b9c23bc48132537a6acaac770576eac38bcbdfa516e56ac0b7470c48d261a3c3cb142b0ef1bc8a9e164cc61871aed24e9aa19eb91c124556bbce9c53062fe28254d1989134fe90d28749a5424350f52729032ebf49f750da3667501f2afe3e419bbb4ebad677ee85467a8ebacb9caf85d7e94ae1efc07d4b49eb007d707d5b6926025089a90634060e4c76511f3f0f213fe0216bdbf16b7c9a7feb18d0b2ed94168ecaf486bebbb854fbe934bbe0b08faf1d48160b1754da3b3d4e5fc10a08a06fda3b8f995897e62325f45b124fba9de83b3cb14987961dff8b4fef2bcbc11a253b1a8a95f68ced1aa46348058e3120062a9f93aa64ed5ae8d12a66328747c67d67ca461bf6102bce255414628f50fc57c3be3b71ae163d429352a150b28549cd1d7ae45dd7bb6321be778d565179754f39c4e1c5d28588f880055b1a61ac4001ac10e058d3f4e9ba0358e97e6b89a31274869f9cd85fe9c7f27a7f6d37ada62bf94e7fd4737a552361a0b5343af14cba2f106ac9062460d35a8678a3da31113f327926a6e036a85bc942bae1c0e4a90f6e056fbd5e7d9413afddfac1449aafada09ea63d0bfa7b16bf20baa3fb4c5493b582e7246c4c74f475ea819605a753e6f264467e62e3b164b0d9fc12757a2a525746b5d6b3c9f27ff049aed7766c1aa427b755816fe2a87583172f754d1f52c426a2c97e8f371f32c733361d4c314133df2b35c670294a71bd6a361114b67e9fb39e04b70000747461557e9b49917a563f816f8c0cbae2590509403cacb4bef588273c688dfb469a3cf47578c67c62fe91fa495bbd9544abf6aca400c2a97cb05d811810feb490e3e30b173ded640df599eaf1d08b16dfa18e82e7d9d52f4ee637e3c0345055677ad0ca5b1be25ec27acfee2ef6f8244acfbe23044f20b1b39ee9ce222078a3a5cd94d268e67d339caffc76ed2bf1a5af449d517dde9d9694b835661196ec20a6e71d27ec859afe59acd7d97632406ebe9e5b4bd9c4e705ec50b2847278cbe859979639883180e880b80713a45f0cde79833aaa5c93cae54ca98fa5338fc286144daeb8b7b6a221d1685c8f012d629ceade4a985970351db80776144f774603e4b4019dd4c8e8315b5a112f829b98c017d5a2a796435510671c0e5891d860b64e348c44fad8c381791a0b09e55d7685b662e47b09ac3adfec9680ae9d8f0f348b1faf9cb1aca20fe15f8a0b97f63da9e3c0b02df5e0bc0e0951dbfa8dc9a00729d8a83469a4725c87d1e014ce2d71cce59a4f40dd4ac5ebc53a171c5d88a4b078318a1199d6b385b4d2355adaea5eb1cb7d9246616cea38e088ff328137ce576daa99acdfd8c8fdd0968685fb906dc272b9f2e1256d4f10a995d4a7e69f85237581f1365461a6151d493a5c597ee94fba574e5d3c0a38d34ac9fa50872216e87fa23e5425302bd2899f6a54fc5a8b9889cef4424ab7810d490610ce971c024003fe3c0eee505dce8f1e8e5541286ca2b8a8b96079e63e3562b2c14ef10cc804d0d7242099123ee6149ad653d497ffa9005b062b1bfed71ef757a0d5c0c175894effc4f135e29bf559bda50f772cbf471fa4b89797c4ebaa66d85186521a0e768e8e2e37239d321bbfbc3767e12f4383036f75075d916845dc0203b3125c84960fc7cf136ef0fd3efc20d3a0aa0677d67e60e0bf6761a6ba12148fa3594d5f7459048ea9184cbfd1232d4d40cc8ad7ac302a6e0d60a90825519ed94df3e5e9859d91e31b43649f58ad28beb8abe64b6d3bfb95af6f60353c8f5a8b6ca1550d5606cc7f48e2d2aa96b0add33e9f5359dd99174c0797f6d101d016bdfa2cd6615a7b62df7ef12b3141ffd0720723f59b7106044ea69a09ed207d7d7c452bd35c85585939ae3690339ddaf53a6c89246791b22cee0e7ca1c1e3a8629c22a47a898a1a7e08fa0c04896128894d3bcdf72f1bb1531966dec8421532084ba47f85b004971c81c934effb6db9209afd0ac08742a466d782856f9cc9eafc1a99b89a419b317b9c5cc94ac8ba5108b4fc946cee8976be2ca7a0b7aab50f5f9ec4ed20333622040f60e502893d36a5b412c831a4974e500be29ad50a5dfc32b3710b33c476a7a8cb363019a06b3baa80e1244ba727065e6f3c5e63c36e0021b9a1b825dfb820f2b901b2df0deeedc7e1acb244328424bafaefed340dffa21a82a85c2c160974e4ee7c28a2c8a4ae40b7dcec3400b021221a5058cdf2c996d77f6a5bf189ed4cef469583d58cb30c46f0d528aa195d5fc1147d5ac1be689da330aaf720843ad8c16190d498b8bef763c7b00d81a57361fe24d090b7d48c455686fa34f38b5374c76e09b084a2f3df15cdacf122cf247df6aa304178f3fd41148fb60d5680289059ce878a7fdb306ff5abefb34d4a2cba9821907ab2a9cc65825abfb09dce4d8e03a173855baaa734c13a0502b8fd3ce2a12e3d531657bba017b08eb3290c7088cccdffbdc9ca6ea3e80691710c3789100280b02ad30a41d1d7294cf495e73ac28d6573b5f2780b501102f93ba408dcfae296910593f6a0020731694ab8a4b89aa37a0679c74dc820750fb00cb4753c63eb82a3fdc5319e89207666e1c190e960119bbc6dda0d0e69458b82a6e526147e0b3cd43f1075a98a2bc4361a7985cca490ab3dd64adc64c2fcb0777f1ba6d9d76ba13f71d41ec217d0d1f780b7ac5db5c19a4ee9cd76b1936168e136e160aef226d882c78be888c7b3f7bffacb44b3dc4e25e8ce9f527e89137fdb66414ca639dbe6535eae895ed44fdfd81e6255441b63dc0807f8fc02edb74be0cfcd7027f41757ea0fd2e05ebc9741fd6fd07566a11e6ac131d6e794fbabaf22b487c110df93165f602c8295608dcc3fe97cf811e5c3c03dfd7c6403b93232614cb1170d7606ab0232939190832450cb3e440f2bb2465b188145c30f3a44a45d549301855e118cfc4559deae123225ace6a2bb61dce1bba7c9a6b74610976854c766c189b2f4351375150a782dfe0ac4dcfde5d103fd1a3b59960c47fcf9318587953a1180dcb8665b13bef24b6d4629259ec83488031aeb96a2a2c27c44e991b5974294bdda051a2b66b3385985bbe7bc6ba247626cf2dbbdb1344a300deadeee871bafceddda11f8ac1bea53fc8d06049fde512e72d10105c1bb58a1bd32cdcb2a346402cdb268c31d0110bad38499bba5d0f875ebbee8d4f04fb72321cadb713d28dec00414a4c8c4f7d163a55cf34e90d128d940a83cde09c53ef85e5df7b3d7ac6110229bc6621852f8e1a3708ab66cf8c046fe015f17ddc41bde1ef442f9334734d3a3af38d8089784aa759685238a1eae404273ab938f39b8a82da06d639e62f02b97a2158350d6315240b4e4df1c405e3a5d0b206936f21b15a299506f4fbabcddeb811686cc9a8120a3e0bc286f26d9cd39bc8fccb563cef597866240ca6a6e85b519082f288869dc7039df45e327a5629427776933eed3c1f3214899197df7036a4136a7d956b9d0e2795acda9f8ac56b8b13434ca79d22311cc91af8e4856da8b55fed56bee972279655bd4122f6ebc6cea1b4dfdf8ace7da5d0561549051b3ee2787607f195ce7b811d15d12b17e3edc5b48dbdc5fc4653ff895d699d19cb06b37efbe0604bac05bc7c08752648f6b23d82308d827f4500eecdd2faad159566286127c6e56212af6d4b80e4abe9fc19fc9a40f09995517e99b7e22ba5431cac4879ed1116dbc0ede959ff9abea0f3a722c1ac141a25bb04e89ed10e2c63bb53e" diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/slhdsa/slhdsa.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/slhdsa/slhdsa.go new file mode 100644 index 0000000000..5aebf9c4ab --- /dev/null +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/slhdsa/slhdsa.go @@ -0,0 +1,66 @@ +// Package slhdsa implements SLH-DSA-SHAKE for OpenPGP, +// according to https://www.rfc-editor.org/rfc/rfc9980.html#name-slh-dsa-2. +package slhdsa + +import ( + goerrors "errors" + "fmt" + "io" + + "github.com/ProtonMail/go-crypto/openpgp/errors" + "github.com/cloudflare/circl/sign" +) + +type PublicKey struct { + AlgId uint8 + Slhdsa sign.Scheme + PublicSlhdsa sign.PublicKey +} + +type PrivateKey struct { + PublicKey + SecretSlhdsa sign.PrivateKey +} + +// GenerateKey generates a SLH-DSA key. +func GenerateKey(rand io.Reader, algId uint8, scheme sign.Scheme) (priv *PrivateKey, err error) { + priv = new(PrivateKey) + + priv.PublicKey.AlgId = algId + priv.PublicKey.Slhdsa = scheme + + keySeed := make([]byte, scheme.SeedSize()) + if _, err = rand.Read(keySeed); err != nil { + return nil, err + } + priv.PublicKey.PublicSlhdsa, priv.SecretSlhdsa = priv.PublicKey.Slhdsa.DeriveKey(keySeed) + + return priv, nil +} + +// Sign generates a SLH-DSA signature. +func Sign(priv *PrivateKey, message []byte) (signature []byte, err error) { + signature, err = priv.SecretSlhdsa.Sign(nil, message, nil) + if err != nil { + return nil, fmt.Errorf("slhdsa: unable to sign with SLH-DSA: %s", err) + } + if signature == nil { + return nil, goerrors.New("slhdsa: unable to sign with SLH-DSA") + } + + return signature, nil +} + +// Verify verifies the SLH-DSA signature. +func Verify(pub *PublicKey, message, dSig []byte) bool { + return pub.Slhdsa.Verify(pub.PublicSlhdsa, message, dSig, nil) +} + +// Validate checks that the public key corresponds to the private key +func Validate(priv *PrivateKey) (err error) { + if !priv.PublicSlhdsa.Equal(priv.SecretSlhdsa.Public()) { + return errors.KeyInvalidError("slhdsa: invalid public key") + } + + return nil +} diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/write.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/write.go index b0f6ef7b09..6137ba3e33 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/write.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/write.go @@ -253,34 +253,12 @@ func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entit } var hash crypto.Hash - for _, hashId := range candidateHashes { - if h, ok := algorithm.HashIdToHash(hashId); ok && h.Available() { - hash = h - break - } - } - - // If the hash specified by config is a candidate, we'll use that. - if configuredHash := config.Hash(); configuredHash.Available() { - for _, hashId := range candidateHashes { - if h, ok := algorithm.HashIdToHash(hashId); ok && h == configuredHash { - hash = h - break - } - } - } - - if hash == 0 { - hashId := candidateHashes[0] - name, ok := algorithm.HashIdToString(hashId) - if !ok { - name = "#" + strconv.Itoa(int(hashId)) - } - return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)") - } - var salt []byte if signer != nil { + if hash, err = selectHash(candidateHashes, config.Hash(), signer); err != nil { + return nil, err + } + var opsVersion = 3 if signer.Version == 6 { opsVersion = signer.Version @@ -391,6 +369,7 @@ func encrypt(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *En // AEAD is used only if config enables it and every key supports it aeadSupported := config.AEAD() != nil + allPQ := len(to) > 0 for i := range to { var ok bool encryptKeys[i], ok = to[i].EncryptionKey(config.Now()) @@ -398,6 +377,10 @@ func encrypt(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *En return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no valid encryption keys") } + if !encryptKeys[i].PublicKey.IsPQ() { + allPQ = false + } + primarySelfSignature, _ := to[i].PrimarySelfSignature() if primarySelfSignature == nil { return nil, errors.InvalidArgumentError("entity without a self-signature") @@ -424,8 +407,12 @@ func encrypt(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *En candidateHashes = []uint8{hashToHashId(crypto.SHA256)} } if len(candidateCipherSuites) == 0 { - // https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-9.6 - candidateCipherSuites = [][2]uint8{{uint8(packet.CipherAES128), uint8(packet.AEADModeOCB)}} + if allPQ { + candidateCipherSuites = [][2]uint8{{uint8(packet.CipherAES256), uint8(packet.AEADModeOCB)}} + } else { + // https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-9.6 + candidateCipherSuites = [][2]uint8{{uint8(packet.CipherAES128), uint8(packet.AEADModeOCB)}} + } } cipher := packet.CipherFunction(candidateCiphers[0]) @@ -558,15 +545,37 @@ func (s signatureWriter) Close() error { return s.encryptedData.Close() } +func selectHashForSigningKey(config *packet.Config, signer *packet.PublicKey) crypto.Hash { + acceptableHashes := acceptableHashesToWrite(signer) + hash, ok := algorithm.HashToHashId(config.Hash()) + if !ok { + return config.Hash() + } + for _, acceptableHashes := range acceptableHashes { + if acceptableHashes == hash { + return config.Hash() + } + } + if len(acceptableHashes) > 0 { + defaultAcceptedHash, ok := algorithm.HashIdToHash(acceptableHashes[0]) + if ok { + return defaultAcceptedHash + } + } + return config.Hash() +} + func createSignaturePacket(signer *packet.PublicKey, sigType packet.SignatureType, config *packet.Config) *packet.Signature { sigLifetimeSecs := config.SigLifetime() + hash := selectHashForSigningKey(config, signer) return &packet.Signature{ Version: signer.Version, SigType: sigType, PubKeyAlgo: signer.PubKeyAlgo, - Hash: config.Hash(), + Hash: hash, CreationTime: config.Now(), IssuerKeyId: &signer.KeyId, + IssuerKeyVersion: uint8(signer.Version), IssuerFingerprint: signer.Fingerprint, Notations: config.Notations(), SigLifetimeSecs: &sigLifetimeSecs, @@ -618,3 +627,74 @@ func handleCompression(compressed io.WriteCloser, candidateCompression []uint8, } return data, nil } + +// selectHash selects the preferred hash given the candidateHashes and the configuredHash +func selectHash(candidateHashes []byte, configuredHash crypto.Hash, signer *packet.PrivateKey) (hash crypto.Hash, err error) { + acceptableHashes := acceptableHashesToWrite(&signer.PublicKey) + candidateHashes = intersectPreferences(acceptableHashes, candidateHashes) + + for _, hashId := range candidateHashes { + if h, ok := algorithm.HashIdToHash(hashId); ok && h.Available() { + hash = h + break + } + } + + // If the hash specified by config is a candidate, we'll use that. + if configuredHash.Available() { + for _, hashId := range candidateHashes { + if h, ok := algorithm.HashIdToHash(hashId); ok && h == configuredHash { + hash = h + break + } + } + } + + if hash == 0 { + if len(acceptableHashes) > 0 { + if h, ok := algorithm.HashIdToHash(acceptableHashes[0]); ok { + hash = h + } else { + return 0, errors.UnsupportedError("no candidate hash functions are compiled in.") + } + } else { + return 0, errors.UnsupportedError("no candidate hash functions are compiled in.") + } + } + return +} + +func acceptableHashesToWrite(singingKey *packet.PublicKey) []uint8 { + switch singingKey.PubKeyAlgo { + case packet.PubKeyAlgoEd448, packet.PubKeyAlgoMldsa87Ed448, packet.PubKeyAlgoSlhdsaShake256s: + return []uint8{ + hashToHashId(crypto.SHA512), + hashToHashId(crypto.SHA3_512), + } + case packet.PubKeyAlgoECDSA, packet.PubKeyAlgoEdDSA: + if curve, err := singingKey.Curve(); err == nil { + if curve == packet.Curve448 || + curve == packet.CurveNistP521 || + curve == packet.CurveBrainpoolP512 { + return []uint8{ + hashToHashId(crypto.SHA512), + hashToHashId(crypto.SHA3_512), + } + } else if curve == packet.CurveBrainpoolP384 || + curve == packet.CurveNistP384 { + return []uint8{ + hashToHashId(crypto.SHA384), + hashToHashId(crypto.SHA512), + hashToHashId(crypto.SHA3_512), + } + } + } + } + return []uint8{ + hashToHashId(crypto.SHA256), + hashToHashId(crypto.SHA384), + hashToHashId(crypto.SHA512), + hashToHashId(crypto.SHA3_256), + hashToHashId(crypto.SHA3_512), + } +} diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/x25519/x25519.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/x25519/x25519.go index 38afcc74fa..6403cddf19 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/x25519/x25519.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/x25519/x25519.go @@ -80,7 +80,7 @@ func generateKey(rand io.Reader, privateKey *x25519lib.Key, publicKey *x25519lib // Encrypt encrypts a sessionKey with x25519 according to // the OpenPGP crypto refresh specification section 5.1.6. The function assumes that the // sessionKey has the correct format and padding according to the specification. -func Encrypt(rand io.Reader, publicKey *PublicKey, sessionKey []byte) (ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, err error) { +func Encrypt(rand io.Reader, publicKey *PublicKey, sessionKey []byte) (ephemeralPublicKey, encryptedSessionKey []byte, err error) { var ephemeralPrivate, ephemeralPublic, staticPublic, shared x25519lib.Key // Check that the input static public key has 32 bytes if len(publicKey.Point) != KeySize { @@ -99,11 +99,9 @@ func Encrypt(rand io.Reader, publicKey *PublicKey, sessionKey []byte) (ephemeral err = errors.KeyInvalidError("x25519: the public key is a low order point") return } + ephemeralPublicKey = ephemeralPublic[:] // Derive the encryption key from the shared secret - encryptionKey := applyHKDF(ephemeralPublic[:], publicKey.Point[:], shared[:]) - ephemeralPublicKey = &PublicKey{ - Point: ephemeralPublic[:], - } + encryptionKey := applyHKDF(ephemeralPublicKey, publicKey.Point[:], shared[:]) // Encrypt the sessionKey with aes key wrapping encryptedSessionKey, err = keywrap.Wrap(encryptionKey, sessionKey) return @@ -111,14 +109,14 @@ func Encrypt(rand io.Reader, publicKey *PublicKey, sessionKey []byte) (ephemeral // Decrypt decrypts a session key stored in ciphertext with the provided x25519 // private key and ephemeral public key. -func Decrypt(privateKey *PrivateKey, ephemeralPublicKey *PublicKey, ciphertext []byte) (encodedSessionKey []byte, err error) { +func Decrypt(privateKey *PrivateKey, ephemeralPublicKey, ciphertext []byte) (encodedSessionKey []byte, err error) { var ephemeralPublic, staticPrivate, shared x25519lib.Key // Check that the input ephemeral public key has 32 bytes - if len(ephemeralPublicKey.Point) != KeySize { + if len(ephemeralPublicKey) != KeySize { err = errors.KeyInvalidError("x25519: the public key has the wrong size") return } - copy(ephemeralPublic[:], ephemeralPublicKey.Point) + copy(ephemeralPublic[:], ephemeralPublicKey) subtle.ConstantTimeCopy(1, staticPrivate[:], privateKey.Secret) // Compute shared key ok := x25519lib.Shared(&shared, &staticPrivate, &ephemeralPublic) @@ -127,7 +125,7 @@ func Decrypt(privateKey *PrivateKey, ephemeralPublicKey *PublicKey, ciphertext [ return } // Derive the encryption key from the shared secret - encryptionKey := applyHKDF(ephemeralPublicKey.Point[:], privateKey.PublicKey.Point[:], shared[:]) + encryptionKey := applyHKDF(ephemeralPublicKey, privateKey.PublicKey.Point[:], shared[:]) // Decrypt the session key with aes key wrapping encodedSessionKey, err = keywrap.Unwrap(encryptionKey, ciphertext) return @@ -168,12 +166,12 @@ func EncodedFieldsLength(encryptedSessionKey []byte, v6 bool) int { // EncodeField encodes x25519 session key encryption fields as // ephemeral x25519 public key | follow byte length | cipherFunction (v3 only) | encryptedSessionKey // and writes it to writer. -func EncodeFields(writer io.Writer, ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, cipherFunction byte, v6 bool) (err error) { +func EncodeFields(writer io.Writer, ephemeralPublicKey, encryptedSessionKey []byte, cipherFunction byte, v6 bool) (err error) { lenAlgorithm := 0 if !v6 { lenAlgorithm = 1 } - if _, err = writer.Write(ephemeralPublicKey.Point); err != nil { + if _, err = writer.Write(ephemeralPublicKey); err != nil { return err } if _, err = writer.Write([]byte{byte(len(encryptedSessionKey) + lenAlgorithm)}); err != nil { @@ -190,13 +188,11 @@ func EncodeFields(writer io.Writer, ephemeralPublicKey *PublicKey, encryptedSess // DecodeField decodes a x25519 session key encryption as // ephemeral x25519 public key | follow byte length | cipherFunction (v3 only) | encryptedSessionKey. -func DecodeFields(reader io.Reader, v6 bool) (ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, cipherFunction byte, err error) { +func DecodeFields(reader io.Reader, v6 bool) (ephemeralPublicKey, encryptedSessionKey []byte, cipherFunction byte, err error) { var buf [1]byte - ephemeralPublicKey = &PublicKey{ - Point: make([]byte, KeySize), - } + ephemeralPublicKey = make([]byte, KeySize) // 32 octets representing an ephemeral x25519 public key. - if _, err = io.ReadFull(reader, ephemeralPublicKey.Point); err != nil { + if _, err = io.ReadFull(reader, ephemeralPublicKey); err != nil { return nil, nil, 0, err } // A one-octet size of the following fields. diff --git a/vendor/github.com/ProtonMail/go-crypto/openpgp/x448/x448.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/x448/x448.go index 65a082dabd..b66263dd30 100644 --- a/vendor/github.com/ProtonMail/go-crypto/openpgp/x448/x448.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/x448/x448.go @@ -81,7 +81,7 @@ func generateKey(rand io.Reader, privateKey *x448lib.Key, publicKey *x448lib.Key // Encrypt encrypts a sessionKey with x448 according to // the OpenPGP crypto refresh specification section 5.1.7. The function assumes that the // sessionKey has the correct format and padding according to the specification. -func Encrypt(rand io.Reader, publicKey *PublicKey, sessionKey []byte) (ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, err error) { +func Encrypt(rand io.Reader, publicKey *PublicKey, sessionKey []byte) (ephemeralPublicKey, encryptedSessionKey []byte, err error) { var ephemeralPrivate, ephemeralPublic, staticPublic, shared x448lib.Key // Check that the input static public key has 56 bytes. if len(publicKey.Point) != KeySize { @@ -99,11 +99,9 @@ func Encrypt(rand io.Reader, publicKey *PublicKey, sessionKey []byte) (ephemeral err = errors.KeyInvalidError("x448: the public key is a low order point") return nil, nil, err } + ephemeralPublicKey = ephemeralPublic[:] // Derive the encryption key from the shared secret. - encryptionKey := applyHKDF(ephemeralPublic[:], publicKey.Point[:], shared[:]) - ephemeralPublicKey = &PublicKey{ - Point: ephemeralPublic[:], - } + encryptionKey := applyHKDF(ephemeralPublicKey, publicKey.Point[:], shared[:]) // Encrypt the sessionKey with aes key wrapping. encryptedSessionKey, err = keywrap.Wrap(encryptionKey, sessionKey) if err != nil { @@ -114,14 +112,14 @@ func Encrypt(rand io.Reader, publicKey *PublicKey, sessionKey []byte) (ephemeral // Decrypt decrypts a session key stored in ciphertext with the provided x448 // private key and ephemeral public key. -func Decrypt(privateKey *PrivateKey, ephemeralPublicKey *PublicKey, ciphertext []byte) (encodedSessionKey []byte, err error) { +func Decrypt(privateKey *PrivateKey, ephemeralPublicKey, ciphertext []byte) (encodedSessionKey []byte, err error) { var ephemeralPublic, staticPrivate, shared x448lib.Key // Check that the input ephemeral public key has 56 bytes. - if len(ephemeralPublicKey.Point) != KeySize { + if len(ephemeralPublicKey) != KeySize { err = errors.KeyInvalidError("x448: the public key has the wrong size") return nil, err } - copy(ephemeralPublic[:], ephemeralPublicKey.Point) + copy(ephemeralPublic[:], ephemeralPublicKey) subtle.ConstantTimeCopy(1, staticPrivate[:], privateKey.Secret) // Compute shared key. ok := x448lib.Shared(&shared, &staticPrivate, &ephemeralPublic) @@ -130,7 +128,7 @@ func Decrypt(privateKey *PrivateKey, ephemeralPublicKey *PublicKey, ciphertext [ return nil, err } // Derive the encryption key from the shared secret. - encryptionKey := applyHKDF(ephemeralPublicKey.Point[:], privateKey.PublicKey.Point[:], shared[:]) + encryptionKey := applyHKDF(ephemeralPublicKey, privateKey.PublicKey.Point[:], shared[:]) // Decrypt the session key with aes key wrapping. encodedSessionKey, err = keywrap.Unwrap(encryptionKey, ciphertext) if err != nil { @@ -174,12 +172,12 @@ func EncodedFieldsLength(encryptedSessionKey []byte, v6 bool) int { // EncodeField encodes x448 session key encryption fields as // ephemeral x448 public key | follow byte length | cipherFunction (v3 only) | encryptedSessionKey // and writes it to writer. -func EncodeFields(writer io.Writer, ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, cipherFunction byte, v6 bool) (err error) { +func EncodeFields(writer io.Writer, ephemeralPublicKey, encryptedSessionKey []byte, cipherFunction byte, v6 bool) (err error) { lenAlgorithm := 0 if !v6 { lenAlgorithm = 1 } - if _, err = writer.Write(ephemeralPublicKey.Point); err != nil { + if _, err = writer.Write(ephemeralPublicKey); err != nil { return err } if _, err = writer.Write([]byte{byte(len(encryptedSessionKey) + lenAlgorithm)}); err != nil { @@ -198,13 +196,11 @@ func EncodeFields(writer io.Writer, ephemeralPublicKey *PublicKey, encryptedSess // DecodeField decodes a x448 session key encryption as // ephemeral x448 public key | follow byte length | cipherFunction (v3 only) | encryptedSessionKey. -func DecodeFields(reader io.Reader, v6 bool) (ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, cipherFunction byte, err error) { +func DecodeFields(reader io.Reader, v6 bool) (ephemeralPublicKey, encryptedSessionKey []byte, cipherFunction byte, err error) { var buf [1]byte - ephemeralPublicKey = &PublicKey{ - Point: make([]byte, KeySize), - } + ephemeralPublicKey = make([]byte, KeySize) // 56 octets representing an ephemeral x448 public key. - if _, err = io.ReadFull(reader, ephemeralPublicKey.Point); err != nil { + if _, err = io.ReadFull(reader, ephemeralPublicKey); err != nil { return nil, nil, 0, err } // A one-octet size of the following fields. diff --git a/vendor/github.com/bitly/go-simplejson/.travis.yml b/vendor/github.com/bitly/go-simplejson/.travis.yml deleted file mode 100644 index 55accb9bfd..0000000000 --- a/vendor/github.com/bitly/go-simplejson/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: go -go: - - 1.0.3 - - 1.1.2 - - 1.2 - - tip -install: - - go get github.com/bmizerany/assert -notifications: - email: false diff --git a/vendor/github.com/bitly/go-simplejson/README.md b/vendor/github.com/bitly/go-simplejson/README.md index 8c6c101a82..f0d2419b36 100644 --- a/vendor/github.com/bitly/go-simplejson/README.md +++ b/vendor/github.com/bitly/go-simplejson/README.md @@ -2,7 +2,10 @@ a Go package to interact with arbitrary JSON -[![Build Status](https://secure.travis-ci.org/bitly/go-simplejson.png)](http://travis-ci.org/bitly/go-simplejson) +[![Build Status](https://github.com/bitly/go-simplejson/actions/workflows/ci.yaml/badge.svg)](https://github.com/bitly/go-simplejson/actions) +[![GoDoc](https://pkg.go.dev/badge/github.com/bitly/go-simplejson)](https://pkg.go.dev/github.com/bitly/go-simplejson) +[![GitHub release](https://img.shields.io/github/release/bitly/go-simplejson.svg)](https://github.com/bitly/go-simplejson/releases/latest) + ### Importing @@ -10,4 +13,4 @@ a Go package to interact with arbitrary JSON ### Documentation -Visit the docs on [gopkgdoc](http://godoc.org/github.com/bitly/go-simplejson) +Visit the docs on [Go package discovery & docs](https://pkg.go.dev/github.com/bitly/go-simplejson) diff --git a/vendor/github.com/bitly/go-simplejson/simplejson.go b/vendor/github.com/bitly/go-simplejson/simplejson.go index 27ce986167..486fe49c24 100644 --- a/vendor/github.com/bitly/go-simplejson/simplejson.go +++ b/vendor/github.com/bitly/go-simplejson/simplejson.go @@ -8,7 +8,7 @@ import ( // returns the current implementation version func Version() string { - return "0.5.0" + return "0.5.1" } type Json struct { @@ -115,7 +115,8 @@ func (j *Json) Del(key string) { // for `key` in its `map` representation // // useful for chaining operations (to traverse a nested JSON): -// js.Get("top_level").Get("dict").Get("value").Int() +// +// js.Get("top_level").Get("dict").Get("value").Int() func (j *Json) Get(key string) *Json { m, err := j.Map() if err == nil { @@ -129,7 +130,7 @@ func (j *Json) Get(key string) *Json { // GetPath searches for the item as specified by the branch // without the need to deep dive using Get()'s. // -// js.GetPath("top_level", "dict") +// js.GetPath("top_level", "dict") func (j *Json) GetPath(branch ...string) *Json { jin := j for _, p := range branch { @@ -143,7 +144,8 @@ func (j *Json) GetPath(branch ...string) *Json { // // this is the analog to Get when accessing elements of // a json array instead of a json object: -// js.Get("top_level").Get("array").GetIndex(1).Get("key").Int() +// +// js.Get("top_level").Get("array").GetIndex(1).Get("key").Int() func (j *Json) GetIndex(index int) *Json { a, err := j.Array() if err == nil { @@ -158,9 +160,10 @@ func (j *Json) GetIndex(index int) *Json { // a `bool` identifying success or failure // // useful for chained operations when success is important: -// if data, ok := js.Get("top_level").CheckGet("inner"); ok { -// log.Println(data) -// } +// +// if data, ok := js.Get("top_level").CheckGet("inner"); ok { +// log.Println(data) +// } func (j *Json) CheckGet(key string) (*Json, bool) { m, err := j.Map() if err == nil { @@ -225,7 +228,7 @@ func (j *Json) StringArray() ([]string, error) { } s, ok := a.(string) if !ok { - return nil, err + return nil, errors.New("type assertion to []string failed") } retArr = append(retArr, s) } @@ -235,9 +238,10 @@ func (j *Json) StringArray() ([]string, error) { // MustArray guarantees the return of a `[]interface{}` (with optional default) // // useful when you want to interate over array values in a succinct manner: -// for i, v := range js.Get("results").MustArray() { -// fmt.Println(i, v) -// } +// +// for i, v := range js.Get("results").MustArray() { +// fmt.Println(i, v) +// } func (j *Json) MustArray(args ...[]interface{}) []interface{} { var def []interface{} @@ -260,9 +264,10 @@ func (j *Json) MustArray(args ...[]interface{}) []interface{} { // MustMap guarantees the return of a `map[string]interface{}` (with optional default) // // useful when you want to interate over map values in a succinct manner: -// for k, v := range js.Get("dictionary").MustMap() { -// fmt.Println(k, v) -// } +// +// for k, v := range js.Get("dictionary").MustMap() { +// fmt.Println(k, v) +// } func (j *Json) MustMap(args ...map[string]interface{}) map[string]interface{} { var def map[string]interface{} @@ -285,7 +290,8 @@ func (j *Json) MustMap(args ...map[string]interface{}) map[string]interface{} { // MustString guarantees the return of a `string` (with optional default) // // useful when you explicitly want a `string` in a single value return context: -// myFunc(js.Get("param1").MustString(), js.Get("optional_param").MustString("my_default")) +// +// myFunc(js.Get("param1").MustString(), js.Get("optional_param").MustString("my_default")) func (j *Json) MustString(args ...string) string { var def string @@ -308,9 +314,10 @@ func (j *Json) MustString(args ...string) string { // MustStringArray guarantees the return of a `[]string` (with optional default) // // useful when you want to interate over array values in a succinct manner: -// for i, s := range js.Get("results").MustStringArray() { -// fmt.Println(i, s) -// } +// +// for i, s := range js.Get("results").MustStringArray() { +// fmt.Println(i, s) +// } func (j *Json) MustStringArray(args ...[]string) []string { var def []string @@ -333,7 +340,8 @@ func (j *Json) MustStringArray(args ...[]string) []string { // MustInt guarantees the return of an `int` (with optional default) // // useful when you explicitly want an `int` in a single value return context: -// myFunc(js.Get("param1").MustInt(), js.Get("optional_param").MustInt(5150)) +// +// myFunc(js.Get("param1").MustInt(), js.Get("optional_param").MustInt(5150)) func (j *Json) MustInt(args ...int) int { var def int @@ -356,7 +364,8 @@ func (j *Json) MustInt(args ...int) int { // MustFloat64 guarantees the return of a `float64` (with optional default) // // useful when you explicitly want a `float64` in a single value return context: -// myFunc(js.Get("param1").MustFloat64(), js.Get("optional_param").MustFloat64(5.150)) +// +// myFunc(js.Get("param1").MustFloat64(), js.Get("optional_param").MustFloat64(5.150)) func (j *Json) MustFloat64(args ...float64) float64 { var def float64 @@ -379,7 +388,8 @@ func (j *Json) MustFloat64(args ...float64) float64 { // MustBool guarantees the return of a `bool` (with optional default) // // useful when you explicitly want a `bool` in a single value return context: -// myFunc(js.Get("param1").MustBool(), js.Get("optional_param").MustBool(true)) +// +// myFunc(js.Get("param1").MustBool(), js.Get("optional_param").MustBool(true)) func (j *Json) MustBool(args ...bool) bool { var def bool @@ -402,7 +412,8 @@ func (j *Json) MustBool(args ...bool) bool { // MustInt64 guarantees the return of an `int64` (with optional default) // // useful when you explicitly want an `int64` in a single value return context: -// myFunc(js.Get("param1").MustInt64(), js.Get("optional_param").MustInt64(5150)) +// +// myFunc(js.Get("param1").MustInt64(), js.Get("optional_param").MustInt64(5150)) func (j *Json) MustInt64(args ...int64) int64 { var def int64 @@ -425,7 +436,8 @@ func (j *Json) MustInt64(args ...int64) int64 { // MustUInt64 guarantees the return of an `uint64` (with optional default) // // useful when you explicitly want an `uint64` in a single value return context: -// myFunc(js.Get("param1").MustUint64(), js.Get("optional_param").MustUint64(5150)) +// +// myFunc(js.Get("param1").MustUint64(), js.Get("optional_param").MustUint64(5150)) func (j *Json) MustUint64(args ...uint64) uint64 { var def uint64 diff --git a/vendor/github.com/bitly/go-simplejson/simplejson_go10.go b/vendor/github.com/bitly/go-simplejson/simplejson_go10.go deleted file mode 100644 index c9151e9be8..0000000000 --- a/vendor/github.com/bitly/go-simplejson/simplejson_go10.go +++ /dev/null @@ -1,75 +0,0 @@ -// +build !go1.1 - -package simplejson - -import ( - "encoding/json" - "errors" - "io" - "reflect" -) - -// NewFromReader returns a *Json by decoding from an io.Reader -func NewFromReader(r io.Reader) (*Json, error) { - j := new(Json) - dec := json.NewDecoder(r) - err := dec.Decode(&j.data) - return j, err -} - -// Implements the json.Unmarshaler interface. -func (j *Json) UnmarshalJSON(p []byte) error { - return json.Unmarshal(p, &j.data) -} - -// Float64 coerces into a float64 -func (j *Json) Float64() (float64, error) { - switch j.data.(type) { - case float32, float64: - return reflect.ValueOf(j.data).Float(), nil - case int, int8, int16, int32, int64: - return float64(reflect.ValueOf(j.data).Int()), nil - case uint, uint8, uint16, uint32, uint64: - return float64(reflect.ValueOf(j.data).Uint()), nil - } - return 0, errors.New("invalid value type") -} - -// Int coerces into an int -func (j *Json) Int() (int, error) { - switch j.data.(type) { - case float32, float64: - return int(reflect.ValueOf(j.data).Float()), nil - case int, int8, int16, int32, int64: - return int(reflect.ValueOf(j.data).Int()), nil - case uint, uint8, uint16, uint32, uint64: - return int(reflect.ValueOf(j.data).Uint()), nil - } - return 0, errors.New("invalid value type") -} - -// Int64 coerces into an int64 -func (j *Json) Int64() (int64, error) { - switch j.data.(type) { - case float32, float64: - return int64(reflect.ValueOf(j.data).Float()), nil - case int, int8, int16, int32, int64: - return reflect.ValueOf(j.data).Int(), nil - case uint, uint8, uint16, uint32, uint64: - return int64(reflect.ValueOf(j.data).Uint()), nil - } - return 0, errors.New("invalid value type") -} - -// Uint64 coerces into an uint64 -func (j *Json) Uint64() (uint64, error) { - switch j.data.(type) { - case float32, float64: - return uint64(reflect.ValueOf(j.data).Float()), nil - case int, int8, int16, int32, int64: - return uint64(reflect.ValueOf(j.data).Int()), nil - case uint, uint8, uint16, uint32, uint64: - return reflect.ValueOf(j.data).Uint(), nil - } - return 0, errors.New("invalid value type") -} diff --git a/vendor/github.com/bitly/go-simplejson/simplejson_go11.go b/vendor/github.com/bitly/go-simplejson/simplejson_reader.go similarity index 99% rename from vendor/github.com/bitly/go-simplejson/simplejson_go11.go rename to vendor/github.com/bitly/go-simplejson/simplejson_reader.go index 1c479532cf..a109013ffe 100644 --- a/vendor/github.com/bitly/go-simplejson/simplejson_go11.go +++ b/vendor/github.com/bitly/go-simplejson/simplejson_reader.go @@ -1,5 +1,3 @@ -// +build go1.1 - package simplejson import ( diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/curve.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/curve.go index 1f165141a9..c8648bddb4 100644 --- a/vendor/github.com/cloudflare/circl/ecc/goldilocks/curve.go +++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/curve.go @@ -61,6 +61,9 @@ func (Curve) Double(P *Point) *Point { R := *P; R.Double(); return &R } func (Curve) Add(P, Q *Point) *Point { R := *P; R.Add(Q); return &R } // ScalarMult returns kP. This function runs in constant time. +// +// The result equals [k]P only when P is in the prime-order subgroup; any +// torsion component of P is dropped. func (e Curve) ScalarMult(k *Scalar, P *Point) *Point { k4 := &Scalar{} k4.divBy4(k) @@ -75,6 +78,9 @@ func (e Curve) ScalarBaseMult(k *Scalar) *Point { } // CombinedMult returns mG+nP, where G is the generator point. This function is non-constant time. +// +// Like ScalarMult, the result equals [m]G+[n]P only when P is in the +// prime-order subgroup; any torsion component of P is dropped. func (e Curve) CombinedMult(m, n *Scalar, P *Point) *Point { m4 := &Scalar{} n4 := &Scalar{} diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/point.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/point.go index 11f73de054..8b09ab47a6 100644 --- a/vendor/github.com/cloudflare/circl/ecc/goldilocks/point.go +++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/point.go @@ -46,6 +46,9 @@ func FromBytes(in []byte) (*Point, error) { } err := errors.New("invalid decoding") P := &Point{} + if in[fp.Size]&0x7F != 0 { + return nil, err + } signX := in[fp.Size] >> 7 copy(P.y[:], in[:fp.Size]) p := fp.P() @@ -135,7 +138,14 @@ func (P *Point) MarshalBinary() (data []byte, err error) { } // UnmarshalBinary must be able to decode the form generated by MarshalBinary. -func (P *Point) UnmarshalBinary(data []byte) error { Q, err := FromBytes(data); *P = *Q; return err } +func (P *Point) UnmarshalBinary(data []byte) error { + Q, err := FromBytes(data) + if err != nil { + return err + } + *P = *Q + return nil +} // Double sets P = 2Q. func (P *Point) Double() { P.Add(P) } diff --git a/vendor/github.com/cloudflare/circl/kem/kem.go b/vendor/github.com/cloudflare/circl/kem/kem.go new file mode 100644 index 0000000000..a2f6a2aae7 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/kem/kem.go @@ -0,0 +1,121 @@ +// Package kem provides a unified interface for KEM schemes. +// +// A register of schemes is available in the package +// +// github.com/cloudflare/circl/kem/schemes +package kem + +import ( + "encoding" + "errors" +) + +// A KEM public key +type PublicKey interface { + // Returns the scheme for this public key + Scheme() Scheme + + encoding.BinaryMarshaler + Equal(PublicKey) bool +} + +// A KEM private key +type PrivateKey interface { + // Returns the scheme for this private key + Scheme() Scheme + + encoding.BinaryMarshaler + Equal(PrivateKey) bool + Public() PublicKey +} + +// A Scheme represents a specific instance of a KEM. +type Scheme interface { + // Name of the scheme + Name() string + + // GenerateKeyPair creates a new key pair. + GenerateKeyPair() (PublicKey, PrivateKey, error) + + // Encapsulate generates a shared key ss for the public key and + // encapsulates it into a ciphertext ct. + Encapsulate(pk PublicKey) (ct, ss []byte, err error) + + // Returns the shared key encapsulated in ciphertext ct for the + // private key sk. + Decapsulate(sk PrivateKey, ct []byte) ([]byte, error) + + // Unmarshals a PublicKey from the provided buffer. + UnmarshalBinaryPublicKey([]byte) (PublicKey, error) + + // Unmarshals a PrivateKey from the provided buffer. + UnmarshalBinaryPrivateKey([]byte) (PrivateKey, error) + + // Size of encapsulated keys. + CiphertextSize() int + + // Size of established shared keys. + SharedKeySize() int + + // Size of packed private keys. + PrivateKeySize() int + + // Size of packed public keys. + PublicKeySize() int + + // DeriveKeyPair deterministically derives a pair of keys from a seed. + // Panics if the length of seed is not equal to the value returned by + // SeedSize. + DeriveKeyPair(seed []byte) (PublicKey, PrivateKey) + + // Size of seed used in DeriveKey + SeedSize() int + + // EncapsulateDeterministically generates a shared key ss for the public + // key deterministically from the given seed and encapsulates it into + // a ciphertext ct. If unsure, you're better off using Encapsulate(). + EncapsulateDeterministically(pk PublicKey, seed []byte) ( + ct, ss []byte, err error) + + // Size of seed used in EncapsulateDeterministically(). + EncapsulationSeedSize() int +} + +// AuthScheme represents a KEM that supports authenticated key encapsulation. +type AuthScheme interface { + Scheme + AuthEncapsulate(pkr PublicKey, sks PrivateKey) (ct, ss []byte, err error) + AuthEncapsulateDeterministically(pkr PublicKey, sks PrivateKey, seed []byte) (ct, ss []byte, err error) + AuthDecapsulate(skr PrivateKey, ct []byte, pks PublicKey) ([]byte, error) +} + +var ( + // ErrTypeMismatch is the error used if types of, for instance, private + // and public keys don't match + ErrTypeMismatch = errors.New("types mismatch") + + // ErrSeedSize is the error used if the provided seed is of the wrong + // size. + ErrSeedSize = errors.New("wrong seed size") + + // ErrPubKeySize is the error used if the provided public key is of + // the wrong size. + ErrPubKeySize = errors.New("wrong size for public key") + + // ErrCiphertextSize is the error used if the provided ciphertext + // is of the wrong size. + ErrCiphertextSize = errors.New("wrong size for ciphertext") + + // ErrPrivKeySize is the error used if the provided private key is of + // the wrong size. + ErrPrivKeySize = errors.New("wrong size for private key") + + // ErrPubKey is the error used if the provided public key is invalid. + ErrPubKey = errors.New("invalid public key") + + // ErrPrivKey is the error used if the provided private key is invalid. + ErrPrivKey = errors.New("invalid private key") + + // ErrCipherText is the error used if the provided ciphertext is invalid. + ErrCipherText = errors.New("invalid ciphertext") +) diff --git a/vendor/github.com/cloudflare/circl/kem/mlkem/mlkem1024/kyber.go b/vendor/github.com/cloudflare/circl/kem/mlkem/mlkem1024/kyber.go new file mode 100644 index 0000000000..c548faa2ab --- /dev/null +++ b/vendor/github.com/cloudflare/circl/kem/mlkem/mlkem1024/kyber.go @@ -0,0 +1,407 @@ +// Code generated from pkg.templ.go. DO NOT EDIT. + +// Package mlkem1024 implements the IND-CCA2 secure key encapsulation mechanism +// ML-KEM-1024 as defined in FIPS203. +package mlkem1024 + +import ( + "bytes" + "crypto/subtle" + "io" + + cryptoRand "crypto/rand" + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + cpapke "github.com/cloudflare/circl/pke/kyber/kyber1024" +) + +const ( + // Size of seed for NewKeyFromSeed + KeySeedSize = cpapke.KeySeedSize + 32 + + // Size of seed for EncapsulateTo. + EncapsulationSeedSize = 32 + + // Size of the established shared key. + SharedKeySize = 32 + + // Size of the encapsulated shared key. + CiphertextSize = cpapke.CiphertextSize + + // Size of a packed public key. + PublicKeySize = cpapke.PublicKeySize + + // Size of a packed private key. + PrivateKeySize = cpapke.PrivateKeySize + cpapke.PublicKeySize + 64 +) + +// Type of a ML-KEM-1024 public key +type PublicKey struct { + pk *cpapke.PublicKey + + hpk [32]byte // H(pk) +} + +// Type of a ML-KEM-1024 private key +type PrivateKey struct { + sk *cpapke.PrivateKey + pk *cpapke.PublicKey + hpk [32]byte // H(pk) + z [32]byte +} + +// NewKeyFromSeed derives a public/private keypair deterministically +// from the given seed. +// +// Panics if seed is not of length KeySeedSize. +func NewKeyFromSeed(seed []byte) (*PublicKey, *PrivateKey) { + var sk PrivateKey + var pk PublicKey + + if len(seed) != KeySeedSize { + panic("seed must be of length KeySeedSize") + } + + pk.pk, sk.sk = cpapke.NewKeyFromSeedMLKEM(seed[:cpapke.KeySeedSize]) + sk.pk = pk.pk + copy(sk.z[:], seed[cpapke.KeySeedSize:]) + + // Compute H(pk) + var ppk [cpapke.PublicKeySize]byte + sk.pk.Pack(ppk[:]) + h := sha3.New256() + h.Write(ppk[:]) + h.Read(sk.hpk[:]) + copy(pk.hpk[:], sk.hpk[:]) + + return &pk, &sk +} + +// GenerateKeyPair generates public and private keys using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKeyPair(rand io.Reader) (*PublicKey, *PrivateKey, error) { + var seed [KeySeedSize]byte + if rand == nil { + rand = cryptoRand.Reader + } + _, err := io.ReadFull(rand, seed[:]) + if err != nil { + return nil, nil, err + } + pk, sk := NewKeyFromSeed(seed[:]) + return pk, sk, nil +} + +// EncapsulateTo generates a shared key and ciphertext that contains it +// for the public key using randomness from seed and writes the shared key +// to ss and ciphertext to ct. +// +// Panics if ss, ct or seed are not of length SharedKeySize, CiphertextSize +// and EncapsulationSeedSize respectively. +// +// seed may be nil, in which case crypto/rand.Reader is used to generate one. +func (pk *PublicKey) EncapsulateTo(ct, ss []byte, seed []byte) { + if seed == nil { + seed = make([]byte, EncapsulationSeedSize) + if _, err := cryptoRand.Read(seed[:]); err != nil { + panic(err) + } + } else { + if len(seed) != EncapsulationSeedSize { + panic("seed must be of length EncapsulationSeedSize") + } + } + + if len(ct) != CiphertextSize { + panic("ct must be of length CiphertextSize") + } + + if len(ss) != SharedKeySize { + panic("ss must be of length SharedKeySize") + } + + var m [32]byte + copy(m[:], seed) + + // (K', r) = G(m ‖ H(pk)) + var kr [64]byte + g := sha3.New512() + g.Write(m[:]) + g.Write(pk.hpk[:]) + g.Read(kr[:]) + + // c = Kyber.CPAPKE.Enc(pk, m, r) + pk.pk.EncryptTo(ct, m[:], kr[32:]) + + copy(ss, kr[:SharedKeySize]) +} + +// DecapsulateTo computes the shared key which is encapsulated in ct +// for the private key. +// +// Panics if ct or ss are not of length CiphertextSize and SharedKeySize +// respectively. +func (sk *PrivateKey) DecapsulateTo(ss, ct []byte) { + if len(ct) != CiphertextSize { + panic("ct must be of length CiphertextSize") + } + + if len(ss) != SharedKeySize { + panic("ss must be of length SharedKeySize") + } + + // m' = Kyber.CPAPKE.Dec(sk, ct) + var m2 [32]byte + sk.sk.DecryptTo(m2[:], ct) + + // (K'', r') = G(m' ‖ H(pk)) + var kr2 [64]byte + g := sha3.New512() + g.Write(m2[:]) + g.Write(sk.hpk[:]) + g.Read(kr2[:]) + + // c' = Kyber.CPAPKE.Enc(pk, m', r') + var ct2 [CiphertextSize]byte + sk.pk.EncryptTo(ct2[:], m2[:], kr2[32:]) + + var ss2 [SharedKeySize]byte + + // Compute shared secret in case of rejection: ss₂ = PRF(z ‖ c) + prf := sha3.NewShake256() + prf.Write(sk.z[:]) + prf.Write(ct[:CiphertextSize]) + prf.Read(ss2[:]) + + // Set ss2 to the real shared secret if c = c'. + subtle.ConstantTimeCopy( + subtle.ConstantTimeCompare(ct, ct2[:]), + ss2[:], + kr2[:SharedKeySize], + ) + + copy(ss, ss2[:]) +} + +// Packs sk to buf. +// +// Panics if buf is not of size PrivateKeySize. +func (sk *PrivateKey) Pack(buf []byte) { + if len(buf) != PrivateKeySize { + panic("buf must be of length PrivateKeySize") + } + + sk.sk.Pack(buf[:cpapke.PrivateKeySize]) + buf = buf[cpapke.PrivateKeySize:] + sk.pk.Pack(buf[:cpapke.PublicKeySize]) + buf = buf[cpapke.PublicKeySize:] + copy(buf, sk.hpk[:]) + buf = buf[32:] + copy(buf, sk.z[:]) +} + +// Unpacks sk from buf. +// +// Panics if buf is not of size PrivateKeySize. +// +// Returns an error if buf is not of size PrivateKeySize, or private key +// doesn't pass the ML-KEM decapsulation key check. +func (sk *PrivateKey) Unpack(buf []byte) error { + if len(buf) != PrivateKeySize { + return kem.ErrPrivKeySize + } + + sk.sk = new(cpapke.PrivateKey) + sk.sk.Unpack(buf[:cpapke.PrivateKeySize]) + buf = buf[cpapke.PrivateKeySize:] + sk.pk = new(cpapke.PublicKey) + sk.pk.Unpack(buf[:cpapke.PublicKeySize]) + var hpk [32]byte + h := sha3.New256() + h.Write(buf[:cpapke.PublicKeySize]) + h.Read(hpk[:]) + buf = buf[cpapke.PublicKeySize:] + copy(sk.hpk[:], buf[:32]) + copy(sk.z[:], buf[32:]) + if !bytes.Equal(hpk[:], sk.hpk[:]) { + return kem.ErrPrivKey + } + return nil +} + +// Packs pk to buf. +// +// Panics if buf is not of size PublicKeySize. +func (pk *PublicKey) Pack(buf []byte) { + if len(buf) != PublicKeySize { + panic("buf must be of length PublicKeySize") + } + + pk.pk.Pack(buf) +} + +// Unpacks pk from buf. +// +// Returns an error if buf is not of size PublicKeySize, or the public key +// is not normalized. +func (pk *PublicKey) Unpack(buf []byte) error { + if len(buf) != PublicKeySize { + return kem.ErrPubKeySize + } + + pk.pk = new(cpapke.PublicKey) + if err := pk.pk.UnpackMLKEM(buf); err != nil { + return err + } + + // Compute cached H(pk) + h := sha3.New256() + h.Write(buf) + h.Read(pk.hpk[:]) + + return nil +} + +// Boilerplate down below for the KEM scheme API. + +type scheme struct{} + +var sch kem.Scheme = &scheme{} + +// Scheme returns a KEM interface. +func Scheme() kem.Scheme { return sch } + +func (*scheme) Name() string { return "ML-KEM-1024" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SeedSize() int { return KeySeedSize } +func (*scheme) SharedKeySize() int { return SharedKeySize } +func (*scheme) CiphertextSize() int { return CiphertextSize } +func (*scheme) EncapsulationSeedSize() int { return EncapsulationSeedSize } + +func (sk *PrivateKey) Scheme() kem.Scheme { return sch } +func (pk *PublicKey) Scheme() kem.Scheme { return sch } + +func (sk *PrivateKey) MarshalBinary() ([]byte, error) { + var ret [PrivateKeySize]byte + sk.Pack(ret[:]) + return ret[:], nil +} + +func (sk *PrivateKey) Equal(other kem.PrivateKey) bool { + oth, ok := other.(*PrivateKey) + if !ok { + return false + } + if sk.pk == nil && oth.pk == nil { + return true + } + if sk.pk == nil || oth.pk == nil { + return false + } + if !bytes.Equal(sk.hpk[:], oth.hpk[:]) || + subtle.ConstantTimeCompare(sk.z[:], oth.z[:]) != 1 { + return false + } + return sk.sk.Equal(oth.sk) +} + +func (pk *PublicKey) Equal(other kem.PublicKey) bool { + oth, ok := other.(*PublicKey) + if !ok { + return false + } + if pk.pk == nil && oth.pk == nil { + return true + } + if pk.pk == nil || oth.pk == nil { + return false + } + return bytes.Equal(pk.hpk[:], oth.hpk[:]) +} + +func (sk *PrivateKey) Public() kem.PublicKey { + pk := new(PublicKey) + pk.pk = sk.pk + copy(pk.hpk[:], sk.hpk[:]) + return pk +} + +func (pk *PublicKey) MarshalBinary() ([]byte, error) { + var ret [PublicKeySize]byte + pk.Pack(ret[:]) + return ret[:], nil +} + +func (*scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) { + return GenerateKeyPair(cryptoRand.Reader) +} + +func (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { + if len(seed) != KeySeedSize { + panic(kem.ErrSeedSize) + } + return NewKeyFromSeed(seed[:]) +} + +func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) { + ct = make([]byte, CiphertextSize) + ss = make([]byte, SharedKeySize) + + pub, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + pub.EncapsulateTo(ct, ss, nil) + return +} + +func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) ( + ct, ss []byte, err error) { + if len(seed) != EncapsulationSeedSize { + return nil, nil, kem.ErrSeedSize + } + + ct = make([]byte, CiphertextSize) + ss = make([]byte, SharedKeySize) + + pub, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + pub.EncapsulateTo(ct, ss, seed) + return +} + +func (*scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) { + if len(ct) != CiphertextSize { + return nil, kem.ErrCiphertextSize + } + + priv, ok := sk.(*PrivateKey) + if !ok { + return nil, kem.ErrTypeMismatch + } + ss := make([]byte, SharedKeySize) + priv.DecapsulateTo(ss, ct) + return ss, nil +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) { + var ret PublicKey + if err := ret.Unpack(buf); err != nil { + return nil, err + } + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, kem.ErrPrivKeySize + } + var ret PrivateKey + if err := ret.Unpack(buf); err != nil { + return nil, err + } + return &ret, nil +} diff --git a/vendor/github.com/cloudflare/circl/kem/mlkem/mlkem768/kyber.go b/vendor/github.com/cloudflare/circl/kem/mlkem/mlkem768/kyber.go new file mode 100644 index 0000000000..afa4831567 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/kem/mlkem/mlkem768/kyber.go @@ -0,0 +1,407 @@ +// Code generated from pkg.templ.go. DO NOT EDIT. + +// Package mlkem768 implements the IND-CCA2 secure key encapsulation mechanism +// ML-KEM-768 as defined in FIPS203. +package mlkem768 + +import ( + "bytes" + "crypto/subtle" + "io" + + cryptoRand "crypto/rand" + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + cpapke "github.com/cloudflare/circl/pke/kyber/kyber768" +) + +const ( + // Size of seed for NewKeyFromSeed + KeySeedSize = cpapke.KeySeedSize + 32 + + // Size of seed for EncapsulateTo. + EncapsulationSeedSize = 32 + + // Size of the established shared key. + SharedKeySize = 32 + + // Size of the encapsulated shared key. + CiphertextSize = cpapke.CiphertextSize + + // Size of a packed public key. + PublicKeySize = cpapke.PublicKeySize + + // Size of a packed private key. + PrivateKeySize = cpapke.PrivateKeySize + cpapke.PublicKeySize + 64 +) + +// Type of a ML-KEM-768 public key +type PublicKey struct { + pk *cpapke.PublicKey + + hpk [32]byte // H(pk) +} + +// Type of a ML-KEM-768 private key +type PrivateKey struct { + sk *cpapke.PrivateKey + pk *cpapke.PublicKey + hpk [32]byte // H(pk) + z [32]byte +} + +// NewKeyFromSeed derives a public/private keypair deterministically +// from the given seed. +// +// Panics if seed is not of length KeySeedSize. +func NewKeyFromSeed(seed []byte) (*PublicKey, *PrivateKey) { + var sk PrivateKey + var pk PublicKey + + if len(seed) != KeySeedSize { + panic("seed must be of length KeySeedSize") + } + + pk.pk, sk.sk = cpapke.NewKeyFromSeedMLKEM(seed[:cpapke.KeySeedSize]) + sk.pk = pk.pk + copy(sk.z[:], seed[cpapke.KeySeedSize:]) + + // Compute H(pk) + var ppk [cpapke.PublicKeySize]byte + sk.pk.Pack(ppk[:]) + h := sha3.New256() + h.Write(ppk[:]) + h.Read(sk.hpk[:]) + copy(pk.hpk[:], sk.hpk[:]) + + return &pk, &sk +} + +// GenerateKeyPair generates public and private keys using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKeyPair(rand io.Reader) (*PublicKey, *PrivateKey, error) { + var seed [KeySeedSize]byte + if rand == nil { + rand = cryptoRand.Reader + } + _, err := io.ReadFull(rand, seed[:]) + if err != nil { + return nil, nil, err + } + pk, sk := NewKeyFromSeed(seed[:]) + return pk, sk, nil +} + +// EncapsulateTo generates a shared key and ciphertext that contains it +// for the public key using randomness from seed and writes the shared key +// to ss and ciphertext to ct. +// +// Panics if ss, ct or seed are not of length SharedKeySize, CiphertextSize +// and EncapsulationSeedSize respectively. +// +// seed may be nil, in which case crypto/rand.Reader is used to generate one. +func (pk *PublicKey) EncapsulateTo(ct, ss []byte, seed []byte) { + if seed == nil { + seed = make([]byte, EncapsulationSeedSize) + if _, err := cryptoRand.Read(seed[:]); err != nil { + panic(err) + } + } else { + if len(seed) != EncapsulationSeedSize { + panic("seed must be of length EncapsulationSeedSize") + } + } + + if len(ct) != CiphertextSize { + panic("ct must be of length CiphertextSize") + } + + if len(ss) != SharedKeySize { + panic("ss must be of length SharedKeySize") + } + + var m [32]byte + copy(m[:], seed) + + // (K', r) = G(m ‖ H(pk)) + var kr [64]byte + g := sha3.New512() + g.Write(m[:]) + g.Write(pk.hpk[:]) + g.Read(kr[:]) + + // c = Kyber.CPAPKE.Enc(pk, m, r) + pk.pk.EncryptTo(ct, m[:], kr[32:]) + + copy(ss, kr[:SharedKeySize]) +} + +// DecapsulateTo computes the shared key which is encapsulated in ct +// for the private key. +// +// Panics if ct or ss are not of length CiphertextSize and SharedKeySize +// respectively. +func (sk *PrivateKey) DecapsulateTo(ss, ct []byte) { + if len(ct) != CiphertextSize { + panic("ct must be of length CiphertextSize") + } + + if len(ss) != SharedKeySize { + panic("ss must be of length SharedKeySize") + } + + // m' = Kyber.CPAPKE.Dec(sk, ct) + var m2 [32]byte + sk.sk.DecryptTo(m2[:], ct) + + // (K'', r') = G(m' ‖ H(pk)) + var kr2 [64]byte + g := sha3.New512() + g.Write(m2[:]) + g.Write(sk.hpk[:]) + g.Read(kr2[:]) + + // c' = Kyber.CPAPKE.Enc(pk, m', r') + var ct2 [CiphertextSize]byte + sk.pk.EncryptTo(ct2[:], m2[:], kr2[32:]) + + var ss2 [SharedKeySize]byte + + // Compute shared secret in case of rejection: ss₂ = PRF(z ‖ c) + prf := sha3.NewShake256() + prf.Write(sk.z[:]) + prf.Write(ct[:CiphertextSize]) + prf.Read(ss2[:]) + + // Set ss2 to the real shared secret if c = c'. + subtle.ConstantTimeCopy( + subtle.ConstantTimeCompare(ct, ct2[:]), + ss2[:], + kr2[:SharedKeySize], + ) + + copy(ss, ss2[:]) +} + +// Packs sk to buf. +// +// Panics if buf is not of size PrivateKeySize. +func (sk *PrivateKey) Pack(buf []byte) { + if len(buf) != PrivateKeySize { + panic("buf must be of length PrivateKeySize") + } + + sk.sk.Pack(buf[:cpapke.PrivateKeySize]) + buf = buf[cpapke.PrivateKeySize:] + sk.pk.Pack(buf[:cpapke.PublicKeySize]) + buf = buf[cpapke.PublicKeySize:] + copy(buf, sk.hpk[:]) + buf = buf[32:] + copy(buf, sk.z[:]) +} + +// Unpacks sk from buf. +// +// Panics if buf is not of size PrivateKeySize. +// +// Returns an error if buf is not of size PrivateKeySize, or private key +// doesn't pass the ML-KEM decapsulation key check. +func (sk *PrivateKey) Unpack(buf []byte) error { + if len(buf) != PrivateKeySize { + return kem.ErrPrivKeySize + } + + sk.sk = new(cpapke.PrivateKey) + sk.sk.Unpack(buf[:cpapke.PrivateKeySize]) + buf = buf[cpapke.PrivateKeySize:] + sk.pk = new(cpapke.PublicKey) + sk.pk.Unpack(buf[:cpapke.PublicKeySize]) + var hpk [32]byte + h := sha3.New256() + h.Write(buf[:cpapke.PublicKeySize]) + h.Read(hpk[:]) + buf = buf[cpapke.PublicKeySize:] + copy(sk.hpk[:], buf[:32]) + copy(sk.z[:], buf[32:]) + if !bytes.Equal(hpk[:], sk.hpk[:]) { + return kem.ErrPrivKey + } + return nil +} + +// Packs pk to buf. +// +// Panics if buf is not of size PublicKeySize. +func (pk *PublicKey) Pack(buf []byte) { + if len(buf) != PublicKeySize { + panic("buf must be of length PublicKeySize") + } + + pk.pk.Pack(buf) +} + +// Unpacks pk from buf. +// +// Returns an error if buf is not of size PublicKeySize, or the public key +// is not normalized. +func (pk *PublicKey) Unpack(buf []byte) error { + if len(buf) != PublicKeySize { + return kem.ErrPubKeySize + } + + pk.pk = new(cpapke.PublicKey) + if err := pk.pk.UnpackMLKEM(buf); err != nil { + return err + } + + // Compute cached H(pk) + h := sha3.New256() + h.Write(buf) + h.Read(pk.hpk[:]) + + return nil +} + +// Boilerplate down below for the KEM scheme API. + +type scheme struct{} + +var sch kem.Scheme = &scheme{} + +// Scheme returns a KEM interface. +func Scheme() kem.Scheme { return sch } + +func (*scheme) Name() string { return "ML-KEM-768" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SeedSize() int { return KeySeedSize } +func (*scheme) SharedKeySize() int { return SharedKeySize } +func (*scheme) CiphertextSize() int { return CiphertextSize } +func (*scheme) EncapsulationSeedSize() int { return EncapsulationSeedSize } + +func (sk *PrivateKey) Scheme() kem.Scheme { return sch } +func (pk *PublicKey) Scheme() kem.Scheme { return sch } + +func (sk *PrivateKey) MarshalBinary() ([]byte, error) { + var ret [PrivateKeySize]byte + sk.Pack(ret[:]) + return ret[:], nil +} + +func (sk *PrivateKey) Equal(other kem.PrivateKey) bool { + oth, ok := other.(*PrivateKey) + if !ok { + return false + } + if sk.pk == nil && oth.pk == nil { + return true + } + if sk.pk == nil || oth.pk == nil { + return false + } + if !bytes.Equal(sk.hpk[:], oth.hpk[:]) || + subtle.ConstantTimeCompare(sk.z[:], oth.z[:]) != 1 { + return false + } + return sk.sk.Equal(oth.sk) +} + +func (pk *PublicKey) Equal(other kem.PublicKey) bool { + oth, ok := other.(*PublicKey) + if !ok { + return false + } + if pk.pk == nil && oth.pk == nil { + return true + } + if pk.pk == nil || oth.pk == nil { + return false + } + return bytes.Equal(pk.hpk[:], oth.hpk[:]) +} + +func (sk *PrivateKey) Public() kem.PublicKey { + pk := new(PublicKey) + pk.pk = sk.pk + copy(pk.hpk[:], sk.hpk[:]) + return pk +} + +func (pk *PublicKey) MarshalBinary() ([]byte, error) { + var ret [PublicKeySize]byte + pk.Pack(ret[:]) + return ret[:], nil +} + +func (*scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) { + return GenerateKeyPair(cryptoRand.Reader) +} + +func (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { + if len(seed) != KeySeedSize { + panic(kem.ErrSeedSize) + } + return NewKeyFromSeed(seed[:]) +} + +func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) { + ct = make([]byte, CiphertextSize) + ss = make([]byte, SharedKeySize) + + pub, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + pub.EncapsulateTo(ct, ss, nil) + return +} + +func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) ( + ct, ss []byte, err error) { + if len(seed) != EncapsulationSeedSize { + return nil, nil, kem.ErrSeedSize + } + + ct = make([]byte, CiphertextSize) + ss = make([]byte, SharedKeySize) + + pub, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + pub.EncapsulateTo(ct, ss, seed) + return +} + +func (*scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) { + if len(ct) != CiphertextSize { + return nil, kem.ErrCiphertextSize + } + + priv, ok := sk.(*PrivateKey) + if !ok { + return nil, kem.ErrTypeMismatch + } + ss := make([]byte, SharedKeySize) + priv.DecapsulateTo(ss, ct) + return ss, nil +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) { + var ret PublicKey + if err := ret.Unpack(buf); err != nil { + return nil, err + } + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, kem.ErrPrivKeySize + } + var ret PrivateKey + if err := ret.Unpack(buf); err != nil { + return nil, err + } + return &ret, nil +} diff --git a/vendor/github.com/cloudflare/circl/math/mlsbset/mlsbset.go b/vendor/github.com/cloudflare/circl/math/mlsbset/mlsbset.go index a43851b8bb..2adace4206 100644 --- a/vendor/github.com/cloudflare/circl/math/mlsbset/mlsbset.go +++ b/vendor/github.com/cloudflare/circl/math/mlsbset/mlsbset.go @@ -9,9 +9,6 @@ package mlsbset import ( "errors" "fmt" - "math/big" - - "github.com/cloudflare/circl/internal/conv" ) // EltG is a group element. @@ -69,17 +66,43 @@ func (m Encoder) Encode(k []byte) (*Power, error) { k = append(k, make([]byte, ap)...) s := m.signs(k) b := make([]int32, m.p.L-m.p.D) - c := conv.BytesLe2BigInt(k) - c.Rsh(c, m.p.D) - var bi big.Int + + // Original algorithm starts with c := k >> D, then computes + // + // b_(i-D) = s_(i%D) * lsb(c) + // c = [ (c>>1)+1 if b_(i-D) = -1 + // [ c>>1 otherwise + // + // To prevent keeping a large k around, we note that at any step i we have + // + // c = (k >> i) + t for t in {0,1} + // + // Base case is obvious. For induction, write kbit for the i-th bit of k. + // Note lsb(c) = kbit ^ t. From that we can compute b_(i-D). Now we need + // to compute the next t. + // + // Consider c >> 1 = (k >> i) + t) >> 1. This equals k >> (i+1) + // unless t = 1 = kbit. + // + // If b_(i-D) is negative, then we must have had 1=lsb(c)=kbit^t, and so + // c >> 1 = k >> (i+1), as desired with new t equal to 1. + // For the other case assume b_(i-D) isn't negative. Now it is possible + // that t = 1 = kbit, and only in that case the new t is equal to 1. + var t uint64 for i := m.p.D; i < m.p.L; i++ { - c0 := int32(c.Bit(0)) - b[i-m.p.D] = s[i%m.p.D] * c0 - bi.SetInt64(int64(b[i-m.p.D] >> 1)) - c.Rsh(c, 1) - c.Sub(c, &bi) + si := s[i%m.p.D] + kbit := uint64(k[i>>3]>>(i&7)) & 1 + lsbc := kbit ^ t + neg := uint64(si>>31) & 1 // 1 iff si == -1 + b[i-m.p.D] = si * int32(lsbc) + t = (kbit & t) | (lsbc & neg) + } + // carry = (k >> L) + t: any bits of k at positions >= L (present when L is + // not a multiple of 8) plus the final carry, matching the original. + carry := int(t) + for pos := m.p.L; int(pos>>3) < len(k); pos++ { + carry += int((k[pos>>3]>>(pos&7))&1) << (pos - m.p.L) } - carry := int(c.Int64()) return &Power{m, s, b, carry}, nil } diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/amd64.go b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/amd64.go new file mode 100644 index 0000000000..2c96563c7d --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/amd64.go @@ -0,0 +1,302 @@ +//go:build amd64 && !purego +// +build amd64,!purego + +package common + +import ( + "golang.org/x/sys/cpu" +) + +// ZetasAVX2 contains all ζ used in NTT (like the Zetas array), but also +// the values int16(zeta * 62209) for each zeta, which is used in +// Montgomery reduction. There is some duplication and reordering as +// compared to Zetas to make it more convenient for use with AVX2. +var ZetasAVX2 = [...]int16{ + // level 1: int16(Zetas[1]*62209) and Zetas[1] + 31499, 2571, + + // level 2 + // + // int16(Zetas[2]*62209), Zetas[2], int16(Zetas[3]*62209), Zetas[3] + 14746, 2970, 788, 1812, + + // level 3, like level 2. + 13525, 1493, -12402, 1422, 28191, 287, -16694, 202, + + 0, 0, // padding + + // layer 4. offset: 1*16 + // + // The precomputed multiplication and zetas are grouped by 16 at a + // time as used in the set of butterflies, etc. + -20906, -20906, -20906, -20906, -20906, -20906, -20906, -20906, + 27758, 27758, 27758, 27758, 27758, 27758, 27758, 27758, + 3158, 3158, 3158, 3158, 3158, 3158, 3158, 3158, + 622, 622, 622, 622, 622, 622, 622, 622, + -3799, -3799, -3799, -3799, -3799, -3799, -3799, -3799, + -15690, -15690, -15690, -15690, -15690, -15690, -15690, -15690, + 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, + 182, 182, 182, 182, 182, 182, 182, 182, + 10690, 10690, 10690, 10690, 10690, 10690, 10690, 10690, + 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, + 962, 962, 962, 962, 962, 962, 962, 962, + 2127, 2127, 2127, 2127, 2127, 2127, 2127, 2127, + -11201, -11201, -11201, -11201, -11201, -11201, -11201, -11201, + 31164, 31164, 31164, 31164, 31164, 31164, 31164, 31164, + 1855, 1855, 1855, 1855, 1855, 1855, 1855, 1855, + 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, + + // layer 5. offset: 9*16 + -5827, -5827, -5827, -5827, 17364, 17364, 17364, 17364, + -26360, -26360, -26360, -26360, -29057, -29057, -29057, -29057, + 573, 573, 573, 573, 2004, 2004, 2004, 2004, + 264, 264, 264, 264, 383, 383, 383, 383, + 5572, 5572, 5572, 5572, -1102, -1102, -1102, -1102, + 21439, 21439, 21439, 21439, -26241, -26241, -26241, -26241, + 2500, 2500, 2500, 2500, 1458, 1458, 1458, 1458, + 1727, 1727, 1727, 1727, 3199, 3199, 3199, 3199, + -28072, -28072, -28072, -28072, 24313, 24313, 24313, 24313, + -10532, -10532, -10532, -10532, 8800, 8800, 8800, 8800, + 2648, 2648, 2648, 2648, 1017, 1017, 1017, 1017, + 732, 732, 732, 732, 608, 608, 608, 608, + 18427, 18427, 18427, 18427, 8859, 8859, 8859, 8859, + 26676, 26676, 26676, 26676, -16162, -16162, -16162, -16162, + 1787, 1787, 1787, 1787, 411, 411, 411, 411, + 3124, 3124, 3124, 3124, 1758, 1758, 1758, 1758, + + // layer 6. offset: 17*16 + -5689, -5689, -6516, -6516, 1497, 1497, 30967, 30967, + -23564, -23564, 20179, 20179, 20711, 20711, 25081, 25081, + 1223, 1223, 652, 652, 2777, 2777, 1015, 1015, + 2036, 2036, 1491, 1491, 3047, 3047, 1785, 1785, + -12796, -12796, 26617, 26617, 16065, 16065, -12441, -12441, + 9135, 9135, -649, -649, -25986, -25986, 27837, 27837, + 516, 516, 3321, 3321, 3009, 3009, 2663, 2663, + 1711, 1711, 2167, 2167, 126, 126, 1469, 1469, + 19884, 19884, -28249, -28249, -15886, -15886, -8898, -8898, + -28309, -28309, 9076, 9076, -30198, -30198, 18250, 18250, + 2476, 2476, 3239, 3239, 3058, 3058, 830, 830, + 107, 107, 1908, 1908, 3082, 3082, 2378, 2378, + 13427, 13427, 14017, 14017, -29155, -29155, -12756, -12756, + 16832, 16832, 4312, 4312, -24155, -24155, -17914, -17914, + 2931, 2931, 961, 961, 1821, 1821, 2604, 2604, + 448, 448, 2264, 2264, 677, 677, 2054, 2054, + + // layer 7. offset: 25*16 + -334, 11182, -11477, 13387, -32226, -14233, 20494, -21655, + -27738, 13131, 945, -4586, -14882, 23093, 6182, 5493, + 2226, 430, 555, 843, 2078, 871, 1550, 105, + 422, 587, 177, 3094, 3038, 2869, 1574, 1653, + 32011, -32502, 10631, 30318, 29176, -18741, -28761, 12639, + -18485, 20100, 17561, 18525, -14430, 19529, -5275, -12618, + 3083, 778, 1159, 3182, 2552, 1483, 2727, 1119, + 1739, 644, 2457, 349, 418, 329, 3173, 3254, + -31183, 20297, 25435, 2146, -7382, 15356, 24392, -32384, + -20926, -6279, 10946, -14902, 24215, -11044, 16990, 14470, + 817, 1097, 603, 610, 1322, 2044, 1864, 384, + 2114, 3193, 1218, 1994, 2455, 220, 2142, 1670, + 10336, -21497, -7933, -20198, -22501, 23211, 10907, -17442, + 31637, -23859, 28644, -20257, 23998, 7757, -17422, 23132, + 2144, 1799, 2051, 794, 1819, 2475, 2459, 478, + 3221, 3021, 996, 991, 958, 1869, 1522, 1628, + + // layer 1 inverse + 23132, -17422, 7757, 23998, -20257, 28644, -23859, 31637, + -17442, 10907, 23211, -22501, -20198, -7933, -21497, 10336, + 1628, 1522, 1869, 958, 991, 996, 3021, 3221, + 478, 2459, 2475, 1819, 794, 2051, 1799, 2144, + 14470, 16990, -11044, 24215, -14902, 10946, -6279, -20926, + -32384, 24392, 15356, -7382, 2146, 25435, 20297, -31183, + 1670, 2142, 220, 2455, 1994, 1218, 3193, 2114, + 384, 1864, 2044, 1322, 610, 603, 1097, 817, + -12618, -5275, 19529, -14430, 18525, 17561, 20100, -18485, + 12639, -28761, -18741, 29176, 30318, 10631, -32502, 32011, + 3254, 3173, 329, 418, 349, 2457, 644, 1739, + 1119, 2727, 1483, 2552, 3182, 1159, 778, 3083, + 5493, 6182, 23093, -14882, -4586, 945, 13131, -27738, + -21655, 20494, -14233, -32226, 13387, -11477, 11182, -334, + 1653, 1574, 2869, 3038, 3094, 177, 587, 422, + 105, 1550, 871, 2078, 843, 555, 430, 2226, + + // layer 2 inverse + -17914, -17914, -24155, -24155, 4312, 4312, 16832, 16832, + -12756, -12756, -29155, -29155, 14017, 14017, 13427, 13427, + 2054, 2054, 677, 677, 2264, 2264, 448, 448, + 2604, 2604, 1821, 1821, 961, 961, 2931, 2931, + 18250, 18250, -30198, -30198, 9076, 9076, -28309, -28309, + -8898, -8898, -15886, -15886, -28249, -28249, 19884, 19884, + 2378, 2378, 3082, 3082, 1908, 1908, 107, 107, + 830, 830, 3058, 3058, 3239, 3239, 2476, 2476, + 27837, 27837, -25986, -25986, -649, -649, 9135, 9135, + -12441, -12441, 16065, 16065, 26617, 26617, -12796, -12796, + 1469, 1469, 126, 126, 2167, 2167, 1711, 1711, + 2663, 2663, 3009, 3009, 3321, 3321, 516, 516, + 25081, 25081, 20711, 20711, 20179, 20179, -23564, -23564, + 30967, 30967, 1497, 1497, -6516, -6516, -5689, -5689, + 1785, 1785, 3047, 3047, 1491, 1491, 2036, 2036, + 1015, 1015, 2777, 2777, 652, 652, 1223, 1223, + + // layer 3 inverse + -16162, -16162, -16162, -16162, 26676, 26676, 26676, 26676, + 8859, 8859, 8859, 8859, 18427, 18427, 18427, 18427, + 1758, 1758, 1758, 1758, 3124, 3124, 3124, 3124, + 411, 411, 411, 411, 1787, 1787, 1787, 1787, + 8800, 8800, 8800, 8800, -10532, -10532, -10532, -10532, + 24313, 24313, 24313, 24313, -28072, -28072, -28072, -28072, + 608, 608, 608, 608, 732, 732, 732, 732, + 1017, 1017, 1017, 1017, 2648, 2648, 2648, 2648, + -26241, -26241, -26241, -26241, 21439, 21439, 21439, 21439, + -1102, -1102, -1102, -1102, 5572, 5572, 5572, 5572, + 3199, 3199, 3199, 3199, 1727, 1727, 1727, 1727, + 1458, 1458, 1458, 1458, 2500, 2500, 2500, 2500, + -29057, -29057, -29057, -29057, -26360, -26360, -26360, -26360, + 17364, 17364, 17364, 17364, -5827, -5827, -5827, -5827, + 383, 383, 383, 383, 264, 264, 264, 264, + 2004, 2004, 2004, 2004, 573, 573, 573, 573, + + // layer 4 inverse + 31164, 31164, 31164, 31164, 31164, 31164, 31164, 31164, + -11201, -11201, -11201, -11201, -11201, -11201, -11201, -11201, + 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, + 1855, 1855, 1855, 1855, 1855, 1855, 1855, 1855, + 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, + 10690, 10690, 10690, 10690, 10690, 10690, 10690, 10690, + 2127, 2127, 2127, 2127, 2127, 2127, 2127, 2127, + 962, 962, 962, 962, 962, 962, 962, 962, + -15690, -15690, -15690, -15690, -15690, -15690, -15690, -15690, + -3799, -3799, -3799, -3799, -3799, -3799, -3799, -3799, + 182, 182, 182, 182, 182, 182, 182, 182, + 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, + 27758, 27758, 27758, 27758, 27758, 27758, 27758, 27758, + -20906, -20906, -20906, -20906, -20906, -20906, -20906, -20906, + 622, 622, 622, 622, 622, 622, 622, 622, + 3158, 3158, 3158, 3158, 3158, 3158, 3158, 3158, + + // layer 5 inverse + -16694, 202, 28191, 287, -12402, 1422, 13525, 1493, + + // layer 6 inverse + 788, 1812, 14746, 2970, + + // layer 7 inverse + 31499, 2571, +} + +// Sets p to a + b. Does not normalize coefficients. +func (p *Poly) Add(a, b *Poly) { + if cpu.X86.HasAVX2 { + addAVX2( + (*[N]int16)(p), + (*[N]int16)(a), + (*[N]int16)(b), + ) + } else { + p.addGeneric(a, b) + } +} + +// Sets p to a - b. Does not normalize coefficients. +func (p *Poly) Sub(a, b *Poly) { + if cpu.X86.HasAVX2 { + subAVX2( + (*[N]int16)(p), + (*[N]int16)(a), + (*[N]int16)(b), + ) + } else { + p.subGeneric(a, b) + } +} + +// Executes an in-place forward "NTT" on p. +// +// Assumes the coefficients are in absolute value ≤q. The resulting +// coefficients are in absolute value ≤7q. If the input is in Montgomery +// form, then the result is in Montgomery form and so (by linearity of the NTT) +// if the input is in regular form, then the result is also in regular form. +// The order of coefficients will be "tangled". These can be put back into +// their proper order by calling Detangle(). +func (p *Poly) NTT() { + if cpu.X86.HasAVX2 { + nttAVX2((*[N]int16)(p)) + } else { + p.nttGeneric() + } +} + +// Executes an in-place inverse "NTT" on p and multiply by the Montgomery +// factor R. +// +// Requires coefficients to be in "tangled" order, see Tangle(). +// Assumes the coefficients are in absolute value ≤q. The resulting +// coefficients are in absolute value ≤q. If the input is in Montgomery +// form, then the result is in Montgomery form and so (by linearity) +// if the input is in regular form, then the result is also in regular form. +func (p *Poly) InvNTT() { + if cpu.X86.HasAVX2 { + invNttAVX2((*[N]int16)(p)) + } else { + p.invNTTGeneric() + } +} + +// Sets p to the "pointwise" multiplication of a and b. +// +// That is: InvNTT(p) = InvNTT(a) * InvNTT(b). Assumes a and b are in +// Montgomery form. Products between coefficients of a and b must be strictly +// bounded in absolute value by 2¹⁵q. p will be in Montgomery form and +// bounded in absolute value by 2q. +// +// Requires a and b to be in "tangled" order, see Tangle(). p will be in +// tangled order as well. +func (p *Poly) MulHat(a, b *Poly) { + if cpu.X86.HasAVX2 { + mulHatAVX2( + (*[N]int16)(p), + (*[N]int16)(a), + (*[N]int16)(b), + ) + } else { + p.mulHatGeneric(a, b) + } +} + +// Puts p into the right form to be used with (among others) InvNTT(). +func (p *Poly) Tangle() { + if cpu.X86.HasAVX2 { + tangleAVX2((*[N]int16)(p)) + } + + // When AVX2 is not available, we use the standard order. +} + +// Puts p back into standard form. +func (p *Poly) Detangle() { + if cpu.X86.HasAVX2 { + detangleAVX2((*[N]int16)(p)) + } + + // When AVX2 is not available, we use the standard order. +} + +// Almost normalizes coefficients. +// +// Ensures each coefficient is in {0, …, q}. +func (p *Poly) BarrettReduce() { + if cpu.X86.HasAVX2 { + barrettReduceAVX2((*[N]int16)(p)) + } else { + p.barrettReduceGeneric() + } +} + +// Normalizes coefficients. +// +// Ensures each coefficient is in {0, …, q-1}. +func (p *Poly) Normalize() { + if cpu.X86.HasAVX2 { + normalizeAVX2((*[N]int16)(p)) + } else { + p.normalizeGeneric() + } +} diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/amd64.s b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/amd64.s new file mode 100644 index 0000000000..5c7536b701 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/amd64.s @@ -0,0 +1,2354 @@ +// Code generated by command: go run src.go -out ../amd64.s -stubs ../stubs_amd64.go -pkg common. DO NOT EDIT. + +//go:build amd64 && !purego + +#include "textflag.h" + +// func addAVX2(p *[256]int16, a *[256]int16, b *[256]int16) +// Requires: AVX, AVX2 +TEXT ·addAVX2(SB), NOSPLIT, $0-24 + MOVQ p+0(FP), AX + MOVQ a+8(FP), CX + MOVQ b+16(FP), DX + VMOVDQU (CX), Y0 + VMOVDQU 32(CX), Y2 + VMOVDQU 64(CX), Y4 + VMOVDQU 96(CX), Y6 + VMOVDQU 128(CX), Y8 + VMOVDQU 160(CX), Y10 + VMOVDQU 192(CX), Y12 + VMOVDQU 224(CX), Y14 + VMOVDQU (DX), Y1 + VMOVDQU 32(DX), Y3 + VMOVDQU 64(DX), Y5 + VMOVDQU 96(DX), Y7 + VMOVDQU 128(DX), Y9 + VMOVDQU 160(DX), Y11 + VMOVDQU 192(DX), Y13 + VMOVDQU 224(DX), Y15 + VPADDW Y0, Y1, Y1 + VPADDW Y2, Y3, Y3 + VPADDW Y4, Y5, Y5 + VPADDW Y6, Y7, Y7 + VPADDW Y8, Y9, Y9 + VPADDW Y10, Y11, Y11 + VPADDW Y12, Y13, Y13 + VPADDW Y14, Y15, Y15 + VMOVDQU Y1, (AX) + VMOVDQU Y3, 32(AX) + VMOVDQU Y5, 64(AX) + VMOVDQU Y7, 96(AX) + VMOVDQU Y9, 128(AX) + VMOVDQU Y11, 160(AX) + VMOVDQU Y13, 192(AX) + VMOVDQU Y15, 224(AX) + VMOVDQU 256(CX), Y0 + VMOVDQU 288(CX), Y2 + VMOVDQU 320(CX), Y4 + VMOVDQU 352(CX), Y6 + VMOVDQU 384(CX), Y8 + VMOVDQU 416(CX), Y10 + VMOVDQU 448(CX), Y12 + VMOVDQU 480(CX), Y14 + VMOVDQU 256(DX), Y1 + VMOVDQU 288(DX), Y3 + VMOVDQU 320(DX), Y5 + VMOVDQU 352(DX), Y7 + VMOVDQU 384(DX), Y9 + VMOVDQU 416(DX), Y11 + VMOVDQU 448(DX), Y13 + VMOVDQU 480(DX), Y15 + VPADDW Y0, Y1, Y1 + VPADDW Y2, Y3, Y3 + VPADDW Y4, Y5, Y5 + VPADDW Y6, Y7, Y7 + VPADDW Y8, Y9, Y9 + VPADDW Y10, Y11, Y11 + VPADDW Y12, Y13, Y13 + VPADDW Y14, Y15, Y15 + VMOVDQU Y1, 256(AX) + VMOVDQU Y3, 288(AX) + VMOVDQU Y5, 320(AX) + VMOVDQU Y7, 352(AX) + VMOVDQU Y9, 384(AX) + VMOVDQU Y11, 416(AX) + VMOVDQU Y13, 448(AX) + VMOVDQU Y15, 480(AX) + RET + +// func subAVX2(p *[256]int16, a *[256]int16, b *[256]int16) +// Requires: AVX, AVX2 +TEXT ·subAVX2(SB), NOSPLIT, $0-24 + MOVQ p+0(FP), AX + MOVQ a+8(FP), CX + MOVQ b+16(FP), DX + VMOVDQU (CX), Y0 + VMOVDQU 32(CX), Y2 + VMOVDQU 64(CX), Y4 + VMOVDQU 96(CX), Y6 + VMOVDQU 128(CX), Y8 + VMOVDQU 160(CX), Y10 + VMOVDQU 192(CX), Y12 + VMOVDQU 224(CX), Y14 + VMOVDQU (DX), Y1 + VMOVDQU 32(DX), Y3 + VMOVDQU 64(DX), Y5 + VMOVDQU 96(DX), Y7 + VMOVDQU 128(DX), Y9 + VMOVDQU 160(DX), Y11 + VMOVDQU 192(DX), Y13 + VMOVDQU 224(DX), Y15 + VPSUBW Y1, Y0, Y1 + VPSUBW Y3, Y2, Y3 + VPSUBW Y5, Y4, Y5 + VPSUBW Y7, Y6, Y7 + VPSUBW Y9, Y8, Y9 + VPSUBW Y11, Y10, Y11 + VPSUBW Y13, Y12, Y13 + VPSUBW Y15, Y14, Y15 + VMOVDQU Y1, (AX) + VMOVDQU Y3, 32(AX) + VMOVDQU Y5, 64(AX) + VMOVDQU Y7, 96(AX) + VMOVDQU Y9, 128(AX) + VMOVDQU Y11, 160(AX) + VMOVDQU Y13, 192(AX) + VMOVDQU Y15, 224(AX) + VMOVDQU 256(CX), Y0 + VMOVDQU 288(CX), Y2 + VMOVDQU 320(CX), Y4 + VMOVDQU 352(CX), Y6 + VMOVDQU 384(CX), Y8 + VMOVDQU 416(CX), Y10 + VMOVDQU 448(CX), Y12 + VMOVDQU 480(CX), Y14 + VMOVDQU 256(DX), Y1 + VMOVDQU 288(DX), Y3 + VMOVDQU 320(DX), Y5 + VMOVDQU 352(DX), Y7 + VMOVDQU 384(DX), Y9 + VMOVDQU 416(DX), Y11 + VMOVDQU 448(DX), Y13 + VMOVDQU 480(DX), Y15 + VPSUBW Y1, Y0, Y1 + VPSUBW Y3, Y2, Y3 + VPSUBW Y5, Y4, Y5 + VPSUBW Y7, Y6, Y7 + VPSUBW Y9, Y8, Y9 + VPSUBW Y11, Y10, Y11 + VPSUBW Y13, Y12, Y13 + VPSUBW Y15, Y14, Y15 + VMOVDQU Y1, 256(AX) + VMOVDQU Y3, 288(AX) + VMOVDQU Y5, 320(AX) + VMOVDQU Y7, 352(AX) + VMOVDQU Y9, 384(AX) + VMOVDQU Y11, 416(AX) + VMOVDQU Y13, 448(AX) + VMOVDQU Y15, 480(AX) + RET + +// func nttAVX2(p *[256]int16) +// Requires: AVX, AVX2 +TEXT ·nttAVX2(SB), NOSPLIT, $0-8 + MOVQ p+0(FP), AX + LEAQ ·ZetasAVX2+0(SB), CX + MOVL $0x00000d01, DX + VMOVD DX, X0 + VPBROADCASTW X0, Y15 + VPBROADCASTW (CX), Y0 + VPBROADCASTW 2(CX), Y1 + VMOVDQU (AX), Y7 + VMOVDQU 32(AX), Y8 + VMOVDQU 64(AX), Y9 + VMOVDQU 96(AX), Y10 + VMOVDQU 256(AX), Y11 + VMOVDQU 288(AX), Y12 + VMOVDQU 320(AX), Y13 + VMOVDQU 352(AX), Y14 + VPMULLW Y11, Y0, Y2 + VPMULLW Y12, Y0, Y3 + VPMULLW Y13, Y0, Y4 + VPMULLW Y14, Y0, Y5 + VPMULHW Y11, Y1, Y11 + VPMULHW Y12, Y1, Y12 + VPMULHW Y13, Y1, Y13 + VPMULHW Y14, Y1, Y14 + VPMULHW Y2, Y15, Y2 + VPMULHW Y3, Y15, Y3 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPSUBW Y2, Y11, Y2 + VPSUBW Y3, Y12, Y3 + VPSUBW Y4, Y13, Y4 + VPSUBW Y5, Y14, Y5 + VPSUBW Y2, Y7, Y11 + VPSUBW Y3, Y8, Y12 + VPSUBW Y4, Y9, Y13 + VPSUBW Y5, Y10, Y14 + VPADDW Y2, Y7, Y7 + VPADDW Y3, Y8, Y8 + VPADDW Y4, Y9, Y9 + VPADDW Y5, Y10, Y10 + VMOVDQU Y7, (AX) + VMOVDQU Y8, 32(AX) + VMOVDQU Y9, 64(AX) + VMOVDQU Y10, 96(AX) + VMOVDQU Y11, 256(AX) + VMOVDQU Y12, 288(AX) + VMOVDQU Y13, 320(AX) + VMOVDQU Y14, 352(AX) + VMOVDQU 128(AX), Y7 + VMOVDQU 160(AX), Y8 + VMOVDQU 192(AX), Y9 + VMOVDQU 224(AX), Y10 + VMOVDQU 384(AX), Y11 + VMOVDQU 416(AX), Y12 + VMOVDQU 448(AX), Y13 + VMOVDQU 480(AX), Y14 + VPMULLW Y11, Y0, Y2 + VPMULLW Y12, Y0, Y3 + VPMULLW Y13, Y0, Y4 + VPMULLW Y14, Y0, Y5 + VPMULHW Y11, Y1, Y11 + VPMULHW Y12, Y1, Y12 + VPMULHW Y13, Y1, Y13 + VPMULHW Y14, Y1, Y14 + VPMULHW Y2, Y15, Y2 + VPMULHW Y3, Y15, Y3 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPSUBW Y2, Y11, Y2 + VPSUBW Y3, Y12, Y3 + VPSUBW Y4, Y13, Y4 + VPSUBW Y5, Y14, Y5 + VPSUBW Y2, Y7, Y11 + VPSUBW Y3, Y8, Y12 + VPSUBW Y4, Y9, Y13 + VPSUBW Y5, Y10, Y14 + VPADDW Y2, Y7, Y7 + VPADDW Y3, Y8, Y8 + VPADDW Y4, Y9, Y9 + VPADDW Y5, Y10, Y10 + VMOVDQU Y7, 128(AX) + VMOVDQU Y8, 160(AX) + VMOVDQU Y9, 192(AX) + VMOVDQU Y10, 224(AX) + VMOVDQU Y11, 384(AX) + VMOVDQU Y12, 416(AX) + VMOVDQU Y13, 448(AX) + VMOVDQU Y14, 480(AX) + VPBROADCASTW 4(CX), Y0 + VPBROADCASTW 6(CX), Y1 + VMOVDQU (AX), Y7 + VMOVDQU 32(AX), Y8 + VMOVDQU 64(AX), Y9 + VMOVDQU 96(AX), Y10 + VMOVDQU 128(AX), Y11 + VMOVDQU 160(AX), Y12 + VMOVDQU 192(AX), Y13 + VMOVDQU 224(AX), Y14 + VPMULLW Y11, Y0, Y2 + VPMULLW Y12, Y0, Y3 + VPMULLW Y13, Y0, Y4 + VPMULLW Y14, Y0, Y5 + VPMULHW Y11, Y1, Y11 + VPMULHW Y12, Y1, Y12 + VPMULHW Y13, Y1, Y13 + VPMULHW Y14, Y1, Y14 + VPMULHW Y2, Y15, Y2 + VPMULHW Y3, Y15, Y3 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPSUBW Y2, Y11, Y2 + VPSUBW Y3, Y12, Y3 + VPSUBW Y4, Y13, Y4 + VPSUBW Y5, Y14, Y5 + VPSUBW Y2, Y7, Y11 + VPSUBW Y3, Y8, Y12 + VPSUBW Y4, Y9, Y13 + VPSUBW Y5, Y10, Y14 + VPADDW Y2, Y7, Y7 + VPADDW Y3, Y8, Y8 + VPADDW Y4, Y9, Y9 + VPADDW Y5, Y10, Y10 + VPBROADCASTW 12(CX), Y0 + VPBROADCASTW 14(CX), Y1 + VPBROADCASTW 16(CX), Y2 + VPBROADCASTW 18(CX), Y3 + VPMULLW Y9, Y0, Y4 + VPMULLW Y10, Y0, Y5 + VPMULLW Y13, Y2, Y6 + VPMULLW Y14, Y2, Y0 + VPMULHW Y9, Y1, Y9 + VPMULHW Y10, Y1, Y10 + VPMULHW Y13, Y3, Y13 + VPMULHW Y14, Y3, Y14 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPMULHW Y6, Y15, Y6 + VPMULHW Y0, Y15, Y0 + VPSUBW Y4, Y9, Y4 + VPSUBW Y5, Y10, Y5 + VPSUBW Y6, Y13, Y6 + VPSUBW Y0, Y14, Y0 + VPSUBW Y4, Y7, Y9 + VPSUBW Y5, Y8, Y10 + VPSUBW Y6, Y11, Y13 + VPSUBW Y0, Y12, Y14 + VPADDW Y4, Y7, Y7 + VPADDW Y5, Y8, Y8 + VPADDW Y6, Y11, Y11 + VPADDW Y0, Y12, Y12 + VMOVDQU 32(CX), Y0 + VMOVDQU 64(CX), Y1 + VMOVDQU 96(CX), Y2 + VMOVDQU 128(CX), Y3 + VPERM2I128 $0x20, Y9, Y7, Y4 + VPERM2I128 $0x31, Y9, Y7, Y9 + VMOVDQA Y4, Y7 + VPERM2I128 $0x20, Y10, Y8, Y4 + VPERM2I128 $0x31, Y10, Y8, Y10 + VMOVDQA Y4, Y8 + VPERM2I128 $0x20, Y13, Y11, Y4 + VPERM2I128 $0x31, Y13, Y11, Y13 + VMOVDQA Y4, Y11 + VPERM2I128 $0x20, Y14, Y12, Y4 + VPERM2I128 $0x31, Y14, Y12, Y14 + VMOVDQA Y4, Y12 + VPMULLW Y8, Y0, Y4 + VPMULLW Y10, Y0, Y5 + VPMULLW Y12, Y2, Y6 + VPMULLW Y14, Y2, Y0 + VPMULHW Y8, Y1, Y8 + VPMULHW Y10, Y1, Y10 + VPMULHW Y12, Y3, Y12 + VPMULHW Y14, Y3, Y14 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPMULHW Y6, Y15, Y6 + VPMULHW Y0, Y15, Y0 + VPSUBW Y4, Y8, Y4 + VPSUBW Y5, Y10, Y5 + VPSUBW Y6, Y12, Y6 + VPSUBW Y0, Y14, Y0 + VPSUBW Y4, Y7, Y8 + VPSUBW Y5, Y9, Y10 + VPSUBW Y6, Y11, Y12 + VPSUBW Y0, Y13, Y14 + VPADDW Y4, Y7, Y7 + VPADDW Y5, Y9, Y9 + VPADDW Y6, Y11, Y11 + VPADDW Y0, Y13, Y13 + VMOVDQU 288(CX), Y0 + VMOVDQU 320(CX), Y1 + VMOVDQU 352(CX), Y2 + VMOVDQU 384(CX), Y3 + VPUNPCKLQDQ Y8, Y7, Y4 + VPUNPCKHQDQ Y8, Y7, Y8 + VMOVDQA Y4, Y7 + VPUNPCKLQDQ Y10, Y9, Y4 + VPUNPCKHQDQ Y10, Y9, Y10 + VMOVDQA Y4, Y9 + VPUNPCKLQDQ Y12, Y11, Y4 + VPUNPCKHQDQ Y12, Y11, Y12 + VMOVDQA Y4, Y11 + VPUNPCKLQDQ Y14, Y13, Y4 + VPUNPCKHQDQ Y14, Y13, Y14 + VMOVDQA Y4, Y13 + VPMULLW Y9, Y0, Y4 + VPMULLW Y10, Y0, Y5 + VPMULLW Y13, Y2, Y6 + VPMULLW Y14, Y2, Y0 + VPMULHW Y9, Y1, Y9 + VPMULHW Y10, Y1, Y10 + VPMULHW Y13, Y3, Y13 + VPMULHW Y14, Y3, Y14 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPMULHW Y6, Y15, Y6 + VPMULHW Y0, Y15, Y0 + VPSUBW Y4, Y9, Y4 + VPSUBW Y5, Y10, Y5 + VPSUBW Y6, Y13, Y6 + VPSUBW Y0, Y14, Y0 + VPSUBW Y4, Y7, Y9 + VPSUBW Y5, Y8, Y10 + VPSUBW Y6, Y11, Y13 + VPSUBW Y0, Y12, Y14 + VPADDW Y4, Y7, Y7 + VPADDW Y5, Y8, Y8 + VPADDW Y6, Y11, Y11 + VPADDW Y0, Y12, Y12 + VMOVDQU 544(CX), Y0 + VMOVDQU 576(CX), Y1 + VMOVDQU 608(CX), Y2 + VMOVDQU 640(CX), Y3 + VMOVSLDUP Y9, Y4 + VPBLENDD $0xaa, Y4, Y7, Y4 + VPSRLQ $0x20, Y7, Y7 + VPBLENDD $0xaa, Y9, Y7, Y9 + VMOVDQA Y4, Y7 + VMOVSLDUP Y10, Y4 + VPBLENDD $0xaa, Y4, Y8, Y4 + VPSRLQ $0x20, Y8, Y8 + VPBLENDD $0xaa, Y10, Y8, Y10 + VMOVDQA Y4, Y8 + VMOVSLDUP Y13, Y4 + VPBLENDD $0xaa, Y4, Y11, Y4 + VPSRLQ $0x20, Y11, Y11 + VPBLENDD $0xaa, Y13, Y11, Y13 + VMOVDQA Y4, Y11 + VMOVSLDUP Y14, Y4 + VPBLENDD $0xaa, Y4, Y12, Y4 + VPSRLQ $0x20, Y12, Y12 + VPBLENDD $0xaa, Y14, Y12, Y14 + VMOVDQA Y4, Y12 + VPMULLW Y8, Y0, Y4 + VPMULLW Y10, Y0, Y5 + VPMULLW Y12, Y2, Y6 + VPMULLW Y14, Y2, Y0 + VPMULHW Y8, Y1, Y8 + VPMULHW Y10, Y1, Y10 + VPMULHW Y12, Y3, Y12 + VPMULHW Y14, Y3, Y14 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPMULHW Y6, Y15, Y6 + VPMULHW Y0, Y15, Y0 + VPSUBW Y4, Y8, Y4 + VPSUBW Y5, Y10, Y5 + VPSUBW Y6, Y12, Y6 + VPSUBW Y0, Y14, Y0 + VPSUBW Y4, Y7, Y8 + VPSUBW Y5, Y9, Y10 + VPSUBW Y6, Y11, Y12 + VPSUBW Y0, Y13, Y14 + VPADDW Y4, Y7, Y7 + VPADDW Y5, Y9, Y9 + VPADDW Y6, Y11, Y11 + VPADDW Y0, Y13, Y13 + VMOVDQU 800(CX), Y0 + VMOVDQU 832(CX), Y1 + VMOVDQU 864(CX), Y2 + VMOVDQU 896(CX), Y3 + VPSLLD $0x10, Y8, Y4 + VPBLENDW $0xaa, Y4, Y7, Y4 + VPSRLD $0x10, Y7, Y7 + VPBLENDW $0xaa, Y8, Y7, Y8 + VMOVDQA Y4, Y7 + VPSLLD $0x10, Y10, Y4 + VPBLENDW $0xaa, Y4, Y9, Y4 + VPSRLD $0x10, Y9, Y9 + VPBLENDW $0xaa, Y10, Y9, Y10 + VMOVDQA Y4, Y9 + VPSLLD $0x10, Y12, Y4 + VPBLENDW $0xaa, Y4, Y11, Y4 + VPSRLD $0x10, Y11, Y11 + VPBLENDW $0xaa, Y12, Y11, Y12 + VMOVDQA Y4, Y11 + VPSLLD $0x10, Y14, Y4 + VPBLENDW $0xaa, Y4, Y13, Y4 + VPSRLD $0x10, Y13, Y13 + VPBLENDW $0xaa, Y14, Y13, Y14 + VMOVDQA Y4, Y13 + VPMULLW Y9, Y0, Y4 + VPMULLW Y10, Y0, Y5 + VPMULLW Y13, Y2, Y6 + VPMULLW Y14, Y2, Y0 + VPMULHW Y9, Y1, Y9 + VPMULHW Y10, Y1, Y10 + VPMULHW Y13, Y3, Y13 + VPMULHW Y14, Y3, Y14 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPMULHW Y6, Y15, Y6 + VPMULHW Y0, Y15, Y0 + VPSUBW Y4, Y9, Y4 + VPSUBW Y5, Y10, Y5 + VPSUBW Y6, Y13, Y6 + VPSUBW Y0, Y14, Y0 + VPSUBW Y4, Y7, Y9 + VPSUBW Y5, Y8, Y10 + VPSUBW Y6, Y11, Y13 + VPSUBW Y0, Y12, Y14 + VPADDW Y4, Y7, Y7 + VPADDW Y5, Y8, Y8 + VPADDW Y6, Y11, Y11 + VPADDW Y0, Y12, Y12 + VMOVDQU Y7, (AX) + VMOVDQU Y8, 32(AX) + VMOVDQU Y9, 64(AX) + VMOVDQU Y10, 96(AX) + VMOVDQU Y11, 128(AX) + VMOVDQU Y12, 160(AX) + VMOVDQU Y13, 192(AX) + VMOVDQU Y14, 224(AX) + VPBROADCASTW 8(CX), Y0 + VPBROADCASTW 10(CX), Y1 + VMOVDQU 256(AX), Y7 + VMOVDQU 288(AX), Y8 + VMOVDQU 320(AX), Y9 + VMOVDQU 352(AX), Y10 + VMOVDQU 384(AX), Y11 + VMOVDQU 416(AX), Y12 + VMOVDQU 448(AX), Y13 + VMOVDQU 480(AX), Y14 + VPMULLW Y11, Y0, Y2 + VPMULLW Y12, Y0, Y3 + VPMULLW Y13, Y0, Y4 + VPMULLW Y14, Y0, Y5 + VPMULHW Y11, Y1, Y11 + VPMULHW Y12, Y1, Y12 + VPMULHW Y13, Y1, Y13 + VPMULHW Y14, Y1, Y14 + VPMULHW Y2, Y15, Y2 + VPMULHW Y3, Y15, Y3 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPSUBW Y2, Y11, Y2 + VPSUBW Y3, Y12, Y3 + VPSUBW Y4, Y13, Y4 + VPSUBW Y5, Y14, Y5 + VPSUBW Y2, Y7, Y11 + VPSUBW Y3, Y8, Y12 + VPSUBW Y4, Y9, Y13 + VPSUBW Y5, Y10, Y14 + VPADDW Y2, Y7, Y7 + VPADDW Y3, Y8, Y8 + VPADDW Y4, Y9, Y9 + VPADDW Y5, Y10, Y10 + VPBROADCASTW 20(CX), Y0 + VPBROADCASTW 22(CX), Y1 + VPBROADCASTW 24(CX), Y2 + VPBROADCASTW 26(CX), Y3 + VPMULLW Y9, Y0, Y4 + VPMULLW Y10, Y0, Y5 + VPMULLW Y13, Y2, Y6 + VPMULLW Y14, Y2, Y0 + VPMULHW Y9, Y1, Y9 + VPMULHW Y10, Y1, Y10 + VPMULHW Y13, Y3, Y13 + VPMULHW Y14, Y3, Y14 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPMULHW Y6, Y15, Y6 + VPMULHW Y0, Y15, Y0 + VPSUBW Y4, Y9, Y4 + VPSUBW Y5, Y10, Y5 + VPSUBW Y6, Y13, Y6 + VPSUBW Y0, Y14, Y0 + VPSUBW Y4, Y7, Y9 + VPSUBW Y5, Y8, Y10 + VPSUBW Y6, Y11, Y13 + VPSUBW Y0, Y12, Y14 + VPADDW Y4, Y7, Y7 + VPADDW Y5, Y8, Y8 + VPADDW Y6, Y11, Y11 + VPADDW Y0, Y12, Y12 + VMOVDQU 160(CX), Y0 + VMOVDQU 192(CX), Y1 + VMOVDQU 224(CX), Y2 + VMOVDQU 256(CX), Y3 + VPERM2I128 $0x20, Y9, Y7, Y4 + VPERM2I128 $0x31, Y9, Y7, Y9 + VMOVDQA Y4, Y7 + VPERM2I128 $0x20, Y10, Y8, Y4 + VPERM2I128 $0x31, Y10, Y8, Y10 + VMOVDQA Y4, Y8 + VPERM2I128 $0x20, Y13, Y11, Y4 + VPERM2I128 $0x31, Y13, Y11, Y13 + VMOVDQA Y4, Y11 + VPERM2I128 $0x20, Y14, Y12, Y4 + VPERM2I128 $0x31, Y14, Y12, Y14 + VMOVDQA Y4, Y12 + VPMULLW Y8, Y0, Y4 + VPMULLW Y10, Y0, Y5 + VPMULLW Y12, Y2, Y6 + VPMULLW Y14, Y2, Y0 + VPMULHW Y8, Y1, Y8 + VPMULHW Y10, Y1, Y10 + VPMULHW Y12, Y3, Y12 + VPMULHW Y14, Y3, Y14 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPMULHW Y6, Y15, Y6 + VPMULHW Y0, Y15, Y0 + VPSUBW Y4, Y8, Y4 + VPSUBW Y5, Y10, Y5 + VPSUBW Y6, Y12, Y6 + VPSUBW Y0, Y14, Y0 + VPSUBW Y4, Y7, Y8 + VPSUBW Y5, Y9, Y10 + VPSUBW Y6, Y11, Y12 + VPSUBW Y0, Y13, Y14 + VPADDW Y4, Y7, Y7 + VPADDW Y5, Y9, Y9 + VPADDW Y6, Y11, Y11 + VPADDW Y0, Y13, Y13 + VMOVDQU 416(CX), Y0 + VMOVDQU 448(CX), Y1 + VMOVDQU 480(CX), Y2 + VMOVDQU 512(CX), Y3 + VPUNPCKLQDQ Y8, Y7, Y4 + VPUNPCKHQDQ Y8, Y7, Y8 + VMOVDQA Y4, Y7 + VPUNPCKLQDQ Y10, Y9, Y4 + VPUNPCKHQDQ Y10, Y9, Y10 + VMOVDQA Y4, Y9 + VPUNPCKLQDQ Y12, Y11, Y4 + VPUNPCKHQDQ Y12, Y11, Y12 + VMOVDQA Y4, Y11 + VPUNPCKLQDQ Y14, Y13, Y4 + VPUNPCKHQDQ Y14, Y13, Y14 + VMOVDQA Y4, Y13 + VPMULLW Y9, Y0, Y4 + VPMULLW Y10, Y0, Y5 + VPMULLW Y13, Y2, Y6 + VPMULLW Y14, Y2, Y0 + VPMULHW Y9, Y1, Y9 + VPMULHW Y10, Y1, Y10 + VPMULHW Y13, Y3, Y13 + VPMULHW Y14, Y3, Y14 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPMULHW Y6, Y15, Y6 + VPMULHW Y0, Y15, Y0 + VPSUBW Y4, Y9, Y4 + VPSUBW Y5, Y10, Y5 + VPSUBW Y6, Y13, Y6 + VPSUBW Y0, Y14, Y0 + VPSUBW Y4, Y7, Y9 + VPSUBW Y5, Y8, Y10 + VPSUBW Y6, Y11, Y13 + VPSUBW Y0, Y12, Y14 + VPADDW Y4, Y7, Y7 + VPADDW Y5, Y8, Y8 + VPADDW Y6, Y11, Y11 + VPADDW Y0, Y12, Y12 + VMOVDQU 672(CX), Y0 + VMOVDQU 704(CX), Y1 + VMOVDQU 736(CX), Y2 + VMOVDQU 768(CX), Y3 + VMOVSLDUP Y9, Y4 + VPBLENDD $0xaa, Y4, Y7, Y4 + VPSRLQ $0x20, Y7, Y7 + VPBLENDD $0xaa, Y9, Y7, Y9 + VMOVDQA Y4, Y7 + VMOVSLDUP Y10, Y4 + VPBLENDD $0xaa, Y4, Y8, Y4 + VPSRLQ $0x20, Y8, Y8 + VPBLENDD $0xaa, Y10, Y8, Y10 + VMOVDQA Y4, Y8 + VMOVSLDUP Y13, Y4 + VPBLENDD $0xaa, Y4, Y11, Y4 + VPSRLQ $0x20, Y11, Y11 + VPBLENDD $0xaa, Y13, Y11, Y13 + VMOVDQA Y4, Y11 + VMOVSLDUP Y14, Y4 + VPBLENDD $0xaa, Y4, Y12, Y4 + VPSRLQ $0x20, Y12, Y12 + VPBLENDD $0xaa, Y14, Y12, Y14 + VMOVDQA Y4, Y12 + VPMULLW Y8, Y0, Y4 + VPMULLW Y10, Y0, Y5 + VPMULLW Y12, Y2, Y6 + VPMULLW Y14, Y2, Y0 + VPMULHW Y8, Y1, Y8 + VPMULHW Y10, Y1, Y10 + VPMULHW Y12, Y3, Y12 + VPMULHW Y14, Y3, Y14 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPMULHW Y6, Y15, Y6 + VPMULHW Y0, Y15, Y0 + VPSUBW Y4, Y8, Y4 + VPSUBW Y5, Y10, Y5 + VPSUBW Y6, Y12, Y6 + VPSUBW Y0, Y14, Y0 + VPSUBW Y4, Y7, Y8 + VPSUBW Y5, Y9, Y10 + VPSUBW Y6, Y11, Y12 + VPSUBW Y0, Y13, Y14 + VPADDW Y4, Y7, Y7 + VPADDW Y5, Y9, Y9 + VPADDW Y6, Y11, Y11 + VPADDW Y0, Y13, Y13 + VMOVDQU 928(CX), Y0 + VMOVDQU 960(CX), Y1 + VMOVDQU 992(CX), Y2 + VMOVDQU 1024(CX), Y3 + VPSLLD $0x10, Y8, Y4 + VPBLENDW $0xaa, Y4, Y7, Y4 + VPSRLD $0x10, Y7, Y7 + VPBLENDW $0xaa, Y8, Y7, Y8 + VMOVDQA Y4, Y7 + VPSLLD $0x10, Y10, Y4 + VPBLENDW $0xaa, Y4, Y9, Y4 + VPSRLD $0x10, Y9, Y9 + VPBLENDW $0xaa, Y10, Y9, Y10 + VMOVDQA Y4, Y9 + VPSLLD $0x10, Y12, Y4 + VPBLENDW $0xaa, Y4, Y11, Y4 + VPSRLD $0x10, Y11, Y11 + VPBLENDW $0xaa, Y12, Y11, Y12 + VMOVDQA Y4, Y11 + VPSLLD $0x10, Y14, Y4 + VPBLENDW $0xaa, Y4, Y13, Y4 + VPSRLD $0x10, Y13, Y13 + VPBLENDW $0xaa, Y14, Y13, Y14 + VMOVDQA Y4, Y13 + VPMULLW Y9, Y0, Y4 + VPMULLW Y10, Y0, Y5 + VPMULLW Y13, Y2, Y6 + VPMULLW Y14, Y2, Y0 + VPMULHW Y9, Y1, Y9 + VPMULHW Y10, Y1, Y10 + VPMULHW Y13, Y3, Y13 + VPMULHW Y14, Y3, Y14 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPMULHW Y6, Y15, Y6 + VPMULHW Y0, Y15, Y0 + VPSUBW Y4, Y9, Y4 + VPSUBW Y5, Y10, Y5 + VPSUBW Y6, Y13, Y6 + VPSUBW Y0, Y14, Y0 + VPSUBW Y4, Y7, Y9 + VPSUBW Y5, Y8, Y10 + VPSUBW Y6, Y11, Y13 + VPSUBW Y0, Y12, Y14 + VPADDW Y4, Y7, Y7 + VPADDW Y5, Y8, Y8 + VPADDW Y6, Y11, Y11 + VPADDW Y0, Y12, Y12 + VMOVDQU Y7, 256(AX) + VMOVDQU Y8, 288(AX) + VMOVDQU Y9, 320(AX) + VMOVDQU Y10, 352(AX) + VMOVDQU Y11, 384(AX) + VMOVDQU Y12, 416(AX) + VMOVDQU Y13, 448(AX) + VMOVDQU Y14, 480(AX) + RET + +// func invNttAVX2(p *[256]int16) +// Requires: AVX, AVX2 +TEXT ·invNttAVX2(SB), NOSPLIT, $0-8 + MOVQ p+0(FP), AX + LEAQ ·ZetasAVX2+0(SB), CX + MOVL $0x00000d01, DX + VMOVD DX, X0 + VPBROADCASTW X0, Y15 + VMOVDQU (AX), Y7 + VMOVDQU 32(AX), Y8 + VMOVDQU 64(AX), Y9 + VMOVDQU 96(AX), Y10 + VMOVDQU 128(AX), Y11 + VMOVDQU 160(AX), Y12 + VMOVDQU 192(AX), Y13 + VMOVDQU 224(AX), Y14 + VMOVDQU 1056(CX), Y0 + VMOVDQU 1088(CX), Y1 + VMOVDQU 1120(CX), Y2 + VMOVDQU 1152(CX), Y3 + VPSUBW Y7, Y9, Y4 + VPSUBW Y8, Y10, Y5 + VPSUBW Y11, Y13, Y6 + VPADDW Y7, Y9, Y7 + VPADDW Y8, Y10, Y8 + VPADDW Y11, Y13, Y11 + VPMULLW Y4, Y0, Y9 + VPMULLW Y5, Y0, Y10 + VPSUBW Y12, Y14, Y0 + VPMULLW Y6, Y2, Y13 + VPADDW Y12, Y14, Y12 + VPMULLW Y0, Y2, Y14 + VPMULHW Y4, Y1, Y4 + VPMULHW Y5, Y1, Y5 + VPMULHW Y6, Y3, Y6 + VPMULHW Y0, Y3, Y0 + VPMULHW Y9, Y15, Y9 + VPMULHW Y10, Y15, Y10 + VPMULHW Y13, Y15, Y13 + VPMULHW Y14, Y15, Y14 + VPSUBW Y9, Y4, Y9 + VPSUBW Y10, Y5, Y10 + VPSUBW Y13, Y6, Y13 + VPSUBW Y14, Y0, Y14 + VMOVDQU 1312(CX), Y0 + VMOVDQU 1344(CX), Y1 + VMOVDQU 1376(CX), Y2 + VMOVDQU 1408(CX), Y3 + VPSLLD $0x10, Y8, Y4 + VPBLENDW $0xaa, Y4, Y7, Y4 + VPSRLD $0x10, Y7, Y7 + VPBLENDW $0xaa, Y8, Y7, Y8 + VMOVDQA Y4, Y7 + VPSLLD $0x10, Y10, Y4 + VPBLENDW $0xaa, Y4, Y9, Y4 + VPSRLD $0x10, Y9, Y9 + VPBLENDW $0xaa, Y10, Y9, Y10 + VMOVDQA Y4, Y9 + VPSLLD $0x10, Y12, Y4 + VPBLENDW $0xaa, Y4, Y11, Y4 + VPSRLD $0x10, Y11, Y11 + VPBLENDW $0xaa, Y12, Y11, Y12 + VMOVDQA Y4, Y11 + VPSLLD $0x10, Y14, Y4 + VPBLENDW $0xaa, Y4, Y13, Y4 + VPSRLD $0x10, Y13, Y13 + VPBLENDW $0xaa, Y14, Y13, Y14 + VMOVDQA Y4, Y13 + VPSUBW Y7, Y8, Y4 + VPSUBW Y9, Y10, Y5 + VPSUBW Y11, Y12, Y6 + VPADDW Y7, Y8, Y7 + VPADDW Y9, Y10, Y9 + VPADDW Y11, Y12, Y11 + VPMULLW Y4, Y0, Y8 + VPMULLW Y5, Y0, Y10 + VPSUBW Y13, Y14, Y0 + VPMULLW Y6, Y2, Y12 + VPADDW Y13, Y14, Y13 + VPMULLW Y0, Y2, Y14 + VPMULHW Y4, Y1, Y4 + VPMULHW Y5, Y1, Y5 + VPMULHW Y6, Y3, Y6 + VPMULHW Y0, Y3, Y0 + VPMULHW Y8, Y15, Y8 + VPMULHW Y10, Y15, Y10 + VPMULHW Y12, Y15, Y12 + VPMULHW Y14, Y15, Y14 + VPSUBW Y8, Y4, Y8 + VPSUBW Y10, Y5, Y10 + VPSUBW Y12, Y6, Y12 + VPSUBW Y14, Y0, Y14 + VMOVDQU 1568(CX), Y0 + VMOVDQU 1600(CX), Y1 + VMOVDQU 1632(CX), Y2 + VMOVDQU 1664(CX), Y3 + VMOVSLDUP Y9, Y4 + VPBLENDD $0xaa, Y4, Y7, Y4 + VPSRLQ $0x20, Y7, Y7 + VPBLENDD $0xaa, Y9, Y7, Y9 + VMOVDQA Y4, Y7 + VMOVSLDUP Y10, Y4 + VPBLENDD $0xaa, Y4, Y8, Y4 + VPSRLQ $0x20, Y8, Y8 + VPBLENDD $0xaa, Y10, Y8, Y10 + VMOVDQA Y4, Y8 + VMOVSLDUP Y13, Y4 + VPBLENDD $0xaa, Y4, Y11, Y4 + VPSRLQ $0x20, Y11, Y11 + VPBLENDD $0xaa, Y13, Y11, Y13 + VMOVDQA Y4, Y11 + VMOVSLDUP Y14, Y4 + VPBLENDD $0xaa, Y4, Y12, Y4 + VPSRLQ $0x20, Y12, Y12 + VPBLENDD $0xaa, Y14, Y12, Y14 + VMOVDQA Y4, Y12 + VPSUBW Y7, Y9, Y4 + VPSUBW Y8, Y10, Y5 + VPSUBW Y11, Y13, Y6 + VPADDW Y7, Y9, Y7 + VPADDW Y8, Y10, Y8 + VPADDW Y11, Y13, Y11 + VPMULLW Y4, Y0, Y9 + VPMULLW Y5, Y0, Y10 + VPSUBW Y12, Y14, Y0 + VPMULLW Y6, Y2, Y13 + VPADDW Y12, Y14, Y12 + VPMULLW Y0, Y2, Y14 + VPMULHW Y4, Y1, Y4 + VPMULHW Y5, Y1, Y5 + VPMULHW Y6, Y3, Y6 + VPMULHW Y0, Y3, Y0 + VPMULHW Y9, Y15, Y9 + VPMULHW Y10, Y15, Y10 + VPMULHW Y13, Y15, Y13 + VPMULHW Y14, Y15, Y14 + VPSUBW Y9, Y4, Y9 + VPSUBW Y10, Y5, Y10 + VPSUBW Y13, Y6, Y13 + VPSUBW Y14, Y0, Y14 + MOVL $0x00004ebf, DX + VMOVD DX, X0 + VPBROADCASTW X0, Y4 + VPMULHW Y4, Y7, Y5 + VPSRAW $0x0a, Y5, Y5 + VPMULLW Y15, Y5, Y5 + VPSUBW Y5, Y7, Y7 + VPMULHW Y4, Y11, Y5 + VPSRAW $0x0a, Y5, Y5 + VPMULLW Y15, Y5, Y5 + VPSUBW Y5, Y11, Y11 + VMOVDQU 1824(CX), Y0 + VMOVDQU 1856(CX), Y1 + VMOVDQU 1888(CX), Y2 + VMOVDQU 1920(CX), Y3 + VPUNPCKLQDQ Y8, Y7, Y4 + VPUNPCKHQDQ Y8, Y7, Y8 + VMOVDQA Y4, Y7 + VPUNPCKLQDQ Y10, Y9, Y4 + VPUNPCKHQDQ Y10, Y9, Y10 + VMOVDQA Y4, Y9 + VPUNPCKLQDQ Y12, Y11, Y4 + VPUNPCKHQDQ Y12, Y11, Y12 + VMOVDQA Y4, Y11 + VPUNPCKLQDQ Y14, Y13, Y4 + VPUNPCKHQDQ Y14, Y13, Y14 + VMOVDQA Y4, Y13 + VPSUBW Y7, Y8, Y4 + VPSUBW Y9, Y10, Y5 + VPSUBW Y11, Y12, Y6 + VPADDW Y7, Y8, Y7 + VPADDW Y9, Y10, Y9 + VPADDW Y11, Y12, Y11 + VPMULLW Y4, Y0, Y8 + VPMULLW Y5, Y0, Y10 + VPSUBW Y13, Y14, Y0 + VPMULLW Y6, Y2, Y12 + VPADDW Y13, Y14, Y13 + VPMULLW Y0, Y2, Y14 + VPMULHW Y4, Y1, Y4 + VPMULHW Y5, Y1, Y5 + VPMULHW Y6, Y3, Y6 + VPMULHW Y0, Y3, Y0 + VPMULHW Y8, Y15, Y8 + VPMULHW Y10, Y15, Y10 + VPMULHW Y12, Y15, Y12 + VPMULHW Y14, Y15, Y14 + VPSUBW Y8, Y4, Y8 + VPSUBW Y10, Y5, Y10 + VPSUBW Y12, Y6, Y12 + VPSUBW Y14, Y0, Y14 + VPBROADCASTW 2080(CX), Y0 + VPBROADCASTW 2082(CX), Y1 + VPBROADCASTW 2084(CX), Y2 + VPBROADCASTW 2086(CX), Y3 + VPERM2I128 $0x20, Y9, Y7, Y4 + VPERM2I128 $0x31, Y9, Y7, Y9 + VMOVDQA Y4, Y7 + VPERM2I128 $0x20, Y10, Y8, Y4 + VPERM2I128 $0x31, Y10, Y8, Y10 + VMOVDQA Y4, Y8 + VPERM2I128 $0x20, Y13, Y11, Y4 + VPERM2I128 $0x31, Y13, Y11, Y13 + VMOVDQA Y4, Y11 + VPERM2I128 $0x20, Y14, Y12, Y4 + VPERM2I128 $0x31, Y14, Y12, Y14 + VMOVDQA Y4, Y12 + VPSUBW Y7, Y9, Y4 + VPSUBW Y8, Y10, Y5 + VPSUBW Y11, Y13, Y6 + VPADDW Y7, Y9, Y7 + VPADDW Y8, Y10, Y8 + VPADDW Y11, Y13, Y11 + VPMULLW Y4, Y0, Y9 + VPMULLW Y5, Y0, Y10 + VPSUBW Y12, Y14, Y0 + VPMULLW Y6, Y2, Y13 + VPADDW Y12, Y14, Y12 + VPMULLW Y0, Y2, Y14 + VPMULHW Y4, Y1, Y4 + VPMULHW Y5, Y1, Y5 + VPMULHW Y6, Y3, Y6 + VPMULHW Y0, Y3, Y0 + VPMULHW Y9, Y15, Y9 + VPMULHW Y10, Y15, Y10 + VPMULHW Y13, Y15, Y13 + VPMULHW Y14, Y15, Y14 + VPSUBW Y9, Y4, Y9 + VPSUBW Y10, Y5, Y10 + VPSUBW Y13, Y6, Y13 + VPSUBW Y14, Y0, Y14 + MOVL $0x00004ebf, DX + VMOVD DX, X0 + VPBROADCASTW X0, Y4 + VPMULHW Y4, Y7, Y5 + VPSRAW $0x0a, Y5, Y5 + VPMULLW Y15, Y5, Y5 + VPSUBW Y5, Y7, Y7 + VPMULHW Y4, Y11, Y5 + VPSRAW $0x0a, Y5, Y5 + VPMULLW Y15, Y5, Y5 + VPSUBW Y5, Y11, Y11 + VPBROADCASTW 2096(CX), Y0 + VPBROADCASTW 2098(CX), Y1 + VPSUBW Y7, Y11, Y4 + VPSUBW Y8, Y12, Y5 + VPSUBW Y9, Y13, Y6 + VPADDW Y7, Y11, Y7 + VPADDW Y8, Y12, Y8 + VPADDW Y9, Y13, Y9 + VPMULLW Y4, Y0, Y11 + VPMULLW Y5, Y0, Y12 + VPSUBW Y10, Y14, Y2 + VPMULLW Y6, Y0, Y13 + VPADDW Y10, Y14, Y10 + VPMULLW Y2, Y0, Y14 + VPMULHW Y4, Y1, Y4 + VPMULHW Y5, Y1, Y5 + VPMULHW Y6, Y1, Y6 + VPMULHW Y2, Y1, Y2 + VPMULHW Y11, Y15, Y11 + VPMULHW Y12, Y15, Y12 + VPMULHW Y13, Y15, Y13 + VPMULHW Y14, Y15, Y14 + VPSUBW Y11, Y4, Y11 + VPSUBW Y12, Y5, Y12 + VPSUBW Y13, Y6, Y13 + VPSUBW Y14, Y2, Y14 + VMOVDQU Y7, (AX) + VMOVDQU Y8, 32(AX) + VMOVDQU Y9, 64(AX) + VMOVDQU Y10, 96(AX) + VMOVDQU Y11, 128(AX) + VMOVDQU Y12, 160(AX) + VMOVDQU Y13, 192(AX) + VMOVDQU Y14, 224(AX) + VMOVDQU 256(AX), Y7 + VMOVDQU 288(AX), Y8 + VMOVDQU 320(AX), Y9 + VMOVDQU 352(AX), Y10 + VMOVDQU 384(AX), Y11 + VMOVDQU 416(AX), Y12 + VMOVDQU 448(AX), Y13 + VMOVDQU 480(AX), Y14 + VMOVDQU 1184(CX), Y0 + VMOVDQU 1216(CX), Y1 + VMOVDQU 1248(CX), Y2 + VMOVDQU 1280(CX), Y3 + VPSUBW Y7, Y9, Y4 + VPSUBW Y8, Y10, Y5 + VPSUBW Y11, Y13, Y6 + VPADDW Y7, Y9, Y7 + VPADDW Y8, Y10, Y8 + VPADDW Y11, Y13, Y11 + VPMULLW Y4, Y0, Y9 + VPMULLW Y5, Y0, Y10 + VPSUBW Y12, Y14, Y0 + VPMULLW Y6, Y2, Y13 + VPADDW Y12, Y14, Y12 + VPMULLW Y0, Y2, Y14 + VPMULHW Y4, Y1, Y4 + VPMULHW Y5, Y1, Y5 + VPMULHW Y6, Y3, Y6 + VPMULHW Y0, Y3, Y0 + VPMULHW Y9, Y15, Y9 + VPMULHW Y10, Y15, Y10 + VPMULHW Y13, Y15, Y13 + VPMULHW Y14, Y15, Y14 + VPSUBW Y9, Y4, Y9 + VPSUBW Y10, Y5, Y10 + VPSUBW Y13, Y6, Y13 + VPSUBW Y14, Y0, Y14 + VMOVDQU 1440(CX), Y0 + VMOVDQU 1472(CX), Y1 + VMOVDQU 1504(CX), Y2 + VMOVDQU 1536(CX), Y3 + VPSLLD $0x10, Y8, Y4 + VPBLENDW $0xaa, Y4, Y7, Y4 + VPSRLD $0x10, Y7, Y7 + VPBLENDW $0xaa, Y8, Y7, Y8 + VMOVDQA Y4, Y7 + VPSLLD $0x10, Y10, Y4 + VPBLENDW $0xaa, Y4, Y9, Y4 + VPSRLD $0x10, Y9, Y9 + VPBLENDW $0xaa, Y10, Y9, Y10 + VMOVDQA Y4, Y9 + VPSLLD $0x10, Y12, Y4 + VPBLENDW $0xaa, Y4, Y11, Y4 + VPSRLD $0x10, Y11, Y11 + VPBLENDW $0xaa, Y12, Y11, Y12 + VMOVDQA Y4, Y11 + VPSLLD $0x10, Y14, Y4 + VPBLENDW $0xaa, Y4, Y13, Y4 + VPSRLD $0x10, Y13, Y13 + VPBLENDW $0xaa, Y14, Y13, Y14 + VMOVDQA Y4, Y13 + VPSUBW Y7, Y8, Y4 + VPSUBW Y9, Y10, Y5 + VPSUBW Y11, Y12, Y6 + VPADDW Y7, Y8, Y7 + VPADDW Y9, Y10, Y9 + VPADDW Y11, Y12, Y11 + VPMULLW Y4, Y0, Y8 + VPMULLW Y5, Y0, Y10 + VPSUBW Y13, Y14, Y0 + VPMULLW Y6, Y2, Y12 + VPADDW Y13, Y14, Y13 + VPMULLW Y0, Y2, Y14 + VPMULHW Y4, Y1, Y4 + VPMULHW Y5, Y1, Y5 + VPMULHW Y6, Y3, Y6 + VPMULHW Y0, Y3, Y0 + VPMULHW Y8, Y15, Y8 + VPMULHW Y10, Y15, Y10 + VPMULHW Y12, Y15, Y12 + VPMULHW Y14, Y15, Y14 + VPSUBW Y8, Y4, Y8 + VPSUBW Y10, Y5, Y10 + VPSUBW Y12, Y6, Y12 + VPSUBW Y14, Y0, Y14 + VMOVDQU 1696(CX), Y0 + VMOVDQU 1728(CX), Y1 + VMOVDQU 1760(CX), Y2 + VMOVDQU 1792(CX), Y3 + VMOVSLDUP Y9, Y4 + VPBLENDD $0xaa, Y4, Y7, Y4 + VPSRLQ $0x20, Y7, Y7 + VPBLENDD $0xaa, Y9, Y7, Y9 + VMOVDQA Y4, Y7 + VMOVSLDUP Y10, Y4 + VPBLENDD $0xaa, Y4, Y8, Y4 + VPSRLQ $0x20, Y8, Y8 + VPBLENDD $0xaa, Y10, Y8, Y10 + VMOVDQA Y4, Y8 + VMOVSLDUP Y13, Y4 + VPBLENDD $0xaa, Y4, Y11, Y4 + VPSRLQ $0x20, Y11, Y11 + VPBLENDD $0xaa, Y13, Y11, Y13 + VMOVDQA Y4, Y11 + VMOVSLDUP Y14, Y4 + VPBLENDD $0xaa, Y4, Y12, Y4 + VPSRLQ $0x20, Y12, Y12 + VPBLENDD $0xaa, Y14, Y12, Y14 + VMOVDQA Y4, Y12 + VPSUBW Y7, Y9, Y4 + VPSUBW Y8, Y10, Y5 + VPSUBW Y11, Y13, Y6 + VPADDW Y7, Y9, Y7 + VPADDW Y8, Y10, Y8 + VPADDW Y11, Y13, Y11 + VPMULLW Y4, Y0, Y9 + VPMULLW Y5, Y0, Y10 + VPSUBW Y12, Y14, Y0 + VPMULLW Y6, Y2, Y13 + VPADDW Y12, Y14, Y12 + VPMULLW Y0, Y2, Y14 + VPMULHW Y4, Y1, Y4 + VPMULHW Y5, Y1, Y5 + VPMULHW Y6, Y3, Y6 + VPMULHW Y0, Y3, Y0 + VPMULHW Y9, Y15, Y9 + VPMULHW Y10, Y15, Y10 + VPMULHW Y13, Y15, Y13 + VPMULHW Y14, Y15, Y14 + VPSUBW Y9, Y4, Y9 + VPSUBW Y10, Y5, Y10 + VPSUBW Y13, Y6, Y13 + VPSUBW Y14, Y0, Y14 + MOVL $0x00004ebf, DX + VMOVD DX, X0 + VPBROADCASTW X0, Y4 + VPMULHW Y4, Y7, Y5 + VPSRAW $0x0a, Y5, Y5 + VPMULLW Y15, Y5, Y5 + VPSUBW Y5, Y7, Y7 + VPMULHW Y4, Y11, Y5 + VPSRAW $0x0a, Y5, Y5 + VPMULLW Y15, Y5, Y5 + VPSUBW Y5, Y11, Y11 + VMOVDQU 1952(CX), Y0 + VMOVDQU 1984(CX), Y1 + VMOVDQU 2016(CX), Y2 + VMOVDQU 2048(CX), Y3 + VPUNPCKLQDQ Y8, Y7, Y4 + VPUNPCKHQDQ Y8, Y7, Y8 + VMOVDQA Y4, Y7 + VPUNPCKLQDQ Y10, Y9, Y4 + VPUNPCKHQDQ Y10, Y9, Y10 + VMOVDQA Y4, Y9 + VPUNPCKLQDQ Y12, Y11, Y4 + VPUNPCKHQDQ Y12, Y11, Y12 + VMOVDQA Y4, Y11 + VPUNPCKLQDQ Y14, Y13, Y4 + VPUNPCKHQDQ Y14, Y13, Y14 + VMOVDQA Y4, Y13 + VPSUBW Y7, Y8, Y4 + VPSUBW Y9, Y10, Y5 + VPSUBW Y11, Y12, Y6 + VPADDW Y7, Y8, Y7 + VPADDW Y9, Y10, Y9 + VPADDW Y11, Y12, Y11 + VPMULLW Y4, Y0, Y8 + VPMULLW Y5, Y0, Y10 + VPSUBW Y13, Y14, Y0 + VPMULLW Y6, Y2, Y12 + VPADDW Y13, Y14, Y13 + VPMULLW Y0, Y2, Y14 + VPMULHW Y4, Y1, Y4 + VPMULHW Y5, Y1, Y5 + VPMULHW Y6, Y3, Y6 + VPMULHW Y0, Y3, Y0 + VPMULHW Y8, Y15, Y8 + VPMULHW Y10, Y15, Y10 + VPMULHW Y12, Y15, Y12 + VPMULHW Y14, Y15, Y14 + VPSUBW Y8, Y4, Y8 + VPSUBW Y10, Y5, Y10 + VPSUBW Y12, Y6, Y12 + VPSUBW Y14, Y0, Y14 + VPBROADCASTW 2088(CX), Y0 + VPBROADCASTW 2090(CX), Y1 + VPBROADCASTW 2092(CX), Y2 + VPBROADCASTW 2094(CX), Y3 + VPERM2I128 $0x20, Y9, Y7, Y4 + VPERM2I128 $0x31, Y9, Y7, Y9 + VMOVDQA Y4, Y7 + VPERM2I128 $0x20, Y10, Y8, Y4 + VPERM2I128 $0x31, Y10, Y8, Y10 + VMOVDQA Y4, Y8 + VPERM2I128 $0x20, Y13, Y11, Y4 + VPERM2I128 $0x31, Y13, Y11, Y13 + VMOVDQA Y4, Y11 + VPERM2I128 $0x20, Y14, Y12, Y4 + VPERM2I128 $0x31, Y14, Y12, Y14 + VMOVDQA Y4, Y12 + VPSUBW Y7, Y9, Y4 + VPSUBW Y8, Y10, Y5 + VPSUBW Y11, Y13, Y6 + VPADDW Y7, Y9, Y7 + VPADDW Y8, Y10, Y8 + VPADDW Y11, Y13, Y11 + VPMULLW Y4, Y0, Y9 + VPMULLW Y5, Y0, Y10 + VPSUBW Y12, Y14, Y0 + VPMULLW Y6, Y2, Y13 + VPADDW Y12, Y14, Y12 + VPMULLW Y0, Y2, Y14 + VPMULHW Y4, Y1, Y4 + VPMULHW Y5, Y1, Y5 + VPMULHW Y6, Y3, Y6 + VPMULHW Y0, Y3, Y0 + VPMULHW Y9, Y15, Y9 + VPMULHW Y10, Y15, Y10 + VPMULHW Y13, Y15, Y13 + VPMULHW Y14, Y15, Y14 + VPSUBW Y9, Y4, Y9 + VPSUBW Y10, Y5, Y10 + VPSUBW Y13, Y6, Y13 + VPSUBW Y14, Y0, Y14 + MOVL $0x00004ebf, DX + VMOVD DX, X0 + VPBROADCASTW X0, Y4 + VPMULHW Y4, Y7, Y5 + VPSRAW $0x0a, Y5, Y5 + VPMULLW Y15, Y5, Y5 + VPSUBW Y5, Y7, Y7 + VPMULHW Y4, Y11, Y5 + VPSRAW $0x0a, Y5, Y5 + VPMULLW Y15, Y5, Y5 + VPSUBW Y5, Y11, Y11 + VPBROADCASTW 2100(CX), Y0 + VPBROADCASTW 2102(CX), Y1 + VPSUBW Y7, Y11, Y4 + VPSUBW Y8, Y12, Y5 + VPSUBW Y9, Y13, Y6 + VPADDW Y7, Y11, Y7 + VPADDW Y8, Y12, Y8 + VPADDW Y9, Y13, Y9 + VPMULLW Y4, Y0, Y11 + VPMULLW Y5, Y0, Y12 + VPSUBW Y10, Y14, Y2 + VPMULLW Y6, Y0, Y13 + VPADDW Y10, Y14, Y10 + VPMULLW Y2, Y0, Y14 + VPMULHW Y4, Y1, Y4 + VPMULHW Y5, Y1, Y5 + VPMULHW Y6, Y1, Y6 + VPMULHW Y2, Y1, Y2 + VPMULHW Y11, Y15, Y11 + VPMULHW Y12, Y15, Y12 + VPMULHW Y13, Y15, Y13 + VPMULHW Y14, Y15, Y14 + VPSUBW Y11, Y4, Y11 + VPSUBW Y12, Y5, Y12 + VPSUBW Y13, Y6, Y13 + VPSUBW Y14, Y2, Y14 + VMOVDQU Y7, 256(AX) + VMOVDQU Y8, 288(AX) + VMOVDQU Y9, 320(AX) + VMOVDQU Y10, 352(AX) + VMOVDQU Y11, 384(AX) + VMOVDQU Y12, 416(AX) + VMOVDQU Y13, 448(AX) + VMOVDQU Y14, 480(AX) + VPBROADCASTW 2104(CX), Y0 + VPBROADCASTW 2106(CX), Y1 + VMOVDQU (AX), Y7 + VMOVDQU 32(AX), Y8 + VMOVDQU 64(AX), Y9 + VMOVDQU 96(AX), Y10 + VMOVDQU 256(AX), Y11 + VMOVDQU 288(AX), Y12 + VMOVDQU 320(AX), Y13 + VMOVDQU 352(AX), Y14 + VPSUBW Y7, Y11, Y2 + VPSUBW Y8, Y12, Y3 + VPSUBW Y9, Y13, Y4 + VPADDW Y7, Y11, Y7 + VPADDW Y8, Y12, Y8 + VPADDW Y9, Y13, Y9 + VPMULLW Y2, Y0, Y11 + VPMULLW Y3, Y0, Y12 + VPSUBW Y10, Y14, Y5 + VPMULLW Y4, Y0, Y13 + VPADDW Y10, Y14, Y10 + VPMULLW Y5, Y0, Y14 + VPMULHW Y2, Y1, Y2 + VPMULHW Y3, Y1, Y3 + VPMULHW Y4, Y1, Y4 + VPMULHW Y5, Y1, Y5 + VPMULHW Y11, Y15, Y11 + VPMULHW Y12, Y15, Y12 + VPMULHW Y13, Y15, Y13 + VPMULHW Y14, Y15, Y14 + VPSUBW Y11, Y2, Y11 + VPSUBW Y12, Y3, Y12 + VPSUBW Y13, Y4, Y13 + VPSUBW Y14, Y5, Y14 + MOVL $0xffffd8a1, DX + VMOVD DX, X0 + VPBROADCASTW X0, Y0 + MOVL $0x000005a1, DX + VMOVD DX, X1 + VPBROADCASTW X1, Y1 + VPMULLW Y7, Y0, Y2 + VPMULLW Y8, Y0, Y3 + VPMULLW Y9, Y0, Y4 + VPMULLW Y10, Y0, Y5 + VPMULHW Y7, Y1, Y7 + VPMULHW Y8, Y1, Y8 + VPMULHW Y9, Y1, Y9 + VPMULHW Y10, Y1, Y10 + VPMULHW Y2, Y15, Y2 + VPMULHW Y3, Y15, Y3 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPSUBW Y2, Y7, Y7 + VPSUBW Y3, Y8, Y8 + VPSUBW Y4, Y9, Y9 + VPSUBW Y5, Y10, Y10 + VPMULLW Y11, Y0, Y2 + VPMULLW Y12, Y0, Y3 + VPMULLW Y13, Y0, Y4 + VPMULLW Y14, Y0, Y5 + VPMULHW Y11, Y1, Y11 + VPMULHW Y12, Y1, Y12 + VPMULHW Y13, Y1, Y13 + VPMULHW Y14, Y1, Y14 + VPMULHW Y2, Y15, Y2 + VPMULHW Y3, Y15, Y3 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPSUBW Y2, Y11, Y11 + VPSUBW Y3, Y12, Y12 + VPSUBW Y4, Y13, Y13 + VPSUBW Y5, Y14, Y14 + VMOVDQU Y7, (AX) + VMOVDQU Y8, 32(AX) + VMOVDQU Y9, 64(AX) + VMOVDQU Y10, 96(AX) + VMOVDQU Y11, 256(AX) + VMOVDQU Y12, 288(AX) + VMOVDQU Y13, 320(AX) + VMOVDQU Y14, 352(AX) + VPBROADCASTW 2104(CX), Y0 + VPBROADCASTW 2106(CX), Y1 + VMOVDQU 128(AX), Y7 + VMOVDQU 160(AX), Y8 + VMOVDQU 192(AX), Y9 + VMOVDQU 224(AX), Y10 + VMOVDQU 384(AX), Y11 + VMOVDQU 416(AX), Y12 + VMOVDQU 448(AX), Y13 + VMOVDQU 480(AX), Y14 + VPSUBW Y7, Y11, Y2 + VPSUBW Y8, Y12, Y3 + VPSUBW Y9, Y13, Y4 + VPADDW Y7, Y11, Y7 + VPADDW Y8, Y12, Y8 + VPADDW Y9, Y13, Y9 + VPMULLW Y2, Y0, Y11 + VPMULLW Y3, Y0, Y12 + VPSUBW Y10, Y14, Y5 + VPMULLW Y4, Y0, Y13 + VPADDW Y10, Y14, Y10 + VPMULLW Y5, Y0, Y14 + VPMULHW Y2, Y1, Y2 + VPMULHW Y3, Y1, Y3 + VPMULHW Y4, Y1, Y4 + VPMULHW Y5, Y1, Y5 + VPMULHW Y11, Y15, Y11 + VPMULHW Y12, Y15, Y12 + VPMULHW Y13, Y15, Y13 + VPMULHW Y14, Y15, Y14 + VPSUBW Y11, Y2, Y11 + VPSUBW Y12, Y3, Y12 + VPSUBW Y13, Y4, Y13 + VPSUBW Y14, Y5, Y14 + MOVL $0xffffd8a1, CX + VMOVD CX, X0 + VPBROADCASTW X0, Y0 + MOVL $0x000005a1, CX + VMOVD CX, X1 + VPBROADCASTW X1, Y1 + VPMULLW Y7, Y0, Y2 + VPMULLW Y8, Y0, Y3 + VPMULLW Y9, Y0, Y4 + VPMULLW Y10, Y0, Y5 + VPMULHW Y7, Y1, Y7 + VPMULHW Y8, Y1, Y8 + VPMULHW Y9, Y1, Y9 + VPMULHW Y10, Y1, Y10 + VPMULHW Y2, Y15, Y2 + VPMULHW Y3, Y15, Y3 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPSUBW Y2, Y7, Y7 + VPSUBW Y3, Y8, Y8 + VPSUBW Y4, Y9, Y9 + VPSUBW Y5, Y10, Y10 + VPMULLW Y11, Y0, Y2 + VPMULLW Y12, Y0, Y3 + VPMULLW Y13, Y0, Y4 + VPMULLW Y14, Y0, Y5 + VPMULHW Y11, Y1, Y11 + VPMULHW Y12, Y1, Y12 + VPMULHW Y13, Y1, Y13 + VPMULHW Y14, Y1, Y14 + VPMULHW Y2, Y15, Y2 + VPMULHW Y3, Y15, Y3 + VPMULHW Y4, Y15, Y4 + VPMULHW Y5, Y15, Y5 + VPSUBW Y2, Y11, Y11 + VPSUBW Y3, Y12, Y12 + VPSUBW Y4, Y13, Y13 + VPSUBW Y5, Y14, Y14 + VMOVDQU Y7, 128(AX) + VMOVDQU Y8, 160(AX) + VMOVDQU Y9, 192(AX) + VMOVDQU Y10, 224(AX) + VMOVDQU Y11, 384(AX) + VMOVDQU Y12, 416(AX) + VMOVDQU Y13, 448(AX) + VMOVDQU Y14, 480(AX) + RET + +// func mulHatAVX2(p *[256]int16, a *[256]int16, b *[256]int16) +// Requires: AVX, AVX2 +TEXT ·mulHatAVX2(SB), NOSPLIT, $8-24 + MOVQ p+0(FP), AX + MOVQ a+8(FP), CX + MOVQ b+16(FP), DX + LEAQ ·ZetasAVX2+0(SB), BX + MOVL $0xfffff301, SI + VMOVD SI, X0 + VPBROADCASTW X0, Y14 + MOVL $0x00000d01, SI + VMOVD SI, X0 + VPBROADCASTW X0, Y15 + VMOVDQU (CX), Y0 + VMOVDQU 32(CX), Y1 + VMOVDQU 64(CX), Y2 + VMOVDQU 96(CX), Y3 + VMOVDQU (DX), Y4 + VMOVDQU 32(DX), Y5 + VMOVDQU 64(DX), Y6 + VMOVDQU 96(DX), Y7 + VPMULLW Y1, Y5, Y8 + VPMULLW Y0, Y4, Y9 + VPMULLW Y0, Y5, Y10 + VPMULLW Y1, Y4, Y11 + VPMULLW Y8, Y14, Y8 + VPMULLW Y9, Y14, Y9 + VPMULLW Y10, Y14, Y10 + VPMULLW Y11, Y14, Y11 + VPMULHW Y1, Y5, Y12 + VPMULHW Y0, Y4, Y13 + VPMULHW Y0, Y5, Y0 + VPMULHW Y1, Y4, Y1 + VMOVDQA Y12, Y4 + VMOVDQA Y13, Y5 + VPMULHW Y8, Y15, Y8 + VPMULHW Y9, Y15, Y9 + VPMULHW Y10, Y15, Y10 + VPMULHW Y11, Y15, Y11 + VPSUBW Y8, Y4, Y4 + VPSUBW Y9, Y5, Y5 + VPSUBW Y10, Y0, Y0 + VPSUBW Y11, Y1, Y1 + VMOVDQU 800(BX), Y12 + VMOVDQU 832(BX), Y13 + VPMULLW Y4, Y12, Y8 + VPMULHW Y4, Y13, Y4 + VPMULHW Y8, Y15, Y8 + VPSUBW Y8, Y4, Y4 + VPADDW Y4, Y5, Y4 + VPADDW Y0, Y1, Y5 + VPMULLW Y3, Y7, Y8 + VPMULLW Y2, Y6, Y9 + VPMULLW Y2, Y7, Y10 + VPMULLW Y3, Y6, Y11 + VPMULLW Y8, Y14, Y8 + VPMULLW Y9, Y14, Y9 + VPMULLW Y10, Y14, Y10 + VPMULLW Y11, Y14, Y11 + VPMULHW Y3, Y7, Y12 + VPMULHW Y2, Y6, Y13 + VPMULHW Y2, Y7, Y2 + VPMULHW Y3, Y6, Y3 + VMOVDQA Y12, Y6 + VMOVDQA Y13, Y7 + VPMULHW Y8, Y15, Y8 + VPMULHW Y9, Y15, Y9 + VPMULHW Y10, Y15, Y10 + VPMULHW Y11, Y15, Y11 + VPSUBW Y8, Y6, Y6 + VPSUBW Y9, Y7, Y7 + VPSUBW Y10, Y2, Y2 + VPSUBW Y11, Y3, Y3 + VMOVDQU 800(BX), Y12 + VMOVDQU 832(BX), Y13 + VPMULLW Y6, Y12, Y8 + VPMULHW Y6, Y13, Y6 + VPMULHW Y8, Y15, Y8 + VPSUBW Y8, Y6, Y6 + VPSUBW Y6, Y7, Y6 + VPADDW Y2, Y3, Y7 + VMOVDQU Y4, (AX) + VMOVDQU Y5, 32(AX) + VMOVDQU Y6, 64(AX) + VMOVDQU Y7, 96(AX) + VMOVDQU 128(CX), Y0 + VMOVDQU 160(CX), Y1 + VMOVDQU 192(CX), Y2 + VMOVDQU 224(CX), Y3 + VMOVDQU 128(DX), Y4 + VMOVDQU 160(DX), Y5 + VMOVDQU 192(DX), Y6 + VMOVDQU 224(DX), Y7 + VPMULLW Y1, Y5, Y8 + VPMULLW Y0, Y4, Y9 + VPMULLW Y0, Y5, Y10 + VPMULLW Y1, Y4, Y11 + VPMULLW Y8, Y14, Y8 + VPMULLW Y9, Y14, Y9 + VPMULLW Y10, Y14, Y10 + VPMULLW Y11, Y14, Y11 + VPMULHW Y1, Y5, Y12 + VPMULHW Y0, Y4, Y13 + VPMULHW Y0, Y5, Y0 + VPMULHW Y1, Y4, Y1 + VMOVDQA Y12, Y4 + VMOVDQA Y13, Y5 + VPMULHW Y8, Y15, Y8 + VPMULHW Y9, Y15, Y9 + VPMULHW Y10, Y15, Y10 + VPMULHW Y11, Y15, Y11 + VPSUBW Y8, Y4, Y4 + VPSUBW Y9, Y5, Y5 + VPSUBW Y10, Y0, Y0 + VPSUBW Y11, Y1, Y1 + VMOVDQU 864(BX), Y12 + VMOVDQU 896(BX), Y13 + VPMULLW Y4, Y12, Y8 + VPMULHW Y4, Y13, Y4 + VPMULHW Y8, Y15, Y8 + VPSUBW Y8, Y4, Y4 + VPADDW Y4, Y5, Y4 + VPADDW Y0, Y1, Y5 + VPMULLW Y3, Y7, Y8 + VPMULLW Y2, Y6, Y9 + VPMULLW Y2, Y7, Y10 + VPMULLW Y3, Y6, Y11 + VPMULLW Y8, Y14, Y8 + VPMULLW Y9, Y14, Y9 + VPMULLW Y10, Y14, Y10 + VPMULLW Y11, Y14, Y11 + VPMULHW Y3, Y7, Y12 + VPMULHW Y2, Y6, Y13 + VPMULHW Y2, Y7, Y2 + VPMULHW Y3, Y6, Y3 + VMOVDQA Y12, Y6 + VMOVDQA Y13, Y7 + VPMULHW Y8, Y15, Y8 + VPMULHW Y9, Y15, Y9 + VPMULHW Y10, Y15, Y10 + VPMULHW Y11, Y15, Y11 + VPSUBW Y8, Y6, Y6 + VPSUBW Y9, Y7, Y7 + VPSUBW Y10, Y2, Y2 + VPSUBW Y11, Y3, Y3 + VMOVDQU 864(BX), Y12 + VMOVDQU 896(BX), Y13 + VPMULLW Y6, Y12, Y8 + VPMULHW Y6, Y13, Y6 + VPMULHW Y8, Y15, Y8 + VPSUBW Y8, Y6, Y6 + VPSUBW Y6, Y7, Y6 + VPADDW Y2, Y3, Y7 + VMOVDQU Y4, 128(AX) + VMOVDQU Y5, 160(AX) + VMOVDQU Y6, 192(AX) + VMOVDQU Y7, 224(AX) + VMOVDQU 256(CX), Y0 + VMOVDQU 288(CX), Y1 + VMOVDQU 320(CX), Y2 + VMOVDQU 352(CX), Y3 + VMOVDQU 256(DX), Y4 + VMOVDQU 288(DX), Y5 + VMOVDQU 320(DX), Y6 + VMOVDQU 352(DX), Y7 + VPMULLW Y1, Y5, Y8 + VPMULLW Y0, Y4, Y9 + VPMULLW Y0, Y5, Y10 + VPMULLW Y1, Y4, Y11 + VPMULLW Y8, Y14, Y8 + VPMULLW Y9, Y14, Y9 + VPMULLW Y10, Y14, Y10 + VPMULLW Y11, Y14, Y11 + VPMULHW Y1, Y5, Y12 + VPMULHW Y0, Y4, Y13 + VPMULHW Y0, Y5, Y0 + VPMULHW Y1, Y4, Y1 + VMOVDQA Y12, Y4 + VMOVDQA Y13, Y5 + VPMULHW Y8, Y15, Y8 + VPMULHW Y9, Y15, Y9 + VPMULHW Y10, Y15, Y10 + VPMULHW Y11, Y15, Y11 + VPSUBW Y8, Y4, Y4 + VPSUBW Y9, Y5, Y5 + VPSUBW Y10, Y0, Y0 + VPSUBW Y11, Y1, Y1 + VMOVDQU 928(BX), Y12 + VMOVDQU 960(BX), Y13 + VPMULLW Y4, Y12, Y8 + VPMULHW Y4, Y13, Y4 + VPMULHW Y8, Y15, Y8 + VPSUBW Y8, Y4, Y4 + VPADDW Y4, Y5, Y4 + VPADDW Y0, Y1, Y5 + VPMULLW Y3, Y7, Y8 + VPMULLW Y2, Y6, Y9 + VPMULLW Y2, Y7, Y10 + VPMULLW Y3, Y6, Y11 + VPMULLW Y8, Y14, Y8 + VPMULLW Y9, Y14, Y9 + VPMULLW Y10, Y14, Y10 + VPMULLW Y11, Y14, Y11 + VPMULHW Y3, Y7, Y12 + VPMULHW Y2, Y6, Y13 + VPMULHW Y2, Y7, Y2 + VPMULHW Y3, Y6, Y3 + VMOVDQA Y12, Y6 + VMOVDQA Y13, Y7 + VPMULHW Y8, Y15, Y8 + VPMULHW Y9, Y15, Y9 + VPMULHW Y10, Y15, Y10 + VPMULHW Y11, Y15, Y11 + VPSUBW Y8, Y6, Y6 + VPSUBW Y9, Y7, Y7 + VPSUBW Y10, Y2, Y2 + VPSUBW Y11, Y3, Y3 + VMOVDQU 928(BX), Y12 + VMOVDQU 960(BX), Y13 + VPMULLW Y6, Y12, Y8 + VPMULHW Y6, Y13, Y6 + VPMULHW Y8, Y15, Y8 + VPSUBW Y8, Y6, Y6 + VPSUBW Y6, Y7, Y6 + VPADDW Y2, Y3, Y7 + VMOVDQU Y4, 256(AX) + VMOVDQU Y5, 288(AX) + VMOVDQU Y6, 320(AX) + VMOVDQU Y7, 352(AX) + VMOVDQU 384(CX), Y0 + VMOVDQU 416(CX), Y1 + VMOVDQU 448(CX), Y2 + VMOVDQU 480(CX), Y3 + VMOVDQU 384(DX), Y4 + VMOVDQU 416(DX), Y5 + VMOVDQU 448(DX), Y6 + VMOVDQU 480(DX), Y7 + VPMULLW Y1, Y5, Y8 + VPMULLW Y0, Y4, Y9 + VPMULLW Y0, Y5, Y10 + VPMULLW Y1, Y4, Y11 + VPMULLW Y8, Y14, Y8 + VPMULLW Y9, Y14, Y9 + VPMULLW Y10, Y14, Y10 + VPMULLW Y11, Y14, Y11 + VPMULHW Y1, Y5, Y12 + VPMULHW Y0, Y4, Y13 + VPMULHW Y0, Y5, Y0 + VPMULHW Y1, Y4, Y1 + VMOVDQA Y12, Y4 + VMOVDQA Y13, Y5 + VPMULHW Y8, Y15, Y8 + VPMULHW Y9, Y15, Y9 + VPMULHW Y10, Y15, Y10 + VPMULHW Y11, Y15, Y11 + VPSUBW Y8, Y4, Y4 + VPSUBW Y9, Y5, Y5 + VPSUBW Y10, Y0, Y0 + VPSUBW Y11, Y1, Y1 + VMOVDQU 992(BX), Y12 + VMOVDQU 1024(BX), Y13 + VPMULLW Y4, Y12, Y8 + VPMULHW Y4, Y13, Y4 + VPMULHW Y8, Y15, Y8 + VPSUBW Y8, Y4, Y4 + VPADDW Y4, Y5, Y4 + VPADDW Y0, Y1, Y5 + VPMULLW Y3, Y7, Y8 + VPMULLW Y2, Y6, Y9 + VPMULLW Y2, Y7, Y10 + VPMULLW Y3, Y6, Y11 + VPMULLW Y8, Y14, Y8 + VPMULLW Y9, Y14, Y9 + VPMULLW Y10, Y14, Y10 + VPMULLW Y11, Y14, Y11 + VPMULHW Y3, Y7, Y12 + VPMULHW Y2, Y6, Y13 + VPMULHW Y2, Y7, Y2 + VPMULHW Y3, Y6, Y3 + VMOVDQA Y12, Y6 + VMOVDQA Y13, Y7 + VPMULHW Y8, Y15, Y8 + VPMULHW Y9, Y15, Y9 + VPMULHW Y10, Y15, Y10 + VPMULHW Y11, Y15, Y11 + VPSUBW Y8, Y6, Y6 + VPSUBW Y9, Y7, Y7 + VPSUBW Y10, Y2, Y2 + VPSUBW Y11, Y3, Y3 + VMOVDQU 992(BX), Y12 + VMOVDQU 1024(BX), Y13 + VPMULLW Y6, Y12, Y8 + VPMULHW Y6, Y13, Y6 + VPMULHW Y8, Y15, Y8 + VPSUBW Y8, Y6, Y6 + VPSUBW Y6, Y7, Y6 + VPADDW Y2, Y3, Y7 + VMOVDQU Y4, 384(AX) + VMOVDQU Y5, 416(AX) + VMOVDQU Y6, 448(AX) + VMOVDQU Y7, 480(AX) + RET + +// func detangleAVX2(p *[256]int16) +// Requires: AVX, AVX2 +TEXT ·detangleAVX2(SB), NOSPLIT, $0-8 + MOVQ p+0(FP), AX + VMOVDQU (AX), Y0 + VMOVDQU 32(AX), Y1 + VMOVDQU 64(AX), Y2 + VMOVDQU 96(AX), Y3 + VMOVDQU 128(AX), Y4 + VMOVDQU 160(AX), Y5 + VMOVDQU 192(AX), Y6 + VMOVDQU 224(AX), Y7 + VPSLLD $0x10, Y1, Y8 + VPBLENDW $0xaa, Y8, Y0, Y8 + VPSRLD $0x10, Y0, Y0 + VPBLENDW $0xaa, Y1, Y0, Y1 + VMOVDQA Y8, Y0 + VPSLLD $0x10, Y3, Y8 + VPBLENDW $0xaa, Y8, Y2, Y8 + VPSRLD $0x10, Y2, Y2 + VPBLENDW $0xaa, Y3, Y2, Y3 + VMOVDQA Y8, Y2 + VPSLLD $0x10, Y5, Y8 + VPBLENDW $0xaa, Y8, Y4, Y8 + VPSRLD $0x10, Y4, Y4 + VPBLENDW $0xaa, Y5, Y4, Y5 + VMOVDQA Y8, Y4 + VPSLLD $0x10, Y7, Y8 + VPBLENDW $0xaa, Y8, Y6, Y8 + VPSRLD $0x10, Y6, Y6 + VPBLENDW $0xaa, Y7, Y6, Y7 + VMOVDQA Y8, Y6 + VMOVSLDUP Y2, Y8 + VPBLENDD $0xaa, Y8, Y0, Y8 + VPSRLQ $0x20, Y0, Y0 + VPBLENDD $0xaa, Y2, Y0, Y2 + VMOVDQA Y8, Y0 + VMOVSLDUP Y3, Y8 + VPBLENDD $0xaa, Y8, Y1, Y8 + VPSRLQ $0x20, Y1, Y1 + VPBLENDD $0xaa, Y3, Y1, Y3 + VMOVDQA Y8, Y1 + VMOVSLDUP Y6, Y8 + VPBLENDD $0xaa, Y8, Y4, Y8 + VPSRLQ $0x20, Y4, Y4 + VPBLENDD $0xaa, Y6, Y4, Y6 + VMOVDQA Y8, Y4 + VMOVSLDUP Y7, Y8 + VPBLENDD $0xaa, Y8, Y5, Y8 + VPSRLQ $0x20, Y5, Y5 + VPBLENDD $0xaa, Y7, Y5, Y7 + VMOVDQA Y8, Y5 + VPUNPCKLQDQ Y1, Y0, Y8 + VPUNPCKHQDQ Y1, Y0, Y1 + VMOVDQA Y8, Y0 + VPUNPCKLQDQ Y3, Y2, Y8 + VPUNPCKHQDQ Y3, Y2, Y3 + VMOVDQA Y8, Y2 + VPUNPCKLQDQ Y5, Y4, Y8 + VPUNPCKHQDQ Y5, Y4, Y5 + VMOVDQA Y8, Y4 + VPUNPCKLQDQ Y7, Y6, Y8 + VPUNPCKHQDQ Y7, Y6, Y7 + VMOVDQA Y8, Y6 + VPERM2I128 $0x20, Y2, Y0, Y8 + VPERM2I128 $0x31, Y2, Y0, Y2 + VMOVDQA Y8, Y0 + VPERM2I128 $0x20, Y3, Y1, Y8 + VPERM2I128 $0x31, Y3, Y1, Y3 + VMOVDQA Y8, Y1 + VPERM2I128 $0x20, Y6, Y4, Y8 + VPERM2I128 $0x31, Y6, Y4, Y6 + VMOVDQA Y8, Y4 + VPERM2I128 $0x20, Y7, Y5, Y8 + VPERM2I128 $0x31, Y7, Y5, Y7 + VMOVDQA Y8, Y5 + VMOVDQU Y0, (AX) + VMOVDQU Y1, 32(AX) + VMOVDQU Y2, 64(AX) + VMOVDQU Y3, 96(AX) + VMOVDQU Y4, 128(AX) + VMOVDQU Y5, 160(AX) + VMOVDQU Y6, 192(AX) + VMOVDQU Y7, 224(AX) + VMOVDQU 256(AX), Y0 + VMOVDQU 288(AX), Y1 + VMOVDQU 320(AX), Y2 + VMOVDQU 352(AX), Y3 + VMOVDQU 384(AX), Y4 + VMOVDQU 416(AX), Y5 + VMOVDQU 448(AX), Y6 + VMOVDQU 480(AX), Y7 + VPSLLD $0x10, Y1, Y8 + VPBLENDW $0xaa, Y8, Y0, Y8 + VPSRLD $0x10, Y0, Y0 + VPBLENDW $0xaa, Y1, Y0, Y1 + VMOVDQA Y8, Y0 + VPSLLD $0x10, Y3, Y8 + VPBLENDW $0xaa, Y8, Y2, Y8 + VPSRLD $0x10, Y2, Y2 + VPBLENDW $0xaa, Y3, Y2, Y3 + VMOVDQA Y8, Y2 + VPSLLD $0x10, Y5, Y8 + VPBLENDW $0xaa, Y8, Y4, Y8 + VPSRLD $0x10, Y4, Y4 + VPBLENDW $0xaa, Y5, Y4, Y5 + VMOVDQA Y8, Y4 + VPSLLD $0x10, Y7, Y8 + VPBLENDW $0xaa, Y8, Y6, Y8 + VPSRLD $0x10, Y6, Y6 + VPBLENDW $0xaa, Y7, Y6, Y7 + VMOVDQA Y8, Y6 + VMOVSLDUP Y2, Y8 + VPBLENDD $0xaa, Y8, Y0, Y8 + VPSRLQ $0x20, Y0, Y0 + VPBLENDD $0xaa, Y2, Y0, Y2 + VMOVDQA Y8, Y0 + VMOVSLDUP Y3, Y8 + VPBLENDD $0xaa, Y8, Y1, Y8 + VPSRLQ $0x20, Y1, Y1 + VPBLENDD $0xaa, Y3, Y1, Y3 + VMOVDQA Y8, Y1 + VMOVSLDUP Y6, Y8 + VPBLENDD $0xaa, Y8, Y4, Y8 + VPSRLQ $0x20, Y4, Y4 + VPBLENDD $0xaa, Y6, Y4, Y6 + VMOVDQA Y8, Y4 + VMOVSLDUP Y7, Y8 + VPBLENDD $0xaa, Y8, Y5, Y8 + VPSRLQ $0x20, Y5, Y5 + VPBLENDD $0xaa, Y7, Y5, Y7 + VMOVDQA Y8, Y5 + VPUNPCKLQDQ Y1, Y0, Y8 + VPUNPCKHQDQ Y1, Y0, Y1 + VMOVDQA Y8, Y0 + VPUNPCKLQDQ Y3, Y2, Y8 + VPUNPCKHQDQ Y3, Y2, Y3 + VMOVDQA Y8, Y2 + VPUNPCKLQDQ Y5, Y4, Y8 + VPUNPCKHQDQ Y5, Y4, Y5 + VMOVDQA Y8, Y4 + VPUNPCKLQDQ Y7, Y6, Y8 + VPUNPCKHQDQ Y7, Y6, Y7 + VMOVDQA Y8, Y6 + VPERM2I128 $0x20, Y2, Y0, Y8 + VPERM2I128 $0x31, Y2, Y0, Y2 + VMOVDQA Y8, Y0 + VPERM2I128 $0x20, Y3, Y1, Y8 + VPERM2I128 $0x31, Y3, Y1, Y3 + VMOVDQA Y8, Y1 + VPERM2I128 $0x20, Y6, Y4, Y8 + VPERM2I128 $0x31, Y6, Y4, Y6 + VMOVDQA Y8, Y4 + VPERM2I128 $0x20, Y7, Y5, Y8 + VPERM2I128 $0x31, Y7, Y5, Y7 + VMOVDQA Y8, Y5 + VMOVDQU Y0, 256(AX) + VMOVDQU Y1, 288(AX) + VMOVDQU Y2, 320(AX) + VMOVDQU Y3, 352(AX) + VMOVDQU Y4, 384(AX) + VMOVDQU Y5, 416(AX) + VMOVDQU Y6, 448(AX) + VMOVDQU Y7, 480(AX) + RET + +// func tangleAVX2(p *[256]int16) +// Requires: AVX, AVX2 +TEXT ·tangleAVX2(SB), NOSPLIT, $0-8 + MOVQ p+0(FP), AX + VMOVDQU (AX), Y0 + VMOVDQU 32(AX), Y1 + VMOVDQU 64(AX), Y2 + VMOVDQU 96(AX), Y3 + VMOVDQU 128(AX), Y4 + VMOVDQU 160(AX), Y5 + VMOVDQU 192(AX), Y6 + VMOVDQU 224(AX), Y7 + VPERM2I128 $0x20, Y2, Y0, Y8 + VPERM2I128 $0x31, Y2, Y0, Y2 + VMOVDQA Y8, Y0 + VPERM2I128 $0x20, Y3, Y1, Y8 + VPERM2I128 $0x31, Y3, Y1, Y3 + VMOVDQA Y8, Y1 + VPERM2I128 $0x20, Y6, Y4, Y8 + VPERM2I128 $0x31, Y6, Y4, Y6 + VMOVDQA Y8, Y4 + VPERM2I128 $0x20, Y7, Y5, Y8 + VPERM2I128 $0x31, Y7, Y5, Y7 + VMOVDQA Y8, Y5 + VPUNPCKLQDQ Y1, Y0, Y8 + VPUNPCKHQDQ Y1, Y0, Y1 + VMOVDQA Y8, Y0 + VPUNPCKLQDQ Y3, Y2, Y8 + VPUNPCKHQDQ Y3, Y2, Y3 + VMOVDQA Y8, Y2 + VPUNPCKLQDQ Y5, Y4, Y8 + VPUNPCKHQDQ Y5, Y4, Y5 + VMOVDQA Y8, Y4 + VPUNPCKLQDQ Y7, Y6, Y8 + VPUNPCKHQDQ Y7, Y6, Y7 + VMOVDQA Y8, Y6 + VMOVSLDUP Y2, Y8 + VPBLENDD $0xaa, Y8, Y0, Y8 + VPSRLQ $0x20, Y0, Y0 + VPBLENDD $0xaa, Y2, Y0, Y2 + VMOVDQA Y8, Y0 + VMOVSLDUP Y3, Y8 + VPBLENDD $0xaa, Y8, Y1, Y8 + VPSRLQ $0x20, Y1, Y1 + VPBLENDD $0xaa, Y3, Y1, Y3 + VMOVDQA Y8, Y1 + VMOVSLDUP Y6, Y8 + VPBLENDD $0xaa, Y8, Y4, Y8 + VPSRLQ $0x20, Y4, Y4 + VPBLENDD $0xaa, Y6, Y4, Y6 + VMOVDQA Y8, Y4 + VMOVSLDUP Y7, Y8 + VPBLENDD $0xaa, Y8, Y5, Y8 + VPSRLQ $0x20, Y5, Y5 + VPBLENDD $0xaa, Y7, Y5, Y7 + VMOVDQA Y8, Y5 + VPSLLD $0x10, Y1, Y8 + VPBLENDW $0xaa, Y8, Y0, Y8 + VPSRLD $0x10, Y0, Y0 + VPBLENDW $0xaa, Y1, Y0, Y1 + VMOVDQA Y8, Y0 + VPSLLD $0x10, Y3, Y8 + VPBLENDW $0xaa, Y8, Y2, Y8 + VPSRLD $0x10, Y2, Y2 + VPBLENDW $0xaa, Y3, Y2, Y3 + VMOVDQA Y8, Y2 + VPSLLD $0x10, Y5, Y8 + VPBLENDW $0xaa, Y8, Y4, Y8 + VPSRLD $0x10, Y4, Y4 + VPBLENDW $0xaa, Y5, Y4, Y5 + VMOVDQA Y8, Y4 + VPSLLD $0x10, Y7, Y8 + VPBLENDW $0xaa, Y8, Y6, Y8 + VPSRLD $0x10, Y6, Y6 + VPBLENDW $0xaa, Y7, Y6, Y7 + VMOVDQA Y8, Y6 + VMOVDQU Y0, (AX) + VMOVDQU Y1, 32(AX) + VMOVDQU Y2, 64(AX) + VMOVDQU Y3, 96(AX) + VMOVDQU Y4, 128(AX) + VMOVDQU Y5, 160(AX) + VMOVDQU Y6, 192(AX) + VMOVDQU Y7, 224(AX) + VMOVDQU 256(AX), Y0 + VMOVDQU 288(AX), Y1 + VMOVDQU 320(AX), Y2 + VMOVDQU 352(AX), Y3 + VMOVDQU 384(AX), Y4 + VMOVDQU 416(AX), Y5 + VMOVDQU 448(AX), Y6 + VMOVDQU 480(AX), Y7 + VPERM2I128 $0x20, Y2, Y0, Y8 + VPERM2I128 $0x31, Y2, Y0, Y2 + VMOVDQA Y8, Y0 + VPERM2I128 $0x20, Y3, Y1, Y8 + VPERM2I128 $0x31, Y3, Y1, Y3 + VMOVDQA Y8, Y1 + VPERM2I128 $0x20, Y6, Y4, Y8 + VPERM2I128 $0x31, Y6, Y4, Y6 + VMOVDQA Y8, Y4 + VPERM2I128 $0x20, Y7, Y5, Y8 + VPERM2I128 $0x31, Y7, Y5, Y7 + VMOVDQA Y8, Y5 + VPUNPCKLQDQ Y1, Y0, Y8 + VPUNPCKHQDQ Y1, Y0, Y1 + VMOVDQA Y8, Y0 + VPUNPCKLQDQ Y3, Y2, Y8 + VPUNPCKHQDQ Y3, Y2, Y3 + VMOVDQA Y8, Y2 + VPUNPCKLQDQ Y5, Y4, Y8 + VPUNPCKHQDQ Y5, Y4, Y5 + VMOVDQA Y8, Y4 + VPUNPCKLQDQ Y7, Y6, Y8 + VPUNPCKHQDQ Y7, Y6, Y7 + VMOVDQA Y8, Y6 + VMOVSLDUP Y2, Y8 + VPBLENDD $0xaa, Y8, Y0, Y8 + VPSRLQ $0x20, Y0, Y0 + VPBLENDD $0xaa, Y2, Y0, Y2 + VMOVDQA Y8, Y0 + VMOVSLDUP Y3, Y8 + VPBLENDD $0xaa, Y8, Y1, Y8 + VPSRLQ $0x20, Y1, Y1 + VPBLENDD $0xaa, Y3, Y1, Y3 + VMOVDQA Y8, Y1 + VMOVSLDUP Y6, Y8 + VPBLENDD $0xaa, Y8, Y4, Y8 + VPSRLQ $0x20, Y4, Y4 + VPBLENDD $0xaa, Y6, Y4, Y6 + VMOVDQA Y8, Y4 + VMOVSLDUP Y7, Y8 + VPBLENDD $0xaa, Y8, Y5, Y8 + VPSRLQ $0x20, Y5, Y5 + VPBLENDD $0xaa, Y7, Y5, Y7 + VMOVDQA Y8, Y5 + VPSLLD $0x10, Y1, Y8 + VPBLENDW $0xaa, Y8, Y0, Y8 + VPSRLD $0x10, Y0, Y0 + VPBLENDW $0xaa, Y1, Y0, Y1 + VMOVDQA Y8, Y0 + VPSLLD $0x10, Y3, Y8 + VPBLENDW $0xaa, Y8, Y2, Y8 + VPSRLD $0x10, Y2, Y2 + VPBLENDW $0xaa, Y3, Y2, Y3 + VMOVDQA Y8, Y2 + VPSLLD $0x10, Y5, Y8 + VPBLENDW $0xaa, Y8, Y4, Y8 + VPSRLD $0x10, Y4, Y4 + VPBLENDW $0xaa, Y5, Y4, Y5 + VMOVDQA Y8, Y4 + VPSLLD $0x10, Y7, Y8 + VPBLENDW $0xaa, Y8, Y6, Y8 + VPSRLD $0x10, Y6, Y6 + VPBLENDW $0xaa, Y7, Y6, Y7 + VMOVDQA Y8, Y6 + VMOVDQU Y0, 256(AX) + VMOVDQU Y1, 288(AX) + VMOVDQU Y2, 320(AX) + VMOVDQU Y3, 352(AX) + VMOVDQU Y4, 384(AX) + VMOVDQU Y5, 416(AX) + VMOVDQU Y6, 448(AX) + VMOVDQU Y7, 480(AX) + RET + +// func barrettReduceAVX2(p *[256]int16) +// Requires: AVX, AVX2 +TEXT ·barrettReduceAVX2(SB), NOSPLIT, $0-8 + MOVQ p+0(FP), AX + MOVL $0x00000d01, CX + VMOVD CX, X0 + VPBROADCASTW X0, Y9 + MOVL $0x00004ebf, CX + VMOVD CX, X0 + VPBROADCASTW X0, Y8 + VMOVDQU (AX), Y0 + VMOVDQU 32(AX), Y1 + VMOVDQU 64(AX), Y2 + VMOVDQU 96(AX), Y3 + VPMULHW Y8, Y0, Y4 + VPMULHW Y8, Y1, Y5 + VPMULHW Y8, Y2, Y6 + VPMULHW Y8, Y3, Y7 + VPSRAW $0x0a, Y4, Y4 + VPSRAW $0x0a, Y5, Y5 + VPSRAW $0x0a, Y6, Y6 + VPSRAW $0x0a, Y7, Y7 + VPMULLW Y9, Y4, Y4 + VPMULLW Y9, Y5, Y5 + VPMULLW Y9, Y6, Y6 + VPMULLW Y9, Y7, Y7 + VPSUBW Y4, Y0, Y0 + VPSUBW Y5, Y1, Y1 + VPSUBW Y6, Y2, Y2 + VPSUBW Y7, Y3, Y3 + VMOVDQU Y0, (AX) + VMOVDQU Y1, 32(AX) + VMOVDQU Y2, 64(AX) + VMOVDQU Y3, 96(AX) + VMOVDQU 128(AX), Y0 + VMOVDQU 160(AX), Y1 + VMOVDQU 192(AX), Y2 + VMOVDQU 224(AX), Y3 + VPMULHW Y8, Y0, Y4 + VPMULHW Y8, Y1, Y5 + VPMULHW Y8, Y2, Y6 + VPMULHW Y8, Y3, Y7 + VPSRAW $0x0a, Y4, Y4 + VPSRAW $0x0a, Y5, Y5 + VPSRAW $0x0a, Y6, Y6 + VPSRAW $0x0a, Y7, Y7 + VPMULLW Y9, Y4, Y4 + VPMULLW Y9, Y5, Y5 + VPMULLW Y9, Y6, Y6 + VPMULLW Y9, Y7, Y7 + VPSUBW Y4, Y0, Y0 + VPSUBW Y5, Y1, Y1 + VPSUBW Y6, Y2, Y2 + VPSUBW Y7, Y3, Y3 + VMOVDQU Y0, 128(AX) + VMOVDQU Y1, 160(AX) + VMOVDQU Y2, 192(AX) + VMOVDQU Y3, 224(AX) + VMOVDQU 256(AX), Y0 + VMOVDQU 288(AX), Y1 + VMOVDQU 320(AX), Y2 + VMOVDQU 352(AX), Y3 + VPMULHW Y8, Y0, Y4 + VPMULHW Y8, Y1, Y5 + VPMULHW Y8, Y2, Y6 + VPMULHW Y8, Y3, Y7 + VPSRAW $0x0a, Y4, Y4 + VPSRAW $0x0a, Y5, Y5 + VPSRAW $0x0a, Y6, Y6 + VPSRAW $0x0a, Y7, Y7 + VPMULLW Y9, Y4, Y4 + VPMULLW Y9, Y5, Y5 + VPMULLW Y9, Y6, Y6 + VPMULLW Y9, Y7, Y7 + VPSUBW Y4, Y0, Y0 + VPSUBW Y5, Y1, Y1 + VPSUBW Y6, Y2, Y2 + VPSUBW Y7, Y3, Y3 + VMOVDQU Y0, 256(AX) + VMOVDQU Y1, 288(AX) + VMOVDQU Y2, 320(AX) + VMOVDQU Y3, 352(AX) + VMOVDQU 384(AX), Y0 + VMOVDQU 416(AX), Y1 + VMOVDQU 448(AX), Y2 + VMOVDQU 480(AX), Y3 + VPMULHW Y8, Y0, Y4 + VPMULHW Y8, Y1, Y5 + VPMULHW Y8, Y2, Y6 + VPMULHW Y8, Y3, Y7 + VPSRAW $0x0a, Y4, Y4 + VPSRAW $0x0a, Y5, Y5 + VPSRAW $0x0a, Y6, Y6 + VPSRAW $0x0a, Y7, Y7 + VPMULLW Y9, Y4, Y4 + VPMULLW Y9, Y5, Y5 + VPMULLW Y9, Y6, Y6 + VPMULLW Y9, Y7, Y7 + VPSUBW Y4, Y0, Y0 + VPSUBW Y5, Y1, Y1 + VPSUBW Y6, Y2, Y2 + VPSUBW Y7, Y3, Y3 + VMOVDQU Y0, 384(AX) + VMOVDQU Y1, 416(AX) + VMOVDQU Y2, 448(AX) + VMOVDQU Y3, 480(AX) + RET + +// func normalizeAVX2(p *[256]int16) +// Requires: AVX, AVX2 +TEXT ·normalizeAVX2(SB), NOSPLIT, $0-8 + MOVQ p+0(FP), AX + MOVL $0x00000d01, CX + VMOVD CX, X0 + VPBROADCASTW X0, Y9 + MOVL $0x00004ebf, CX + VMOVD CX, X0 + VPBROADCASTW X0, Y8 + VMOVDQU (AX), Y0 + VMOVDQU 32(AX), Y1 + VMOVDQU 64(AX), Y2 + VMOVDQU 96(AX), Y3 + VPMULHW Y8, Y0, Y4 + VPMULHW Y8, Y1, Y5 + VPMULHW Y8, Y2, Y6 + VPMULHW Y8, Y3, Y7 + VPSRAW $0x0a, Y4, Y4 + VPSRAW $0x0a, Y5, Y5 + VPSRAW $0x0a, Y6, Y6 + VPSRAW $0x0a, Y7, Y7 + VPMULLW Y9, Y4, Y4 + VPMULLW Y9, Y5, Y5 + VPMULLW Y9, Y6, Y6 + VPMULLW Y9, Y7, Y7 + VPSUBW Y4, Y0, Y0 + VPSUBW Y5, Y1, Y1 + VPSUBW Y6, Y2, Y2 + VPSUBW Y7, Y3, Y3 + VPSUBW Y9, Y0, Y0 + VPSUBW Y9, Y1, Y1 + VPSUBW Y9, Y2, Y2 + VPSUBW Y9, Y3, Y3 + VPSRAW $0x0f, Y0, Y4 + VPSRAW $0x0f, Y1, Y5 + VPSRAW $0x0f, Y2, Y6 + VPSRAW $0x0f, Y3, Y7 + VPAND Y4, Y9, Y4 + VPAND Y5, Y9, Y5 + VPAND Y6, Y9, Y6 + VPAND Y7, Y9, Y7 + VPADDW Y0, Y4, Y0 + VPADDW Y1, Y5, Y1 + VPADDW Y2, Y6, Y2 + VPADDW Y3, Y7, Y3 + VMOVDQU Y0, (AX) + VMOVDQU Y1, 32(AX) + VMOVDQU Y2, 64(AX) + VMOVDQU Y3, 96(AX) + VMOVDQU 128(AX), Y0 + VMOVDQU 160(AX), Y1 + VMOVDQU 192(AX), Y2 + VMOVDQU 224(AX), Y3 + VPMULHW Y8, Y0, Y4 + VPMULHW Y8, Y1, Y5 + VPMULHW Y8, Y2, Y6 + VPMULHW Y8, Y3, Y7 + VPSRAW $0x0a, Y4, Y4 + VPSRAW $0x0a, Y5, Y5 + VPSRAW $0x0a, Y6, Y6 + VPSRAW $0x0a, Y7, Y7 + VPMULLW Y9, Y4, Y4 + VPMULLW Y9, Y5, Y5 + VPMULLW Y9, Y6, Y6 + VPMULLW Y9, Y7, Y7 + VPSUBW Y4, Y0, Y0 + VPSUBW Y5, Y1, Y1 + VPSUBW Y6, Y2, Y2 + VPSUBW Y7, Y3, Y3 + VPSUBW Y9, Y0, Y0 + VPSUBW Y9, Y1, Y1 + VPSUBW Y9, Y2, Y2 + VPSUBW Y9, Y3, Y3 + VPSRAW $0x0f, Y0, Y4 + VPSRAW $0x0f, Y1, Y5 + VPSRAW $0x0f, Y2, Y6 + VPSRAW $0x0f, Y3, Y7 + VPAND Y4, Y9, Y4 + VPAND Y5, Y9, Y5 + VPAND Y6, Y9, Y6 + VPAND Y7, Y9, Y7 + VPADDW Y0, Y4, Y0 + VPADDW Y1, Y5, Y1 + VPADDW Y2, Y6, Y2 + VPADDW Y3, Y7, Y3 + VMOVDQU Y0, 128(AX) + VMOVDQU Y1, 160(AX) + VMOVDQU Y2, 192(AX) + VMOVDQU Y3, 224(AX) + VMOVDQU 256(AX), Y0 + VMOVDQU 288(AX), Y1 + VMOVDQU 320(AX), Y2 + VMOVDQU 352(AX), Y3 + VPMULHW Y8, Y0, Y4 + VPMULHW Y8, Y1, Y5 + VPMULHW Y8, Y2, Y6 + VPMULHW Y8, Y3, Y7 + VPSRAW $0x0a, Y4, Y4 + VPSRAW $0x0a, Y5, Y5 + VPSRAW $0x0a, Y6, Y6 + VPSRAW $0x0a, Y7, Y7 + VPMULLW Y9, Y4, Y4 + VPMULLW Y9, Y5, Y5 + VPMULLW Y9, Y6, Y6 + VPMULLW Y9, Y7, Y7 + VPSUBW Y4, Y0, Y0 + VPSUBW Y5, Y1, Y1 + VPSUBW Y6, Y2, Y2 + VPSUBW Y7, Y3, Y3 + VPSUBW Y9, Y0, Y0 + VPSUBW Y9, Y1, Y1 + VPSUBW Y9, Y2, Y2 + VPSUBW Y9, Y3, Y3 + VPSRAW $0x0f, Y0, Y4 + VPSRAW $0x0f, Y1, Y5 + VPSRAW $0x0f, Y2, Y6 + VPSRAW $0x0f, Y3, Y7 + VPAND Y4, Y9, Y4 + VPAND Y5, Y9, Y5 + VPAND Y6, Y9, Y6 + VPAND Y7, Y9, Y7 + VPADDW Y0, Y4, Y0 + VPADDW Y1, Y5, Y1 + VPADDW Y2, Y6, Y2 + VPADDW Y3, Y7, Y3 + VMOVDQU Y0, 256(AX) + VMOVDQU Y1, 288(AX) + VMOVDQU Y2, 320(AX) + VMOVDQU Y3, 352(AX) + VMOVDQU 384(AX), Y0 + VMOVDQU 416(AX), Y1 + VMOVDQU 448(AX), Y2 + VMOVDQU 480(AX), Y3 + VPMULHW Y8, Y0, Y4 + VPMULHW Y8, Y1, Y5 + VPMULHW Y8, Y2, Y6 + VPMULHW Y8, Y3, Y7 + VPSRAW $0x0a, Y4, Y4 + VPSRAW $0x0a, Y5, Y5 + VPSRAW $0x0a, Y6, Y6 + VPSRAW $0x0a, Y7, Y7 + VPMULLW Y9, Y4, Y4 + VPMULLW Y9, Y5, Y5 + VPMULLW Y9, Y6, Y6 + VPMULLW Y9, Y7, Y7 + VPSUBW Y4, Y0, Y0 + VPSUBW Y5, Y1, Y1 + VPSUBW Y6, Y2, Y2 + VPSUBW Y7, Y3, Y3 + VPSUBW Y9, Y0, Y0 + VPSUBW Y9, Y1, Y1 + VPSUBW Y9, Y2, Y2 + VPSUBW Y9, Y3, Y3 + VPSRAW $0x0f, Y0, Y4 + VPSRAW $0x0f, Y1, Y5 + VPSRAW $0x0f, Y2, Y6 + VPSRAW $0x0f, Y3, Y7 + VPAND Y4, Y9, Y4 + VPAND Y5, Y9, Y5 + VPAND Y6, Y9, Y6 + VPAND Y7, Y9, Y7 + VPADDW Y0, Y4, Y0 + VPADDW Y1, Y5, Y1 + VPADDW Y2, Y6, Y2 + VPADDW Y3, Y7, Y3 + VMOVDQU Y0, 384(AX) + VMOVDQU Y1, 416(AX) + VMOVDQU Y2, 448(AX) + VMOVDQU Y3, 480(AX) + RET diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/arm64.go b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/arm64.go new file mode 100644 index 0000000000..f6891b708d --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/arm64.go @@ -0,0 +1,83 @@ +//go:build arm64 && !purego +// +build arm64,!purego + +package common + +// Sets p to a + b. Does not normalize coefficients. +func (p *Poly) Add(a, b *Poly) { + polyAddARM64(p, a, b) +} + +// Sets p to a - b. Does not normalize coefficients. +func (p *Poly) Sub(a, b *Poly) { + polySubARM64(p, a, b) +} + +// Executes an in-place forward "NTT" on p. +// +// Assumes the coefficients are in absolute value ≤q. The resulting +// coefficients are in absolute value ≤7q. If the input is in Montgomery +// form, then the result is in Montgomery form and so (by linearity of the NTT) +// if the input is in regular form, then the result is also in regular form. +// The order of coefficients will be "tangled". These can be put back into +// their proper order by calling Detangle(). +func (p *Poly) NTT() { + p.nttGeneric() +} + +// Executes an in-place inverse "NTT" on p and multiply by the Montgomery +// factor R. +// +// Requires coefficients to be in "tangled" order, see Tangle(). +// Assumes the coefficients are in absolute value ≤q. The resulting +// coefficients are in absolute value ≤q. If the input is in Montgomery +// form, then the result is in Montgomery form and so (by linearity) +// if the input is in regular form, then the result is also in regular form. +func (p *Poly) InvNTT() { + p.invNTTGeneric() +} + +// Sets p to the "pointwise" multiplication of a and b. +// +// That is: InvNTT(p) = InvNTT(a) * InvNTT(b). Assumes a and b are in +// Montgomery form. Products between coefficients of a and b must be strictly +// bounded in absolute value by 2¹⁵q. p will be in Montgomery form and +// bounded in absolute value by 2q. +// +// Requires a and b to be in "tangled" order, see Tangle(). p will be in +// tangled order as well. +func (p *Poly) MulHat(a, b *Poly) { + p.mulHatGeneric(a, b) +} + +// Puts p into the right form to be used with (among others) InvNTT(). +func (p *Poly) Tangle() { + // In the generic implementation there is no advantage to using a + // different order, so we use the standard order everywhere. +} + +// Puts p back into standard form. +func (p *Poly) Detangle() { + // In the generic implementation there is no advantage to using a + // different order, so we use the standard order everywhere. +} + +// Almost normalizes coefficients. +// +// Ensures each coefficient is in {0, …, q}. +func (p *Poly) BarrettReduce() { + p.barrettReduceGeneric() +} + +// Normalizes coefficients. +// +// Ensures each coefficient is in {0, …, q-1}. +func (p *Poly) Normalize() { + p.normalizeGeneric() +} + +//go:noescape +func polyAddARM64(p, a, b *Poly) + +//go:noescape +func polySubARM64(p, a, b *Poly) diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/arm64.s b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/arm64.s new file mode 100644 index 0000000000..90c94a1a47 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/arm64.s @@ -0,0 +1,53 @@ +//go:build arm64 && !purego + +#include "go_asm.h" +#include "textflag.h" + +// func polyAddARM64(p, a, b *Poly) +TEXT ·polyAddARM64(SB), NOSPLIT|NOFRAME, $0-24 + MOVD p+0(FP), R0 + MOVD a+8(FP), R1 + MOVD b+16(FP), R2 + + MOVW $(const_N / 32), R3 + +loop: + VLD1.P (64)(R1), [V0.H8, V1.H8, V2.H8, V3.H8] + VLD1.P (64)(R2), [V4.H8, V5.H8, V6.H8, V7.H8] + + VADD V4.H8, V0.H8, V0.H8 + VADD V5.H8, V1.H8, V1.H8 + VADD V6.H8, V2.H8, V2.H8 + VADD V7.H8, V3.H8, V3.H8 + + VST1.P [V0.H8, V1.H8, V2.H8, V3.H8], (64)(R0) + + SUBS $1, R3, R3 + BGT loop + + RET + + +// func polySubARM64(p, a, b *Poly) +TEXT ·polySubARM64(SB), NOSPLIT|NOFRAME, $0-24 + MOVD p+0(FP), R0 + MOVD a+8(FP), R1 + MOVD b+16(FP), R2 + + MOVW $(const_N / 32), R3 + +loop: + VLD1.P (64)(R1), [V0.H8, V1.H8, V2.H8, V3.H8] + VLD1.P (64)(R2), [V4.H8, V5.H8, V6.H8, V7.H8] + + VSUB V4.H8, V0.H8, V0.H8 + VSUB V5.H8, V1.H8, V1.H8 + VSUB V6.H8, V2.H8, V2.H8 + VSUB V7.H8, V3.H8, V3.H8 + + VST1.P [V0.H8, V1.H8, V2.H8, V3.H8], (64)(R0) + + SUBS $1, R3, R3 + BGT loop + + RET diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/field.go b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/field.go new file mode 100644 index 0000000000..31e93ed524 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/field.go @@ -0,0 +1,74 @@ +package common + +// Given -2¹⁵ q ≤ x < 2¹⁵ q, returns -q < y < q with x 2⁻¹⁶ = y (mod q). +func montReduce(x int32) int16 { + // This is Montgomery reduction with R=2¹⁶. + // + // Note gcd(2¹⁶, q) = 1 as q is prime. Write q' := 62209 = q⁻¹ mod R. + // First we compute + // + // m := ((x mod R) q') mod R + // = x q' mod R + // = int16(x q') + // = int16(int32(x) * int32(q')) + // + // Note that x q' might be as big as 2³² and could overflow the int32 + // multiplication in the last line. However for any int32s a and b, + // we have int32(int64(a)*int64(b)) = int32(a*b) and so the result is ok. + m := int16(x * 62209) + + // Note that x - m q is divisible by R; indeed modulo R we have + // + // x - m q ≡ x - x q' q ≡ x - x q⁻¹ q ≡ x - x = 0. + // + // We return y := (x - m q) / R. Note that y is indeed correct as + // modulo q we have + // + // y ≡ x R⁻¹ - m q R⁻¹ = x R⁻¹ + // + // and as both 2¹⁵ q ≤ m q, x < 2¹⁵ q, we have + // 2¹⁶ q ≤ x - m q < 2¹⁶ and so q ≤ (x - m q) / R < q as desired. + return int16(uint32(x-int32(m)*int32(Q)) >> 16) +} + +// Given any x, returns x R mod q where R=2¹⁶. +func toMont(x int16) int16 { + // Note |1353 x| ≤ 1353 2¹⁵ ≤ 13318 q ≤ 2¹⁵ q and so we're within + // the bounds of montReduce. + return montReduce(int32(x) * 1353) // 1353 = R² mod q. +} + +// Given any x, compute 0 ≤ y ≤ q with x = y (mod q). +// +// Beware: we might have barrettReduce(x) = q ≠ 0 for some x. In fact, +// this happens if and only if x = -nq for some positive integer n. +func barrettReduce(x int16) int16 { + // This is standard Barrett reduction. + // + // For any x we have x mod q = x - ⌊x/q⌋ q. We will use 20159/2²⁶ as + // an approximation of 1/q. Note that 0 ≤ 20159/2²⁶ - 1/q ≤ 0.135/2²⁶ + // and so | x 20156/2²⁶ - x/q | ≤ 2⁻¹⁰ for |x| ≤ 2¹⁶. For all x + // not a multiple of q, the number x/q is further than 1/q from any integer + // and so ⌊x 20156/2²⁶⌋ = ⌊x/q⌋. If x is a multiple of q and x is positive, + // then x 20156/2²⁶ is larger than x/q so ⌊x 20156/2²⁶⌋ = ⌊x/q⌋ as well. + // Finally, if x is negative multiple of q, then ⌊x 20156/2²⁶⌋ = ⌊x/q⌋-1. + // Thus + // [ q if x=-nq for pos. integer n + // x - ⌊x 20156/2²⁶⌋ q = [ + // [ x mod q otherwise + // + // To compute actually compute this, note that + // + // ⌊x 20156/2²⁶⌋ = (20159 x) >> 26. + return x - int16((int32(x)*20159)>>26)*Q +} + +// Returns x if x < q and x - q otherwise. Assumes x ≥ -29439. +func csubq(x int16) int16 { + x -= Q // no overflow due to assumption x ≥ -29439. + // If x is positive, then x >> 15 = 0. If x is negative, + // then uint16(x >> 15) = 2¹⁶-1. So this will add back in q + // if x was smaller than q. + x += (x >> 15) & Q + return x +} diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/generic.go b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/generic.go new file mode 100644 index 0000000000..fd1e2950e8 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/generic.go @@ -0,0 +1,77 @@ +//go:build (!amd64 && !arm64) || purego +// +build !amd64,!arm64 purego + +package common + +// Sets p to a + b. Does not normalize coefficients. +func (p *Poly) Add(a, b *Poly) { + p.addGeneric(a, b) +} + +// Sets p to a - b. Does not normalize coefficients. +func (p *Poly) Sub(a, b *Poly) { + p.subGeneric(a, b) +} + +// Executes an in-place forward "NTT" on p. +// +// Assumes the coefficients are in absolute value ≤q. The resulting +// coefficients are in absolute value ≤7q. If the input is in Montgomery +// form, then the result is in Montgomery form and so (by linearity of the NTT) +// if the input is in regular form, then the result is also in regular form. +// The order of coefficients will be "tangled". These can be put back into +// their proper order by calling Detangle(). +func (p *Poly) NTT() { + p.nttGeneric() +} + +// Executes an in-place inverse "NTT" on p and multiply by the Montgomery +// factor R. +// +// Requires coefficients to be in "tangled" order, see Tangle(). +// Assumes the coefficients are in absolute value ≤q. The resulting +// coefficients are in absolute value ≤q. If the input is in Montgomery +// form, then the result is in Montgomery form and so (by linearity) +// if the input is in regular form, then the result is also in regular form. +func (p *Poly) InvNTT() { + p.invNTTGeneric() +} + +// Sets p to the "pointwise" multiplication of a and b. +// +// That is: InvNTT(p) = InvNTT(a) * InvNTT(b). Assumes a and b are in +// Montgomery form. Products between coefficients of a and b must be strictly +// bounded in absolute value by 2¹⁵q. p will be in Montgomery form and +// bounded in absolute value by 2q. +// +// Requires a and b to be in "tangled" order, see Tangle(). p will be in +// tangled order as well. +func (p *Poly) MulHat(a, b *Poly) { + p.mulHatGeneric(a, b) +} + +// Puts p into the right form to be used with (among others) InvNTT(). +func (p *Poly) Tangle() { + // In the generic implementation there is no advantage to using a + // different order, so we use the standard order everywhere. +} + +// Puts p back into standard form. +func (p *Poly) Detangle() { + // In the generic implementation there is no advantage to using a + // different order, so we use the standard order everywhere. +} + +// Almost normalizes coefficients. +// +// Ensures each coefficient is in {0, …, q}. +func (p *Poly) BarrettReduce() { + p.barrettReduceGeneric() +} + +// Normalizes coefficients. +// +// Ensures each coefficient is in {0, …, q-1}. +func (p *Poly) Normalize() { + p.normalizeGeneric() +} diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/ntt.go b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/ntt.go new file mode 100644 index 0000000000..5e565b3440 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/ntt.go @@ -0,0 +1,193 @@ +package common + +// Zetas lists precomputed powers of the primitive root of unity in +// Montgomery representation used for the NTT: +// +// Zetas[i] = ζᵇʳᵛ⁽ⁱ⁾ R mod q +// +// where ζ = 17, brv(i) is the bitreversal of a 7-bit number and R=2¹⁶ mod q. +// +// The following Python code generates the Zetas arrays: +// +// q = 13*2**8 + 1; zeta = 17 +// R = 2**16 % q # Montgomery const. +// def brv(x): return int(''.join(reversed(bin(x)[2:].zfill(7))),2) +// print([(pow(zeta, brv(i), q)*R)%q for i in range(128)]) +var Zetas = [128]int16{ + 2285, 2571, 2970, 1812, 1493, 1422, 287, 202, 3158, 622, 1577, 182, + 962, 2127, 1855, 1468, 573, 2004, 264, 383, 2500, 1458, 1727, 3199, + 2648, 1017, 732, 608, 1787, 411, 3124, 1758, 1223, 652, 2777, 1015, + 2036, 1491, 3047, 1785, 516, 3321, 3009, 2663, 1711, 2167, 126, + 1469, 2476, 3239, 3058, 830, 107, 1908, 3082, 2378, 2931, 961, 1821, + 2604, 448, 2264, 677, 2054, 2226, 430, 555, 843, 2078, 871, 1550, + 105, 422, 587, 177, 3094, 3038, 2869, 1574, 1653, 3083, 778, 1159, + 3182, 2552, 1483, 2727, 1119, 1739, 644, 2457, 349, 418, 329, 3173, + 3254, 817, 1097, 603, 610, 1322, 2044, 1864, 384, 2114, 3193, 1218, + 1994, 2455, 220, 2142, 1670, 2144, 1799, 2051, 794, 1819, 2475, + 2459, 478, 3221, 3021, 996, 991, 958, 1869, 1522, 1628, +} + +// InvNTTReductions keeps track of which coefficients to apply Barrett +// reduction to in Poly.InvNTT(). +// +// Generated in a lazily: once a butterfly is computed which is about to +// overflow the int16, the largest coefficient is reduced. If that is +// not enough, the other coefficient is reduced as well. +// +// This is actually optimal, as proven in https://eprint.iacr.org/2020/1377.pdf +var InvNTTReductions = [...]int{ + -1, // after layer 1 + -1, // after layer 2 + 16, 17, 48, 49, 80, 81, 112, 113, 144, 145, 176, 177, 208, 209, 240, + 241, -1, // after layer 3 + 0, 1, 32, 33, 34, 35, 64, 65, 96, 97, 98, 99, 128, 129, 160, 161, 162, 163, + 192, 193, 224, 225, 226, 227, -1, // after layer 4 + 2, 3, 66, 67, 68, 69, 70, 71, 130, 131, 194, 195, 196, 197, 198, + 199, -1, // after layer 5 + 4, 5, 6, 7, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, -1, // after layer 6 + -1, // after layer 7 +} + +// Executes an in-place forward "NTT" on p. +// +// Assumes the coefficients are in absolute value ≤q. The resulting +// coefficients are in absolute value ≤7q. If the input is in Montgomery +// form, then the result is in Montgomery form and so (by linearity of the NTT) +// if the input is in regular form, then the result is also in regular form. +// The order of coefficients will be "tangled". These can be put back into +// their proper order by calling Detangle(). +func (p *Poly) nttGeneric() { + // Note that ℤ_q does not have a primitive 512ᵗʰ root of unity (as 512 + // does not divide into q-1) and so we cannot do a regular NTT. ℤ_q + // does have a primitive 256ᵗʰ root of unity, the smallest of which + // is ζ := 17. + // + // Recall that our base ring R := ℤ_q[x] / (x²⁵⁶ + 1). The polynomial + // x²⁵⁶+1 will not split completely (as its roots would be 512ᵗʰ roots + // of unity.) However, it does split almost (using ζ¹²⁸ = -1): + // + // x²⁵⁶ + 1 = (x²)¹²⁸ - ζ¹²⁸ + // = ((x²)⁶⁴ - ζ⁶⁴)((x²)⁶⁴ + ζ⁶⁴) + // = ((x²)³² - ζ³²)((x²)³² + ζ³²)((x²)³² - ζ⁹⁶)((x²)³² + ζ⁹⁶) + // ⋮ + // = (x² - ζ)(x² + ζ)(x² - ζ⁶⁵)(x² + ζ⁶⁵) … (x² + ζ¹²⁷) + // + // Note that the powers of ζ that appear (from the second line down) are + // in binary + // + // 0100000 1100000 + // 0010000 1010000 0110000 1110000 + // 0001000 1001000 0101000 1101000 0011000 1011000 0111000 1111000 + // … + // + // That is: brv(2), brv(3), brv(4), …, where brv(x) denotes the 7-bit + // bitreversal of x. These powers of ζ are given by the Zetas array. + // + // The polynomials x² ± ζⁱ are irreducible and coprime, hence by + // the Chinese Remainder Theorem we know + // + // ℤ_q[x]/(x²⁵⁶+1) → ℤ_q[x]/(x²-ζ) x … x ℤ_q[x]/(x²+ζ¹²⁷) + // + // given by a ↦ ( a mod x²-ζ, …, a mod x²+ζ¹²⁷ ) + // is an isomorphism, which is the "NTT". It can be efficiently computed by + // + // + // a ↦ ( a mod (x²)⁶⁴ - ζ⁶⁴, a mod (x²)⁶⁴ + ζ⁶⁴ ) + // ↦ ( a mod (x²)³² - ζ³², a mod (x²)³² + ζ³², + // a mod (x²)⁹⁶ - ζ⁹⁶, a mod (x²)⁹⁶ + ζ⁹⁶ ) + // + // et cetera + // + // If N was 8 then this can be pictured in the following diagram: + // + // https://cnx.org/resources/17ee4dfe517a6adda05377b25a00bf6e6c93c334/File0026.png + // + // Each cross is a Cooley-Tukey butterfly: it's the map + // + // (a, b) ↦ (a + ζb, a - ζb) + // + // for the appropriate power ζ for that column and row group. + + k := 0 // Index into Zetas + + // l runs effectively over the columns in the diagram above; it is half the + // height of a row group, i.e. the number of butterflies in each row group. + // In the diagram above it would be 4, 2, 1. + for l := N / 2; l > 1; l >>= 1 { + // On the nᵗʰ iteration of the l-loop, the absolute value of the + // coefficients are bounded by nq. + + // offset effectively loops over the row groups in this column; it is + // the first row in the row group. + for offset := 0; offset < N-l; offset += 2 * l { + k++ + zeta := int32(Zetas[k]) + + // j loops over each butterfly in the row group. + for j := offset; j < offset+l; j++ { + t := montReduce(zeta * int32(p[j+l])) + p[j+l] = p[j] - t + p[j] += t + } + } + } +} + +// Executes an in-place inverse "NTT" on p and multiply by the Montgomery +// factor R. +// +// Requires coefficients to be in "tangled" order, see Tangle(). +// Assumes the coefficients are in absolute value ≤q. The resulting +// coefficients are in absolute value ≤q. If the input is in Montgomery +// form, then the result is in Montgomery form and so (by linearity) +// if the input is in regular form, then the result is also in regular form. +func (p *Poly) invNTTGeneric() { + k := 127 // Index into Zetas + r := -1 // Index into InvNTTReductions. + + // We basically do the opposite of NTT, but postpone dividing by 2 in the + // inverse of the Cooley-Tukey butterfly and accumulate that into a big + // division by 2⁷ at the end. See the comments in the NTT() function. + + for l := 2; l < N; l <<= 1 { + for offset := 0; offset < N-l; offset += 2 * l { + // As we're inverting, we need powers of ζ⁻¹ (instead of ζ). + // To be precise, we need ζᵇʳᵛ⁽ᵏ⁾⁻¹²⁸. However, as ζ⁻¹²⁸ = -1, + // we can use the existing Zetas table instead of + // keeping a separate InvZetas table as in Dilithium. + + minZeta := int32(Zetas[k]) + k-- + + for j := offset; j < offset+l; j++ { + // Gentleman-Sande butterfly: (a, b) ↦ (a + b, ζ(a-b)) + t := p[j+l] - p[j] + p[j] += p[j+l] + p[j+l] = montReduce(minZeta * int32(t)) + + // Note that if we had |a| < αq and |b| < βq before the + // butterfly, then now we have |a| < (α+β)q and |b| < q. + } + } + + // We let the InvNTTReductions instruct us which coefficients to + // Barrett reduce. See TestInvNTTReductions, which tests whether + // there is an overflow. + for { + r++ + i := InvNTTReductions[r] + if i < 0 { + break + } + p[i] = barrettReduce(p[i]) + } + } + + for j := 0; j < N; j++ { + // Note 1441 = (128)⁻¹ R². The coefficients are bounded by 9q, so + // as 1441 * 9 ≈ 2¹⁴ < 2¹⁵, we're within the required bounds + // for montReduce(). + p[j] = montReduce(1441 * int32(p[j])) + } +} diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/params.go b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/params.go new file mode 100644 index 0000000000..f04d1aaa32 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/params.go @@ -0,0 +1,22 @@ +package common + +import ( + "github.com/cloudflare/circl/pke/kyber/internal/common/params" +) + +const ( + // Q is the parameter q ≡ 3329 = 2¹¹ + 2¹⁰ + 2⁸ + 1. + Q = params.Q + + // N is the parameter N: the length of the polynomials + N = params.N + + // PolySize is the size of a packed polynomial. + PolySize = params.PolySize + + // PlaintextSize is the size of the plaintext + PlaintextSize = params.PlaintextSize + + // Eta2 is the parameter η₂ + Eta2 = params.Eta2 +) diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/params/params.go b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/params/params.go new file mode 100644 index 0000000000..dee58ee99e --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/params/params.go @@ -0,0 +1,21 @@ +package params + +// We put these parameters in a separate package so that the Go code, +// such as asm/src.go, that generates assembler can import it. + +const ( + // Q is the parameter q ≡ 3329 = 2¹¹ + 2¹⁰ + 2⁸ + 1. + Q int16 = 3329 + + // N is the parameter N: the length of the polynomials + N = 256 + + // PolySize is the size of a packed polynomial. + PolySize = 384 + + // PlaintextSize is the size of the plaintext + PlaintextSize = 32 + + // Eta2 is the parameter η₂ + Eta2 = 2 +) diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/poly.go b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/poly.go new file mode 100644 index 0000000000..f580e9150d --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/poly.go @@ -0,0 +1,332 @@ +package common + +// An element of our base ring R which are polynomials over ℤ_q +// modulo the equation Xᴺ = -1, where q=3329 and N=256. +// +// This type is also used to store NTT-transformed polynomials, +// see Poly.NTT(). +// +// Coefficients aren't always reduced. See Normalize(). +type Poly [N]int16 + +// Sets p to a + b. Does not normalize coefficients. +func (p *Poly) addGeneric(a, b *Poly) { + for i := 0; i < N; i++ { + p[i] = a[i] + b[i] + } +} + +// Sets p to a - b. Does not normalize coefficients. +func (p *Poly) subGeneric(a, b *Poly) { + for i := 0; i < N; i++ { + p[i] = a[i] - b[i] + } +} + +// Almost normalizes coefficients. +// +// Ensures each coefficient is in {0, …, q}. +func (p *Poly) barrettReduceGeneric() { + for i := 0; i < N; i++ { + p[i] = barrettReduce(p[i]) + } +} + +// Normalizes coefficients. +// +// Ensures each coefficient is in {0, …, q-1}. +func (p *Poly) normalizeGeneric() { + for i := 0; i < N; i++ { + p[i] = csubq(barrettReduce(p[i])) + } +} + +// Multiplies p in-place by the Montgomery factor 2¹⁶. +// +// Coefficients of p can be arbitrary. Resulting coefficients are bounded +// in absolute value by q. +func (p *Poly) ToMont() { + for i := 0; i < N; i++ { + p[i] = toMont(p[i]) + } +} + +// Sets p to the "pointwise" multiplication of a and b. +// +// That is: InvNTT(p) = InvNTT(a) * InvNTT(b). Assumes a and b are in +// Montgomery form. Products between coefficients of a and b must be strictly +// bounded in absolute value by 2¹⁵q. p will be in Montgomery form and +// bounded in absolute value by 2q. +// +// Requires a and b to be in "tangled" order, see Tangle(). p will be in +// tangled order as well. +func (p *Poly) mulHatGeneric(a, b *Poly) { + // Recall from the discussion in NTT(), that a transformed polynomial is + // an element of ℤ_q[x]/(x²-ζ) x … x ℤ_q[x]/(x²+ζ¹²⁷); + // that is: 128 degree-one polynomials instead of simply 256 elements + // from ℤ_q as in the regular NTT. So instead of pointwise multiplication, + // we multiply the 128 pairs of degree-one polynomials modulo the + // right equation: + // + // (a₁ + a₂x)(b₁ + b₂x) = a₁b₁ + a₂b₂ζ' + (a₁b₂ + a₂b₁)x, + // + // where ζ' is the appropriate power of ζ. + + k := 64 + for i := 0; i < N; i += 4 { + zeta := int32(Zetas[k]) + k++ + + p0 := montReduce(int32(a[i+1]) * int32(b[i+1])) + p0 = montReduce(int32(p0) * zeta) + p0 += montReduce(int32(a[i]) * int32(b[i])) + + p1 := montReduce(int32(a[i]) * int32(b[i+1])) + p1 += montReduce(int32(a[i+1]) * int32(b[i])) + + p[i] = p0 + p[i+1] = p1 + + p2 := montReduce(int32(a[i+3]) * int32(b[i+3])) + p2 = -montReduce(int32(p2) * zeta) + p2 += montReduce(int32(a[i+2]) * int32(b[i+2])) + + p3 := montReduce(int32(a[i+2]) * int32(b[i+3])) + p3 += montReduce(int32(a[i+3]) * int32(b[i+2])) + + p[i+2] = p2 + p[i+3] = p3 + } +} + +// Packs p into buf. buf should be of length PolySize. +// +// Assumes p is normalized (and not just Barrett reduced) and "tangled", +// see Tangle(). +func (p *Poly) Pack(buf []byte) { + q := *p + q.Detangle() + for i := 0; i < 128; i++ { + t0 := q[2*i] + t1 := q[2*i+1] + buf[3*i] = byte(t0) + buf[3*i+1] = byte(t0>>8) | byte(t1<<4) + buf[3*i+2] = byte(t1 >> 4) + } +} + +// Unpacks p from buf. +// +// buf should be of length PolySize. p will be "tangled", see Detangle(). +// +// p will not be normalized; instead 0 ≤ p[i] < 4096. +func (p *Poly) Unpack(buf []byte) { + for i := 0; i < 128; i++ { + p[2*i] = int16(buf[3*i]) | ((int16(buf[3*i+1]) << 8) & 0xfff) + p[2*i+1] = int16(buf[3*i+1]>>4) | (int16(buf[3*i+2]) << 4) + } + p.Tangle() +} + +// Set p to Decompress_q(m, 1). +// +// p will be normalized. m has to be of PlaintextSize. +func (p *Poly) DecompressMessage(m []byte) { + // Decompress_q(x, 1) = ⌈xq/2⌋ = ⌊xq/2+½⌋ = (xq+1) >> 1 and so + // Decompress_q(0, 1) = 0 and Decompress_q(1, 1) = (q+1)/2. + for i := 0; i < 32; i++ { + for j := 0; j < 8; j++ { + bit := (m[i] >> uint(j)) & 1 + + // Set coefficient to either 0 or (q+1)/2 depending on the bit. + p[8*i+j] = -int16(bit) & ((Q + 1) / 2) + } + } +} + +// Writes Compress_q(p, 1) to m. +// +// Assumes p is normalized. m has to be of length at least PlaintextSize. +func (p *Poly) CompressMessageTo(m []byte) { + // Compress_q(x, 1) is 1 on {833, …, 2496} and zero elsewhere. + for i := 0; i < 32; i++ { + m[i] = 0 + for j := 0; j < 8; j++ { + x := 1664 - p[8*i+j] + // With the previous substitution, we want to return 1 if + // and only if x is in {831, …, -832}. + x = (x >> 15) ^ x + // Note (x >> 15)ˣ if x≥0 and -x-1 otherwise. Thus now we want + // to return 1 iff x ≤ 831, ie. x - 832 < 0. + x -= 832 + m[i] |= ((byte(x >> 15)) & 1) << uint(j) + } + } +} + +// Set p to Decompress_q(m, 1). +// +// Assumes d is in {4, 5, 10, 11}. p will be normalized. +func (p *Poly) Decompress(m []byte, d int) { + // Decompress_q(x, d) = ⌈(q/2ᵈ)x⌋ + // = ⌊(q/2ᵈ)x+½⌋ + // = ⌊(qx + 2ᵈ⁻¹)/2ᵈ⌋ + // = (qx + (1<<(d-1))) >> d + switch d { + case 4: + for i := 0; i < N/2; i++ { + p[2*i] = int16(((1 << 3) + + uint32(m[i]&15)*uint32(Q)) >> 4) + p[2*i+1] = int16(((1 << 3) + + uint32(m[i]>>4)*uint32(Q)) >> 4) + } + case 5: + var t [8]uint16 + idx := 0 + for i := 0; i < N/8; i++ { + t[0] = uint16(m[idx]) + t[1] = (uint16(m[idx]) >> 5) | (uint16(m[idx+1] << 3)) + t[2] = uint16(m[idx+1]) >> 2 + t[3] = (uint16(m[idx+1]) >> 7) | (uint16(m[idx+2] << 1)) + t[4] = (uint16(m[idx+2]) >> 4) | (uint16(m[idx+3] << 4)) + t[5] = uint16(m[idx+3]) >> 1 + t[6] = (uint16(m[idx+3]) >> 6) | (uint16(m[idx+4] << 2)) + t[7] = uint16(m[idx+4]) >> 3 + + for j := 0; j < 8; j++ { + p[8*i+j] = int16(((1 << 4) + + uint32(t[j]&((1<<5)-1))*uint32(Q)) >> 5) + } + + idx += 5 + } + + case 10: + var t [4]uint16 + idx := 0 + for i := 0; i < N/4; i++ { + t[0] = uint16(m[idx]) | (uint16(m[idx+1]) << 8) + t[1] = (uint16(m[idx+1]) >> 2) | (uint16(m[idx+2]) << 6) + t[2] = (uint16(m[idx+2]) >> 4) | (uint16(m[idx+3]) << 4) + t[3] = (uint16(m[idx+3]) >> 6) | (uint16(m[idx+4]) << 2) + + for j := 0; j < 4; j++ { + p[4*i+j] = int16(((1 << 9) + + uint32(t[j]&((1<<10)-1))*uint32(Q)) >> 10) + } + + idx += 5 + } + case 11: + var t [8]uint16 + idx := 0 + for i := 0; i < N/8; i++ { + t[0] = uint16(m[idx]) | (uint16(m[idx+1]) << 8) + t[1] = (uint16(m[idx+1]) >> 3) | (uint16(m[idx+2]) << 5) + t[2] = (uint16(m[idx+2]) >> 6) | (uint16(m[idx+3]) << 2) | (uint16(m[idx+4]) << 10) + t[3] = (uint16(m[idx+4]) >> 1) | (uint16(m[idx+5]) << 7) + t[4] = (uint16(m[idx+5]) >> 4) | (uint16(m[idx+6]) << 4) + t[5] = (uint16(m[idx+6]) >> 7) | (uint16(m[idx+7]) << 1) | (uint16(m[idx+8]) << 9) + t[6] = (uint16(m[idx+8]) >> 2) | (uint16(m[idx+9]) << 6) + t[7] = (uint16(m[idx+9]) >> 5) | (uint16(m[idx+10]) << 3) + + for j := 0; j < 8; j++ { + p[8*i+j] = int16(((1 << 10) + + uint32(t[j]&((1<<11)-1))*uint32(Q)) >> 11) + } + + idx += 11 + } + default: + panic("unsupported d") + } +} + +// Writes Compress_q(p, d) to m. +// +// Assumes p is normalized and d is in {4, 5, 10, 11}. +func (p *Poly) CompressTo(m []byte, d int) { + // Compress_q(x, d) = ⌈(2ᵈ/q)x⌋ mod⁺ 2ᵈ + // = ⌊(2ᵈ/q)x+½⌋ mod⁺ 2ᵈ + // = ⌊((x << d) + q/2) / q⌋ mod⁺ 2ᵈ + // = DIV((x << d) + q/2, q) & ((1<>e, where a/(2^e) ≈ 1/q. + // For d in {10,11} we use 20,642,679/2^36, which computes division by x/q + // correctly for 0 ≤ x < 41,522,616, which fits (q << 11) + q/2 comfortably. + // For d in {4,5} we use 315/2^20, which doesn't compute division by x/q + // correctly for all inputs, but it's close enough that the end result + // of the compression is correct. The advantage is that we do not need + // to use a 64-bit intermediate value. + switch d { + case 4: + var t [8]uint16 + idx := 0 + for i := 0; i < N/8; i++ { + for j := 0; j < 8; j++ { + t[j] = uint16((((uint32(p[8*i+j])<<4)+uint32(Q)/2)*315)>> + 20) & ((1 << 4) - 1) + } + m[idx] = byte(t[0]) | byte(t[1]<<4) + m[idx+1] = byte(t[2]) | byte(t[3]<<4) + m[idx+2] = byte(t[4]) | byte(t[5]<<4) + m[idx+3] = byte(t[6]) | byte(t[7]<<4) + idx += 4 + } + + case 5: + var t [8]uint16 + idx := 0 + for i := 0; i < N/8; i++ { + for j := 0; j < 8; j++ { + t[j] = uint16((((uint32(p[8*i+j])<<5)+uint32(Q)/2)*315)>> + 20) & ((1 << 5) - 1) + } + m[idx] = byte(t[0]) | byte(t[1]<<5) + m[idx+1] = byte(t[1]>>3) | byte(t[2]<<2) | byte(t[3]<<7) + m[idx+2] = byte(t[3]>>1) | byte(t[4]<<4) + m[idx+3] = byte(t[4]>>4) | byte(t[5]<<1) | byte(t[6]<<6) + m[idx+4] = byte(t[6]>>2) | byte(t[7]<<3) + idx += 5 + } + + case 10: + var t [4]uint16 + idx := 0 + for i := 0; i < N/4; i++ { + for j := 0; j < 4; j++ { + t[j] = uint16((uint64((uint32(p[4*i+j])<<10)+uint32(Q)/2)* + 20642679)>>36) & ((1 << 10) - 1) + } + m[idx] = byte(t[0]) + m[idx+1] = byte(t[0]>>8) | byte(t[1]<<2) + m[idx+2] = byte(t[1]>>6) | byte(t[2]<<4) + m[idx+3] = byte(t[2]>>4) | byte(t[3]<<6) + m[idx+4] = byte(t[3] >> 2) + idx += 5 + } + case 11: + var t [8]uint16 + idx := 0 + for i := 0; i < N/8; i++ { + for j := 0; j < 8; j++ { + t[j] = uint16((uint64((uint32(p[8*i+j])<<11)+uint32(Q)/2)* + 20642679)>>36) & ((1 << 11) - 1) + } + m[idx] = byte(t[0]) + m[idx+1] = byte(t[0]>>8) | byte(t[1]<<3) + m[idx+2] = byte(t[1]>>5) | byte(t[2]<<6) + m[idx+3] = byte(t[2] >> 2) + m[idx+4] = byte(t[2]>>10) | byte(t[3]<<1) + m[idx+5] = byte(t[3]>>7) | byte(t[4]<<4) + m[idx+6] = byte(t[4]>>4) | byte(t[5]<<7) + m[idx+7] = byte(t[5] >> 1) + m[idx+8] = byte(t[5]>>9) | byte(t[6]<<2) + m[idx+9] = byte(t[6]>>6) | byte(t[7]<<5) + m[idx+10] = byte(t[7] >> 3) + idx += 11 + } + default: + panic("unsupported d") + } +} diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/sample.go b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/sample.go new file mode 100644 index 0000000000..033ff4e305 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/sample.go @@ -0,0 +1,236 @@ +package common + +import ( + "encoding/binary" + + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/simd/keccakf1600" +) + +// DeriveX4Available indicates whether the system supports the quick fourway +// sampling variants like PolyDeriveUniformX4. +var DeriveX4Available = keccakf1600.IsEnabledX4() + +// Samples p from a centered binomial distribution with given η. +// +// Essentially CBD_η(PRF(seed, nonce)) from the specification. +func (p *Poly) DeriveNoise(seed []byte, nonce uint8, eta int) { + switch eta { + case 2: + p.DeriveNoise2(seed, nonce) + case 3: + p.DeriveNoise3(seed, nonce) + default: + panic("unsupported eta") + } +} + +// Sample p from a centered binomial distribution with n=6 and p=½ - that is: +// coefficients are in {-3, -2, -1, 0, 1, 2, 3} with probabilities {1/64, 3/32, +// 15/64, 5/16, 16/64, 3/32, 1/64}. +func (p *Poly) DeriveNoise3(seed []byte, nonce uint8) { + keySuffix := [1]byte{nonce} + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + _, _ = h.Write(keySuffix[:]) + + // The distribution at hand is exactly the same as that + // of (a₁ + a₂ + a₃) - (b₁ + b₂+b₃) where a_i,b_i~U(1). Thus we need + // 6 bits per coefficients, thus 192 bytes of input entropy. + + // We add two extra zero bytes in the buffer to be able to read 8 bytes + // at the same time (while using only 6.) + var buf [192 + 2]byte + _, _ = h.Read(buf[:192]) + + for i := 0; i < 32; i++ { + // t is interpreted as a₁ + 2a₂ + 4a₃ + 8b₁ + 16b₂ + …. + t := binary.LittleEndian.Uint64(buf[6*i:]) + + d := t & 0x249249249249 // a₁ + 8b₁ + … + d += (t >> 1) & 0x249249249249 // a₁ + a₂ + 8(b₁ + b₂) + … + d += (t >> 2) & 0x249249249249 // a₁ + a₂ + a₃ + 4(b₁ + b₂ + b₃) + … + + for j := 0; j < 8; j++ { + a := int16(d) & 0x7 // a₁ + a₂ + a₃ + d >>= 3 + b := int16(d) & 0x7 // b₁ + b₂ + b₃ + d >>= 3 + p[8*i+j] = a - b + } + } +} + +// Sample p from a centered binomial distribution with n=4 and p=½ - that is: +// coefficients are in {-2, -1, 0, 1, 2} with probabilities {1/16, 1/4, +// 3/8, 1/4, 1/16}. +func (p *Poly) DeriveNoise2(seed []byte, nonce uint8) { + keySuffix := [1]byte{nonce} + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + _, _ = h.Write(keySuffix[:]) + + // The distribution at hand is exactly the same as that + // of (a + a') - (b + b') where a,a',b,b'~U(1). Thus we need 4 bits per + // coefficients, thus 128 bytes of input entropy. + + var buf [128]byte + _, _ = h.Read(buf[:]) + + for i := 0; i < 16; i++ { + // t is interpreted as a + 2a' + 4b + 8b' + …. + t := binary.LittleEndian.Uint64(buf[8*i:]) + + d := t & 0x5555555555555555 // a + 4b + … + d += (t >> 1) & 0x5555555555555555 // a+a' + 4(b + b') + … + + for j := 0; j < 16; j++ { + a := int16(d) & 0x3 + d >>= 2 + b := int16(d) & 0x3 + d >>= 2 + p[16*i+j] = a - b + } + } +} + +// For each i, sample ps[i] uniformly from the given seed for coordinates +// xs[i] and ys[i]. ps[i] may be nil and is ignored in that case. +// +// Can only be called when DeriveX4Available is true. +func PolyDeriveUniformX4(ps [4]*Poly, seed *[32]byte, xs, ys [4]uint8) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < 4; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // Absorb the coordinates, the SHAKE128 domain separator (0b1111), the + // start of the padding (0b…001) and the end of the padding 0b100…. + // Recall that the rate of SHAKE128 is 168; ie. 21 uint64s. + for j := 0; j < 4; j++ { + state[4*4+j] = uint64(xs[j]) | (uint64(ys[j]) << 8) | (0x1f << 16) + state[20*4+j] = 0x80 << 56 + } + + var idx [4]int // indices into ps + for j := 0; j < 4; j++ { + if ps[j] == nil { + idx[j] = N // mark nil polynomials as completed + } + } + + done := false + for !done { + // Applies KeccaK-f[1600] to state to get the next 21 uint64s of each of + // the four SHAKE128 streams. + perm.Permute() + + done = true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == N { + continue + } + for i := 0; i < 7; i++ { + var t [16]uint16 + + v1 := state[i*3*4+j] + v2 := state[(i*3+1)*4+j] + v3 := state[(i*3+2)*4+j] + + t[0] = uint16(v1) & 0xfff + t[1] = uint16(v1>>12) & 0xfff + t[2] = uint16(v1>>24) & 0xfff + t[3] = uint16(v1>>36) & 0xfff + t[4] = uint16(v1>>48) & 0xfff + t[5] = uint16((v1>>60)|(v2<<4)) & 0xfff + + t[6] = uint16(v2>>8) & 0xfff + t[7] = uint16(v2>>20) & 0xfff + t[8] = uint16(v2>>32) & 0xfff + t[9] = uint16(v2>>44) & 0xfff + t[10] = uint16((v2>>56)|(v3<<8)) & 0xfff + + t[11] = uint16(v3>>4) & 0xfff + t[12] = uint16(v3>>16) & 0xfff + t[13] = uint16(v3>>28) & 0xfff + t[14] = uint16(v3>>40) & 0xfff + t[15] = uint16(v3>>52) & 0xfff + + for k := 0; k < 16; k++ { + if t[k] < uint16(Q) { + ps[j][idx[j]] = int16(t[k]) + idx[j]++ + if idx[j] == N { + continue PolyLoop + } + } + } + } + + done = false + } + } + + for i := 0; i < 4; i++ { + if ps[i] != nil { + ps[i].Tangle() + } + } +} + +// Sample p uniformly from the given seed and x and y coordinates. +// +// Coefficients are reduced and will be in "tangled" order. See Tangle(). +func (p *Poly) DeriveUniform(seed *[32]byte, x, y uint8) { + var seedSuffix [2]byte + var buf [168]byte // rate of SHAKE-128 + + seedSuffix[0] = x + seedSuffix[1] = y + + h := sha3.NewShake128() + _, _ = h.Write(seed[:]) + _, _ = h.Write(seedSuffix[:]) + + i := 0 + for { + _, _ = h.Read(buf[:]) + + for j := 0; j < 168; j += 3 { + t1 := (uint16(buf[j]) | (uint16(buf[j+1]) << 8)) & 0xfff //#nosec G602 -- buf has fixed length 168 + t2 := (uint16(buf[j+1]>>4) | (uint16(buf[j+2]) << 4)) & 0xfff //#nosec G602 -- buf has fixed length 168 + + if t1 < uint16(Q) { + p[i] = int16(t1) + i++ + + if i == N { + break + } + } + + if t2 < uint16(Q) { + p[i] = int16(t2) + i++ + + if i == N { + break + } + } + } + + if i == N { + break + } + } + + p.Tangle() +} diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/stubs_amd64.go b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/stubs_amd64.go new file mode 100644 index 0000000000..4b4700dfd9 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/internal/common/stubs_amd64.go @@ -0,0 +1,32 @@ +// Code generated by command: go run src.go -out ../amd64.s -stubs ../stubs_amd64.go -pkg common. DO NOT EDIT. + +//go:build amd64 && !purego + +package common + +//go:noescape +func addAVX2(p *[256]int16, a *[256]int16, b *[256]int16) + +//go:noescape +func subAVX2(p *[256]int16, a *[256]int16, b *[256]int16) + +//go:noescape +func nttAVX2(p *[256]int16) + +//go:noescape +func invNttAVX2(p *[256]int16) + +//go:noescape +func mulHatAVX2(p *[256]int16, a *[256]int16, b *[256]int16) + +//go:noescape +func detangleAVX2(p *[256]int16) + +//go:noescape +func tangleAVX2(p *[256]int16) + +//go:noescape +func barrettReduceAVX2(p *[256]int16) + +//go:noescape +func normalizeAVX2(p *[256]int16) diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/cpapke.go b/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/cpapke.go new file mode 100644 index 0000000000..bea07e8743 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/cpapke.go @@ -0,0 +1,192 @@ +// Code generated from kyber512/internal/cpapke.go by gen.go + +package internal + +import ( + "bytes" + + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/pke/kyber/internal/common" +) + +// A Kyber.CPAPKE private key. +type PrivateKey struct { + sh Vec // NTT(s), normalized +} + +// A Kyber.CPAPKE public key. +type PublicKey struct { + rho [32]byte // ρ, the seed for the matrix A + th Vec // NTT(t), normalized + + // cached values + aT Mat // the matrix Aᵀ +} + +// Packs the private key to buf. +func (sk *PrivateKey) Pack(buf []byte) { + sk.sh.Pack(buf) +} + +// Unpacks the private key from buf. +func (sk *PrivateKey) Unpack(buf []byte) { + sk.sh.Unpack(buf) + sk.sh.Normalize() +} + +// Packs the public key to buf. +func (pk *PublicKey) Pack(buf []byte) { + pk.th.Pack(buf) + copy(buf[K*common.PolySize:], pk.rho[:]) +} + +// Unpacks the public key from buf. Checks if the public key is normalized. +func (pk *PublicKey) UnpackMLKEM(buf []byte) error { + pk.Unpack(buf) + + // FIPS 203 §7.2 "encapsulation key check" (2). + var buf2 [K * common.PolySize]byte + pk.th.Pack(buf2[:]) + if !bytes.Equal(buf[:len(buf2)], buf2[:]) { + return kem.ErrPubKey + } + return nil +} + +// Unpacks the public key from buf. +func (pk *PublicKey) Unpack(buf []byte) { + pk.th.Unpack(buf) + pk.th.Normalize() + copy(pk.rho[:], buf[K*common.PolySize:]) + pk.aT.Derive(&pk.rho, true) +} + +// Derives a new Kyber.CPAPKE keypair from the given seed. +func NewKeyFromSeed(seed []byte) (*PublicKey, *PrivateKey) { + var pk PublicKey + var sk PrivateKey + + var expandedSeed [64]byte + + h := sha3.New512() + _, _ = h.Write(seed) + + // This writes hash into expandedSeed. Yes, this is idiomatic Go. + _, _ = h.Read(expandedSeed[:]) + + copy(pk.rho[:], expandedSeed[:32]) + sigma := expandedSeed[32:] // σ, the noise seed + + pk.aT.Derive(&pk.rho, false) // Expand ρ to matrix A; we'll transpose later + + var eh Vec + sk.sh.DeriveNoise(sigma, 0, Eta1) // Sample secret vector s + sk.sh.NTT() + sk.sh.Normalize() + + eh.DeriveNoise(sigma, K, Eta1) // Sample blind e + eh.NTT() + + // Next, we compute t = A s + e. + for i := 0; i < K; i++ { + // Note that coefficients of s are bounded by q and those of A + // are bounded by 4.5q and so their product is bounded by 2¹⁵q + // as required for multiplication. + PolyDotHat(&pk.th[i], &pk.aT[i], &sk.sh) + + // A and s were not in Montgomery form, so the Montgomery + // multiplications in the inner product added a factor R⁻¹ which + // we'll cancel out now. This will also ensure the coefficients of + // t are bounded in absolute value by q. + pk.th[i].ToMont() + } + + pk.th.Add(&pk.th, &eh) // bounded by 8q. + pk.th.Normalize() + pk.aT.Transpose() + + return &pk, &sk +} + +// Decrypts ciphertext ct meant for private key sk to plaintext pt. +func (sk *PrivateKey) DecryptTo(pt, ct []byte) { + var u Vec + var v, m common.Poly + + u.Decompress(ct, DU) + v.Decompress(ct[K*compressedPolySize(DU):], DV) + + // Compute m = v - + u.NTT() + PolyDotHat(&m, &sk.sh, &u) + m.BarrettReduce() + m.InvNTT() + m.Sub(&v, &m) + m.Normalize() + + // Compress polynomial m to original message + m.CompressMessageTo(pt) +} + +// Encrypts message pt for the public key to ciphertext ct using randomness +// from seed. +// +// seed has to be of length SeedSize, pt of PlaintextSize and ct of +// CiphertextSize. +func (pk *PublicKey) EncryptTo(ct, pt, seed []byte) { + var rh, e1, u Vec + var e2, v, m common.Poly + + // Sample r, e₁ and e₂ from B_η + rh.DeriveNoise(seed, 0, Eta1) + rh.NTT() + rh.BarrettReduce() + + e1.DeriveNoise(seed, K, common.Eta2) + e2.DeriveNoise(seed, 2*K, common.Eta2) + + // Next we compute u = Aᵀ r + e₁. First Aᵀ. + for i := 0; i < K; i++ { + // Note that coefficients of r are bounded by q and those of Aᵀ + // are bounded by 4.5q and so their product is bounded by 2¹⁵q + // as required for multiplication. + PolyDotHat(&u[i], &pk.aT[i], &rh) + } + + u.BarrettReduce() + + // Aᵀ and r were not in Montgomery form, so the Montgomery + // multiplications in the inner product added a factor R⁻¹ which + // the InvNTT cancels out. + u.InvNTT() + + u.Add(&u, &e1) // u = Aᵀ r + e₁ + + // Next compute v = + e₂ + Decompress_q(m, 1). + PolyDotHat(&v, &pk.th, &rh) + v.BarrettReduce() + v.InvNTT() + + m.DecompressMessage(pt) + v.Add(&v, &m) + v.Add(&v, &e2) // v = + e₂ + Decompress_q(m, 1) + + // Pack ciphertext + u.Normalize() + v.Normalize() + + u.CompressTo(ct, DU) + v.CompressTo(ct[K*compressedPolySize(DU):], DV) +} + +// Returns whether sk equals other. +func (sk *PrivateKey) Equal(other *PrivateKey) bool { + ret := int16(0) + for i := 0; i < K; i++ { + for j := 0; j < common.N; j++ { + ret |= sk.sh[i][j] ^ other.sh[i][j] + } + } + return ret == 0 +} diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/mat.go b/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/mat.go new file mode 100644 index 0000000000..404aacfb02 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/mat.go @@ -0,0 +1,85 @@ +// Code generated from kyber512/internal/mat.go by gen.go + +package internal + +import ( + "github.com/cloudflare/circl/pke/kyber/internal/common" +) + +// A k by k matrix of polynomials. +type Mat [K]Vec + +// Expands the given seed to the corresponding matrix A or its transpose Aᵀ. +func (m *Mat) Derive(seed *[32]byte, transpose bool) { + if !common.DeriveX4Available { + if transpose { + for i := 0; i < K; i++ { + for j := 0; j < K; j++ { + m[i][j].DeriveUniform(seed, uint8(i), uint8(j)) + } + } + } else { + for i := 0; i < K; i++ { + for j := 0; j < K; j++ { + m[i][j].DeriveUniform(seed, uint8(j), uint8(i)) + } + } + } + return + } + + var ps [4]*common.Poly + var xs [4]uint8 + var ys [4]uint8 + x := uint8(0) + y := uint8(0) + + for x != K { + idx := 0 + for ; idx < 4; idx++ { + ps[idx] = &m[x][y] + + if transpose { + xs[idx] = x + ys[idx] = y + } else { + xs[idx] = y + ys[idx] = x + } + + y++ + if y == K { + x++ + y = 0 + + if x == K { + if idx == 0 { + // If there is just one left, then a plain DeriveUniform + // is quicker than the X4 variant. + ps[0].DeriveUniform(seed, xs[0], ys[0]) + return + } + + for idx++; idx < 4; idx++ { + ps[idx] = nil + } + + break + } + } + } + + common.PolyDeriveUniformX4(ps, seed, xs, ys) + } +} + +// Transposes A in place. +func (m *Mat) Transpose() { + for i := 0; i < K-1; i++ { + for j := i + 1; j < K; j++ { + t := m[i][j] + m[i][j] = m[j][i] + m[j][i] = t + } + } +} diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/params.go b/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/params.go new file mode 100644 index 0000000000..669b0edaca --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/params.go @@ -0,0 +1,21 @@ +// Code generated from params.templ.go. DO NOT EDIT. + +package internal + +import ( + "github.com/cloudflare/circl/pke/kyber/internal/common" +) + +const ( + K = 4 + Eta1 = 2 + DU = 11 + DV = 5 + PublicKeySize = 32 + K*common.PolySize + + PrivateKeySize = K * common.PolySize + + PlaintextSize = common.PlaintextSize + SeedSize = 32 + CiphertextSize = 1568 +) diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/vec.go b/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/vec.go new file mode 100644 index 0000000000..6681895a72 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/internal/vec.go @@ -0,0 +1,125 @@ +// Code generated from kyber512/internal/vec.go by gen.go + +package internal + +import ( + "github.com/cloudflare/circl/pke/kyber/internal/common" +) + +// A vector of K polynomials +type Vec [K]common.Poly + +// Samples v[i] from a centered binomial distribution with given η, +// seed and nonce+i. +// +// Essentially CBD_η(PRF(seed, nonce+i)) from the specification. +func (v *Vec) DeriveNoise(seed []byte, nonce uint8, eta int) { + for i := 0; i < K; i++ { + v[i].DeriveNoise(seed, nonce+uint8(i), eta) + } +} + +// Sets p to the inner product of a and b using "pointwise" multiplication. +// +// See MulHat() and NTT() for a description of the multiplication. +// Assumes a and b are in Montgomery form. p will be in Montgomery form, +// and its coefficients will be bounded in absolute value by 2kq. +// If a and b are not in Montgomery form, then the action is the same +// as "pointwise" multiplication followed by multiplying by R⁻¹, the inverse +// of the Montgomery factor. +func PolyDotHat(p *common.Poly, a, b *Vec) { + var t common.Poly + *p = common.Poly{} // set p to zero + for i := 0; i < K; i++ { + t.MulHat(&a[i], &b[i]) + p.Add(&t, p) + } +} + +// Almost normalizes coefficients in-place. +// +// Ensures each coefficient is in {0, …, q}. +func (v *Vec) BarrettReduce() { + for i := 0; i < K; i++ { + v[i].BarrettReduce() + } +} + +// Normalizes coefficients in-place. +// +// Ensures each coefficient is in {0, …, q-1}. +func (v *Vec) Normalize() { + for i := 0; i < K; i++ { + v[i].Normalize() + } +} + +// Applies in-place inverse NTT(). See Poly.InvNTT() for assumptions. +func (v *Vec) InvNTT() { + for i := 0; i < K; i++ { + v[i].InvNTT() + } +} + +// Applies in-place forward NTT(). See Poly.NTT() for assumptions. +func (v *Vec) NTT() { + for i := 0; i < K; i++ { + v[i].NTT() + } +} + +// Sets v to a + b. +func (v *Vec) Add(a, b *Vec) { + for i := 0; i < K; i++ { + v[i].Add(&a[i], &b[i]) + } +} + +// Packs v into buf, which must be of length K*PolySize. +func (v *Vec) Pack(buf []byte) { + for i := 0; i < K; i++ { + v[i].Pack(buf[common.PolySize*i:]) + } +} + +// Unpacks v from buf which must be of length K*PolySize. +func (v *Vec) Unpack(buf []byte) { + for i := 0; i < K; i++ { + v[i].Unpack(buf[common.PolySize*i:]) + } +} + +// Writes Compress_q(v, d) to m. +// +// Assumes v is normalized and d is in {3, 4, 5, 10, 11}. +func (v *Vec) CompressTo(m []byte, d int) { + size := compressedPolySize(d) + for i := 0; i < K; i++ { + v[i].CompressTo(m[size*i:], d) + } +} + +// Set v to Decompress_q(m, 1). +// +// Assumes d is in {3, 4, 5, 10, 11}. v will be normalized. +func (v *Vec) Decompress(m []byte, d int) { + size := compressedPolySize(d) + for i := 0; i < K; i++ { + v[i].Decompress(m[size*i:], d) + } +} + +// ⌈(256 d)/8⌉ +func compressedPolySize(d int) int { + switch d { + case 4: + return 128 + case 5: + return 160 + case 10: + return 320 + case 11: + return 352 + } + panic("unsupported d") +} diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/kyber.go b/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/kyber.go new file mode 100644 index 0000000000..86cc6c6dbc --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/kyber1024/kyber.go @@ -0,0 +1,175 @@ +// Code generated from pkg.templ.go. DO NOT EDIT. + +// kyber1024 implements the IND-CPA-secure Public Key Encryption +// scheme Kyber1024.CPAPKE as submitted to round 3 of the NIST PQC competition +// and described in +// +// https://pq-crystals.org/kyber/data/kyber-specification-round3.pdf +package kyber1024 + +import ( + cryptoRand "crypto/rand" + "io" + + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/pke/kyber/kyber1024/internal" +) + +const ( + // Size of seed for NewKeyFromSeed + KeySeedSize = internal.SeedSize + + // Size of seed for EncryptTo + EncryptionSeedSize = internal.SeedSize + + // Size of a packed PublicKey + PublicKeySize = internal.PublicKeySize + + // Size of a packed PrivateKey + PrivateKeySize = internal.PrivateKeySize + + // Size of a ciphertext + CiphertextSize = internal.CiphertextSize + + // Size of a plaintext + PlaintextSize = internal.PlaintextSize +) + +// PublicKey is the type of Kyber1024.CPAPKE public key +type PublicKey internal.PublicKey + +// PrivateKey is the type of Kyber1024.CPAPKE private key +type PrivateKey internal.PrivateKey + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + var seed [KeySeedSize]byte + if rand == nil { + rand = cryptoRand.Reader + } + _, err := io.ReadFull(rand, seed[:]) + if err != nil { + return nil, nil, err + } + pk, sk := internal.NewKeyFromSeed(seed[:]) + return (*PublicKey)(pk), (*PrivateKey)(sk), nil +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +// +// Note: does not include the domain separation of ML-KEM (line 1, algorithm 13 +// of FIPS 203). For that use NewKeyFromSeedMLKEM(). +// +// Panics if seed is not of length KeySeedSize. +func NewKeyFromSeed(seed []byte) (*PublicKey, *PrivateKey) { + if len(seed) != KeySeedSize { + panic("seed must be of length KeySeedSize") + } + pk, sk := internal.NewKeyFromSeed(seed) + return (*PublicKey)(pk), (*PrivateKey)(sk) +} + +// NewKeyFromSeedMLKEM derives a public/private key pair using the given seed +// using the domain separation of ML-KEM. +// +// Panics if seed is not of length KeySeedSize. +func NewKeyFromSeedMLKEM(seed []byte) (*PublicKey, *PrivateKey) { + if len(seed) != KeySeedSize { + panic("seed must be of length KeySeedSize") + } + var seed2 [33]byte + copy(seed2[:32], seed) + seed2[32] = byte(internal.K) + pk, sk := internal.NewKeyFromSeed(seed2[:]) + return (*PublicKey)(pk), (*PrivateKey)(sk) +} + +// EncryptTo encrypts message pt for the public key and writes the ciphertext +// to ct using randomness from seed. +// +// This function panics if the lengths of pt, seed, and ct are not +// PlaintextSize, EncryptionSeedSize, and CiphertextSize respectively. +func (pk *PublicKey) EncryptTo(ct []byte, pt []byte, seed []byte) { + if len(pt) != PlaintextSize { + panic("pt must be of length PlaintextSize") + } + if len(ct) != CiphertextSize { + panic("ct must be of length CiphertextSize") + } + if len(seed) != EncryptionSeedSize { + panic("seed must be of length EncryptionSeedSize") + } + (*internal.PublicKey)(pk).EncryptTo(ct, pt, seed) +} + +// DecryptTo decrypts message ct for the private key and writes the +// plaintext to pt. +// +// This function panics if the lengths of ct and pt are not +// CiphertextSize and PlaintextSize respectively. +func (sk *PrivateKey) DecryptTo(pt []byte, ct []byte) { + if len(pt) != PlaintextSize { + panic("pt must be of length PlaintextSize") + } + if len(ct) != CiphertextSize { + panic("ct must be of length CiphertextSize") + } + (*internal.PrivateKey)(sk).DecryptTo(pt, ct) +} + +// Packs pk into the given buffer. +// +// Panics if buf is not of length PublicKeySize. +func (pk *PublicKey) Pack(buf []byte) { + if len(buf) != PublicKeySize { + panic("buf must be of size PublicKeySize") + } + (*internal.PublicKey)(pk).Pack(buf) +} + +// Packs sk into the given buffer. +// +// Panics if buf is not of length PrivateKeySize. +func (sk *PrivateKey) Pack(buf []byte) { + if len(buf) != PrivateKeySize { + panic("buf must be of size PrivateKeySize") + } + (*internal.PrivateKey)(sk).Pack(buf) +} + +// Unpacks pk from the given buffer. +// +// Panics if buf is not of length PublicKeySize. +func (pk *PublicKey) Unpack(buf []byte) { + if len(buf) != PublicKeySize { + panic("buf must be of size PublicKeySize") + } + (*internal.PublicKey)(pk).Unpack(buf) +} + +// Unpacks pk from the given buffer. +// +// Returns an error if the buffer is not of the right size, or the public +// key is not normalized. +func (pk *PublicKey) UnpackMLKEM(buf []byte) error { + if len(buf) != PublicKeySize { + return kem.ErrPubKeySize + } + return (*internal.PublicKey)(pk).UnpackMLKEM(buf) +} + +// Unpacks sk from the given buffer. +// +// Panics if buf is not of length PrivateKeySize. +func (sk *PrivateKey) Unpack(buf []byte) { + if len(buf) != PrivateKeySize { + panic("buf must be of size PrivateKeySize") + } + (*internal.PrivateKey)(sk).Unpack(buf) +} + +// Returns whether the two private keys are equal. +func (sk *PrivateKey) Equal(other *PrivateKey) bool { + return (*internal.PrivateKey)(sk).Equal((*internal.PrivateKey)(other)) +} diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/cpapke.go b/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/cpapke.go new file mode 100644 index 0000000000..bea07e8743 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/cpapke.go @@ -0,0 +1,192 @@ +// Code generated from kyber512/internal/cpapke.go by gen.go + +package internal + +import ( + "bytes" + + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/pke/kyber/internal/common" +) + +// A Kyber.CPAPKE private key. +type PrivateKey struct { + sh Vec // NTT(s), normalized +} + +// A Kyber.CPAPKE public key. +type PublicKey struct { + rho [32]byte // ρ, the seed for the matrix A + th Vec // NTT(t), normalized + + // cached values + aT Mat // the matrix Aᵀ +} + +// Packs the private key to buf. +func (sk *PrivateKey) Pack(buf []byte) { + sk.sh.Pack(buf) +} + +// Unpacks the private key from buf. +func (sk *PrivateKey) Unpack(buf []byte) { + sk.sh.Unpack(buf) + sk.sh.Normalize() +} + +// Packs the public key to buf. +func (pk *PublicKey) Pack(buf []byte) { + pk.th.Pack(buf) + copy(buf[K*common.PolySize:], pk.rho[:]) +} + +// Unpacks the public key from buf. Checks if the public key is normalized. +func (pk *PublicKey) UnpackMLKEM(buf []byte) error { + pk.Unpack(buf) + + // FIPS 203 §7.2 "encapsulation key check" (2). + var buf2 [K * common.PolySize]byte + pk.th.Pack(buf2[:]) + if !bytes.Equal(buf[:len(buf2)], buf2[:]) { + return kem.ErrPubKey + } + return nil +} + +// Unpacks the public key from buf. +func (pk *PublicKey) Unpack(buf []byte) { + pk.th.Unpack(buf) + pk.th.Normalize() + copy(pk.rho[:], buf[K*common.PolySize:]) + pk.aT.Derive(&pk.rho, true) +} + +// Derives a new Kyber.CPAPKE keypair from the given seed. +func NewKeyFromSeed(seed []byte) (*PublicKey, *PrivateKey) { + var pk PublicKey + var sk PrivateKey + + var expandedSeed [64]byte + + h := sha3.New512() + _, _ = h.Write(seed) + + // This writes hash into expandedSeed. Yes, this is idiomatic Go. + _, _ = h.Read(expandedSeed[:]) + + copy(pk.rho[:], expandedSeed[:32]) + sigma := expandedSeed[32:] // σ, the noise seed + + pk.aT.Derive(&pk.rho, false) // Expand ρ to matrix A; we'll transpose later + + var eh Vec + sk.sh.DeriveNoise(sigma, 0, Eta1) // Sample secret vector s + sk.sh.NTT() + sk.sh.Normalize() + + eh.DeriveNoise(sigma, K, Eta1) // Sample blind e + eh.NTT() + + // Next, we compute t = A s + e. + for i := 0; i < K; i++ { + // Note that coefficients of s are bounded by q and those of A + // are bounded by 4.5q and so their product is bounded by 2¹⁵q + // as required for multiplication. + PolyDotHat(&pk.th[i], &pk.aT[i], &sk.sh) + + // A and s were not in Montgomery form, so the Montgomery + // multiplications in the inner product added a factor R⁻¹ which + // we'll cancel out now. This will also ensure the coefficients of + // t are bounded in absolute value by q. + pk.th[i].ToMont() + } + + pk.th.Add(&pk.th, &eh) // bounded by 8q. + pk.th.Normalize() + pk.aT.Transpose() + + return &pk, &sk +} + +// Decrypts ciphertext ct meant for private key sk to plaintext pt. +func (sk *PrivateKey) DecryptTo(pt, ct []byte) { + var u Vec + var v, m common.Poly + + u.Decompress(ct, DU) + v.Decompress(ct[K*compressedPolySize(DU):], DV) + + // Compute m = v - + u.NTT() + PolyDotHat(&m, &sk.sh, &u) + m.BarrettReduce() + m.InvNTT() + m.Sub(&v, &m) + m.Normalize() + + // Compress polynomial m to original message + m.CompressMessageTo(pt) +} + +// Encrypts message pt for the public key to ciphertext ct using randomness +// from seed. +// +// seed has to be of length SeedSize, pt of PlaintextSize and ct of +// CiphertextSize. +func (pk *PublicKey) EncryptTo(ct, pt, seed []byte) { + var rh, e1, u Vec + var e2, v, m common.Poly + + // Sample r, e₁ and e₂ from B_η + rh.DeriveNoise(seed, 0, Eta1) + rh.NTT() + rh.BarrettReduce() + + e1.DeriveNoise(seed, K, common.Eta2) + e2.DeriveNoise(seed, 2*K, common.Eta2) + + // Next we compute u = Aᵀ r + e₁. First Aᵀ. + for i := 0; i < K; i++ { + // Note that coefficients of r are bounded by q and those of Aᵀ + // are bounded by 4.5q and so their product is bounded by 2¹⁵q + // as required for multiplication. + PolyDotHat(&u[i], &pk.aT[i], &rh) + } + + u.BarrettReduce() + + // Aᵀ and r were not in Montgomery form, so the Montgomery + // multiplications in the inner product added a factor R⁻¹ which + // the InvNTT cancels out. + u.InvNTT() + + u.Add(&u, &e1) // u = Aᵀ r + e₁ + + // Next compute v = + e₂ + Decompress_q(m, 1). + PolyDotHat(&v, &pk.th, &rh) + v.BarrettReduce() + v.InvNTT() + + m.DecompressMessage(pt) + v.Add(&v, &m) + v.Add(&v, &e2) // v = + e₂ + Decompress_q(m, 1) + + // Pack ciphertext + u.Normalize() + v.Normalize() + + u.CompressTo(ct, DU) + v.CompressTo(ct[K*compressedPolySize(DU):], DV) +} + +// Returns whether sk equals other. +func (sk *PrivateKey) Equal(other *PrivateKey) bool { + ret := int16(0) + for i := 0; i < K; i++ { + for j := 0; j < common.N; j++ { + ret |= sk.sh[i][j] ^ other.sh[i][j] + } + } + return ret == 0 +} diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/mat.go b/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/mat.go new file mode 100644 index 0000000000..404aacfb02 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/mat.go @@ -0,0 +1,85 @@ +// Code generated from kyber512/internal/mat.go by gen.go + +package internal + +import ( + "github.com/cloudflare/circl/pke/kyber/internal/common" +) + +// A k by k matrix of polynomials. +type Mat [K]Vec + +// Expands the given seed to the corresponding matrix A or its transpose Aᵀ. +func (m *Mat) Derive(seed *[32]byte, transpose bool) { + if !common.DeriveX4Available { + if transpose { + for i := 0; i < K; i++ { + for j := 0; j < K; j++ { + m[i][j].DeriveUniform(seed, uint8(i), uint8(j)) + } + } + } else { + for i := 0; i < K; i++ { + for j := 0; j < K; j++ { + m[i][j].DeriveUniform(seed, uint8(j), uint8(i)) + } + } + } + return + } + + var ps [4]*common.Poly + var xs [4]uint8 + var ys [4]uint8 + x := uint8(0) + y := uint8(0) + + for x != K { + idx := 0 + for ; idx < 4; idx++ { + ps[idx] = &m[x][y] + + if transpose { + xs[idx] = x + ys[idx] = y + } else { + xs[idx] = y + ys[idx] = x + } + + y++ + if y == K { + x++ + y = 0 + + if x == K { + if idx == 0 { + // If there is just one left, then a plain DeriveUniform + // is quicker than the X4 variant. + ps[0].DeriveUniform(seed, xs[0], ys[0]) + return + } + + for idx++; idx < 4; idx++ { + ps[idx] = nil + } + + break + } + } + } + + common.PolyDeriveUniformX4(ps, seed, xs, ys) + } +} + +// Transposes A in place. +func (m *Mat) Transpose() { + for i := 0; i < K-1; i++ { + for j := i + 1; j < K; j++ { + t := m[i][j] + m[i][j] = m[j][i] + m[j][i] = t + } + } +} diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/params.go b/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/params.go new file mode 100644 index 0000000000..27cdb1abfd --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/params.go @@ -0,0 +1,21 @@ +// Code generated from params.templ.go. DO NOT EDIT. + +package internal + +import ( + "github.com/cloudflare/circl/pke/kyber/internal/common" +) + +const ( + K = 3 + Eta1 = 2 + DU = 10 + DV = 4 + PublicKeySize = 32 + K*common.PolySize + + PrivateKeySize = K * common.PolySize + + PlaintextSize = common.PlaintextSize + SeedSize = 32 + CiphertextSize = 1088 +) diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/vec.go b/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/vec.go new file mode 100644 index 0000000000..6681895a72 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/vec.go @@ -0,0 +1,125 @@ +// Code generated from kyber512/internal/vec.go by gen.go + +package internal + +import ( + "github.com/cloudflare/circl/pke/kyber/internal/common" +) + +// A vector of K polynomials +type Vec [K]common.Poly + +// Samples v[i] from a centered binomial distribution with given η, +// seed and nonce+i. +// +// Essentially CBD_η(PRF(seed, nonce+i)) from the specification. +func (v *Vec) DeriveNoise(seed []byte, nonce uint8, eta int) { + for i := 0; i < K; i++ { + v[i].DeriveNoise(seed, nonce+uint8(i), eta) + } +} + +// Sets p to the inner product of a and b using "pointwise" multiplication. +// +// See MulHat() and NTT() for a description of the multiplication. +// Assumes a and b are in Montgomery form. p will be in Montgomery form, +// and its coefficients will be bounded in absolute value by 2kq. +// If a and b are not in Montgomery form, then the action is the same +// as "pointwise" multiplication followed by multiplying by R⁻¹, the inverse +// of the Montgomery factor. +func PolyDotHat(p *common.Poly, a, b *Vec) { + var t common.Poly + *p = common.Poly{} // set p to zero + for i := 0; i < K; i++ { + t.MulHat(&a[i], &b[i]) + p.Add(&t, p) + } +} + +// Almost normalizes coefficients in-place. +// +// Ensures each coefficient is in {0, …, q}. +func (v *Vec) BarrettReduce() { + for i := 0; i < K; i++ { + v[i].BarrettReduce() + } +} + +// Normalizes coefficients in-place. +// +// Ensures each coefficient is in {0, …, q-1}. +func (v *Vec) Normalize() { + for i := 0; i < K; i++ { + v[i].Normalize() + } +} + +// Applies in-place inverse NTT(). See Poly.InvNTT() for assumptions. +func (v *Vec) InvNTT() { + for i := 0; i < K; i++ { + v[i].InvNTT() + } +} + +// Applies in-place forward NTT(). See Poly.NTT() for assumptions. +func (v *Vec) NTT() { + for i := 0; i < K; i++ { + v[i].NTT() + } +} + +// Sets v to a + b. +func (v *Vec) Add(a, b *Vec) { + for i := 0; i < K; i++ { + v[i].Add(&a[i], &b[i]) + } +} + +// Packs v into buf, which must be of length K*PolySize. +func (v *Vec) Pack(buf []byte) { + for i := 0; i < K; i++ { + v[i].Pack(buf[common.PolySize*i:]) + } +} + +// Unpacks v from buf which must be of length K*PolySize. +func (v *Vec) Unpack(buf []byte) { + for i := 0; i < K; i++ { + v[i].Unpack(buf[common.PolySize*i:]) + } +} + +// Writes Compress_q(v, d) to m. +// +// Assumes v is normalized and d is in {3, 4, 5, 10, 11}. +func (v *Vec) CompressTo(m []byte, d int) { + size := compressedPolySize(d) + for i := 0; i < K; i++ { + v[i].CompressTo(m[size*i:], d) + } +} + +// Set v to Decompress_q(m, 1). +// +// Assumes d is in {3, 4, 5, 10, 11}. v will be normalized. +func (v *Vec) Decompress(m []byte, d int) { + size := compressedPolySize(d) + for i := 0; i < K; i++ { + v[i].Decompress(m[size*i:], d) + } +} + +// ⌈(256 d)/8⌉ +func compressedPolySize(d int) int { + switch d { + case 4: + return 128 + case 5: + return 160 + case 10: + return 320 + case 11: + return 352 + } + panic("unsupported d") +} diff --git a/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/kyber.go b/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/kyber.go new file mode 100644 index 0000000000..75bb7bd34d --- /dev/null +++ b/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/kyber.go @@ -0,0 +1,175 @@ +// Code generated from pkg.templ.go. DO NOT EDIT. + +// kyber768 implements the IND-CPA-secure Public Key Encryption +// scheme Kyber768.CPAPKE as submitted to round 3 of the NIST PQC competition +// and described in +// +// https://pq-crystals.org/kyber/data/kyber-specification-round3.pdf +package kyber768 + +import ( + cryptoRand "crypto/rand" + "io" + + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/pke/kyber/kyber768/internal" +) + +const ( + // Size of seed for NewKeyFromSeed + KeySeedSize = internal.SeedSize + + // Size of seed for EncryptTo + EncryptionSeedSize = internal.SeedSize + + // Size of a packed PublicKey + PublicKeySize = internal.PublicKeySize + + // Size of a packed PrivateKey + PrivateKeySize = internal.PrivateKeySize + + // Size of a ciphertext + CiphertextSize = internal.CiphertextSize + + // Size of a plaintext + PlaintextSize = internal.PlaintextSize +) + +// PublicKey is the type of Kyber768.CPAPKE public key +type PublicKey internal.PublicKey + +// PrivateKey is the type of Kyber768.CPAPKE private key +type PrivateKey internal.PrivateKey + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + var seed [KeySeedSize]byte + if rand == nil { + rand = cryptoRand.Reader + } + _, err := io.ReadFull(rand, seed[:]) + if err != nil { + return nil, nil, err + } + pk, sk := internal.NewKeyFromSeed(seed[:]) + return (*PublicKey)(pk), (*PrivateKey)(sk), nil +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +// +// Note: does not include the domain separation of ML-KEM (line 1, algorithm 13 +// of FIPS 203). For that use NewKeyFromSeedMLKEM(). +// +// Panics if seed is not of length KeySeedSize. +func NewKeyFromSeed(seed []byte) (*PublicKey, *PrivateKey) { + if len(seed) != KeySeedSize { + panic("seed must be of length KeySeedSize") + } + pk, sk := internal.NewKeyFromSeed(seed) + return (*PublicKey)(pk), (*PrivateKey)(sk) +} + +// NewKeyFromSeedMLKEM derives a public/private key pair using the given seed +// using the domain separation of ML-KEM. +// +// Panics if seed is not of length KeySeedSize. +func NewKeyFromSeedMLKEM(seed []byte) (*PublicKey, *PrivateKey) { + if len(seed) != KeySeedSize { + panic("seed must be of length KeySeedSize") + } + var seed2 [33]byte + copy(seed2[:32], seed) + seed2[32] = byte(internal.K) + pk, sk := internal.NewKeyFromSeed(seed2[:]) + return (*PublicKey)(pk), (*PrivateKey)(sk) +} + +// EncryptTo encrypts message pt for the public key and writes the ciphertext +// to ct using randomness from seed. +// +// This function panics if the lengths of pt, seed, and ct are not +// PlaintextSize, EncryptionSeedSize, and CiphertextSize respectively. +func (pk *PublicKey) EncryptTo(ct []byte, pt []byte, seed []byte) { + if len(pt) != PlaintextSize { + panic("pt must be of length PlaintextSize") + } + if len(ct) != CiphertextSize { + panic("ct must be of length CiphertextSize") + } + if len(seed) != EncryptionSeedSize { + panic("seed must be of length EncryptionSeedSize") + } + (*internal.PublicKey)(pk).EncryptTo(ct, pt, seed) +} + +// DecryptTo decrypts message ct for the private key and writes the +// plaintext to pt. +// +// This function panics if the lengths of ct and pt are not +// CiphertextSize and PlaintextSize respectively. +func (sk *PrivateKey) DecryptTo(pt []byte, ct []byte) { + if len(pt) != PlaintextSize { + panic("pt must be of length PlaintextSize") + } + if len(ct) != CiphertextSize { + panic("ct must be of length CiphertextSize") + } + (*internal.PrivateKey)(sk).DecryptTo(pt, ct) +} + +// Packs pk into the given buffer. +// +// Panics if buf is not of length PublicKeySize. +func (pk *PublicKey) Pack(buf []byte) { + if len(buf) != PublicKeySize { + panic("buf must be of size PublicKeySize") + } + (*internal.PublicKey)(pk).Pack(buf) +} + +// Packs sk into the given buffer. +// +// Panics if buf is not of length PrivateKeySize. +func (sk *PrivateKey) Pack(buf []byte) { + if len(buf) != PrivateKeySize { + panic("buf must be of size PrivateKeySize") + } + (*internal.PrivateKey)(sk).Pack(buf) +} + +// Unpacks pk from the given buffer. +// +// Panics if buf is not of length PublicKeySize. +func (pk *PublicKey) Unpack(buf []byte) { + if len(buf) != PublicKeySize { + panic("buf must be of size PublicKeySize") + } + (*internal.PublicKey)(pk).Unpack(buf) +} + +// Unpacks pk from the given buffer. +// +// Returns an error if the buffer is not of the right size, or the public +// key is not normalized. +func (pk *PublicKey) UnpackMLKEM(buf []byte) error { + if len(buf) != PublicKeySize { + return kem.ErrPubKeySize + } + return (*internal.PublicKey)(pk).UnpackMLKEM(buf) +} + +// Unpacks sk from the given buffer. +// +// Panics if buf is not of length PrivateKeySize. +func (sk *PrivateKey) Unpack(buf []byte) { + if len(buf) != PrivateKeySize { + panic("buf must be of size PrivateKeySize") + } + (*internal.PrivateKey)(sk).Unpack(buf) +} + +// Returns whether the two private keys are equal. +func (sk *PrivateKey) Equal(other *PrivateKey) bool { + return (*internal.PrivateKey)(sk).Equal((*internal.PrivateKey)(other)) +} diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go b/vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go index 2c73c26fb1..80f195745c 100644 --- a/vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go +++ b/vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go @@ -1,7 +1,7 @@ // Package ed25519 implements Ed25519 signature scheme as described in RFC-8032. // // This package provides optimized implementations of the three signature -// variants and maintaining closer compatibility with crypto/ed25519. +// variants and maintaining almost full compatibility with crypto/ed25519. // // | Scheme Name | Sign Function | Verification | Context | // |-------------|-------------------|---------------|-------------------| @@ -28,6 +28,13 @@ // operations with the same key more efficient. This package refers to the // RFC-8032 private key as the “seed”. // +// Public keys are decoded following RFC 8032 strictly: an encoding whose +// y-coordinate is not reduced modulo 2^255-19, or whose x-coordinate is zero +// with the sign bit set, is rejected. crypto/ed25519 accepts those +// non-canonical encodings instead, so for a small, fixed set of malformed +// public keys the verification functions here return false where +// crypto/ed25519 returns true. +// // References // // - RFC-8032: https://rfc-editor.org/rfc/rfc8032.txt diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/signapi.go b/vendor/github.com/cloudflare/circl/sign/ed25519/signapi.go index e4520f5203..5640e14473 100644 --- a/vendor/github.com/cloudflare/circl/sign/ed25519/signapi.go +++ b/vendor/github.com/cloudflare/circl/sign/ed25519/signapi.go @@ -69,7 +69,8 @@ func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { } func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { - if len(buf) < PublicKeySize { + // NOTE Old version of CIRCL accepted trailing data. + if len(buf) != PublicKeySize { return nil, sign.ErrPubKeySize } pub := make(PublicKey, PublicKeySize) @@ -78,7 +79,8 @@ func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { } func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { - if len(buf) < PrivateKeySize { + // NOTE Old version of CIRCL accepted trailing data. + if len(buf) != PrivateKeySize { return nil, sign.ErrPrivKeySize } priv := make(PrivateKey, PrivateKeySize) diff --git a/vendor/github.com/cloudflare/circl/sign/ed448/ed448.go b/vendor/github.com/cloudflare/circl/sign/ed448/ed448.go index c368b181b4..df44b8ef97 100644 --- a/vendor/github.com/cloudflare/circl/sign/ed448/ed448.go +++ b/vendor/github.com/cloudflare/circl/sign/ed448/ed448.go @@ -345,6 +345,8 @@ func verify(public PublicKey, message, signature, ctx []byte, preHash bool) bool // The opts.HashFunc() must return zero, this can be achieved by passing // crypto.Hash(0) as the value for opts. // Use a SignerOptions struct to pass a context string for signing. +// +// Uses the default RFC 8032 cofactor-clearing verification. func VerifyAny(public PublicKey, message, signature []byte, opts crypto.SignerOpts) bool { var ctx string var scheme SchemeID @@ -367,6 +369,8 @@ func VerifyAny(public PublicKey, message, signature []byte, opts crypto.SignerOp // signature, or when the public key cannot be decoded. // This function supports the signature variant defined in RFC-8032: Ed448, // also known as the pure version of EdDSA. +// +// Uses the default RFC 8032 cofactor-clearing verification. func Verify(public PublicKey, message, signature []byte, ctx string) bool { return verify(public, message, signature, []byte(ctx), false) } @@ -377,6 +381,8 @@ func Verify(public PublicKey, message, signature []byte, ctx string) bool { // meaning it internally hashes the message using SHAKE-256. // Context could be passed to this function, which length should be no more than // 255. It can be empty. +// +// Uses the default RFC 8032 cofactor-clearing verification. func VerifyPh(public PublicKey, message, signature []byte, ctx string) bool { return verify(public, message, signature, []byte(ctx), true) } diff --git a/vendor/github.com/cloudflare/circl/sign/ed448/signapi.go b/vendor/github.com/cloudflare/circl/sign/ed448/signapi.go index 22da8bc0a5..4ac182599a 100644 --- a/vendor/github.com/cloudflare/circl/sign/ed448/signapi.go +++ b/vendor/github.com/cloudflare/circl/sign/ed448/signapi.go @@ -69,7 +69,8 @@ func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { } func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { - if len(buf) < PublicKeySize { + // NOTE Old version of CIRCL accepted trailing data. + if len(buf) != PublicKeySize { return nil, sign.ErrPubKeySize } pub := make(PublicKey, PublicKeySize) @@ -78,7 +79,8 @@ func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { } func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { - if len(buf) < PrivateKeySize { + // NOTE Old version of CIRCL accepted trailing data. + if len(buf) != PrivateKeySize { return nil, sign.ErrPrivKeySize } priv := make(PrivateKey, PrivateKeySize) diff --git a/vendor/github.com/cloudflare/circl/sign/internal/dilithium/amd64.go b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/amd64.go new file mode 100644 index 0000000000..96e39897dd --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/amd64.go @@ -0,0 +1,162 @@ +//go:build amd64 && !purego +// +build amd64,!purego + +package dilithium + +import ( + "golang.org/x/sys/cpu" +) + +// Execute an in-place forward NTT on as. +// +// Assumes the coefficients are in Montgomery representation and bounded +// by 2*Q. The resulting coefficients are again in Montgomery representation, +// but are only bounded bt 18*Q. +func (p *Poly) NTT() { + if cpu.X86.HasAVX2 { + nttAVX2( + (*[N]uint32)(p), + ) + } else { + p.nttGeneric() + } +} + +// Execute an in-place inverse NTT and multiply by Montgomery factor R +// +// Assumes the coefficients are in Montgomery representation and bounded +// by 2*Q. The resulting coefficients are again in Montgomery representation +// and bounded by 2*Q. +func (p *Poly) InvNTT() { + if cpu.X86.HasAVX2 { + invNttAVX2( + (*[N]uint32)(p), + ) + } else { + p.invNttGeneric() + } +} + +// Sets p to the polynomial whose coefficients are the pointwise multiplication +// of those of a and b. The coefficients of p are bounded by 2q. +// +// Assumes a and b are in Montgomery form and that the pointwise product +// of each coefficient is below 2³² q. +func (p *Poly) MulHat(a, b *Poly) { + if cpu.X86.HasAVX2 { + mulHatAVX2( + (*[N]uint32)(p), + (*[N]uint32)(a), + (*[N]uint32)(b), + ) + } else { + p.mulHatGeneric(a, b) + } +} + +// Sets p to a + b. Does not normalize polynomials. +func (p *Poly) Add(a, b *Poly) { + if cpu.X86.HasAVX2 { + addAVX2( + (*[N]uint32)(p), + (*[N]uint32)(a), + (*[N]uint32)(b), + ) + } else { + p.addGeneric(a, b) + } +} + +// Sets p to a - b. +// +// Warning: assumes coefficients of b are less than 2q. +// Sets p to a + b. Does not normalize polynomials. +func (p *Poly) Sub(a, b *Poly) { + if cpu.X86.HasAVX2 { + subAVX2( + (*[N]uint32)(p), + (*[N]uint32)(a), + (*[N]uint32)(b), + ) + } else { + p.subGeneric(a, b) + } +} + +// Writes p whose coefficients are in [0, 16) to buf, which must be of +// length N/2. +func (p *Poly) PackLe16(buf []byte) { + if cpu.X86.HasAVX2 { + if len(buf) < PolyLe16Size { + panic("buf too small") + } + packLe16AVX2( + (*[N]uint32)(p), + &buf[0], + ) + } else { + p.packLe16Generic(buf) + } +} + +// Reduces each of the coefficients to <2q. +func (p *Poly) ReduceLe2Q() { + if cpu.X86.HasAVX2 { + reduceLe2QAVX2((*[N]uint32)(p)) + } else { + p.reduceLe2QGeneric() + } +} + +// Reduce each of the coefficients to > 23 + x2 := x & 0x7FFFFF // 2²³-1 + return x2 + (x1 << 13) - x1 +} + +// Returns x mod q. +func modQ(x uint32) uint32 { + return le2qModQ(ReduceLe2Q(x)) +} + +// For x R ≤ q 2³², find y ≤ 2q with y = x mod q. +func montReduceLe2Q(x uint64) uint32 { + // Qinv = 4236238847 = -(q⁻¹) mod 2³² + m := (x * Qinv) & 0xffffffff + return uint32((x + m*uint64(Q)) >> 32) +} + +// Returns x mod q for 0 ≤ x < 2q. +func le2qModQ(x uint32) uint32 { + x -= Q + mask := uint32(int32(x) >> 31) // mask is 2³²-1 if x was neg.; 0 otherwise + return x + (mask & Q) +} + +// Splits 0 ≤ a < Q into a0 and a1 with a = a1*2ᴰ + a0 +// and -2ᴰ⁻¹ < a0 < 2ᴰ⁻¹. Returns a0 + Q and a1. +func power2round(a uint32) (a0plusQ, a1 uint32) { + // We effectively compute a0 = a mod± 2ᵈ + // and a1 = (a - a0) / 2ᵈ. + a0 := a & ((1 << D) - 1) // a mod 2ᵈ + + // a0 is one of 0, 1, ..., 2ᵈ⁻¹-1, 2ᵈ⁻¹, 2ᵈ⁻¹+1, ..., 2ᵈ-1 + a0 -= (1 << (D - 1)) + 1 + // now a0 is -2ᵈ⁻¹-1, -2ᵈ⁻¹, ..., -2, -1, 0, ..., 2ᵈ⁻¹-2 + // Next, we add 2ᴰ to those a0 that are negative (seen as int32). + a0 += uint32(int32(a0)>>31) & (1 << D) + // now a0 is 2ᵈ⁻¹-1, 2ᵈ⁻¹, ..., 2ᵈ-2, 2ᵈ-1, 0, ..., 2ᵈ⁻¹-2 + a0 -= (1 << (D - 1)) - 1 + // now a0 id 0, 1, 2, ..., 2ᵈ⁻¹-1, 2ᵈ⁻¹-1, -2ᵈ⁻¹-1, ... + // which is what we want. + a0plusQ = Q + a0 + a1 = (a - a0) >> D + return +} diff --git a/vendor/github.com/cloudflare/circl/sign/internal/dilithium/generic.go b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/generic.go new file mode 100644 index 0000000000..6260d2d206 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/generic.go @@ -0,0 +1,89 @@ +//go:build (!amd64 && !arm64) || purego +// +build !amd64,!arm64 purego + +package dilithium + +// Execute an in-place forward NTT on as. +// +// Assumes the coefficients are in Montgomery representation and bounded +// by 2*Q. The resulting coefficients are again in Montgomery representation, +// but are only bounded bt 18*Q. +func (p *Poly) NTT() { + p.nttGeneric() +} + +// Execute an in-place inverse NTT and multiply by Montgomery factor R +// +// Assumes the coefficients are in Montgomery representation and bounded +// by 2*Q. The resulting coefficients are again in Montgomery representation +// and bounded by 2*Q. +func (p *Poly) InvNTT() { + p.invNttGeneric() +} + +// Sets p to the polynomial whose coefficients are the pointwise multiplication +// of those of a and b. The coefficients of p are bounded by 2q. +// +// Assumes a and b are in Montgomery form and that the pointwise product +// of each coefficient is below 2³² q. +func (p *Poly) MulHat(a, b *Poly) { + p.mulHatGeneric(a, b) +} + +// Sets p to a + b. Does not normalize polynomials. +func (p *Poly) Add(a, b *Poly) { + p.addGeneric(a, b) +} + +// Sets p to a - b. +// +// Warning: assumes coefficients of b are less than 2q. +// Sets p to a + b. Does not normalize polynomials. +func (p *Poly) Sub(a, b *Poly) { + p.subGeneric(a, b) +} + +// Writes p whose coefficients are in [0, 16) to buf, which must be of +// length N/2. +func (p *Poly) PackLe16(buf []byte) { + p.packLe16Generic(buf) +} + +// Reduces each of the coefficients to <2q. +func (p *Poly) ReduceLe2Q() { + p.reduceLe2QGeneric() +} + +// Reduce each of the coefficients to 0; l >>= 1 { + // On the n-th iteration of the l-loop, the coefficients start off + // bounded by n*2*Q. + // + // offset effectively loops over the row groups in this column; it + // is the first row in the row group. + for offset := uint(0); offset < N-l; offset += 2 * l { + k++ + zeta := uint64(Zetas[k]) + + // j loops over each butterfly in the row group. + for j := offset; j < offset+l; j++ { + t := montReduceLe2Q(zeta * uint64(p[j+l])) + p[j+l] = p[j] + (2*Q - t) // Cooley--Tukey butterfly + p[j] += t + } + } + } +} + +// Execute an in-place inverse NTT and multiply by Montgomery factor R +// +// Assumes the coefficients are in Montgomery representation and bounded +// by 2*Q. The resulting coefficients are again in Montgomery representation +// and bounded by 2*Q. +func (p *Poly) invNttGeneric() { + k := 0 // Index into InvZetas + + // We basically do the opposite of NTT, but postpone dividing by 2 in the + // inverse of the Cooley--Tukey butterfly and accumulate that to a big + // division by 2⁸ at the end. See comments in the NTT() function. + + for l := uint(1); l < N; l <<= 1 { + // On the n-th iteration of the l-loop, the coefficients start off + // bounded by 2ⁿ⁻¹*2*Q, so by 256*Q on the last. + for offset := uint(0); offset < N-l; offset += 2 * l { + zeta := uint64(InvZetas[k]) + k++ + for j := offset; j < offset+l; j++ { + t := p[j] // Gentleman--Sande butterfly + p[j] = t + p[j+l] + t += 256*Q - p[j+l] + p[j+l] = montReduceLe2Q(zeta * uint64(t)) + } + } + } + + for j := uint(0); j < N; j++ { + // ROver256 = 41978 = (256)⁻¹ R² + p[j] = montReduceLe2Q(ROver256 * uint64(p[j])) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/internal/dilithium/pack.go b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/pack.go new file mode 100644 index 0000000000..4b952a004f --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/pack.go @@ -0,0 +1,160 @@ +package dilithium + +// Sets p to the polynomial whose coefficients are less than 1024 encoded +// into buf (which must be of size PolyT1Size). +// +// p will be normalized. +func (p *Poly) UnpackT1(buf []byte) { + j := 0 + for i := 0; i < PolyT1Size; i += 5 { + p[j] = (uint32(buf[i]) | (uint32(buf[i+1]) << 8)) & 0x3ff + p[j+1] = (uint32(buf[i+1]>>2) | (uint32(buf[i+2]) << 6)) & 0x3ff + p[j+2] = (uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4)) & 0x3ff + p[j+3] = (uint32(buf[i+3]>>6) | (uint32(buf[i+4]) << 2)) & 0x3ff + j += 4 + } +} + +// Writes p whose coefficients are in (-2ᵈ⁻¹, 2ᵈ⁻¹] into buf which +// has to be of length at least PolyT0Size. +// +// Assumes that the coefficients are not normalized, but lie in the +// range (q-2ᵈ⁻¹, q+2ᵈ⁻¹]. +func (p *Poly) PackT0(buf []byte) { + j := 0 + for i := 0; i < PolyT0Size; i += 13 { + p0 := Q + (1 << (D - 1)) - p[j] + p1 := Q + (1 << (D - 1)) - p[j+1] + p2 := Q + (1 << (D - 1)) - p[j+2] + p3 := Q + (1 << (D - 1)) - p[j+3] + p4 := Q + (1 << (D - 1)) - p[j+4] + p5 := Q + (1 << (D - 1)) - p[j+5] + p6 := Q + (1 << (D - 1)) - p[j+6] + p7 := Q + (1 << (D - 1)) - p[j+7] + + buf[i] = byte(p0 >> 0) + buf[i+1] = byte(p0>>8) | byte(p1<<5) + buf[i+2] = byte(p1 >> 3) + buf[i+3] = byte(p1>>11) | byte(p2<<2) + buf[i+4] = byte(p2>>6) | byte(p3<<7) + buf[i+5] = byte(p3 >> 1) + buf[i+6] = byte(p3>>9) | byte(p4<<4) + buf[i+7] = byte(p4 >> 4) + buf[i+8] = byte(p4>>12) | byte(p5<<1) + buf[i+9] = byte(p5>>7) | byte(p6<<6) + buf[i+10] = byte(p6 >> 2) + buf[i+11] = byte(p6>>10) | byte(p7<<3) + buf[i+12] = byte(p7 >> 5) + j += 8 + } +} + +// Sets p to the polynomial packed into buf by PackT0. +// +// The coefficients of p will not be normalized, but will lie +// in (-2ᵈ⁻¹, 2ᵈ⁻¹]. +func (p *Poly) UnpackT0(buf []byte) { + j := 0 + for i := 0; i < PolyT0Size; i += 13 { + p[j] = Q + (1 << (D - 1)) - ((uint32(buf[i]) | + (uint32(buf[i+1]) << 8)) & 0x1fff) + p[j+1] = Q + (1 << (D - 1)) - (((uint32(buf[i+1]) >> 5) | + (uint32(buf[i+2]) << 3) | + (uint32(buf[i+3]) << 11)) & 0x1fff) + p[j+2] = Q + (1 << (D - 1)) - (((uint32(buf[i+3]) >> 2) | + (uint32(buf[i+4]) << 6)) & 0x1fff) + p[j+3] = Q + (1 << (D - 1)) - (((uint32(buf[i+4]) >> 7) | + (uint32(buf[i+5]) << 1) | + (uint32(buf[i+6]) << 9)) & 0x1fff) + p[j+4] = Q + (1 << (D - 1)) - (((uint32(buf[i+6]) >> 4) | + (uint32(buf[i+7]) << 4) | + (uint32(buf[i+8]) << 12)) & 0x1fff) + p[j+5] = Q + (1 << (D - 1)) - (((uint32(buf[i+8]) >> 1) | + (uint32(buf[i+9]) << 7)) & 0x1fff) + p[j+6] = Q + (1 << (D - 1)) - (((uint32(buf[i+9]) >> 6) | + (uint32(buf[i+10]) << 2) | + (uint32(buf[i+11]) << 10)) & 0x1fff) + p[j+7] = Q + (1 << (D - 1)) - ((uint32(buf[i+11]) >> 3) | + (uint32(buf[i+12]) << 5)) + + j += 8 + } +} + +// Writes p whose coefficients are less than 1024 into buf, which must be +// of size at least PolyT1Size . +// +// Assumes coefficients of p are normalized. +func (p *Poly) PackT1(buf []byte) { + j := 0 + for i := 0; i < PolyT1Size; i += 5 { + buf[i] = byte(p[j]) + buf[i+1] = byte(p[j]>>8) | byte(p[j+1]<<2) + buf[i+2] = byte(p[j+1]>>6) | byte(p[j+2]<<4) + buf[i+3] = byte(p[j+2]>>4) | byte(p[j+3]<<6) + buf[i+4] = byte(p[j+3] >> 2) + j += 4 + } +} + +// Writes p whose coefficients are in [0, 16) to buf, which must be of +// length N/2. +func (p *Poly) packLe16Generic(buf []byte) { + j := 0 + for i := 0; i < PolyLe16Size; i++ { + buf[i] = byte(p[j]) | byte(p[j+1]<<4) + j += 2 + } +} + +// Writes p with 60 non-zero coefficients {-1,1} to buf, which must have +// length 40. +func (p *Poly) PackB60(buf []byte) { + // We start with a mask of the non-zero positions of p (which is 32 bytes) + // and then append 60 packed bits, where a one indicates a negative + // coefficients. + var signs uint64 + mask := uint64(1) + for i := 0; i < 32; i++ { + buf[i] = 0 + for j := 0; j < 8; j++ { + if p[8*i+j] != 0 { + buf[i] |= 1 << uint(j) + if p[8*i+j] == Q-1 { + signs |= mask + } + mask <<= 1 + } + } + } + for i := uint64(0); i < 8; i++ { + buf[i+32] = uint8(signs >> (8 * i)) + } +} + +// UnpackB60 sets p to the polynomial packed into buf with Poly.PackB60(). +// +// Returns whether unpacking was successful. +func (p *Poly) UnpackB60(buf []byte) bool { + *p = Poly{} // zero p + signs := (uint64(buf[32]) | (uint64(buf[33]) << 8) | + (uint64(buf[34]) << 16) | (uint64(buf[35]) << 24) | + (uint64(buf[36]) << 32) | (uint64(buf[37]) << 40) | + (uint64(buf[38]) << 48) | (uint64(buf[39]) << 56)) + if signs>>60 != 0 { + return false // ensure unused bits are zero for strong unforgeability + } + + for i := 0; i < 32; i++ { + for j := 0; j < 8; j++ { + if (buf[i]>>uint(j))&1 == 1 { + p[8*i+j] = 1 + // Note 1 ^ (1 | (Q-1)) = Q-1 and (-1)&x = x + p[8*i+j] ^= uint32(-(signs & 1)) & (1 | (Q - 1)) + signs >>= 1 + } + } + } + + return true +} diff --git a/vendor/github.com/cloudflare/circl/sign/internal/dilithium/params.go b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/params.go new file mode 100644 index 0000000000..f423217f02 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/params.go @@ -0,0 +1,18 @@ +package dilithium + +import ( + "github.com/cloudflare/circl/sign/internal/dilithium/params" +) + +const ( + SeedSize = params.SeedSize + N = params.N + Q = params.Q + QBits = params.QBits + Qinv = params.Qinv + ROver256 = params.ROver256 + D = params.D + PolyT1Size = params.PolyT1Size + PolyT0Size = params.PolyT0Size + PolyLe16Size = params.PolyLe16Size +) diff --git a/vendor/github.com/cloudflare/circl/sign/internal/dilithium/params/params.go b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/params/params.go new file mode 100644 index 0000000000..2df20e3a40 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/params/params.go @@ -0,0 +1,25 @@ +package params + +// We put these parameters in a separate package so that the Go code, +// such as ntt_amd64_src.go, that generates assembler can import it. + +const ( + SeedSize = 32 + N = 256 + Q = 8380417 // 2²³ - 2¹³ + 1 + QBits = 23 + Qinv = 4236238847 // = -(q^-1) mod 2³² + ROver256 = 41978 // = (256)⁻¹ R² mod q, where R=2³² + D = 13 + + // Size of T1 packed. (Note that the formula is not valid in general, + // but it is for the parameters used in the modes of Dilithium.) + PolyT1Size = (N * (QBits - D)) / 8 + + // Size of T0 packed. (Note that the formula is not valid in general, + // but it is for the parameters used in the modes of Dilithium.) + PolyT0Size = (N * D) / 8 + + // Size of a packed polynomial whose coefficients are in [0,16). + PolyLe16Size = N / 2 +) diff --git a/vendor/github.com/cloudflare/circl/sign/internal/dilithium/poly.go b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/poly.go new file mode 100644 index 0000000000..6a0d4874e9 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/poly.go @@ -0,0 +1,101 @@ +package dilithium + +// An element of our base ring R which are polynomials over Z_q modulo +// the equation Xᴺ = -1, where q=2²³ - 2¹³ + 1 and N=256. +// +// Coefficients aren't always reduced. See Normalize(). +type Poly [N]uint32 + +// Reduces each of the coefficients to <2q. +func (p *Poly) reduceLe2QGeneric() { + for i := uint(0); i < N; i++ { + p[i] = ReduceLe2Q(p[i]) + } +} + +// Reduce each of the coefficients to > 31) + // Sets x to {0, 1, ..., (Q-1)/2, (Q-1)/2, ..., 1} + x = int32((Q-1)/2) - x + if uint32(x) >= bound { + return true + } + } + return false +} + +// Splits p into p1 and p0 such that [i]p1 * 2ᴰ + [i]p0 = [i]p +// with -2ᴰ⁻¹ < [i]p0 ≤ 2ᴰ⁻¹. Returns p0 + Q and p1. +// +// Requires the coefficients of p to be normalized. +func (p *Poly) power2RoundGeneric(p0PlusQ, p1 *Poly) { + for i := 0; i < N; i++ { + p0PlusQ[i], p1[i] = power2round(p[i]) + } +} + +// Sets p to the polynomial whose coefficients are the pointwise multiplication +// of those of a and b. The coefficients of p are bounded by 2q. +// +// Assumes a and b are in Montgomery form and that the pointwise product +// of each coefficient is below 2³² q. +func (p *Poly) mulHatGeneric(a, b *Poly) { + for i := 0; i < N; i++ { + p[i] = montReduceLe2Q(uint64(a[i]) * uint64(b[i])) + } +} + +// Sets p to 2ᵈ q without reducing. +// +// So it requires the coefficients of p to be less than 2³²⁻ᴰ. +func (p *Poly) mulBy2toDGeneric(q *Poly) { + for i := 0; i < N; i++ { + p[i] = q[i] << D + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/internal/dilithium/stubs_amd64.go b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/stubs_amd64.go new file mode 100644 index 0000000000..ca92f15ef1 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/internal/dilithium/stubs_amd64.go @@ -0,0 +1,35 @@ +// Code generated by command: go run src.go -out ../amd64.s -stubs ../stubs_amd64.go -pkg dilithium. DO NOT EDIT. + +//go:build amd64 && !purego + +package dilithium + +//go:noescape +func nttAVX2(p *[256]uint32) + +//go:noescape +func invNttAVX2(p *[256]uint32) + +//go:noescape +func mulHatAVX2(p *[256]uint32, a *[256]uint32, b *[256]uint32) + +//go:noescape +func addAVX2(p *[256]uint32, a *[256]uint32, b *[256]uint32) + +//go:noescape +func subAVX2(p *[256]uint32, a *[256]uint32, b *[256]uint32) + +//go:noescape +func packLe16AVX2(p *[256]uint32, buf *byte) + +//go:noescape +func reduceLe2QAVX2(p *[256]uint32) + +//go:noescape +func le2qModQAVX2(p *[256]uint32) + +//go:noescape +func exceedsAVX2(p *[256]uint32, bound uint32) uint8 + +//go:noescape +func mulBy2toDAVX2(p *[256]uint32, q *[256]uint32) diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/dilithium.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/dilithium.go new file mode 100644 index 0000000000..6f8f182eb4 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/dilithium.go @@ -0,0 +1,366 @@ +// Code generated from pkg.templ.go. DO NOT EDIT. + +// mldsa65 implements NIST signature scheme ML-DSA-65 as defined in FIPS204. +package mldsa65 + +import ( + "crypto" + cryptoRand "crypto/rand" + "encoding/asn1" + "errors" + "io" + + "github.com/cloudflare/circl/sign" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/sign/mldsa/mldsa65/internal" +) + +const ( + // Size of seed for NewKeyFromSeed + SeedSize = common.SeedSize + + // Size of a packed PublicKey + PublicKeySize = internal.PublicKeySize + + // Size of a packed PrivateKey + PrivateKeySize = internal.PrivateKeySize + + // Size of a signature + SignatureSize = internal.SignatureSize +) + +// PublicKey is the type of ML-DSA-65 public key +type PublicKey internal.PublicKey + +// PrivateKey is the type of ML-DSA-65 private key +type PrivateKey internal.PrivateKey + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + pk, sk, err := internal.GenerateKey(rand) + return (*PublicKey)(pk), (*PrivateKey)(sk), err +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { + pk, sk := internal.NewKeyFromSeed(seed) + return (*PublicKey)(pk), (*PrivateKey)(sk) +} + +// SignTo signs the given message and writes the signature into signature. +// It will panic if signature is not of length at least SignatureSize. +// +// ctx is the optional context string. Errors if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func SignTo(sk *PrivateKey, msg, ctx []byte, randomized bool, sig []byte) error { + var rnd [32]byte + if randomized { + _, err := cryptoRand.Read(rnd[:]) + if err != nil { + return err + } + } + + if len(ctx) > 255 { + return sign.ErrContextTooLong + } + + internal.SignTo( + (*internal.PrivateKey)(sk), + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + w.Write(msg) + }, + rnd, + sig, + ) + return nil +} + +// Do not use. Implements ML-DSA.Sign_internal used for compatibility tests. +func (sk *PrivateKey) unsafeSignInternal(msg []byte, rnd [32]byte) []byte { + var ret [SignatureSize]byte + internal.SignTo( + (*internal.PrivateKey)(sk), + func(w io.Writer) { + _, _ = w.Write(msg) + }, + rnd, + ret[:], + ) + return ret[:] +} + +// Do not use. Implements ML-DSA.Verify_internal used for compatibility tests. +func unsafeVerifyInternal(pk *PublicKey, msg, sig []byte) bool { + return internal.Verify( + (*internal.PublicKey)(pk), + func(w io.Writer) { + _, _ = w.Write(msg) + }, + sig, + ) +} + +// Verify checks whether the given signature by pk on msg is valid. +// +// ctx is the optional context string. Fails if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func Verify(pk *PublicKey, msg, ctx, sig []byte) bool { + if len(ctx) > 255 { + return false + } + return internal.Verify( + (*internal.PublicKey)(pk), + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + _, _ = w.Write(msg) + }, + sig, + ) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Unpack(buf) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Unpack(buf) +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Pack(buf) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Pack(buf) +} + +// Packs the public key. +func (pk *PublicKey) Bytes() []byte { + var buf [PublicKeySize]byte + pk.Pack(&buf) + return buf[:] +} + +// Packs the private key. +func (sk *PrivateKey) Bytes() []byte { + var buf [PrivateKeySize]byte + sk.Pack(&buf) + return buf[:] +} + +// Packs the public key. +func (pk *PublicKey) MarshalBinary() ([]byte, error) { + return pk.Bytes(), nil +} + +// Packs the private key. +func (sk *PrivateKey) MarshalBinary() ([]byte, error) { + return sk.Bytes(), nil +} + +// Unpacks the public key from data. +func (pk *PublicKey) UnmarshalBinary(data []byte) error { + if len(data) != PublicKeySize { + return errors.New("packed public key must be of mldsa65.PublicKeySize bytes") + } + var buf [PublicKeySize]byte + copy(buf[:], data) + pk.Unpack(&buf) + return nil +} + +// Unpacks the private key from data. +func (sk *PrivateKey) UnmarshalBinary(data []byte) error { + if len(data) != PrivateKeySize { + return errors.New("packed private key must be of mldsa65.PrivateKeySize bytes") + } + var buf [PrivateKeySize]byte + copy(buf[:], data) + sk.Unpack(&buf) + return nil +} + +// Returns seed used to generate PrivateKey, and nil if not retained. +func (sk *PrivateKey) Seed() []byte { + return (*internal.PrivateKey)(sk).Seed() +} + +// Sign signs the given message. +// +// opts.HashFunc() must return zero, which can be achieved by passing +// crypto.Hash(0) or nil for opts. rand is ignored. Will only return an error +// if opts.HashFunc() is non-zero. +// +// This function is used to make PrivateKey implement the crypto.Signer +// interface. The package-level SignTo function might be more convenient +// to use. +func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( + sig []byte, err error) { + var ret [SignatureSize]byte + + if opts != nil && opts.HashFunc() != crypto.Hash(0) { + return nil, errors.New("dilithium: cannot sign hashed message") + } + if err = SignTo(sk, msg, nil, false, ret[:]); err != nil { + return nil, err + } + + return ret[:], nil +} + +// Computes the public key corresponding to this private key. +// +// Returns a *PublicKey. The type crypto.PublicKey is used to make +// PrivateKey implement the crypto.Signer interface. +func (sk *PrivateKey) Public() crypto.PublicKey { + return (*PublicKey)((*internal.PrivateKey)(sk).Public()) +} + +// Equal returns whether the two private keys equal. +func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool { + castOther, ok := other.(*PrivateKey) + if !ok { + return false + } + return (*internal.PrivateKey)(sk).Equal((*internal.PrivateKey)(castOther)) +} + +// Equal returns whether the two public keys equal. +func (pk *PublicKey) Equal(other crypto.PublicKey) bool { + castOther, ok := other.(*PublicKey) + if !ok { + return false + } + return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) +} + +// Boilerplate for generic signatures API + +type scheme struct{} + +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for ML-DSA-65. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "ML-DSA-65" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } + +// TODO TLSIdentifier() +func (*scheme) Oid() asn1.ObjectIdentifier { + return asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 18} +} + +func (*scheme) SupportsContext() bool { + return true +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + var ctx []byte + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + err := SignTo(priv, msg, ctx, false, sig) + if err != nil { + panic(err) + } + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + var ctx []byte + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + return Verify(pub, msg, ctx, sig) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/dilithium.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/dilithium.go new file mode 100644 index 0000000000..7a370615a5 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/dilithium.go @@ -0,0 +1,509 @@ +// Code generated from mode3/internal/dilithium.go by gen.go + +package internal + +import ( + cryptoRand "crypto/rand" + "crypto/subtle" + "io" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +const ( + // Size of a packed polynomial of norm ≤η. + // (Note that the formula is not valid in general.) + PolyLeqEtaSize = (common.N * DoubleEtaBits) / 8 + + // β = τη, the maximum size of c s₂. + Beta = Tau * Eta + + // γ₁ range of y + Gamma1 = 1 << Gamma1Bits + + // Size of packed polynomial of norm <γ₁ such as z + PolyLeGamma1Size = (Gamma1Bits + 1) * common.N / 8 + + // α = 2γ₂ parameter for decompose + Alpha = 2 * Gamma2 + + // Size of a packed private key + PrivateKeySize = 32 + 32 + TRSize + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K + + // Size of a packed public key + PublicKeySize = 32 + common.PolyT1Size*K + + // Size of a packed signature + SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize + + // Size of packed w₁ + PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 +) + +// PublicKey is the type of Dilithium public keys. +type PublicKey struct { + rho [32]byte + t1 VecK + + // Cached values + t1p [common.PolyT1Size * K]byte + A *Mat + tr [TRSize]byte +} + +// PrivateKey is the type of Dilithium private keys. +type PrivateKey struct { + rho [32]byte + key [32]byte + s1 VecL + s2 VecK + t0 VecK + tr [TRSize]byte + + // Cached values + A Mat // ExpandA(ρ) + s1h VecL // NTT(s₁) + s2h VecK // NTT(s₂) + t0h VecK // NTT(t₀) + + seed [common.SeedSize]byte + seedSet bool +} + +type unpackedSignature struct { + z VecL + hint VecK + c [CTildeSize]byte +} + +// Packs the signature into buf. +func (sig *unpackedSignature) Pack(buf []byte) { + copy(buf[:], sig.c[:]) + sig.z.PackLeGamma1(buf[CTildeSize:]) + sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) +} + +// Sets sig to the signature encoded in the buffer. +// +// Returns whether buf contains a properly packed signature. +func (sig *unpackedSignature) Unpack(buf []byte) bool { + // NOTE: Previously the Dilithium (but not ML-DSA) implementation accepted + // signatures with trailing data. + if len(buf) != SignatureSize { + return false + } + copy(sig.c[:], buf[:]) + sig.z.UnpackLeGamma1(buf[CTildeSize:]) + if sig.z.Exceeds(Gamma1 - Beta) { + return false + } + if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { + return false + } + return true +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + copy(buf[:32], pk.rho[:]) + copy(buf[32:], pk.t1p[:]) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + copy(pk.rho[:], buf[:32]) + copy(pk.t1p[:], buf[32:]) + + pk.t1.UnpackT1(pk.t1p[:]) + pk.A = new(Mat) + pk.A.Derive(&pk.rho) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + h := sha3.NewShake256() + _, _ = h.Write(buf[:]) + _, _ = h.Read(pk.tr[:]) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + copy(buf[:32], sk.rho[:]) + copy(buf[32:64], sk.key[:]) + copy(buf[64:64+TRSize], sk.tr[:]) + offset := 64 + TRSize + sk.s1.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.PackT0(buf[offset:]) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + sk.seedSet = false + + copy(sk.rho[:], buf[:32]) + copy(sk.key[:], buf[32:64]) + copy(sk.tr[:], buf[64:64+TRSize]) + offset := 64 + TRSize + sk.s1.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.UnpackT0(buf[offset:]) + + // Cached values + sk.A.Derive(&sk.rho) + sk.t0h = sk.t0 + sk.t0h.NTT() + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() +} + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + var seed [32]byte + if rand == nil { + rand = cryptoRand.Reader + } + _, err := io.ReadFull(rand, seed[:]) + if err != nil { + return nil, nil, err + } + pk, sk := NewKeyFromSeed(&seed) + return pk, sk, nil +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { + var eSeed [128]byte // expanded seed + var pk PublicKey + var sk PrivateKey + var sSeed [64]byte + + sk.seedSet = true + copy(sk.seed[:], seed[:]) + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + + if NIST { + _, _ = h.Write([]byte{byte(K), byte(L)}) + } + + _, _ = h.Read(eSeed[:]) + + copy(pk.rho[:], eSeed[:32]) + copy(sSeed[:], eSeed[32:96]) + copy(sk.key[:], eSeed[96:]) + copy(sk.rho[:], pk.rho[:]) + + sk.A.Derive(&pk.rho) + + for i := uint16(0); i < L; i++ { + PolyDeriveUniformLeqEta(&sk.s1[i], &sSeed, i) + } + + for i := uint16(0); i < K; i++ { + PolyDeriveUniformLeqEta(&sk.s2[i], &sSeed, i+L) + } + + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() + + sk.computeT0andT1(&sk.t0, &pk.t1) + + sk.t0h = sk.t0 + sk.t0h.NTT() + + // Complete public key far enough to be packed + pk.t1.PackT1(pk.t1p[:]) + pk.A = &sk.A + + // Finish private key + var packedPk [PublicKeySize]byte + pk.Pack(&packedPk) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + h.Reset() + _, _ = h.Write(packedPk[:]) + _, _ = h.Read(sk.tr[:]) + + // Finish cache of public key + pk.tr = sk.tr + + return &pk, &sk +} + +func (sk *PrivateKey) Seed() []byte { + if !sk.seedSet { + return nil + } + var ret [common.SeedSize]byte + copy(ret[:], sk.seed[:]) + return ret[:] +} + +// Computes t0 and t1 from sk.s1h, sk.s2 and sk.A. +func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { + var t VecK + + // Set t to A s₁ + s₂ + for i := 0; i < K; i++ { + PolyDotHat(&t[i], &sk.A[i], &sk.s1h) + t[i].ReduceLe2Q() + t[i].InvNTT() + } + t.Add(&t, &sk.s2) + t.Normalize() + + // Compute t₀, t₁ = Power2Round(t) + t.Power2Round(t0, t1) +} + +// Verify checks whether the given signature by pk on msg is valid. +// +// For Dilithium this is the top-level verification function. +// In ML-DSA, this is ML-DSA.Verify_internal. +func Verify(pk *PublicKey, msg func(io.Writer), signature []byte) bool { + var sig unpackedSignature + var mu [64]byte + var zh VecL + var Az, Az2dct1, w1 VecK + var ch common.Poly + var cp [CTildeSize]byte + var w1Packed [PolyW1Size * K]byte + + // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β + // and ensured that there at most ω ones in pk.hint. + if !sig.Unpack(signature) { + return false + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(pk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // Compute Az + zh = sig.z + zh.NTT() + + for i := 0; i < K; i++ { + PolyDotHat(&Az[i], &pk.A[i], &zh) + } + + // Next, we compute Az - 2ᵈ·c·t₁. + // Note that the coefficients of t₁ are bounded by 256 = 2⁹, + // so the coefficients of Az2dct1 will bounded by 2⁹⁺ᵈ = 2²³ < 2q, + // which is small enough for NTT(). + Az2dct1.MulBy2toD(&pk.t1) + Az2dct1.NTT() + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + for i := 0; i < K; i++ { + Az2dct1[i].MulHat(&Az2dct1[i], &ch) + } + Az2dct1.Sub(&Az, &Az2dct1) + Az2dct1.ReduceLe2Q() + Az2dct1.InvNTT() + Az2dct1.NormalizeAssumingLe2Q() + + // UseHint(pk.hint, Az - 2ᵈ·c·t₁) + // = UseHint(pk.hint, w - c·s₂ + c·t₀) + // = UseHint(pk.hint, r + c·t₀) + // = r₁ = w₁. + w1.UseHint(&Az2dct1, &sig.hint) + w1.PackW1(w1Packed[:]) + + // c' = H(μ, w₁) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(cp[:]) + + return sig.c == cp +} + +// SignTo signs the given message and writes the signature into signature. +// +// For Dilithium this is the top-level signing function. For ML-DSA +// this is ML-DSA.Sign_internal. +// +//nolint:funlen +func SignTo(sk *PrivateKey, msg func(io.Writer), rnd [32]byte, signature []byte) { + var mu, rhop [64]byte + var w1Packed [PolyW1Size * K]byte + var y, yh VecL + var w, w0, w1, w0mcs2, ct0, w0mcs2pct0 VecK + var ch common.Poly + var yNonce uint16 + var sig unpackedSignature + + if len(signature) < SignatureSize { + panic("Signature does not fit in that byteslice") + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(sk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // ρ' = CRH(key ‖ μ) + h.Reset() + _, _ = h.Write(sk.key[:]) + if NIST { + _, _ = h.Write(rnd[:]) + } + _, _ = h.Write(mu[:]) + _, _ = h.Read(rhop[:]) + + // Main rejection loop + attempt := 0 + for { + attempt++ + if attempt >= 576 { + // Depending on the mode, one try has a chance between 1/7 and 1/4 + // of succeeding. Thus it is safe to say that 576 iterations + // are enough as (6/7)⁵⁷⁶ < 2⁻¹²⁸. + panic("This should only happen 1 in 2^{128}: something is wrong.") + } + + // y = ExpandMask(ρ', key) + VecLDeriveUniformLeGamma1(&y, &rhop, yNonce) + yNonce += uint16(L) + + // Set w to A y + yh = y + yh.NTT() + for i := 0; i < K; i++ { + PolyDotHat(&w[i], &sk.A[i], &yh) + w[i].ReduceLe2Q() + w[i].InvNTT() + } + + // Decompose w into w₀ and w₁ + w.NormalizeAssumingLe2Q() + w.Decompose(&w0, &w1) + + // c~ = H(μ ‖ w₁) + w1.PackW1(w1Packed[:]) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(sig.c[:]) + + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + + // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. + // + // By Lemma 3 of the specification this is equivalent to checking that + // both ‖ r₀ ‖_∞ < γ₂ - β and r₁ = w₁, for the decomposition + // w - c·s₂ = r₁ α + r₀ as computed by decompose(). + // See also §4.1 of the specification. + for i := 0; i < K; i++ { + w0mcs2[i].MulHat(&ch, &sk.s2h[i]) + w0mcs2[i].InvNTT() + } + w0mcs2.Sub(&w0, &w0mcs2) + w0mcs2.Normalize() + + if w0mcs2.Exceeds(Gamma2 - Beta) { + continue + } + + // z = y + c·s₁ + for i := 0; i < L; i++ { + sig.z[i].MulHat(&ch, &sk.s1h[i]) + sig.z[i].InvNTT() + } + sig.z.Add(&sig.z, &y) + sig.z.Normalize() + + // Ensure ‖z‖_∞ < γ₁ - β + if sig.z.Exceeds(Gamma1 - Beta) { + continue + } + + // Compute c·t₀ + for i := 0; i < K; i++ { + ct0[i].MulHat(&ch, &sk.t0h[i]) + ct0[i].InvNTT() + } + ct0.NormalizeAssumingLe2Q() + + // Ensure ‖c·t₀‖_∞ < γ₂. + if ct0.Exceeds(Gamma2) { + continue + } + + // Create the hint to be able to reconstruct w₁ from w - c·s₂ + c·t0. + // Note that we're not using makeHint() in the obvious way as we + // do not know whether ‖ sc·s₂ - c·t₀ ‖_∞ < γ₂. Instead we note + // that our makeHint() is actually the same as a makeHint for a + // different decomposition: + // + // Earlier we ensured indirectly with a check that r₁ = w₁ where + // r = w - c·s₂. Hence r₀ = r - r₁ α = w - c·s₂ - w₁ α = w₀ - c·s₂. + // Thus MakeHint(w₀ - c·s₂ + c·t₀, w₁) = MakeHint(r0 + c·t₀, r₁) + // and UseHint(w - c·s₂ + c·t₀, w₁) = UseHint(r + c·t₀, r₁). + // As we just ensured that ‖ c·t₀ ‖_∞ < γ₂ our usage is correct. + w0mcs2pct0.Add(&w0mcs2, &ct0) + w0mcs2pct0.NormalizeAssumingLe2Q() + hintPop := sig.hint.MakeHint(&w0mcs2pct0, &w1) + if hintPop > Omega { + continue + } + + break + } + + sig.Pack(signature[:]) +} + +// Computes the public key corresponding to this private key. +func (sk *PrivateKey) Public() *PublicKey { + var t0 VecK + pk := &PublicKey{ + rho: sk.rho, + A: &sk.A, + tr: sk.tr, + } + sk.computeT0andT1(&t0, &pk.t1) + pk.t1.PackT1(pk.t1p[:]) + return pk +} + +// Equal returns whether the two public keys are equal +func (pk *PublicKey) Equal(other *PublicKey) bool { + return pk.rho == other.rho && pk.t1 == other.t1 +} + +// Equal returns whether the two private keys are equal +func (sk *PrivateKey) Equal(other *PrivateKey) bool { + ret := (subtle.ConstantTimeCompare(sk.rho[:], other.rho[:]) & + subtle.ConstantTimeCompare(sk.key[:], other.key[:]) & + subtle.ConstantTimeCompare(sk.tr[:], other.tr[:])) + + acc := uint32(0) + for i := 0; i < L; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s1[i][j] ^ other.s1[i][j] + } + } + for i := 0; i < K; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s2[i][j] ^ other.s2[i][j] + acc |= sk.t0[i][j] ^ other.t0[i][j] + } + } + return (ret & subtle.ConstantTimeEq(int32(acc), 0)) == 1 +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/mat.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/mat.go new file mode 100644 index 0000000000..ceaf634fa7 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/mat.go @@ -0,0 +1,59 @@ +// Code generated from mode3/internal/mat.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A k by l matrix of polynomials. +type Mat [K]VecL + +// Expands the given seed to a complete matrix. +// +// This function is called ExpandA in the specification. +func (m *Mat) Derive(seed *[32]byte) { + if !DeriveX4Available { + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) + } + } + return + } + + idx := 0 + var nonces [4]uint16 + var ps [4]*common.Poly + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + nonces[idx] = (i << 8) + j + ps[idx] = &m[i][j] + idx++ + if idx == 4 { + idx = 0 + PolyDeriveUniformX4(ps, seed, nonces) + } + } + } + if idx != 0 { + for i := idx; i < 4; i++ { + ps[i] = nil + } + PolyDeriveUniformX4(ps, seed, nonces) + } +} + +// Set p to the inner product of a and b using pointwise multiplication. +// +// Assumes a and b are in Montgomery form and their coefficients are +// pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting +// coefficients are bounded by 2Lq. +func PolyDotHat(p *common.Poly, a, b *VecL) { + var t common.Poly + *p = common.Poly{} // zero p + for i := 0; i < L; i++ { + t.MulHat(&a[i], &b[i]) + p.Add(&t, p) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/pack.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/pack.go new file mode 100644 index 0000000000..b0567b7db4 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/pack.go @@ -0,0 +1,270 @@ +// Code generated from mode3/internal/pack.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Writes p with norm less than or equal η into buf, which must be of +// size PolyLeqEtaSize. +// +// Assumes coefficients of p are not normalized, but in [q-η,q+η]. +func PolyPackLeqEta(p *common.Poly, buf []byte) { //#nosec G602 -- buf length is fixed (PolyLeqEtaSize) + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + buf[i] = (byte(common.Q+Eta-p[j]) | + byte(common.Q+Eta-p[j+1])<<4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + buf[i] = (byte(common.Q+Eta-p[j]) | + (byte(common.Q+Eta-p[j+1]) << 3) | + (byte(common.Q+Eta-p[j+2]) << 6)) + buf[i+1] = ((byte(common.Q+Eta-p[j+2]) >> 2) | + (byte(common.Q+Eta-p[j+3]) << 1) | + (byte(common.Q+Eta-p[j+4]) << 4) | + (byte(common.Q+Eta-p[j+5]) << 7)) + buf[i+2] = ((byte(common.Q+Eta-p[j+5]) >> 1) | + (byte(common.Q+Eta-p[j+6]) << 2) | + (byte(common.Q+Eta-p[j+7]) << 5)) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Sets p to the polynomial of norm less than or equal η encoded in the +// given buffer of size PolyLeqEtaSize. +// +// Output coefficients of p are not normalized, but in [q-η,q+η] provided +// buf was created using PackLeqEta. +// +// Beware, for arbitrary buf the coefficients of p might end up in +// the interval [q-2^b,q+2^b] where b is the least b with η≤2^b. +func PolyUnpackLeqEta(p *common.Poly, buf []byte) { //#nosec G602 -- buf length is fixed (PolyLeqEtaSize) + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + p[j] = common.Q + Eta - uint32(buf[i]&15) + p[j+1] = common.Q + Eta - uint32(buf[i]>>4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + p[j] = common.Q + Eta - uint32(buf[i]&7) + p[j+1] = common.Q + Eta - uint32((buf[i]>>3)&7) + p[j+2] = common.Q + Eta - uint32((buf[i]>>6)|((buf[i+1]<<2)&7)) + p[j+3] = common.Q + Eta - uint32((buf[i+1]>>1)&7) + p[j+4] = common.Q + Eta - uint32((buf[i+1]>>4)&7) + p[j+5] = common.Q + Eta - uint32((buf[i+1]>>7)|((buf[i+2]<<1)&7)) + p[j+6] = common.Q + Eta - uint32((buf[i+2]>>2)&7) + p[j+7] = common.Q + Eta - uint32((buf[i+2]>>5)&7) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Writes v with coefficients in {0, 1} of which at most ω non-zero +// to buf, which must have length ω+k. +func (v *VecK) PackHint(buf []byte) { + // The packed hint starts with the indices of the non-zero coefficients + // For instance: + // + // (x⁵⁶ + x¹⁰⁰, x²⁵⁵, 0, x² + x²³, x¹) + // + // Yields + // + // 56, 100, 255, 2, 23, 1 + // + // Then we pad with zeroes until we have a list of ω items: + // // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0 + // + // Then we finish with a list of the switch-over-indices in this + // list between polynomials, so: + // + // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0, 2, 3, 3, 5, 6 + + off := uint8(0) + for i := 0; i < K; i++ { + for j := uint16(0); j < common.N; j++ { + if v[i][j] != 0 { + buf[off] = uint8(j) + off++ + } + } + buf[Omega+i] = off + } + for ; off < Omega; off++ { + buf[off] = 0 + } +} + +// Sets v to the vector encoded using VecK.PackHint() +// +// Returns whether unpacking was successful. +func (v *VecK) UnpackHint(buf []byte) bool { + // A priori, there would be several reasonable ways to encode the same + // hint vector. We take care to only allow only one encoding, to ensure + // "strong unforgeability". + // + // See PackHint() source for description of the encoding. + *v = VecK{} // zero v + prevSOP := uint8(0) // previous switch-over-point + for i := 0; i < K; i++ { + SOP := buf[Omega+i] + if SOP < prevSOP || SOP > Omega { + return false // ensures switch-over-points are increasing + } + for j := prevSOP; j < SOP; j++ { + if j > prevSOP && buf[j] <= buf[j-1] { + return false // ensures indices are increasing (within a poly) + } + v[i][buf[j]] = 1 + } + prevSOP = SOP + } + for j := prevSOP; j < Omega; j++ { + if buf[j] != 0 { + return false // ensures padding indices are zero + } + } + + return true +} + +// Sets p to the polynomial packed into buf by PolyPackLeGamma1. +// +// p will be normalized. +func PolyUnpackLeGamma1(p *common.Poly, buf []byte) { //#nosec G602 -- buf length is fixed (PolyLeGamma1Size) + if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0x3) << 16) + p1 := uint32(buf[i+2]>>2) | (uint32(buf[i+3]) << 6) | + (uint32(buf[i+4]&0xf) << 14) + p2 := uint32(buf[i+4]>>4) | (uint32(buf[i+5]) << 4) | + (uint32(buf[i+6]&0x3f) << 12) + p3 := uint32(buf[i+6]>>6) | (uint32(buf[i+7]) << 2) | + (uint32(buf[i+8]) << 10) + + // coefficients in [0,…,2γ₁) + p0 = Gamma1 - p0 // (-γ₁,…,γ₁] + p1 = Gamma1 - p1 + p2 = Gamma1 - p2 + p3 = Gamma1 - p3 + + p0 += uint32(int32(p0)>>31) & common.Q // normalize + p1 += uint32(int32(p1)>>31) & common.Q + p2 += uint32(int32(p2)>>31) & common.Q + p3 += uint32(int32(p3)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + p[j+2] = p2 + p[j+3] = p3 + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0xf) << 16) + p1 := uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4) | + (uint32(buf[i+4]) << 12) + + p0 = Gamma1 - p0 + p1 = Gamma1 - p1 + + p0 += uint32(int32(p0)>>31) & common.Q + p1 += uint32(int32(p1)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Writes p whose coefficients are in (-γ₁,γ₁] into buf +// which has to be of length PolyLeGamma1Size. +// +// Assumes p is normalized. +func PolyPackLeGamma1(p *common.Poly, buf []byte) { //#nosec G602 -- buf length is fixed (PolyLeGamma1Size) + if Gamma1Bits == 17 { + j := 0 + // coefficients in [0,…,γ₁] ∪ (q-γ₁,…,q) + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := Gamma1 - p[j] // [0,…,γ₁] ∪ (γ₁-q,…,2γ₁-q) + p0 += uint32(int32(p0)>>31) & common.Q // [0,…,2γ₁) + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + p2 := Gamma1 - p[j+2] + p2 += uint32(int32(p2)>>31) & common.Q + p3 := Gamma1 - p[j+3] + p3 += uint32(int32(p3)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<2) + buf[i+3] = byte(p1 >> 6) + buf[i+4] = byte(p1>>14) | byte(p2<<4) + buf[i+5] = byte(p2 >> 4) + buf[i+6] = byte(p2>>12) | byte(p3<<6) + buf[i+7] = byte(p3 >> 2) + buf[i+8] = byte(p3 >> 10) + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + // Coefficients are in [0, γ₁] ∪ (Q-γ₁, Q) + p0 := Gamma1 - p[j] + p0 += uint32(int32(p0)>>31) & common.Q + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<4) + buf[i+3] = byte(p1 >> 4) + buf[i+4] = byte(p1 >> 12) + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Pack w₁ into buf, which must be of length PolyW1Size. +// +// Assumes w₁ is normalized. +func PolyPackW1(p *common.Poly, buf []byte) { + if Gamma1Bits == 19 { + p.PackLe16(buf) + } else if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyW1Size; i += 3 { + buf[i] = byte(p[j]) | byte(p[j+1]<<6) + buf[i+1] = byte(p[j+1]>>2) | byte(p[j+2]<<4) + buf[i+2] = byte(p[j+2]>>4) | byte(p[j+3]<<2) + j += 4 + } + } else { + panic("unsupported γ₁") + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/params.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/params.go new file mode 100644 index 0000000000..8a1f866e65 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/params.go @@ -0,0 +1,18 @@ +// Code generated from params.templ.go. DO NOT EDIT. + +package internal + +const ( + Name = "ML-DSA-65" + K = 6 + L = 5 + Eta = 4 + DoubleEtaBits = 4 + Omega = 55 + Tau = 49 + Gamma1Bits = 19 + Gamma2 = 261888 + NIST = true + TRSize = 64 + CTildeSize = 48 +) diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/rounding.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/rounding.go new file mode 100644 index 0000000000..58123c090b --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/rounding.go @@ -0,0 +1,142 @@ +// Code generated from mode3/internal/rounding.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, +// except for when we would have a₁ = (q-1)/α in which case a₁=0 is taken +// and -α/2 ≤ a₀ < 0. Returns a₀ + q. Note 0 ≤ a₁ < (q-1)/α. +// Recall α = 2γ₂. +func decompose(a uint32) (a0plusQ, a1 uint32) { + // a₁ = ⌈a / 128⌉ + a1 = (a + 127) >> 7 + + if Alpha == 523776 { + // 1025/2²² is close enough to 1/4092 so that a₁ + // becomes a/α rounded down. + a1 = ((a1*1025 + (1 << 21)) >> 22) + + // For the corner-case a₁ = (q-1)/α = 16, we have to set a₁=0. + a1 &= 15 + } else if Alpha == 190464 { + // 1488/2²⁴ is close enough to 1/1488 so that a₁ + // becomes a/α rounded down. + a1 = ((a1 * 11275) + (1 << 23)) >> 24 + + // For the corner-case a₁ = (q-1)/α = 44, we have to set a₁=0. + a1 ^= uint32(int32(43-a1)>>31) & a1 + } else { + panic("unsupported α") + } + + a0plusQ = a - a1*Alpha + + // In the corner-case, when we set a₁=0, we will incorrectly + // have a₀ > (q-1)/2 and we'll need to subtract q. As we + // return a₀ + q, that comes down to adding q if a₀ < (q-1)/2. + a0plusQ += uint32(int32(a0plusQ-(common.Q-1)/2)>>31) & common.Q + + return +} + +// Assume 0 ≤ r, f < Q with ‖f‖_∞ ≤ α/2. Decompose r as r = r1*α + r0 as +// computed by decompose(). Write r' := r - f (mod Q). Now, decompose +// r'=r-f again as r' = r'1*α + r'0 using decompose(). As f is small, we +// have r'1 = r1 + h, where h ∈ {-1, 0, 1}. makeHint() computes |h| +// given z0 := r0 - f (mod Q) and r1. With |h|, which is called the hint, +// we can reconstruct r1 using only r' = r - f, which is done by useHint(). +// To wit: +// +// useHint( r - f, makeHint( r0 - f, r1 ) ) = r1. +// +// Assumes 0 ≤ z0 < Q. +func makeHint(z0, r1 uint32) uint32 { + // If -α/2 < r0 - f ≤ α/2, then r1*α + r0 - f is a valid decomposition of r' + // with the restrictions of decompose() and so r'1 = r1. So the hint + // should be 0. This is covered by the first two inequalities. + // There is one other case: if r0 - f = -α/2, then r1*α + r0 - f is also + // a valid decomposition if r1 = 0. In the other cases a one is carried + // and the hint should be 1. + if z0 <= Gamma2 || z0 > common.Q-Gamma2 || (z0 == common.Q-Gamma2 && r1 == 0) { + return 0 + } + return 1 +} + +// Uses the hint created by makeHint() to reconstruct r1 from r'=r-f; see +// documentation of makeHint() for context. +// Assumes 0 ≤ r' < Q. +func useHint(rp uint32, hint uint32) uint32 { + rp0plusQ, rp1 := decompose(rp) + if hint == 0 { + return rp1 + } + if rp0plusQ > common.Q { + return (rp1 + 1) & 15 + } + return (rp1 - 1) & 15 +} + +// Sets p to the hint polynomial for p0 the modified low bits and p1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint polynomial. +func PolyMakeHint(p, p0, p1 *common.Poly) (pop uint32) { + for i := 0; i < common.N; i++ { + h := makeHint(p0[i], p1[i]) + pop += h + p[i] = h + } + return +} + +// Computes corrections to the high bits of the polynomial q according +// to the hints in h and sets p to the corrected high bits. Returns p. +func PolyUseHint(p, q, hint *common.Poly) { + var q0PlusQ common.Poly + + // See useHint() and makeHint() for an explanation. We reimplement it + // here so that we can call Poly.Decompose(), which might be way faster + // than calling decompose() in a loop (for instance when having AVX2.) + + PolyDecompose(q, &q0PlusQ, p) + + for i := 0; i < common.N; i++ { + if hint[i] == 0 { + continue + } + if Gamma2 == 261888 { + if q0PlusQ[i] > common.Q { + p[i] = (p[i] + 1) & 15 + } else { + p[i] = (p[i] - 1) & 15 + } + } else if Gamma2 == 95232 { + if q0PlusQ[i] > common.Q { + if p[i] == 43 { + p[i] = 0 + } else { + p[i]++ + } + } else { + if p[i] == 0 { + p[i] = 43 + } else { + p[i]-- + } + } + } else { + panic("unsupported γ₂") + } + } +} + +// Splits each of the coefficients of p using decompose. +func PolyDecompose(p, p0PlusQ, p1 *common.Poly) { + for i := 0; i < common.N; i++ { + p0PlusQ[i], p1[i] = decompose(p[i]) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/sample.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/sample.go new file mode 100644 index 0000000000..b37370a4ec --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/sample.go @@ -0,0 +1,339 @@ +// Code generated from mode3/internal/sample.go by gen.go + +package internal + +import ( + "encoding/binary" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/simd/keccakf1600" +) + +// DeriveX4Available indicates whether the system supports the quick fourway +// sampling variants like PolyDeriveUniformX4. +var DeriveX4Available = keccakf1600.IsEnabledX4() + +// For each i, sample ps[i] uniformly from the given seed and nonces[i]. +// ps[i] may be nil and is ignored in that case. +// +// Can only be called when DeriveX4Available is true. +func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < 4; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // Absorb the nonces, the SHAKE128 domain separator (0b1111), the + // start of the padding (0b...001) and the end of the padding 0b100... + // Recall that the rate of SHAKE128 is 168 --- i.e. 21 uint64s. + for j := 0; j < 4; j++ { + state[4*4+j] = uint64(nonces[j]) | (0x1f << 16) + state[20*4+j] = 0x80 << 56 + } + + var idx [4]int // indices into ps + for j := 0; j < 4; j++ { + if ps[j] == nil { + idx[j] = common.N // mark nil polynomial as completed + } + } + + done := false + for !done { + // Applies KeccaK-f[1600] to state to get the next 21 uint64s of each + // of the four SHAKE128 streams. + perm.Permute() + + done = true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + for i := 0; i < 7; i++ { + var t [8]uint32 + t[0] = uint32(state[i*3*4+j] & 0x7fffff) + t[1] = uint32((state[i*3*4+j] >> 24) & 0x7fffff) + t[2] = uint32((state[i*3*4+j] >> 48) | + ((state[(i*3+1)*4+j] & 0x7f) << 16)) + t[3] = uint32((state[(i*3+1)*4+j] >> 8) & 0x7fffff) + t[4] = uint32((state[(i*3+1)*4+j] >> 32) & 0x7fffff) + t[5] = uint32((state[(i*3+1)*4+j] >> 56) | + ((state[(i*3+2)*4+j] & 0x7fff) << 8)) + t[6] = uint32((state[(i*3+2)*4+j] >> 16) & 0x7fffff) + t[7] = uint32((state[(i*3+2)*4+j] >> 40) & 0x7fffff) + + for k := 0; k < 8; k++ { + if t[k] < common.Q { + ps[j][idx[j]] = t[k] + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + } + done = false + } + } +} + +// Sample p uniformly from the given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { + var i, length int + var buf [12 * 16]byte // fits 168B SHAKE-128 rate + + length = 168 + + sample := func() { + // Note that 3 divides into 168 and 12*16, so we use up buf completely. + for j := 0; j < length && i < common.N; j += 3 { + t := (uint32(buf[j]) | (uint32(buf[j+1]) << 8) | + (uint32(buf[j+2]) << 16)) & 0x7fffff + + // We use rejection sampling + if t < common.Q { + p[i] = t + i++ + } + } + } + + var iv [32 + 2]byte // 32 byte seed + uint16 nonce + h := sha3.NewShake128() + copy(iv[:32], seed[:]) + iv[32] = uint8(nonce) + iv[33] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:168]) + sample() + } +} + +// Sample p uniformly with coefficients of norm less than or equal η, +// using the given seed and nonce. +// +// p will not be normalized, but will have coefficients in [q-η,q+η]. +func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { + // Assumes 2 < η < 8. + var i, length int + var buf [9 * 16]byte // fits 136B SHAKE-256 rate + + length = 136 + + sample := func() { + // We use rejection sampling + for j := 0; j < length && i < common.N; j++ { + t1 := uint32(buf[j]) & 15 + t2 := uint32(buf[j]) >> 4 + if Eta == 2 { // branch is eliminated by compiler + if t1 <= 14 { + t1 -= ((205 * t1) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 14 && i < common.N { + t2 -= ((205 * t2) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t2 + i++ + } + } else if Eta == 4 { + if t1 <= 2*Eta { + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 2*Eta && i < common.N { + p[i] = common.Q + Eta - t2 + i++ + } + } else { + panic("unsupported η") + } + } + } + + var iv [64 + 2]byte // 64 byte seed + uint16 nonce + + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + + // 136 is SHAKE-256 rate + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:136]) + sample() + } +} + +// Sample v[i] uniformly with coefficients in (-γ₁,…,γ₁] using the +// given seed and nonce+i +// +// p will be normalized. +func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { + for i := 0; i < L; i++ { + PolyDeriveUniformLeGamma1(&v[i], seed, nonce+uint16(i)) + } +} + +// Sample p uniformly with coefficients in (-γ₁,…,γK1s] using the +// given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { + var buf [PolyLeGamma1Size]byte + + var iv [66]byte + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + _, _ = h.Read(buf[:]) + + PolyUnpackLeGamma1(p, buf[:]) +} + +// For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} +// using the given seed and w1[i]. ps[i] may be nil and is ignored +// in that case. ps[i] will be normalized. +// +// Can only be called when DeriveX4Available is true. +// +// This function is currently not used (yet). +func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < CTildeSize/8; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // SHAKE256 domain separator and padding + for j := 0; j < 4; j++ { + state[(CTildeSize/8)*4+j] ^= 0x1f + state[16*4+j] ^= 0x80 << 56 + } + perm.Permute() + + var signs [4]uint64 + var idx [4]uint16 // indices into ps + + for j := 0; j < 4; j++ { + if ps[j] != nil { + signs[j] = state[j] + *ps[j] = common.Poly{} // zero ps[j] + idx[j] = common.N - Tau + } else { + idx[j] = common.N // mark as completed + } + } + + stateOffset := 1 + for { + done := true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + + for i := stateOffset; i < 17; i++ { + var bs [8]byte + binary.LittleEndian.PutUint64(bs[:], state[4*i+j]) + for k := 0; k < 8; k++ { + b := uint16(bs[k]) + + if b > idx[j] { + continue + } + + ps[j][idx[j]] = ps[j][b] + ps[j][b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + ps[j][b] ^= uint32((-(signs[j] & 1)) & (1 | (common.Q - 1))) + signs[j] >>= 1 + + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + + done = false + } + + if done { + break + } + + perm.Permute() + stateOffset = 0 + } +} + +// Samples p uniformly with τ non-zero coefficients in {q-1,1}. +// +// The polynomial p will be normalized. +func PolyDeriveUniformBall(p *common.Poly, seed []byte) { + var buf [136]byte // SHAKE-256 rate is 136 + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + _, _ = h.Read(buf[:]) + + // Essentially we generate a sequence of τ ones or minus ones, + // prepend 196 zeroes and shuffle the concatenation using the + // usual algorithm (Fisher--Yates.) + signs := binary.LittleEndian.Uint64(buf[:]) + bufOff := 8 // offset into buf + + *p = common.Poly{} // zero p + for i := uint16(common.N - Tau); i < common.N; i++ { + var b uint16 + + // Find location of where to move the new coefficient to using + // rejection sampling. + for { + if bufOff >= 136 { + _, _ = h.Read(buf[:]) + bufOff = 0 + } + + b = uint16(buf[bufOff]) + bufOff++ + + if b <= i { + break + } + } + + p[i] = p[b] + p[b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + p[b] ^= uint32((-(signs & 1)) & (1 | (common.Q - 1))) + signs >>= 1 + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/vec.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/vec.go new file mode 100644 index 0000000000..d07d3b2458 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa65/internal/vec.go @@ -0,0 +1,281 @@ +// Code generated from mode3/internal/vec.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A vector of L polynomials. +type VecL [L]common.Poly + +// A vector of K polynomials. +type VecK [K]common.Poly + +// Normalize the polynomials in this vector. +func (v *VecL) Normalize() { + for i := 0; i < L; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecL) NormalizeAssumingLe2Q() { + for i := 0; i < L; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecL) Add(w, u *VecL) { + for i := 0; i < L; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecL) NTT() { + for i := 0; i < L; i++ { + v[i].NTT() + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecL) Exceeds(bound uint32) bool { + for i := 0; i < L; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Power2Round(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Decompose(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecL) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeqEta(). +func (v *VecL) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sequentially packs each polynomial using PolyPackLeGamma1(). +func (v *VecL) PackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeGamma1(). +func (v *VecL) UnpackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Normalize the polynomials in this vector. +func (v *VecK) Normalize() { + for i := 0; i < K; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecK) NormalizeAssumingLe2Q() { + for i := 0; i < K; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecK) Add(w, u *VecK) { + for i := 0; i < K; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecK) Exceeds(bound uint32) bool { + for i := 0; i < K; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Power2Round(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Decompose(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sets v to the hint vector for v0 the modified low bits and v1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint vector. +func (v *VecK) MakeHint(v0, v1 *VecK) (pop uint32) { + for i := 0; i < K; i++ { + pop += PolyMakeHint(&v[i], &v0[i], &v1[i]) + } + return +} + +// Computes corrections to the high bits of the polynomials in the vector +// w using the hints in h and sets v to the corrected high bits. Returns v. +// See useHint(). +func (v *VecK) UseHint(q, hint *VecK) *VecK { + for i := 0; i < K; i++ { + PolyUseHint(&v[i], &q[i], &hint[i]) + } + return v +} + +// Sequentially packs each polynomial using Poly.PackT1(). +func (v *VecK) PackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sets v to the vector packed into buf by PackT1(). +func (v *VecK) UnpackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sequentially packs each polynomial using Poly.PackT0(). +func (v *VecK) PackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sets v to the vector packed into buf by PackT0(). +func (v *VecK) UnpackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecK) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecK.PackLeqEta(). +func (v *VecK) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecK) NTT() { + for i := 0; i < K; i++ { + v[i].NTT() + } +} + +// Sequentially packs each polynomial using PolyPackW1(). +func (v *VecK) PackW1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackW1(&v[i], buf[offset:]) + offset += PolyW1Size + } +} + +// Sets v to a - b. +// +// Warning: assumes coefficients of the polynomials of b are less than 2q. +func (v *VecK) Sub(a, b *VecK) { + for i := 0; i < K; i++ { + v[i].Sub(&a[i], &b[i]) + } +} + +// Sets v to 2ᵈ w without reducing. +func (v *VecK) MulBy2toD(w *VecK) { + for i := 0; i < K; i++ { + v[i].MulBy2toD(&w[i]) + } +} + +// Applies InvNTT componentwise. See Poly.InvNTT() for details. +func (v *VecK) InvNTT() { + for i := 0; i < K; i++ { + v[i].InvNTT() + } +} + +// Applies Poly.ReduceLe2Q() componentwise. +func (v *VecK) ReduceLe2Q() { + for i := 0; i < K; i++ { + v[i].ReduceLe2Q() + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/dilithium.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/dilithium.go new file mode 100644 index 0000000000..f9092c0eed --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/dilithium.go @@ -0,0 +1,366 @@ +// Code generated from pkg.templ.go. DO NOT EDIT. + +// mldsa87 implements NIST signature scheme ML-DSA-87 as defined in FIPS204. +package mldsa87 + +import ( + "crypto" + cryptoRand "crypto/rand" + "encoding/asn1" + "errors" + "io" + + "github.com/cloudflare/circl/sign" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/sign/mldsa/mldsa87/internal" +) + +const ( + // Size of seed for NewKeyFromSeed + SeedSize = common.SeedSize + + // Size of a packed PublicKey + PublicKeySize = internal.PublicKeySize + + // Size of a packed PrivateKey + PrivateKeySize = internal.PrivateKeySize + + // Size of a signature + SignatureSize = internal.SignatureSize +) + +// PublicKey is the type of ML-DSA-87 public key +type PublicKey internal.PublicKey + +// PrivateKey is the type of ML-DSA-87 private key +type PrivateKey internal.PrivateKey + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + pk, sk, err := internal.GenerateKey(rand) + return (*PublicKey)(pk), (*PrivateKey)(sk), err +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { + pk, sk := internal.NewKeyFromSeed(seed) + return (*PublicKey)(pk), (*PrivateKey)(sk) +} + +// SignTo signs the given message and writes the signature into signature. +// It will panic if signature is not of length at least SignatureSize. +// +// ctx is the optional context string. Errors if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func SignTo(sk *PrivateKey, msg, ctx []byte, randomized bool, sig []byte) error { + var rnd [32]byte + if randomized { + _, err := cryptoRand.Read(rnd[:]) + if err != nil { + return err + } + } + + if len(ctx) > 255 { + return sign.ErrContextTooLong + } + + internal.SignTo( + (*internal.PrivateKey)(sk), + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + w.Write(msg) + }, + rnd, + sig, + ) + return nil +} + +// Do not use. Implements ML-DSA.Sign_internal used for compatibility tests. +func (sk *PrivateKey) unsafeSignInternal(msg []byte, rnd [32]byte) []byte { + var ret [SignatureSize]byte + internal.SignTo( + (*internal.PrivateKey)(sk), + func(w io.Writer) { + _, _ = w.Write(msg) + }, + rnd, + ret[:], + ) + return ret[:] +} + +// Do not use. Implements ML-DSA.Verify_internal used for compatibility tests. +func unsafeVerifyInternal(pk *PublicKey, msg, sig []byte) bool { + return internal.Verify( + (*internal.PublicKey)(pk), + func(w io.Writer) { + _, _ = w.Write(msg) + }, + sig, + ) +} + +// Verify checks whether the given signature by pk on msg is valid. +// +// ctx is the optional context string. Fails if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func Verify(pk *PublicKey, msg, ctx, sig []byte) bool { + if len(ctx) > 255 { + return false + } + return internal.Verify( + (*internal.PublicKey)(pk), + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + _, _ = w.Write(msg) + }, + sig, + ) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Unpack(buf) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Unpack(buf) +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + (*internal.PublicKey)(pk).Pack(buf) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + (*internal.PrivateKey)(sk).Pack(buf) +} + +// Packs the public key. +func (pk *PublicKey) Bytes() []byte { + var buf [PublicKeySize]byte + pk.Pack(&buf) + return buf[:] +} + +// Packs the private key. +func (sk *PrivateKey) Bytes() []byte { + var buf [PrivateKeySize]byte + sk.Pack(&buf) + return buf[:] +} + +// Packs the public key. +func (pk *PublicKey) MarshalBinary() ([]byte, error) { + return pk.Bytes(), nil +} + +// Packs the private key. +func (sk *PrivateKey) MarshalBinary() ([]byte, error) { + return sk.Bytes(), nil +} + +// Unpacks the public key from data. +func (pk *PublicKey) UnmarshalBinary(data []byte) error { + if len(data) != PublicKeySize { + return errors.New("packed public key must be of mldsa87.PublicKeySize bytes") + } + var buf [PublicKeySize]byte + copy(buf[:], data) + pk.Unpack(&buf) + return nil +} + +// Unpacks the private key from data. +func (sk *PrivateKey) UnmarshalBinary(data []byte) error { + if len(data) != PrivateKeySize { + return errors.New("packed private key must be of mldsa87.PrivateKeySize bytes") + } + var buf [PrivateKeySize]byte + copy(buf[:], data) + sk.Unpack(&buf) + return nil +} + +// Returns seed used to generate PrivateKey, and nil if not retained. +func (sk *PrivateKey) Seed() []byte { + return (*internal.PrivateKey)(sk).Seed() +} + +// Sign signs the given message. +// +// opts.HashFunc() must return zero, which can be achieved by passing +// crypto.Hash(0) or nil for opts. rand is ignored. Will only return an error +// if opts.HashFunc() is non-zero. +// +// This function is used to make PrivateKey implement the crypto.Signer +// interface. The package-level SignTo function might be more convenient +// to use. +func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( + sig []byte, err error) { + var ret [SignatureSize]byte + + if opts != nil && opts.HashFunc() != crypto.Hash(0) { + return nil, errors.New("dilithium: cannot sign hashed message") + } + if err = SignTo(sk, msg, nil, false, ret[:]); err != nil { + return nil, err + } + + return ret[:], nil +} + +// Computes the public key corresponding to this private key. +// +// Returns a *PublicKey. The type crypto.PublicKey is used to make +// PrivateKey implement the crypto.Signer interface. +func (sk *PrivateKey) Public() crypto.PublicKey { + return (*PublicKey)((*internal.PrivateKey)(sk).Public()) +} + +// Equal returns whether the two private keys equal. +func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool { + castOther, ok := other.(*PrivateKey) + if !ok { + return false + } + return (*internal.PrivateKey)(sk).Equal((*internal.PrivateKey)(castOther)) +} + +// Equal returns whether the two public keys equal. +func (pk *PublicKey) Equal(other crypto.PublicKey) bool { + castOther, ok := other.(*PublicKey) + if !ok { + return false + } + return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) +} + +// Boilerplate for generic signatures API + +type scheme struct{} + +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for ML-DSA-87. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "ML-DSA-87" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } + +// TODO TLSIdentifier() +func (*scheme) Oid() asn1.ObjectIdentifier { + return asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 19} +} + +func (*scheme) SupportsContext() bool { + return true +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + var ctx []byte + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + err := SignTo(priv, msg, ctx, false, sig) + if err != nil { + panic(err) + } + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + var ctx []byte + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + return Verify(pub, msg, ctx, sig) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/dilithium.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/dilithium.go new file mode 100644 index 0000000000..7a370615a5 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/dilithium.go @@ -0,0 +1,509 @@ +// Code generated from mode3/internal/dilithium.go by gen.go + +package internal + +import ( + cryptoRand "crypto/rand" + "crypto/subtle" + "io" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +const ( + // Size of a packed polynomial of norm ≤η. + // (Note that the formula is not valid in general.) + PolyLeqEtaSize = (common.N * DoubleEtaBits) / 8 + + // β = τη, the maximum size of c s₂. + Beta = Tau * Eta + + // γ₁ range of y + Gamma1 = 1 << Gamma1Bits + + // Size of packed polynomial of norm <γ₁ such as z + PolyLeGamma1Size = (Gamma1Bits + 1) * common.N / 8 + + // α = 2γ₂ parameter for decompose + Alpha = 2 * Gamma2 + + // Size of a packed private key + PrivateKeySize = 32 + 32 + TRSize + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K + + // Size of a packed public key + PublicKeySize = 32 + common.PolyT1Size*K + + // Size of a packed signature + SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize + + // Size of packed w₁ + PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 +) + +// PublicKey is the type of Dilithium public keys. +type PublicKey struct { + rho [32]byte + t1 VecK + + // Cached values + t1p [common.PolyT1Size * K]byte + A *Mat + tr [TRSize]byte +} + +// PrivateKey is the type of Dilithium private keys. +type PrivateKey struct { + rho [32]byte + key [32]byte + s1 VecL + s2 VecK + t0 VecK + tr [TRSize]byte + + // Cached values + A Mat // ExpandA(ρ) + s1h VecL // NTT(s₁) + s2h VecK // NTT(s₂) + t0h VecK // NTT(t₀) + + seed [common.SeedSize]byte + seedSet bool +} + +type unpackedSignature struct { + z VecL + hint VecK + c [CTildeSize]byte +} + +// Packs the signature into buf. +func (sig *unpackedSignature) Pack(buf []byte) { + copy(buf[:], sig.c[:]) + sig.z.PackLeGamma1(buf[CTildeSize:]) + sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) +} + +// Sets sig to the signature encoded in the buffer. +// +// Returns whether buf contains a properly packed signature. +func (sig *unpackedSignature) Unpack(buf []byte) bool { + // NOTE: Previously the Dilithium (but not ML-DSA) implementation accepted + // signatures with trailing data. + if len(buf) != SignatureSize { + return false + } + copy(sig.c[:], buf[:]) + sig.z.UnpackLeGamma1(buf[CTildeSize:]) + if sig.z.Exceeds(Gamma1 - Beta) { + return false + } + if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { + return false + } + return true +} + +// Packs the public key into buf. +func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { + copy(buf[:32], pk.rho[:]) + copy(buf[32:], pk.t1p[:]) +} + +// Sets pk to the public key encoded in buf. +func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { + copy(pk.rho[:], buf[:32]) + copy(pk.t1p[:], buf[32:]) + + pk.t1.UnpackT1(pk.t1p[:]) + pk.A = new(Mat) + pk.A.Derive(&pk.rho) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + h := sha3.NewShake256() + _, _ = h.Write(buf[:]) + _, _ = h.Read(pk.tr[:]) +} + +// Packs the private key into buf. +func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { + copy(buf[:32], sk.rho[:]) + copy(buf[32:64], sk.key[:]) + copy(buf[64:64+TRSize], sk.tr[:]) + offset := 64 + TRSize + sk.s1.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.PackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.PackT0(buf[offset:]) +} + +// Sets sk to the private key encoded in buf. +func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { + sk.seedSet = false + + copy(sk.rho[:], buf[:32]) + copy(sk.key[:], buf[32:64]) + copy(sk.tr[:], buf[64:64+TRSize]) + offset := 64 + TRSize + sk.s1.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * L + sk.s2.UnpackLeqEta(buf[offset:]) + offset += PolyLeqEtaSize * K + sk.t0.UnpackT0(buf[offset:]) + + // Cached values + sk.A.Derive(&sk.rho) + sk.t0h = sk.t0 + sk.t0h.NTT() + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() +} + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { + var seed [32]byte + if rand == nil { + rand = cryptoRand.Reader + } + _, err := io.ReadFull(rand, seed[:]) + if err != nil { + return nil, nil, err + } + pk, sk := NewKeyFromSeed(&seed) + return pk, sk, nil +} + +// NewKeyFromSeed derives a public/private key pair using the given seed. +func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { + var eSeed [128]byte // expanded seed + var pk PublicKey + var sk PrivateKey + var sSeed [64]byte + + sk.seedSet = true + copy(sk.seed[:], seed[:]) + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + + if NIST { + _, _ = h.Write([]byte{byte(K), byte(L)}) + } + + _, _ = h.Read(eSeed[:]) + + copy(pk.rho[:], eSeed[:32]) + copy(sSeed[:], eSeed[32:96]) + copy(sk.key[:], eSeed[96:]) + copy(sk.rho[:], pk.rho[:]) + + sk.A.Derive(&pk.rho) + + for i := uint16(0); i < L; i++ { + PolyDeriveUniformLeqEta(&sk.s1[i], &sSeed, i) + } + + for i := uint16(0); i < K; i++ { + PolyDeriveUniformLeqEta(&sk.s2[i], &sSeed, i+L) + } + + sk.s1h = sk.s1 + sk.s1h.NTT() + sk.s2h = sk.s2 + sk.s2h.NTT() + + sk.computeT0andT1(&sk.t0, &pk.t1) + + sk.t0h = sk.t0 + sk.t0h.NTT() + + // Complete public key far enough to be packed + pk.t1.PackT1(pk.t1p[:]) + pk.A = &sk.A + + // Finish private key + var packedPk [PublicKeySize]byte + pk.Pack(&packedPk) + + // tr = CRH(ρ ‖ t1) = CRH(pk) + h.Reset() + _, _ = h.Write(packedPk[:]) + _, _ = h.Read(sk.tr[:]) + + // Finish cache of public key + pk.tr = sk.tr + + return &pk, &sk +} + +func (sk *PrivateKey) Seed() []byte { + if !sk.seedSet { + return nil + } + var ret [common.SeedSize]byte + copy(ret[:], sk.seed[:]) + return ret[:] +} + +// Computes t0 and t1 from sk.s1h, sk.s2 and sk.A. +func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { + var t VecK + + // Set t to A s₁ + s₂ + for i := 0; i < K; i++ { + PolyDotHat(&t[i], &sk.A[i], &sk.s1h) + t[i].ReduceLe2Q() + t[i].InvNTT() + } + t.Add(&t, &sk.s2) + t.Normalize() + + // Compute t₀, t₁ = Power2Round(t) + t.Power2Round(t0, t1) +} + +// Verify checks whether the given signature by pk on msg is valid. +// +// For Dilithium this is the top-level verification function. +// In ML-DSA, this is ML-DSA.Verify_internal. +func Verify(pk *PublicKey, msg func(io.Writer), signature []byte) bool { + var sig unpackedSignature + var mu [64]byte + var zh VecL + var Az, Az2dct1, w1 VecK + var ch common.Poly + var cp [CTildeSize]byte + var w1Packed [PolyW1Size * K]byte + + // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β + // and ensured that there at most ω ones in pk.hint. + if !sig.Unpack(signature) { + return false + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(pk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // Compute Az + zh = sig.z + zh.NTT() + + for i := 0; i < K; i++ { + PolyDotHat(&Az[i], &pk.A[i], &zh) + } + + // Next, we compute Az - 2ᵈ·c·t₁. + // Note that the coefficients of t₁ are bounded by 256 = 2⁹, + // so the coefficients of Az2dct1 will bounded by 2⁹⁺ᵈ = 2²³ < 2q, + // which is small enough for NTT(). + Az2dct1.MulBy2toD(&pk.t1) + Az2dct1.NTT() + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + for i := 0; i < K; i++ { + Az2dct1[i].MulHat(&Az2dct1[i], &ch) + } + Az2dct1.Sub(&Az, &Az2dct1) + Az2dct1.ReduceLe2Q() + Az2dct1.InvNTT() + Az2dct1.NormalizeAssumingLe2Q() + + // UseHint(pk.hint, Az - 2ᵈ·c·t₁) + // = UseHint(pk.hint, w - c·s₂ + c·t₀) + // = UseHint(pk.hint, r + c·t₀) + // = r₁ = w₁. + w1.UseHint(&Az2dct1, &sig.hint) + w1.PackW1(w1Packed[:]) + + // c' = H(μ, w₁) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(cp[:]) + + return sig.c == cp +} + +// SignTo signs the given message and writes the signature into signature. +// +// For Dilithium this is the top-level signing function. For ML-DSA +// this is ML-DSA.Sign_internal. +// +//nolint:funlen +func SignTo(sk *PrivateKey, msg func(io.Writer), rnd [32]byte, signature []byte) { + var mu, rhop [64]byte + var w1Packed [PolyW1Size * K]byte + var y, yh VecL + var w, w0, w1, w0mcs2, ct0, w0mcs2pct0 VecK + var ch common.Poly + var yNonce uint16 + var sig unpackedSignature + + if len(signature) < SignatureSize { + panic("Signature does not fit in that byteslice") + } + + // μ = CRH(tr ‖ msg) + h := sha3.NewShake256() + _, _ = h.Write(sk.tr[:]) + msg(&h) + _, _ = h.Read(mu[:]) + + // ρ' = CRH(key ‖ μ) + h.Reset() + _, _ = h.Write(sk.key[:]) + if NIST { + _, _ = h.Write(rnd[:]) + } + _, _ = h.Write(mu[:]) + _, _ = h.Read(rhop[:]) + + // Main rejection loop + attempt := 0 + for { + attempt++ + if attempt >= 576 { + // Depending on the mode, one try has a chance between 1/7 and 1/4 + // of succeeding. Thus it is safe to say that 576 iterations + // are enough as (6/7)⁵⁷⁶ < 2⁻¹²⁸. + panic("This should only happen 1 in 2^{128}: something is wrong.") + } + + // y = ExpandMask(ρ', key) + VecLDeriveUniformLeGamma1(&y, &rhop, yNonce) + yNonce += uint16(L) + + // Set w to A y + yh = y + yh.NTT() + for i := 0; i < K; i++ { + PolyDotHat(&w[i], &sk.A[i], &yh) + w[i].ReduceLe2Q() + w[i].InvNTT() + } + + // Decompose w into w₀ and w₁ + w.NormalizeAssumingLe2Q() + w.Decompose(&w0, &w1) + + // c~ = H(μ ‖ w₁) + w1.PackW1(w1Packed[:]) + h.Reset() + _, _ = h.Write(mu[:]) + _, _ = h.Write(w1Packed[:]) + _, _ = h.Read(sig.c[:]) + + PolyDeriveUniformBall(&ch, sig.c[:]) + ch.NTT() + + // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. + // + // By Lemma 3 of the specification this is equivalent to checking that + // both ‖ r₀ ‖_∞ < γ₂ - β and r₁ = w₁, for the decomposition + // w - c·s₂ = r₁ α + r₀ as computed by decompose(). + // See also §4.1 of the specification. + for i := 0; i < K; i++ { + w0mcs2[i].MulHat(&ch, &sk.s2h[i]) + w0mcs2[i].InvNTT() + } + w0mcs2.Sub(&w0, &w0mcs2) + w0mcs2.Normalize() + + if w0mcs2.Exceeds(Gamma2 - Beta) { + continue + } + + // z = y + c·s₁ + for i := 0; i < L; i++ { + sig.z[i].MulHat(&ch, &sk.s1h[i]) + sig.z[i].InvNTT() + } + sig.z.Add(&sig.z, &y) + sig.z.Normalize() + + // Ensure ‖z‖_∞ < γ₁ - β + if sig.z.Exceeds(Gamma1 - Beta) { + continue + } + + // Compute c·t₀ + for i := 0; i < K; i++ { + ct0[i].MulHat(&ch, &sk.t0h[i]) + ct0[i].InvNTT() + } + ct0.NormalizeAssumingLe2Q() + + // Ensure ‖c·t₀‖_∞ < γ₂. + if ct0.Exceeds(Gamma2) { + continue + } + + // Create the hint to be able to reconstruct w₁ from w - c·s₂ + c·t0. + // Note that we're not using makeHint() in the obvious way as we + // do not know whether ‖ sc·s₂ - c·t₀ ‖_∞ < γ₂. Instead we note + // that our makeHint() is actually the same as a makeHint for a + // different decomposition: + // + // Earlier we ensured indirectly with a check that r₁ = w₁ where + // r = w - c·s₂. Hence r₀ = r - r₁ α = w - c·s₂ - w₁ α = w₀ - c·s₂. + // Thus MakeHint(w₀ - c·s₂ + c·t₀, w₁) = MakeHint(r0 + c·t₀, r₁) + // and UseHint(w - c·s₂ + c·t₀, w₁) = UseHint(r + c·t₀, r₁). + // As we just ensured that ‖ c·t₀ ‖_∞ < γ₂ our usage is correct. + w0mcs2pct0.Add(&w0mcs2, &ct0) + w0mcs2pct0.NormalizeAssumingLe2Q() + hintPop := sig.hint.MakeHint(&w0mcs2pct0, &w1) + if hintPop > Omega { + continue + } + + break + } + + sig.Pack(signature[:]) +} + +// Computes the public key corresponding to this private key. +func (sk *PrivateKey) Public() *PublicKey { + var t0 VecK + pk := &PublicKey{ + rho: sk.rho, + A: &sk.A, + tr: sk.tr, + } + sk.computeT0andT1(&t0, &pk.t1) + pk.t1.PackT1(pk.t1p[:]) + return pk +} + +// Equal returns whether the two public keys are equal +func (pk *PublicKey) Equal(other *PublicKey) bool { + return pk.rho == other.rho && pk.t1 == other.t1 +} + +// Equal returns whether the two private keys are equal +func (sk *PrivateKey) Equal(other *PrivateKey) bool { + ret := (subtle.ConstantTimeCompare(sk.rho[:], other.rho[:]) & + subtle.ConstantTimeCompare(sk.key[:], other.key[:]) & + subtle.ConstantTimeCompare(sk.tr[:], other.tr[:])) + + acc := uint32(0) + for i := 0; i < L; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s1[i][j] ^ other.s1[i][j] + } + } + for i := 0; i < K; i++ { + for j := 0; j < common.N; j++ { + acc |= sk.s2[i][j] ^ other.s2[i][j] + acc |= sk.t0[i][j] ^ other.t0[i][j] + } + } + return (ret & subtle.ConstantTimeEq(int32(acc), 0)) == 1 +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/mat.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/mat.go new file mode 100644 index 0000000000..ceaf634fa7 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/mat.go @@ -0,0 +1,59 @@ +// Code generated from mode3/internal/mat.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A k by l matrix of polynomials. +type Mat [K]VecL + +// Expands the given seed to a complete matrix. +// +// This function is called ExpandA in the specification. +func (m *Mat) Derive(seed *[32]byte) { + if !DeriveX4Available { + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) + } + } + return + } + + idx := 0 + var nonces [4]uint16 + var ps [4]*common.Poly + for i := uint16(0); i < K; i++ { + for j := uint16(0); j < L; j++ { + nonces[idx] = (i << 8) + j + ps[idx] = &m[i][j] + idx++ + if idx == 4 { + idx = 0 + PolyDeriveUniformX4(ps, seed, nonces) + } + } + } + if idx != 0 { + for i := idx; i < 4; i++ { + ps[i] = nil + } + PolyDeriveUniformX4(ps, seed, nonces) + } +} + +// Set p to the inner product of a and b using pointwise multiplication. +// +// Assumes a and b are in Montgomery form and their coefficients are +// pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting +// coefficients are bounded by 2Lq. +func PolyDotHat(p *common.Poly, a, b *VecL) { + var t common.Poly + *p = common.Poly{} // zero p + for i := 0; i < L; i++ { + t.MulHat(&a[i], &b[i]) + p.Add(&t, p) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/pack.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/pack.go new file mode 100644 index 0000000000..b0567b7db4 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/pack.go @@ -0,0 +1,270 @@ +// Code generated from mode3/internal/pack.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Writes p with norm less than or equal η into buf, which must be of +// size PolyLeqEtaSize. +// +// Assumes coefficients of p are not normalized, but in [q-η,q+η]. +func PolyPackLeqEta(p *common.Poly, buf []byte) { //#nosec G602 -- buf length is fixed (PolyLeqEtaSize) + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + buf[i] = (byte(common.Q+Eta-p[j]) | + byte(common.Q+Eta-p[j+1])<<4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + buf[i] = (byte(common.Q+Eta-p[j]) | + (byte(common.Q+Eta-p[j+1]) << 3) | + (byte(common.Q+Eta-p[j+2]) << 6)) + buf[i+1] = ((byte(common.Q+Eta-p[j+2]) >> 2) | + (byte(common.Q+Eta-p[j+3]) << 1) | + (byte(common.Q+Eta-p[j+4]) << 4) | + (byte(common.Q+Eta-p[j+5]) << 7)) + buf[i+2] = ((byte(common.Q+Eta-p[j+5]) >> 1) | + (byte(common.Q+Eta-p[j+6]) << 2) | + (byte(common.Q+Eta-p[j+7]) << 5)) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Sets p to the polynomial of norm less than or equal η encoded in the +// given buffer of size PolyLeqEtaSize. +// +// Output coefficients of p are not normalized, but in [q-η,q+η] provided +// buf was created using PackLeqEta. +// +// Beware, for arbitrary buf the coefficients of p might end up in +// the interval [q-2^b,q+2^b] where b is the least b with η≤2^b. +func PolyUnpackLeqEta(p *common.Poly, buf []byte) { //#nosec G602 -- buf length is fixed (PolyLeqEtaSize) + if DoubleEtaBits == 4 { // compiler eliminates branch + j := 0 + for i := 0; i < PolyLeqEtaSize; i++ { + p[j] = common.Q + Eta - uint32(buf[i]&15) + p[j+1] = common.Q + Eta - uint32(buf[i]>>4) + j += 2 + } + } else if DoubleEtaBits == 3 { + j := 0 + for i := 0; i < PolyLeqEtaSize; i += 3 { + p[j] = common.Q + Eta - uint32(buf[i]&7) + p[j+1] = common.Q + Eta - uint32((buf[i]>>3)&7) + p[j+2] = common.Q + Eta - uint32((buf[i]>>6)|((buf[i+1]<<2)&7)) + p[j+3] = common.Q + Eta - uint32((buf[i+1]>>1)&7) + p[j+4] = common.Q + Eta - uint32((buf[i+1]>>4)&7) + p[j+5] = common.Q + Eta - uint32((buf[i+1]>>7)|((buf[i+2]<<1)&7)) + p[j+6] = common.Q + Eta - uint32((buf[i+2]>>2)&7) + p[j+7] = common.Q + Eta - uint32((buf[i+2]>>5)&7) + j += 8 + } + } else { + panic("eta not supported") + } +} + +// Writes v with coefficients in {0, 1} of which at most ω non-zero +// to buf, which must have length ω+k. +func (v *VecK) PackHint(buf []byte) { + // The packed hint starts with the indices of the non-zero coefficients + // For instance: + // + // (x⁵⁶ + x¹⁰⁰, x²⁵⁵, 0, x² + x²³, x¹) + // + // Yields + // + // 56, 100, 255, 2, 23, 1 + // + // Then we pad with zeroes until we have a list of ω items: + // // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0 + // + // Then we finish with a list of the switch-over-indices in this + // list between polynomials, so: + // + // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0, 2, 3, 3, 5, 6 + + off := uint8(0) + for i := 0; i < K; i++ { + for j := uint16(0); j < common.N; j++ { + if v[i][j] != 0 { + buf[off] = uint8(j) + off++ + } + } + buf[Omega+i] = off + } + for ; off < Omega; off++ { + buf[off] = 0 + } +} + +// Sets v to the vector encoded using VecK.PackHint() +// +// Returns whether unpacking was successful. +func (v *VecK) UnpackHint(buf []byte) bool { + // A priori, there would be several reasonable ways to encode the same + // hint vector. We take care to only allow only one encoding, to ensure + // "strong unforgeability". + // + // See PackHint() source for description of the encoding. + *v = VecK{} // zero v + prevSOP := uint8(0) // previous switch-over-point + for i := 0; i < K; i++ { + SOP := buf[Omega+i] + if SOP < prevSOP || SOP > Omega { + return false // ensures switch-over-points are increasing + } + for j := prevSOP; j < SOP; j++ { + if j > prevSOP && buf[j] <= buf[j-1] { + return false // ensures indices are increasing (within a poly) + } + v[i][buf[j]] = 1 + } + prevSOP = SOP + } + for j := prevSOP; j < Omega; j++ { + if buf[j] != 0 { + return false // ensures padding indices are zero + } + } + + return true +} + +// Sets p to the polynomial packed into buf by PolyPackLeGamma1. +// +// p will be normalized. +func PolyUnpackLeGamma1(p *common.Poly, buf []byte) { //#nosec G602 -- buf length is fixed (PolyLeGamma1Size) + if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0x3) << 16) + p1 := uint32(buf[i+2]>>2) | (uint32(buf[i+3]) << 6) | + (uint32(buf[i+4]&0xf) << 14) + p2 := uint32(buf[i+4]>>4) | (uint32(buf[i+5]) << 4) | + (uint32(buf[i+6]&0x3f) << 12) + p3 := uint32(buf[i+6]>>6) | (uint32(buf[i+7]) << 2) | + (uint32(buf[i+8]) << 10) + + // coefficients in [0,…,2γ₁) + p0 = Gamma1 - p0 // (-γ₁,…,γ₁] + p1 = Gamma1 - p1 + p2 = Gamma1 - p2 + p3 = Gamma1 - p3 + + p0 += uint32(int32(p0)>>31) & common.Q // normalize + p1 += uint32(int32(p1)>>31) & common.Q + p2 += uint32(int32(p2)>>31) & common.Q + p3 += uint32(int32(p3)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + p[j+2] = p2 + p[j+3] = p3 + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | + (uint32(buf[i+2]&0xf) << 16) + p1 := uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4) | + (uint32(buf[i+4]) << 12) + + p0 = Gamma1 - p0 + p1 = Gamma1 - p1 + + p0 += uint32(int32(p0)>>31) & common.Q + p1 += uint32(int32(p1)>>31) & common.Q + + p[j] = p0 + p[j+1] = p1 + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Writes p whose coefficients are in (-γ₁,γ₁] into buf +// which has to be of length PolyLeGamma1Size. +// +// Assumes p is normalized. +func PolyPackLeGamma1(p *common.Poly, buf []byte) { //#nosec G602 -- buf length is fixed (PolyLeGamma1Size) + if Gamma1Bits == 17 { + j := 0 + // coefficients in [0,…,γ₁] ∪ (q-γ₁,…,q) + for i := 0; i < PolyLeGamma1Size; i += 9 { + p0 := Gamma1 - p[j] // [0,…,γ₁] ∪ (γ₁-q,…,2γ₁-q) + p0 += uint32(int32(p0)>>31) & common.Q // [0,…,2γ₁) + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + p2 := Gamma1 - p[j+2] + p2 += uint32(int32(p2)>>31) & common.Q + p3 := Gamma1 - p[j+3] + p3 += uint32(int32(p3)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<2) + buf[i+3] = byte(p1 >> 6) + buf[i+4] = byte(p1>>14) | byte(p2<<4) + buf[i+5] = byte(p2 >> 4) + buf[i+6] = byte(p2>>12) | byte(p3<<6) + buf[i+7] = byte(p3 >> 2) + buf[i+8] = byte(p3 >> 10) + + j += 4 + } + } else if Gamma1Bits == 19 { + j := 0 + for i := 0; i < PolyLeGamma1Size; i += 5 { + // Coefficients are in [0, γ₁] ∪ (Q-γ₁, Q) + p0 := Gamma1 - p[j] + p0 += uint32(int32(p0)>>31) & common.Q + p1 := Gamma1 - p[j+1] + p1 += uint32(int32(p1)>>31) & common.Q + + buf[i+0] = byte(p0) + buf[i+1] = byte(p0 >> 8) + buf[i+2] = byte(p0>>16) | byte(p1<<4) + buf[i+3] = byte(p1 >> 4) + buf[i+4] = byte(p1 >> 12) + + j += 2 + } + } else { + panic("γ₁ not supported") + } +} + +// Pack w₁ into buf, which must be of length PolyW1Size. +// +// Assumes w₁ is normalized. +func PolyPackW1(p *common.Poly, buf []byte) { + if Gamma1Bits == 19 { + p.PackLe16(buf) + } else if Gamma1Bits == 17 { + j := 0 + for i := 0; i < PolyW1Size; i += 3 { + buf[i] = byte(p[j]) | byte(p[j+1]<<6) + buf[i+1] = byte(p[j+1]>>2) | byte(p[j+2]<<4) + buf[i+2] = byte(p[j+2]>>4) | byte(p[j+3]<<2) + j += 4 + } + } else { + panic("unsupported γ₁") + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/params.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/params.go new file mode 100644 index 0000000000..b5dc669cac --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/params.go @@ -0,0 +1,18 @@ +// Code generated from params.templ.go. DO NOT EDIT. + +package internal + +const ( + Name = "ML-DSA-87" + K = 8 + L = 7 + Eta = 2 + DoubleEtaBits = 3 + Omega = 75 + Tau = 60 + Gamma1Bits = 19 + Gamma2 = 261888 + NIST = true + TRSize = 64 + CTildeSize = 64 +) diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/rounding.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/rounding.go new file mode 100644 index 0000000000..58123c090b --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/rounding.go @@ -0,0 +1,142 @@ +// Code generated from mode3/internal/rounding.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, +// except for when we would have a₁ = (q-1)/α in which case a₁=0 is taken +// and -α/2 ≤ a₀ < 0. Returns a₀ + q. Note 0 ≤ a₁ < (q-1)/α. +// Recall α = 2γ₂. +func decompose(a uint32) (a0plusQ, a1 uint32) { + // a₁ = ⌈a / 128⌉ + a1 = (a + 127) >> 7 + + if Alpha == 523776 { + // 1025/2²² is close enough to 1/4092 so that a₁ + // becomes a/α rounded down. + a1 = ((a1*1025 + (1 << 21)) >> 22) + + // For the corner-case a₁ = (q-1)/α = 16, we have to set a₁=0. + a1 &= 15 + } else if Alpha == 190464 { + // 1488/2²⁴ is close enough to 1/1488 so that a₁ + // becomes a/α rounded down. + a1 = ((a1 * 11275) + (1 << 23)) >> 24 + + // For the corner-case a₁ = (q-1)/α = 44, we have to set a₁=0. + a1 ^= uint32(int32(43-a1)>>31) & a1 + } else { + panic("unsupported α") + } + + a0plusQ = a - a1*Alpha + + // In the corner-case, when we set a₁=0, we will incorrectly + // have a₀ > (q-1)/2 and we'll need to subtract q. As we + // return a₀ + q, that comes down to adding q if a₀ < (q-1)/2. + a0plusQ += uint32(int32(a0plusQ-(common.Q-1)/2)>>31) & common.Q + + return +} + +// Assume 0 ≤ r, f < Q with ‖f‖_∞ ≤ α/2. Decompose r as r = r1*α + r0 as +// computed by decompose(). Write r' := r - f (mod Q). Now, decompose +// r'=r-f again as r' = r'1*α + r'0 using decompose(). As f is small, we +// have r'1 = r1 + h, where h ∈ {-1, 0, 1}. makeHint() computes |h| +// given z0 := r0 - f (mod Q) and r1. With |h|, which is called the hint, +// we can reconstruct r1 using only r' = r - f, which is done by useHint(). +// To wit: +// +// useHint( r - f, makeHint( r0 - f, r1 ) ) = r1. +// +// Assumes 0 ≤ z0 < Q. +func makeHint(z0, r1 uint32) uint32 { + // If -α/2 < r0 - f ≤ α/2, then r1*α + r0 - f is a valid decomposition of r' + // with the restrictions of decompose() and so r'1 = r1. So the hint + // should be 0. This is covered by the first two inequalities. + // There is one other case: if r0 - f = -α/2, then r1*α + r0 - f is also + // a valid decomposition if r1 = 0. In the other cases a one is carried + // and the hint should be 1. + if z0 <= Gamma2 || z0 > common.Q-Gamma2 || (z0 == common.Q-Gamma2 && r1 == 0) { + return 0 + } + return 1 +} + +// Uses the hint created by makeHint() to reconstruct r1 from r'=r-f; see +// documentation of makeHint() for context. +// Assumes 0 ≤ r' < Q. +func useHint(rp uint32, hint uint32) uint32 { + rp0plusQ, rp1 := decompose(rp) + if hint == 0 { + return rp1 + } + if rp0plusQ > common.Q { + return (rp1 + 1) & 15 + } + return (rp1 - 1) & 15 +} + +// Sets p to the hint polynomial for p0 the modified low bits and p1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint polynomial. +func PolyMakeHint(p, p0, p1 *common.Poly) (pop uint32) { + for i := 0; i < common.N; i++ { + h := makeHint(p0[i], p1[i]) + pop += h + p[i] = h + } + return +} + +// Computes corrections to the high bits of the polynomial q according +// to the hints in h and sets p to the corrected high bits. Returns p. +func PolyUseHint(p, q, hint *common.Poly) { + var q0PlusQ common.Poly + + // See useHint() and makeHint() for an explanation. We reimplement it + // here so that we can call Poly.Decompose(), which might be way faster + // than calling decompose() in a loop (for instance when having AVX2.) + + PolyDecompose(q, &q0PlusQ, p) + + for i := 0; i < common.N; i++ { + if hint[i] == 0 { + continue + } + if Gamma2 == 261888 { + if q0PlusQ[i] > common.Q { + p[i] = (p[i] + 1) & 15 + } else { + p[i] = (p[i] - 1) & 15 + } + } else if Gamma2 == 95232 { + if q0PlusQ[i] > common.Q { + if p[i] == 43 { + p[i] = 0 + } else { + p[i]++ + } + } else { + if p[i] == 0 { + p[i] = 43 + } else { + p[i]-- + } + } + } else { + panic("unsupported γ₂") + } + } +} + +// Splits each of the coefficients of p using decompose. +func PolyDecompose(p, p0PlusQ, p1 *common.Poly) { + for i := 0; i < common.N; i++ { + p0PlusQ[i], p1[i] = decompose(p[i]) + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/sample.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/sample.go new file mode 100644 index 0000000000..b37370a4ec --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/sample.go @@ -0,0 +1,339 @@ +// Code generated from mode3/internal/sample.go by gen.go + +package internal + +import ( + "encoding/binary" + + "github.com/cloudflare/circl/internal/sha3" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/simd/keccakf1600" +) + +// DeriveX4Available indicates whether the system supports the quick fourway +// sampling variants like PolyDeriveUniformX4. +var DeriveX4Available = keccakf1600.IsEnabledX4() + +// For each i, sample ps[i] uniformly from the given seed and nonces[i]. +// ps[i] may be nil and is ignored in that case. +// +// Can only be called when DeriveX4Available is true. +func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < 4; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // Absorb the nonces, the SHAKE128 domain separator (0b1111), the + // start of the padding (0b...001) and the end of the padding 0b100... + // Recall that the rate of SHAKE128 is 168 --- i.e. 21 uint64s. + for j := 0; j < 4; j++ { + state[4*4+j] = uint64(nonces[j]) | (0x1f << 16) + state[20*4+j] = 0x80 << 56 + } + + var idx [4]int // indices into ps + for j := 0; j < 4; j++ { + if ps[j] == nil { + idx[j] = common.N // mark nil polynomial as completed + } + } + + done := false + for !done { + // Applies KeccaK-f[1600] to state to get the next 21 uint64s of each + // of the four SHAKE128 streams. + perm.Permute() + + done = true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + for i := 0; i < 7; i++ { + var t [8]uint32 + t[0] = uint32(state[i*3*4+j] & 0x7fffff) + t[1] = uint32((state[i*3*4+j] >> 24) & 0x7fffff) + t[2] = uint32((state[i*3*4+j] >> 48) | + ((state[(i*3+1)*4+j] & 0x7f) << 16)) + t[3] = uint32((state[(i*3+1)*4+j] >> 8) & 0x7fffff) + t[4] = uint32((state[(i*3+1)*4+j] >> 32) & 0x7fffff) + t[5] = uint32((state[(i*3+1)*4+j] >> 56) | + ((state[(i*3+2)*4+j] & 0x7fff) << 8)) + t[6] = uint32((state[(i*3+2)*4+j] >> 16) & 0x7fffff) + t[7] = uint32((state[(i*3+2)*4+j] >> 40) & 0x7fffff) + + for k := 0; k < 8; k++ { + if t[k] < common.Q { + ps[j][idx[j]] = t[k] + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + } + done = false + } + } +} + +// Sample p uniformly from the given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { + var i, length int + var buf [12 * 16]byte // fits 168B SHAKE-128 rate + + length = 168 + + sample := func() { + // Note that 3 divides into 168 and 12*16, so we use up buf completely. + for j := 0; j < length && i < common.N; j += 3 { + t := (uint32(buf[j]) | (uint32(buf[j+1]) << 8) | + (uint32(buf[j+2]) << 16)) & 0x7fffff + + // We use rejection sampling + if t < common.Q { + p[i] = t + i++ + } + } + } + + var iv [32 + 2]byte // 32 byte seed + uint16 nonce + h := sha3.NewShake128() + copy(iv[:32], seed[:]) + iv[32] = uint8(nonce) + iv[33] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:168]) + sample() + } +} + +// Sample p uniformly with coefficients of norm less than or equal η, +// using the given seed and nonce. +// +// p will not be normalized, but will have coefficients in [q-η,q+η]. +func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { + // Assumes 2 < η < 8. + var i, length int + var buf [9 * 16]byte // fits 136B SHAKE-256 rate + + length = 136 + + sample := func() { + // We use rejection sampling + for j := 0; j < length && i < common.N; j++ { + t1 := uint32(buf[j]) & 15 + t2 := uint32(buf[j]) >> 4 + if Eta == 2 { // branch is eliminated by compiler + if t1 <= 14 { + t1 -= ((205 * t1) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 14 && i < common.N { + t2 -= ((205 * t2) >> 10) * 5 // reduce mod 5 + p[i] = common.Q + Eta - t2 + i++ + } + } else if Eta == 4 { + if t1 <= 2*Eta { + p[i] = common.Q + Eta - t1 + i++ + } + if t2 <= 2*Eta && i < common.N { + p[i] = common.Q + Eta - t2 + i++ + } + } else { + panic("unsupported η") + } + } + } + + var iv [64 + 2]byte // 64 byte seed + uint16 nonce + + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + + // 136 is SHAKE-256 rate + _, _ = h.Write(iv[:]) + + for i < common.N { + _, _ = h.Read(buf[:136]) + sample() + } +} + +// Sample v[i] uniformly with coefficients in (-γ₁,…,γ₁] using the +// given seed and nonce+i +// +// p will be normalized. +func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { + for i := 0; i < L; i++ { + PolyDeriveUniformLeGamma1(&v[i], seed, nonce+uint16(i)) + } +} + +// Sample p uniformly with coefficients in (-γ₁,…,γK1s] using the +// given seed and nonce. +// +// p will be normalized. +func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { + var buf [PolyLeGamma1Size]byte + + var iv [66]byte + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + _, _ = h.Read(buf[:]) + + PolyUnpackLeGamma1(p, buf[:]) +} + +// For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} +// using the given seed and w1[i]. ps[i] may be nil and is ignored +// in that case. ps[i] will be normalized. +// +// Can only be called when DeriveX4Available is true. +// +// This function is currently not used (yet). +func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { + var perm keccakf1600.StateX4 + state := perm.Initialize(false) + + // Absorb the seed in the four states + for i := 0; i < CTildeSize/8; i++ { + v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) + for j := 0; j < 4; j++ { + state[i*4+j] = v + } + } + + // SHAKE256 domain separator and padding + for j := 0; j < 4; j++ { + state[(CTildeSize/8)*4+j] ^= 0x1f + state[16*4+j] ^= 0x80 << 56 + } + perm.Permute() + + var signs [4]uint64 + var idx [4]uint16 // indices into ps + + for j := 0; j < 4; j++ { + if ps[j] != nil { + signs[j] = state[j] + *ps[j] = common.Poly{} // zero ps[j] + idx[j] = common.N - Tau + } else { + idx[j] = common.N // mark as completed + } + } + + stateOffset := 1 + for { + done := true + + PolyLoop: + for j := 0; j < 4; j++ { + if idx[j] == common.N { + continue + } + + for i := stateOffset; i < 17; i++ { + var bs [8]byte + binary.LittleEndian.PutUint64(bs[:], state[4*i+j]) + for k := 0; k < 8; k++ { + b := uint16(bs[k]) + + if b > idx[j] { + continue + } + + ps[j][idx[j]] = ps[j][b] + ps[j][b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + ps[j][b] ^= uint32((-(signs[j] & 1)) & (1 | (common.Q - 1))) + signs[j] >>= 1 + + idx[j]++ + if idx[j] == common.N { + continue PolyLoop + } + } + } + + done = false + } + + if done { + break + } + + perm.Permute() + stateOffset = 0 + } +} + +// Samples p uniformly with τ non-zero coefficients in {q-1,1}. +// +// The polynomial p will be normalized. +func PolyDeriveUniformBall(p *common.Poly, seed []byte) { + var buf [136]byte // SHAKE-256 rate is 136 + + h := sha3.NewShake256() + _, _ = h.Write(seed[:]) + _, _ = h.Read(buf[:]) + + // Essentially we generate a sequence of τ ones or minus ones, + // prepend 196 zeroes and shuffle the concatenation using the + // usual algorithm (Fisher--Yates.) + signs := binary.LittleEndian.Uint64(buf[:]) + bufOff := 8 // offset into buf + + *p = common.Poly{} // zero p + for i := uint16(common.N - Tau); i < common.N; i++ { + var b uint16 + + // Find location of where to move the new coefficient to using + // rejection sampling. + for { + if bufOff >= 136 { + _, _ = h.Read(buf[:]) + bufOff = 0 + } + + b = uint16(buf[bufOff]) + bufOff++ + + if b <= i { + break + } + } + + p[i] = p[b] + p[b] = 1 + // Takes least significant bit of signs and uses it for the sign. + // Note 1 ^ (1 | (Q-1)) = Q-1. + p[b] ^= uint32((-(signs & 1)) & (1 | (common.Q - 1))) + signs >>= 1 + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/vec.go b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/vec.go new file mode 100644 index 0000000000..d07d3b2458 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/mldsa/mldsa87/internal/vec.go @@ -0,0 +1,281 @@ +// Code generated from mode3/internal/vec.go by gen.go + +package internal + +import ( + common "github.com/cloudflare/circl/sign/internal/dilithium" +) + +// A vector of L polynomials. +type VecL [L]common.Poly + +// A vector of K polynomials. +type VecK [K]common.Poly + +// Normalize the polynomials in this vector. +func (v *VecL) Normalize() { + for i := 0; i < L; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecL) NormalizeAssumingLe2Q() { + for i := 0; i < L; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecL) Add(w, u *VecL) { + for i := 0; i < L; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecL) NTT() { + for i := 0; i < L; i++ { + v[i].NTT() + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecL) Exceeds(bound uint32) bool { + for i := 0; i < L; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Power2Round(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecL) Decompose(v0PlusQ, v1 *VecL) { + for i := 0; i < L; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecL) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeqEta(). +func (v *VecL) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sequentially packs each polynomial using PolyPackLeGamma1(). +func (v *VecL) PackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyPackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Sets v to the polynomials packed in buf using VecL.PackLeGamma1(). +func (v *VecL) UnpackLeGamma1(buf []byte) { + offset := 0 + for i := 0; i < L; i++ { + PolyUnpackLeGamma1(&v[i], buf[offset:]) + offset += PolyLeGamma1Size + } +} + +// Normalize the polynomials in this vector. +func (v *VecK) Normalize() { + for i := 0; i < K; i++ { + v[i].Normalize() + } +} + +// Normalize the polynomials in this vector assuming their coefficients +// are already bounded by 2q. +func (v *VecK) NormalizeAssumingLe2Q() { + for i := 0; i < K; i++ { + v[i].NormalizeAssumingLe2Q() + } +} + +// Sets v to w + u. Does not normalize. +func (v *VecK) Add(w, u *VecK) { + for i := 0; i < K; i++ { + v[i].Add(&w[i], &u[i]) + } +} + +// Checks whether any of the coefficients exceeds the given bound in supnorm +// +// Requires the vector to be normalized. +func (v *VecK) Exceeds(bound uint32) bool { + for i := 0; i < K; i++ { + if v[i].Exceeds(bound) { + return true + } + } + return false +} + +// Applies Poly.Power2Round componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Power2Round(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + v[i].Power2Round(&v0PlusQ[i], &v1[i]) + } +} + +// Applies Poly.Decompose componentwise. +// +// Requires the vector to be normalized. +func (v *VecK) Decompose(v0PlusQ, v1 *VecK) { + for i := 0; i < K; i++ { + PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) + } +} + +// Sets v to the hint vector for v0 the modified low bits and v1 +// the unmodified high bits --- see makeHint(). +// +// Returns the number of ones in the hint vector. +func (v *VecK) MakeHint(v0, v1 *VecK) (pop uint32) { + for i := 0; i < K; i++ { + pop += PolyMakeHint(&v[i], &v0[i], &v1[i]) + } + return +} + +// Computes corrections to the high bits of the polynomials in the vector +// w using the hints in h and sets v to the corrected high bits. Returns v. +// See useHint(). +func (v *VecK) UseHint(q, hint *VecK) *VecK { + for i := 0; i < K; i++ { + PolyUseHint(&v[i], &q[i], &hint[i]) + } + return v +} + +// Sequentially packs each polynomial using Poly.PackT1(). +func (v *VecK) PackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sets v to the vector packed into buf by PackT1(). +func (v *VecK) UnpackT1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT1(buf[offset:]) + offset += common.PolyT1Size + } +} + +// Sequentially packs each polynomial using Poly.PackT0(). +func (v *VecK) PackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].PackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sets v to the vector packed into buf by PackT0(). +func (v *VecK) UnpackT0(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + v[i].UnpackT0(buf[offset:]) + offset += common.PolyT0Size + } +} + +// Sequentially packs each polynomial using Poly.PackLeqEta(). +func (v *VecK) PackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Sets v to the polynomials packed in buf using VecK.PackLeqEta(). +func (v *VecK) UnpackLeqEta(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyUnpackLeqEta(&v[i], buf[offset:]) + offset += PolyLeqEtaSize + } +} + +// Applies NTT componentwise. See Poly.NTT() for details. +func (v *VecK) NTT() { + for i := 0; i < K; i++ { + v[i].NTT() + } +} + +// Sequentially packs each polynomial using PolyPackW1(). +func (v *VecK) PackW1(buf []byte) { + offset := 0 + for i := 0; i < K; i++ { + PolyPackW1(&v[i], buf[offset:]) + offset += PolyW1Size + } +} + +// Sets v to a - b. +// +// Warning: assumes coefficients of the polynomials of b are less than 2q. +func (v *VecK) Sub(a, b *VecK) { + for i := 0; i < K; i++ { + v[i].Sub(&a[i], &b[i]) + } +} + +// Sets v to 2ᵈ w without reducing. +func (v *VecK) MulBy2toD(w *VecK) { + for i := 0; i < K; i++ { + v[i].MulBy2toD(&w[i]) + } +} + +// Applies InvNTT componentwise. See Poly.InvNTT() for details. +func (v *VecK) InvNTT() { + for i := 0; i < K; i++ { + v[i].InvNTT() + } +} + +// Applies Poly.ReduceLe2Q() componentwise. +func (v *VecK) ReduceLe2Q() { + for i := 0; i < K; i++ { + v[i].ReduceLe2Q() + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/slhdsa/address.go b/vendor/github.com/cloudflare/circl/sign/slhdsa/address.go new file mode 100644 index 0000000000..8a0b2878ac --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/slhdsa/address.go @@ -0,0 +1,92 @@ +package slhdsa + +import "encoding/binary" + +// See FIPS 205 -- Section 4.2 +// Functions and Addressing + +type addrType = uint32 + +const ( + addressWotsHash = addrType(iota) + addressWotsPk + addressTree + addressForsTree + addressForsRoots + addressWotsPrf + addressForsPrf +) + +const ( + addressSizeCompressed = 22 + addressSizeNonCompressed = 32 +) + +type address struct { + b []byte + o int +} + +func (p *params) addressSize() uint32 { + if p.isSHA2 { + return addressSizeCompressed + } else { + return addressSizeNonCompressed + } +} + +func (p *params) addressOffset() int { + if p.isSHA2 { + return 0 + } else { + return 10 + } +} + +func (p *params) NewAddress() (a address) { + var m [addressSizeNonCompressed]byte + a.b = m[:p.addressSize()] + a.o = p.addressOffset() + return +} + +func (a *address) fromBytes(p *params, c *cursor) { + a.b = c.Next(p.addressSize()) + a.o = p.addressOffset() +} + +func (a *address) Set(x address) { copy(a.b, x.b); a.o = x.o } +func (a *address) Clear() { clearSlice(&a.b); a.o = 0 } +func (a *address) SetKeyPairAddress(i uint32) { binary.BigEndian.PutUint32(a.b[a.o+10:], i) } +func (a *address) SetChainAddress(i uint32) { binary.BigEndian.PutUint32(a.b[a.o+14:], i) } +func (a *address) SetTreeHeight(i uint32) { binary.BigEndian.PutUint32(a.b[a.o+14:], i) } +func (a *address) SetHashAddress(i uint32) { binary.BigEndian.PutUint32(a.b[a.o+18:], i) } +func (a *address) SetTreeIndex(i uint32) { binary.BigEndian.PutUint32(a.b[a.o+18:], i) } +func (a *address) GetKeyPairAddress() uint32 { return binary.BigEndian.Uint32(a.b[a.o+10:]) } +func (a *address) SetLayerAddress(l addrType) { + if a.o == 0 { + a.b[0] = byte(l & 0xFF) + } else { + binary.BigEndian.PutUint32(a.b[0:], l) + } +} + +func (a *address) SetTreeAddress(t [3]uint32) { + if a.o == 0 { + binary.BigEndian.PutUint32(a.b[1:], t[1]) + binary.BigEndian.PutUint32(a.b[5:], t[0]) + } else { + binary.BigEndian.PutUint32(a.b[4:], t[2]) + binary.BigEndian.PutUint32(a.b[8:], t[1]) + binary.BigEndian.PutUint32(a.b[12:], t[0]) + } +} + +func (a *address) SetTypeAndClear(t uint32) { + if a.o == 0 { + a.b[9] = byte(t) + } else { + binary.BigEndian.PutUint32(a.b[16:], t) + } + clear(a.b[a.o+10:]) +} diff --git a/vendor/github.com/cloudflare/circl/sign/slhdsa/fors.go b/vendor/github.com/cloudflare/circl/sign/slhdsa/fors.go new file mode 100644 index 0000000000..5d599dc237 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/slhdsa/fors.go @@ -0,0 +1,173 @@ +package slhdsa + +// See FIPS 205 -- Section 8 +// Forest of Random Subsets (FORS) is a few-time signature scheme that is +// used to sign the digests of the actual messages. + +type ( + forsPublicKey []byte // n bytes + forsPrivateKey []byte // n bytes + forsSignature []forsPair // k*forsPairSize() bytes + forsPair struct { + sk forsPrivateKey // forsSkSize() bytes + auth [][]byte // a*n bytes + } // forsSkSize() + a*n bytes +) + +func (p *params) forsMsgSize() uint32 { return (p.k*p.a + 7) / 8 } +func (p *params) forsPkSize() uint32 { return p.n } +func (p *params) forsSkSize() uint32 { return p.n } +func (p *params) forsSigSize() uint32 { return p.k * p.forsPairSize() } +func (p *params) forsPairSize() uint32 { return p.forsSkSize() + p.a*p.n } + +func (fs *forsSignature) fromBytes(p *params, c *cursor) { + *fs = make([]forsPair, p.k) + for i := range *fs { + (*fs)[i].fromBytes(p, c) + } +} + +func (fp *forsPair) fromBytes(p *params, c *cursor) { + fp.sk = c.Next(p.forsSkSize()) + fp.auth = make([][]byte, p.a) + for i := range fp.auth { + fp.auth[i] = c.Next(p.n) + } +} + +// See FIPS 205 -- Section 8.1 -- Algorithm 14. +func (s *statePriv) forsSkGen(addr address, idx uint32) forsPrivateKey { + s.PRF.address.Set(addr) + s.PRF.address.SetTypeAndClear(addressForsPrf) + s.PRF.address.SetKeyPairAddress(addr.GetKeyPairAddress()) + s.PRF.address.SetTreeIndex(idx) + + return s.PRF.Final() +} + +// See FIPS 205 -- Section 8.2 -- Algorithm 15 -- Iterative version. +// +// This is a stack-based implementation that computes the tree leaves +// in order (from the left to the right). +// Its recursive version can be found at fors_test.go file. +func (s *statePriv) forsNodeIter( + stack stackNode, root []byte, i, z uint32, addr address, +) { + if !(z <= s.a && i < s.k<<(s.a-z)) { + panic(ErrTree) + } + + s.F.address.Set(addr) + s.F.address.SetTreeHeight(0) + + s.H.address.Set(addr) + + twoZ := uint32(1) << z + iTwoZ := i << z + for k := range twoZ { + li := iTwoZ + k + lz := uint32(0) + + sk := s.forsSkGen(addr, li) + s.F.address.SetTreeIndex(li) + s.F.SetMessage(sk) + node := s.F.Final() + + for !stack.isEmpty() && stack.top().z == lz { + left := stack.pop() + li = (li - 1) >> 1 + lz = lz + 1 + + s.H.address.SetTreeHeight(lz) + s.H.address.SetTreeIndex(li) + s.H.SetMsgs(left.node, node) + node = s.H.Final() + } + + stack.push(item{node, lz}) + } + + copy(root, stack.pop().node) +} + +// See FIPS 205 -- Section 8.3 -- Algorithm 16. +func (s *statePriv) forsSign(sig forsSignature, digest []byte, addr address) { + stack := s.NewStack(s.a - 1) + defer stack.Clear() + + in, bits, total := 0, uint32(0), uint32(0) + maskA := (uint32(1) << s.a) - 1 + + for i := range s.k { + for bits < s.a { + total = (total << 8) + uint32(digest[in]) + in++ + bits += 8 + } + + bits -= s.a + indicesI := (total >> bits) & maskA + treeIdx := (i << s.a) + indicesI + forsSk := s.forsSkGen(addr, treeIdx) + copy(sig[i].sk, forsSk) + + for j := range s.a { + shift := (indicesI >> j) ^ 1 + s.forsNodeIter(stack, sig[i].auth[j], (i<<(s.a-j))+shift, j, addr) + } + } +} + +// See FIPS 205 -- Section 8.4 -- Algorithm 17. +func (s *state) forsPkFromSig( + sig forsSignature, digest []byte, addr address, +) (pk forsPublicKey) { + pk = make([]byte, s.forsPkSize()) + + s.F.address.Set(addr) + s.F.address.SetTreeHeight(0) + + s.H.address.Set(addr) + + s.T.address.Set(addr) + s.T.address.SetTypeAndClear(addressForsRoots) + s.T.address.SetKeyPairAddress(addr.GetKeyPairAddress()) + s.T.Reset() + + in, bits, total := 0, uint32(0), uint32(0) + maskA := (uint32(1) << s.a) - 1 + + for i := range s.k { + for bits < s.a { + total = (total << 8) + uint32(digest[in]) + in++ + bits += 8 + } + + bits -= s.a + indicesI := (total >> bits) & maskA + treeIdx := (i << s.a) + indicesI + s.F.address.SetTreeIndex(treeIdx) + s.F.SetMessage(sig[i].sk) + node := s.F.Final() + + for j := range s.a { + if (indicesI>>j)&0x1 == 0 { + treeIdx = treeIdx >> 1 + s.H.SetMsgs(node, sig[i].auth[j]) + } else { + treeIdx = (treeIdx - 1) >> 1 + s.H.SetMsgs(sig[i].auth[j], node) + } + + s.H.address.SetTreeHeight(j + 1) + s.H.address.SetTreeIndex(treeIdx) + node = s.H.Final() + } + + s.T.WriteMessage(node) + } + + copy(pk, s.T.Final()) + return pk +} diff --git a/vendor/github.com/cloudflare/circl/sign/slhdsa/hypertree.go b/vendor/github.com/cloudflare/circl/sign/slhdsa/hypertree.go new file mode 100644 index 0000000000..2345e9b3d2 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/slhdsa/hypertree.go @@ -0,0 +1,68 @@ +package slhdsa + +import "bytes" + +// See FIPS 205 -- Section 7 +// SLH-DSA uses a hypertree to sign the FORS keys. + +type hyperTreeSignature []xmssSignature // d*xmssSigSize() bytes + +func (p *params) hyperTreeSigSize() uint32 { return p.d * p.xmssSigSize() } + +func (hts *hyperTreeSignature) fromBytes(p *params, c *cursor) { + *hts = make([]xmssSignature, p.d) + for i := range *hts { + (*hts)[i].fromBytes(p, c) + } +} + +func nextIndex(idxTree *[3]uint32, n uint32) (idxLeaf uint32) { + idxLeaf = idxTree[0] & ((1 << n) - 1) + idxTree[0] = (idxTree[0] >> n) | (idxTree[1] << (32 - n)) + idxTree[1] = (idxTree[1] >> n) | (idxTree[2] << (32 - n)) + idxTree[2] = (idxTree[2] >> n) + + return +} + +// See FIPS 205 -- Section 7.1 -- Algorithm 12. +func (s *statePriv) htSign( + sig hyperTreeSignature, msg []byte, idxTree [3]uint32, idxLeaf uint32, +) { + addr := s.NewAddress() + addr.SetTreeAddress(idxTree) + stack := s.NewStack(s.hPrime - 1) + defer stack.Clear() + + s.xmssSign(stack, sig[0], msg, idxLeaf, addr) + + root := make([]byte, s.xmssPkSize()) + copy(root, msg) + for j := uint32(1); j < s.d; j++ { + s.xmssPkFromSig(root, root, sig[j-1], idxLeaf, addr) + idxLeaf = nextIndex(&idxTree, s.hPrime) + addr.SetLayerAddress(j) + addr.SetTreeAddress(idxTree) + s.xmssSign(stack, sig[j], root, idxLeaf, addr) + } +} + +// See FIPS 205 -- Section 7.2 -- Algorithm 13. +func (s *state) htVerify( + msg, root []byte, idxTree [3]uint32, idxLeaf uint32, sig hyperTreeSignature, +) bool { + addr := s.NewAddress() + addr.SetTreeAddress(idxTree) + + node := make([]byte, s.xmssPkSize()) + s.xmssPkFromSig(node, msg, sig[0], idxLeaf, addr) + + for j := uint32(1); j < s.d; j++ { + idxLeaf = nextIndex(&idxTree, s.hPrime) + addr.SetLayerAddress(j) + addr.SetTreeAddress(idxTree) + s.xmssPkFromSig(node, node, sig[j], idxLeaf, addr) + } + + return bytes.Equal(node, root) +} diff --git a/vendor/github.com/cloudflare/circl/sign/slhdsa/internal.go b/vendor/github.com/cloudflare/circl/sign/slhdsa/internal.go new file mode 100644 index 0000000000..1972b9bf97 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/slhdsa/internal.go @@ -0,0 +1,135 @@ +package slhdsa + +import "encoding/binary" + +// See FIPS 205 -- Section 9 +// SLH-DSA Internal Functions + +// See FIPS 205 -- Section 9.1 -- Algorithm 18. +func slhKeyGenInternal( + p *params, skSeed, skPrf, pkSeed []byte, +) (pub PublicKey, priv PrivateKey) { + s := p.NewStatePriv(skSeed, pkSeed) + defer s.Clear() + + stack := p.NewStack(p.hPrime) + defer stack.Clear() + + addr := p.NewAddress() + addr.SetLayerAddress(p.d - 1) + pkRoot := make([]byte, p.n) + s.xmssNodeIter(stack, pkRoot, 0, p.hPrime, addr) + + pub.ID = p.ID + pub.seed = pkSeed + pub.root = pkRoot + + priv.ID = p.ID + priv.prfKey = skPrf + priv.seed = skSeed + priv.publicKey = pub + + return +} + +func (p *params) parseMsg( + digest []byte, +) (md []byte, idxTree [3]uint32, idxLeaf uint32) { + l1 := (p.k*p.a + 7) / 8 + l2 := (p.h - p.h/p.d + 7) / 8 + l3 := (p.h + 8*p.d - 1) / (8 * p.d) + + c := cursor(digest) + md = c.Next(l1) + s2 := c.Next(l2) + s3 := c.Next(l3) + + var b2 [12]byte + copy(b2[12-len(s2):], s2) + n2 := p.h - p.h/p.d + idxTree[0] = binary.BigEndian.Uint32(b2[8:]) & ((1 << n2) - 1) + n2 -= 32 + idxTree[1] = binary.BigEndian.Uint32(b2[4:]) & ((1 << n2) - 1) + idxTree[2] = binary.BigEndian.Uint32(b2[0:]) + + var b3 [4]byte + copy(b3[4-len(s3):], s3) + mask32 := (uint32(1) << (p.h / p.d)) - 1 + idxLeaf = mask32 & binary.BigEndian.Uint32(b3[0:]) + + return +} + +// See FIPS 205 -- Section 9.2 -- Algorithm 19. +func slhSignInternal(sk *PrivateKey, message, addRand []byte) ([]byte, error) { + p := sk.ID.params() + sigBytes := make([]byte, p.SignatureSize()) + + var sig signature + curSig := cursor(sigBytes) + if !sig.fromBytes(p, &curSig) { + return nil, ErrSigParse + } + + p.PRFMsg(sig.rnd, sk.prfKey, addRand, message) + digest := make([]byte, p.m) + p.HashMsg(digest, sig.rnd, message, &sk.publicKey) + + md, idxTree, idxLeaf := p.parseMsg(digest) + addr := p.NewAddress() + addr.SetTreeAddress(idxTree) + addr.SetTypeAndClear(addressForsTree) + addr.SetKeyPairAddress(idxLeaf) + + s := p.NewStatePriv(sk.seed, sk.publicKey.seed) + defer s.Clear() + + s.forsSign(sig.forsSig, md, addr) + pkFors := s.forsPkFromSig(sig.forsSig, md, addr) + s.htSign(sig.htSig, pkFors, idxTree, idxLeaf) + + return sigBytes, nil +} + +// See FIPS 205 -- Section 9.3 -- Algorithm 20. +func slhVerifyInternal(pub *PublicKey, message, sigBytes []byte) bool { + p := pub.ID.params() + var sig signature + curSig := cursor(sigBytes) + if len(sigBytes) != p.SignatureSize() || !sig.fromBytes(p, &curSig) { + return false + } + + digest := make([]byte, p.m) + p.HashMsg(digest, sig.rnd, message, pub) + + md, idxTree, idxLeaf := p.parseMsg(digest) + addr := p.NewAddress() + addr.SetTreeAddress(idxTree) + addr.SetTypeAndClear(addressForsTree) + addr.SetKeyPairAddress(idxLeaf) + + s := p.NewStatePub(pub.seed) + defer s.Clear() + + pkFors := s.forsPkFromSig(sig.forsSig, md, addr) + return s.htVerify(pkFors, pub.root, idxTree, idxLeaf, sig.htSig) +} + +// signature represents a SLH-DSA signature. +type signature struct { + rnd []byte // n bytes + forsSig forsSignature // forsSigSize() bytes + htSig hyperTreeSignature // hyperTreeSigSize() bytes +} + +func (p *params) SignatureSize() int { + return int(p.n + p.forsSigSize() + p.hyperTreeSigSize()) +} + +func (s *signature) fromBytes(p *params, c *cursor) bool { + s.rnd = c.Next(p.n) + s.forsSig.fromBytes(p, c) + s.htSig.fromBytes(p, c) + return len(*c) == 0 +} diff --git a/vendor/github.com/cloudflare/circl/sign/slhdsa/keys.go b/vendor/github.com/cloudflare/circl/sign/slhdsa/keys.go new file mode 100644 index 0000000000..53e9ced8af --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/slhdsa/keys.go @@ -0,0 +1,137 @@ +package slhdsa + +import ( + "bytes" + "crypto" + "crypto/subtle" + + "github.com/cloudflare/circl/internal/conv" + "golang.org/x/crypto/cryptobyte" +) + +// [PrivateKey] stores a private key of the SLH-DSA scheme. +// It implements the [crypto.Signer] and [crypto.PrivateKey] interfaces. +// For serialization, it also implements [cryptobyte.MarshalingValue], +// [encoding.BinaryMarshaler], and [encoding.BinaryUnmarshaler]. +type PrivateKey struct { + seed, prfKey []byte + publicKey PublicKey + ID +} + +func (p *params) PrivateKeySize() int { return int(2*p.n) + p.PublicKeySize() } + +// Marshal serializes the key using a [cryptobyte.Builder]. +func (k PrivateKey) Marshal(b *cryptobyte.Builder) error { + b.AddBytes(k.seed) + b.AddBytes(k.prfKey) + b.AddValue(k.publicKey) + return nil +} + +// Unmarshal recovers a [PrivateKey] from a [cryptobyte.String]. +// Caller must specify the private key's [ID] in advance. +// Example: +// +// key := PrivateKey{ID: SHA2Small192} +// key.Unmarshal(str) // returns true +func (k *PrivateKey) Unmarshal(s *cryptobyte.String) bool { + params := k.ID.params() + b := make([]byte, params.PrivateKeySize()) + if !s.CopyBytes(b) { + return false + } + + c := cursor(b) + return k.fromBytes(params, &c) +} + +func (k *PrivateKey) fromBytes(p *params, c *cursor) bool { + k.ID = p.ID + k.seed = c.Next(p.n) + k.prfKey = c.Next(p.n) + return k.publicKey.fromBytes(p, c) && k.publicKey.ID == k.ID +} + +// UnmarshalBinary recovers a [PrivateKey] from a slice of bytes. +// Caller must specify the private key's [ID] in advance. +// Example: +// +// key := PrivateKey{ID: SHA2Small192} +// key.UnmarshalBinary(bytes) // returns nil +func (k *PrivateKey) UnmarshalBinary(b []byte) error { return conv.UnmarshalBinary(k, b) } +func (k PrivateKey) MarshalBinary() ([]byte, error) { return conv.MarshalBinary(k) } +func (k PrivateKey) Public() crypto.PublicKey { return k.PublicKey() } +func (k PrivateKey) PublicKey() (pub PublicKey) { + params := k.ID.params() + c := cursor(make([]byte, params.PublicKeySize())) + pub.fromBytes(params, &c) + copy(pub.seed, k.publicKey.seed) + copy(pub.root, k.publicKey.root) + return +} + +func (k PrivateKey) Equal(x crypto.PrivateKey) bool { + other, ok := x.(PrivateKey) + return ok && k.ID == other.ID && + subtle.ConstantTimeCompare(k.seed, other.seed) == 1 && + subtle.ConstantTimeCompare(k.prfKey, other.prfKey) == 1 && + k.publicKey.Equal(other.publicKey) +} + +// [PublicKey] stores a public key of the SLH-DSA scheme. +// It implements the [crypto.PublicKey] interface. +// For serialization, it also implements [cryptobyte.MarshalingValue], +// [encoding.BinaryMarshaler], and [encoding.BinaryUnmarshaler]. +type PublicKey struct { + seed, root []byte + ID +} + +func (p *params) PublicKeySize() int { return int(2 * p.n) } + +// Marshal serializes the key using a [cryptobyte.Builder]. +func (k PublicKey) Marshal(b *cryptobyte.Builder) error { + b.AddBytes(k.seed) + b.AddBytes(k.root) + return nil +} + +// Unmarshal recovers a [PublicKey] from a [cryptobyte.String]. +// Caller must specify the public key's [ID] in advance. +// Example: +// +// key := PublicKey{ID: SHA2Small192} +// key.Unmarshal(str) // returns true +func (k *PublicKey) Unmarshal(s *cryptobyte.String) bool { + params := k.ID.params() + b := make([]byte, params.PublicKeySize()) + if !s.CopyBytes(b) { + return false + } + + c := cursor(b) + return k.fromBytes(params, &c) +} + +func (k *PublicKey) fromBytes(p *params, c *cursor) bool { + k.ID = p.ID + k.seed = c.Next(p.n) + k.root = c.Next(p.n) + return len(*c) == 0 +} + +// UnmarshalBinary recovers a [PublicKey] from a slice of bytes. +// Caller must specify the public key's [ID] in advance. +// Example: +// +// key := PublicKey{ID: SHA2Small192} +// key.UnmarshalBinary(bytes) // returns nil +func (k *PublicKey) UnmarshalBinary(b []byte) error { return conv.UnmarshalBinary(k, b) } +func (k PublicKey) MarshalBinary() ([]byte, error) { return conv.MarshalBinary(k) } +func (k PublicKey) Equal(x crypto.PublicKey) bool { + other, ok := x.(PublicKey) + return ok && k.ID == other.ID && + bytes.Equal(k.seed, other.seed) && + bytes.Equal(k.root, other.root) +} diff --git a/vendor/github.com/cloudflare/circl/sign/slhdsa/message.go b/vendor/github.com/cloudflare/circl/sign/slhdsa/message.go new file mode 100644 index 0000000000..19503677c0 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/slhdsa/message.go @@ -0,0 +1,119 @@ +package slhdsa + +import ( + "crypto" + "hash" + "io" + + "github.com/cloudflare/circl/xof" + _ "golang.org/x/crypto/sha3" +) + +// [PreHash] is a helper for hashing a message before signing. +// It implements the [io.Writer] interface, so the message can be provided +// in chunks before calling the [SignDeterministic], [SignRandomized], or +// [Verify] functions. +// Pre-hash must not be used for generating pure signatures. +type PreHash struct { + writer interface { + io.Writer + Reset() + } + size int + oid byte +} + +// [NewPreHashWithHash] is used to prehash messages using either the SHA2 or +// SHA3 hash functions. +// Returns [ErrPreHash] if the function is not supported. +func NewPreHashWithHash(h crypto.Hash) (*PreHash, error) { + hash2oid := [...]byte{ + crypto.SHA256: 1, + crypto.SHA384: 2, + crypto.SHA512: 3, + crypto.SHA224: 4, + crypto.SHA512_224: 5, + crypto.SHA512_256: 6, + crypto.SHA3_224: 7, + crypto.SHA3_256: 8, + crypto.SHA3_384: 9, + crypto.SHA3_512: 10, + } + + if int(h) >= len(hash2oid) { + return nil, ErrPreHash + } + + oid := hash2oid[h] + if oid == 0 { + return nil, ErrPreHash + } + + return &PreHash{h.New(), h.Size(), oid}, nil +} + +// [NewPreHashWithXof] is used to prehash messages using either SHAKE-128 +// or SHAKE-256. +// Returns [ErrPreHash] if the function is not supported. +func NewPreHashWithXof(x xof.ID) (*PreHash, error) { + switch x { + case xof.SHAKE128: + return &PreHash{x.New(), 32, 11}, nil + case xof.SHAKE256: + return &PreHash{x.New(), 64, 12}, nil + default: + return nil, ErrPreHash + } +} + +func (ph *PreHash) Reset() { ph.writer.Reset() } +func (ph *PreHash) Write(b []byte) (int, error) { return ph.writer.Write(b) } + +// BuildMessage returns a [Message] for signing, and resets the writer. +func (ph *PreHash) BuildMessage() (*Message, error) { + // Source https://csrc.nist.gov/Projects/computer-security-objects-register/algorithm-registration + const oidLen = 11 + oid := [oidLen]byte{ + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, ph.oid, + } + + msg := make([]byte, oidLen+ph.size) + copy(msg, oid[:]) + switch f := ph.writer.(type) { + case hash.Hash: + msg = f.Sum(msg[:oidLen]) + case xof.XOF: + _, err := f.Read(msg[oidLen:]) + if err != nil { + return nil, err + } + default: + return nil, ErrPreHash + } + + ph.Reset() + return &Message{msg, 1}, nil +} + +// [Message] wraps a message for signing. +type Message struct { + msg []byte + isPreHash byte +} + +// For pure signatures, use [NewMessage] to pass the message to be signed. +// For pre-hashed signatures, use [PreHash] to hash the message first, and +// then use [PreHash.BuildMessage] to get a [Message] to be signed. +func NewMessage(msg []byte) *Message { return &Message{msg, 0} } + +func (m *Message) getMsgPrime(context []byte) ([]byte, error) { + // See FIPS 205 -- Section 10.2 -- Algorithm 23 and Algorithm 25. + const MaxContextSize = 255 + if len(context) > MaxContextSize { + return nil, ErrContext + } + + return append(append( + []byte{m.isPreHash, byte(len(context))}, context...), m.msg..., + ), nil +} diff --git a/vendor/github.com/cloudflare/circl/sign/slhdsa/params.go b/vendor/github.com/cloudflare/circl/sign/slhdsa/params.go new file mode 100644 index 0000000000..38e4172a99 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/slhdsa/params.go @@ -0,0 +1,182 @@ +package slhdsa + +import ( + "crypto" + "crypto/hmac" + "crypto/sha256" + "crypto/sha512" + "encoding/binary" + "hash" + "io" + "strings" + + "github.com/cloudflare/circl/internal/sha3" +) + +// [ID] identifies the supported parameter sets of SLH-DSA. +// Note that the zero value is not a valid identifier. +type ID byte + +//nolint:stylecheck +const ( + SHA2_128s ID = iota + 1 // SLH-DSA-SHA2-128s + SHAKE_128s // SLH-DSA-SHAKE-128s + SHA2_128f // SLH-DSA-SHA2-128f + SHAKE_128f // SLH-DSA-SHAKE-128f + SHA2_192s // SLH-DSA-SHA2-192s + SHAKE_192s // SLH-DSA-SHAKE-192s + SHA2_192f // SLH-DSA-SHA2-192f + SHAKE_192f // SLH-DSA-SHAKE-192f + SHA2_256s // SLH-DSA-SHA2-256s + SHAKE_256s // SLH-DSA-SHAKE-256s + SHA2_256f // SLH-DSA-SHA2-256f + SHAKE_256f // SLH-DSA-SHAKE-256f + _MaxParams +) + +// [IDByName] returns the [ID] that corresponds to the given name, +// or an error if no parameter set was found. +// See [ID] documentation for the specific names of each parameter set. +// Names are case insensitive. +// +// Example: +// +// IDByName("SLH-DSA-SHAKE-256s") // returns (SHAKESmall256, nil) +func IDByName(name string) (ID, error) { + v := strings.ToLower(name) + for i := range supportedParams { + if strings.ToLower(supportedParams[i].name) == v { + return supportedParams[i].ID, nil + } + } + + return ID(0), ErrParam +} + +// IsValid returns true if the parameter set is supported. +func (id ID) IsValid() bool { return 0 < id && id < _MaxParams } + +func (id ID) String() string { + if !id.IsValid() { + return ErrParam.Error() + } + return supportedParams[id-1].name +} + +func (id ID) params() *params { + if !id.IsValid() { + panic(ErrParam) + } + return &supportedParams[id-1] +} + +// params contains all the relevant constants of a parameter set. +type params struct { + name string // Name of the parameter set. + n uint32 // Length of WOTS+ messages. + hPrime uint32 // XMSS Merkle tree height. + h uint32 // Total height of a hypertree. + d uint32 // Hypertree has d layers of XMSS trees. + a uint32 // FORS signs a-bit messages. + k uint32 // FORS generates k private keys. + m uint32 // Used by HashMSG function. + isSHA2 bool // True, if the hash function is SHA2, otherwise is SHAKE. + ID // Identifier of the parameter set. +} + +// Stores all the supported (read-only) parameter sets. +var supportedParams = [_MaxParams - 1]params{ + {ID: SHA2_128s, n: 16, h: 63, d: 7, hPrime: 9, a: 12, k: 14, m: 30, isSHA2: true, name: "SLH-DSA-SHA2-128s"}, + {ID: SHAKE_128s, n: 16, h: 63, d: 7, hPrime: 9, a: 12, k: 14, m: 30, isSHA2: false, name: "SLH-DSA-SHAKE-128s"}, + {ID: SHA2_128f, n: 16, h: 66, d: 22, hPrime: 3, a: 6, k: 33, m: 34, isSHA2: true, name: "SLH-DSA-SHA2-128f"}, + {ID: SHAKE_128f, n: 16, h: 66, d: 22, hPrime: 3, a: 6, k: 33, m: 34, isSHA2: false, name: "SLH-DSA-SHAKE-128f"}, + {ID: SHA2_192s, n: 24, h: 63, d: 7, hPrime: 9, a: 14, k: 17, m: 39, isSHA2: true, name: "SLH-DSA-SHA2-192s"}, + {ID: SHAKE_192s, n: 24, h: 63, d: 7, hPrime: 9, a: 14, k: 17, m: 39, isSHA2: false, name: "SLH-DSA-SHAKE-192s"}, + {ID: SHA2_192f, n: 24, h: 66, d: 22, hPrime: 3, a: 8, k: 33, m: 42, isSHA2: true, name: "SLH-DSA-SHA2-192f"}, + {ID: SHAKE_192f, n: 24, h: 66, d: 22, hPrime: 3, a: 8, k: 33, m: 42, isSHA2: false, name: "SLH-DSA-SHAKE-192f"}, + {ID: SHA2_256s, n: 32, h: 64, d: 8, hPrime: 8, a: 14, k: 22, m: 47, isSHA2: true, name: "SLH-DSA-SHA2-256s"}, + {ID: SHAKE_256s, n: 32, h: 64, d: 8, hPrime: 8, a: 14, k: 22, m: 47, isSHA2: false, name: "SLH-DSA-SHAKE-256s"}, + {ID: SHA2_256f, n: 32, h: 68, d: 17, hPrime: 4, a: 9, k: 35, m: 49, isSHA2: true, name: "SLH-DSA-SHA2-256f"}, + {ID: SHAKE_256f, n: 32, h: 68, d: 17, hPrime: 4, a: 9, k: 35, m: 49, isSHA2: false, name: "SLH-DSA-SHAKE-256f"}, +} + +// See FIPS-205, Section 11.1 and Section 11.2. +func (p *params) PRFMsg(out, skPrf, optRand, msg []byte) { + if p.isSHA2 { + var h crypto.Hash + if p.n == 16 { + h = crypto.SHA256 + } else { + h = crypto.SHA512 + } + + mac := hmac.New(h.New, skPrf) + concat(mac, optRand, msg) + mac.Sum(out[:0]) + } else { + state := sha3.NewShake256() + concat(&state, skPrf, optRand, msg) + _, _ = state.Read(out) + } +} + +// See FIPS-205, Section 11.1 and Section 11.2. +func (p *params) HashMsg(out, r, msg []byte, pk *PublicKey) { + if p.isSHA2 { + var hLen uint32 + var state hash.Hash + if p.n == 16 { + hLen = sha256.Size + state = sha256.New() + } else { + hLen = sha512.Size + state = sha512.New() + } + + mgfSeed := make([]byte, 2*p.n+hLen+4) + c := cursor(mgfSeed) + copy(c.Next(p.n), r) + copy(c.Next(p.n), pk.seed) + sumInter := c.Next(hLen) + + concat(state, r, pk.seed, pk.root, msg) + state.Sum(sumInter[:0]) + p.mgf1(out, mgfSeed, p.m) + } else { + state := sha3.NewShake256() + concat(&state, r, pk.seed, pk.root, msg) + _, _ = state.Read(out) + } +} + +// MGF1 described in Appendix B.2.1 of RFC 8017. +func (p *params) mgf1(out, mgfSeed []byte, maskLen uint32) { + var hLen uint32 + var hashFn func(out, in []byte) + if p.n == 16 { + hLen = sha256.Size + hashFn = sha256sum + } else { + hLen = sha512.Size + hashFn = sha512sum + } + + offset := uint32(0) + end := (maskLen + hLen - 1) / hLen + counterBytes := mgfSeed[len(mgfSeed)-4:] + + for counter := range end { + binary.BigEndian.PutUint32(counterBytes, counter) + hashFn(out[offset:], mgfSeed) + offset += hLen + } +} + +func concat(w io.Writer, list ...[]byte) { + for _, li := range list { + _, err := w.Write(li) + if err != nil { + panic(ErrWriting) + } + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/slhdsa/scheme.go b/vendor/github.com/cloudflare/circl/sign/slhdsa/scheme.go new file mode 100644 index 0000000000..e6210f1213 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/slhdsa/scheme.go @@ -0,0 +1,114 @@ +package slhdsa + +import ( + "crypto/rand" + + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/sign" +) + +func (id ID) Scheme() sign.Scheme { return scheme{id.params()} } + +type scheme struct{ *params } + +func (s scheme) Name() string { return s.name } +func (s scheme) SeedSize() int { return s.PrivateKeySize() } +func (s scheme) SupportsContext() bool { return true } + +// GenerateKey is similar to [GenerateKey] function, except it always reads +// random bytes from [rand.Reader]. +func (s scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(rand.Reader, s.ID) +} + +// Sign returns a randomized pure signature of the message with the context +// given. +// If options is nil, an empty context is used. +// It returns an empty slice if the signature generation fails. +// +// Panics if the key is not a [PrivateKey] or when the [ID] mismatches. +func (s scheme) Sign( + priv sign.PrivateKey, message []byte, options *sign.SignatureOpts, +) []byte { + k, ok := priv.(PrivateKey) + if !ok || s.ID != k.ID { + panic(sign.ErrTypeMismatch) + } + + var context []byte + if options != nil { + context = []byte(options.Context) + } + + sig, err := SignRandomized(&k, rand.Reader, NewMessage(message), context) + if err != nil { + return nil + } + + return sig +} + +// Verify returns true if the signature of the message with the specified +// context is valid. +// If options is nil, an empty context is used. +// +// Panics if the key is not a [PublicKey] or when the [ID] mismatches. +func (s scheme) Verify( + pub sign.PublicKey, message, signature []byte, options *sign.SignatureOpts, +) bool { + k, ok := pub.(PublicKey) + if !ok || s.ID != k.ID { + panic(sign.ErrTypeMismatch) + } + + var context []byte + if options != nil { + context = []byte(options.Context) + } + + return Verify(&k, NewMessage(message), signature, context) +} + +// DeriveKey deterministically generates a pair of keys from a seed. +// +// Panics if seed is not of length [sign.Scheme.SeedSize]. +func (s scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != s.SeedSize() { + panic(sign.ErrSeedSize) + } + + n := s.n + buf := make([]byte, 3*n) + if s.isSHA2 { + s.mgf1(buf, seed, 3*n) + } else { + sha3.ShakeSum256(buf, seed) + } + + c := cursor(buf) + skSeed := c.Next(n) + skPrf := c.Next(n) + pkSeed := c.Next(n) + + return slhKeyGenInternal(s.params, skSeed, skPrf, pkSeed) +} + +func (s scheme) UnmarshalBinaryPublicKey(b []byte) (sign.PublicKey, error) { + k := PublicKey{ID: s.ID} + err := k.UnmarshalBinary(b) + if err != nil { + return nil, err + } + + return k, nil +} + +func (s scheme) UnmarshalBinaryPrivateKey(b []byte) (sign.PrivateKey, error) { + k := PrivateKey{ID: s.ID} + err := k.UnmarshalBinary(b) + if err != nil { + return nil, err + } + + return k, nil +} diff --git a/vendor/github.com/cloudflare/circl/sign/slhdsa/slhdsa.go b/vendor/github.com/cloudflare/circl/sign/slhdsa/slhdsa.go new file mode 100644 index 0000000000..d5dabf56e6 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/slhdsa/slhdsa.go @@ -0,0 +1,131 @@ +// Package slhdsa provides Stateless Hash-based Digital Signature Algorithm. +// +// This package is compliant with [FIPS 205] and the [ID] represents +// the following parameter sets: +// +// Category 1 +// - Based on SHA2: [SHA2_128s] and [SHA2_128f]. +// - Based on SHAKE: [SHAKE_128s] and [SHAKE_128f]. +// +// Category 3 +// - Based on SHA2: [SHA2_192s] and [SHA2_192f] +// - Based on SHAKE: [SHAKE_192s] and [SHAKE_192f] +// +// Category 5 +// - Based on SHA2: [SHA2_256s] and [SHA2_256f]. +// - Based on SHAKE: [SHAKE_256s] and [SHAKE_256f]. +// +// [FIPS 205]: https://doi.org/10.6028/NIST.FIPS.205 +package slhdsa + +import ( + "crypto" + "crypto/rand" + "errors" + "io" +) + +// [GenerateKey] returns a pair of keys using the parameter set specified. +// It returns an error if it fails reading from the random source. +func GenerateKey( + random io.Reader, id ID, +) (pub PublicKey, priv PrivateKey, err error) { + // See FIPS 205 -- Section 10.1 -- Algorithm 21. + params := id.params() + + var skSeed, skPrf, pkSeed []byte + skSeed, err = readRandom(random, params.n) + if err != nil { + return + } + + skPrf, err = readRandom(random, params.n) + if err != nil { + return + } + + pkSeed, err = readRandom(random, params.n) + if err != nil { + return + } + + pub, priv = slhKeyGenInternal(params, skSeed, skPrf, pkSeed) + + return +} + +// [SignDeterministic] returns the signature of the message with the +// specified context. +func SignDeterministic( + priv *PrivateKey, message *Message, context []byte, +) (signature []byte, err error) { + return priv.doSign(message, context, priv.publicKey.seed) +} + +// [SignRandomized] returns a random signature of the message with the +// specified context. +// It returns an error if it fails reading from the random source. +func SignRandomized( + priv *PrivateKey, random io.Reader, message *Message, context []byte, +) (signature []byte, err error) { + params := priv.ID.params() + addRand, err := readRandom(random, params.n) + if err != nil { + return nil, err + } + + return priv.doSign(message, context, addRand) +} + +// [PrivateKey.Sign] returns a randomized signature of the message with an +// empty context. +// Any parameter passed in [crypto.SignerOpts] is discarded. +// It returns an error if it fails reading from the random source. +func (k PrivateKey) Sign( + random io.Reader, message []byte, _ crypto.SignerOpts, +) (signature []byte, err error) { + return SignRandomized(&k, random, NewMessage(message), nil) +} + +func (k *PrivateKey) doSign( + message *Message, context, addRand []byte, +) ([]byte, error) { + // See FIPS 205 -- Section 10.2 -- Algorithm 22 and Algorithm 23. + msgPrime, err := message.getMsgPrime(context) + if err != nil { + return nil, err + } + + return slhSignInternal(k, msgPrime, addRand) +} + +// [Verify] returns true if the signature of the message with the specified +// context is valid. +func Verify(key *PublicKey, message *Message, signature, context []byte) bool { + // See FIPS 205 -- Section 10.3 -- Algorithm 24. + msgPrime, err := message.getMsgPrime(context) + if err != nil { + return false + } + + return slhVerifyInternal(key, msgPrime, signature) +} + +func readRandom(random io.Reader, size uint32) (out []byte, err error) { + out = make([]byte, size) + if random == nil { + random = rand.Reader + } + _, err = io.ReadFull(random, out) + return +} + +var ( + ErrContext = errors.New("sign/slhdsa: context is larger than 255 bytes") + ErrMsgLen = errors.New("sign/slhdsa: invalid message length") + ErrParam = errors.New("sign/slhdsa: invalid SLH-DSA parameter") + ErrPreHash = errors.New("sign/slhdsa: invalid prehash function") + ErrSigParse = errors.New("sign/slhdsa: failed to decode the signature") + ErrTree = errors.New("sign/slhdsa: invalid tree height or tree index") + ErrWriting = errors.New("sign/slhdsa: failed to write to a hash function") +) diff --git a/vendor/github.com/cloudflare/circl/sign/slhdsa/state.go b/vendor/github.com/cloudflare/circl/sign/slhdsa/state.go new file mode 100644 index 0000000000..9613e6fc81 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/slhdsa/state.go @@ -0,0 +1,357 @@ +package slhdsa + +import ( + "crypto/sha256" + "crypto/sha512" + "hash" + "io" + + "github.com/cloudflare/circl/internal/sha3" +) + +// statePriv encapsulates common data for performing a private operation. +type statePriv struct { + state + PRF statePRF +} + +func (s *statePriv) Size(p *params) uint32 { + return s.state.Size(p) + s.PRF.Size(p) +} + +func (p *params) NewStatePriv(skSeed, pkSeed []byte) (s statePriv) { + c := cursor(make([]byte, s.Size(p))) + s.state.init(p, &c, pkSeed) + s.PRF.Init(p, &c, skSeed, pkSeed) + + return +} + +func (s *statePriv) Clear() { + s.PRF.Clear() + s.state.Clear() +} + +// state encapsulates common data for performing a public operation. +type state struct { + *params + + F stateF + H stateH + T stateT +} + +func (s *state) Size(p *params) uint32 { + return s.F.Size(p) + s.H.Size(p) + s.T.Size(p) +} + +func (p *params) NewStatePub(pkSeed []byte) (s state) { + c := cursor(make([]byte, s.Size(p))) + s.init(p, &c, pkSeed) + + return +} + +func (s *state) init(p *params, c *cursor, pkSeed []byte) { + s.params = p + s.F.Init(p, c, pkSeed) + s.H.Init(p, c, pkSeed) + s.T.Init(p, c, pkSeed) +} + +func (s *state) Clear() { + s.F.Clear() + s.H.Clear() + s.T.Clear() + s.params = nil +} + +func sha256sum(out, in []byte) { s := sha256.Sum256(in); copy(out, s[:]) } +func sha512sum(out, in []byte) { s := sha512.Sum512(in); copy(out, s[:]) } + +type baseHasher struct { + hash func(out, in []byte) + input, output []byte + address +} + +func (b *baseHasher) Size(p *params) uint32 { + return p.n + p.addressSize() +} + +func (b *baseHasher) Clear() { + clearSlice(&b.input) + clearSlice(&b.output) + b.address.Clear() +} + +func (b *baseHasher) Final() []byte { + b.hash(b.output, b.input) + return b.output +} + +type statePRF struct{ baseHasher } + +func (s *statePRF) Init(p *params, cur *cursor, skSeed, pkSeed []byte) { + c := cursor(cur.Next(s.Size(p))) + s.output = c.Next(p.n) + s.input = c.Rest() + copy(c.Next(p.n), pkSeed) + _ = c.Next(s.padSize(p)) + s.address.fromBytes(p, &c) + copy(c.Next(p.n), skSeed) + + if p.isSHA2 { + s.hash = sha256sum + } else { + s.hash = sha3.ShakeSum256 + } +} + +func (s *statePRF) Size(p *params) uint32 { + return 2*p.n + s.padSize(p) + s.baseHasher.Size(p) +} + +func (s *statePRF) padSize(p *params) uint32 { + if p.isSHA2 { + return 64 - p.n + } else { + return 0 + } +} + +type stateF struct { + msg []byte + baseHasher +} + +func (s *stateF) Init(p *params, cur *cursor, pkSeed []byte) { + c := cursor(cur.Next(s.Size(p))) + s.output = c.Next(p.n) + s.input = c.Rest() + copy(c.Next(p.n), pkSeed) + _ = c.Next(s.padSize(p)) + s.address.fromBytes(p, &c) + s.msg = c.Next(p.n) + + if p.isSHA2 { + s.hash = sha256sum + } else { + s.hash = sha3.ShakeSum256 + } +} + +func (s *stateF) SetMessage(msg []byte) { copy(s.msg, msg) } + +func (s *stateF) Clear() { + s.baseHasher.Clear() + clearSlice(&s.msg) +} + +func (s *stateF) Size(p *params) uint32 { + return 2*p.n + s.padSize(p) + s.baseHasher.Size(p) +} + +func (s *stateF) padSize(p *params) uint32 { + if p.isSHA2 { + return 64 - p.n + } else { + return 0 + } +} + +type stateH struct { + msg0, msg1 []byte + baseHasher +} + +func (s *stateH) Init(p *params, cur *cursor, pkSeed []byte) { + c := cursor(cur.Next(s.Size(p))) + s.output = c.Next(p.n) + s.input = c.Rest() + copy(c.Next(p.n), pkSeed) + _ = c.Next(s.padSize(p)) + s.address.fromBytes(p, &c) + s.msg0 = c.Next(p.n) + s.msg1 = c.Next(p.n) + + if p.isSHA2 { + if p.n == 16 { + s.hash = sha256sum + } else { + s.hash = sha512sum + } + } else { + s.hash = sha3.ShakeSum256 + } +} + +func (s *stateH) SetMsgs(m0, m1 []byte) { + copy(s.msg0, m0) + copy(s.msg1, m1) +} + +func (s *stateH) Clear() { + s.baseHasher.Clear() + clearSlice(&s.msg0) + clearSlice(&s.msg1) +} + +func (s *stateH) Size(p *params) uint32 { + return 3*p.n + s.padSize(p) + s.baseHasher.Size(p) +} + +func (s *stateH) padSize(p *params) uint32 { + if p.isSHA2 { + if p.n == 16 { + return 64 - p.n + } else { + return 128 - p.n + } + } else { + return 0 + } +} + +type stateT struct { + hash interface { + io.Writer + Reset() + Final([]byte) + } + input, output []byte + address +} + +func (s *stateT) Init(p *params, cur *cursor, pkSeed []byte) { + c := cursor(cur.Next(s.Size(p))) + s.output = c.Next(s.outputSize(p))[:p.n] + s.input = c.Rest() + copy(c.Next(p.n), pkSeed) + _ = c.Next(s.padSize(p)) + s.address.fromBytes(p, &c) + + if p.isSHA2 { + if p.n == 16 { + s.hash = &sha2rw{sha256.New()} + } else { + s.hash = &sha2rw{sha512.New()} + } + } else { + s.hash = &sha3rw{sha3.NewShake256()} + } +} + +func (s *stateT) Clear() { + clearSlice(&s.input) + clearSlice(&s.output) + s.address.Clear() + s.hash.Reset() +} + +func (s *stateT) Reset() { + s.hash.Reset() + _, _ = s.hash.Write(s.input) +} + +func (s *stateT) WriteMessage(msg []byte) { _, _ = s.hash.Write(msg) } + +func (s *stateT) Final() []byte { + s.hash.Final(s.output) + return s.output +} + +func (s *stateT) Size(p *params) uint32 { + return s.outputSize(p) + s.padSize(p) + p.n + p.addressSize() +} + +func (s *stateT) outputSize(p *params) uint32 { + if p.isSHA2 { + if p.n == 16 { + return sha256.Size + } else { + return sha512.Size + } + } else { + return p.n + } +} + +func (s *stateT) padSize(p *params) uint32 { + if p.isSHA2 { + if p.n == 16 { + return 64 - p.n + } else { + return 128 - p.n + } + } else { + return 0 + } +} + +type sha2rw struct{ hash.Hash } + +func (s *sha2rw) Final(out []byte) { s.Sum(out[:0]) } +func (s *sha2rw) SumIdempotent(out []byte) { s.Sum(out[:0]) } + +type sha3rw struct{ sha3.State } + +func (s *sha3rw) Final(out []byte) { _, _ = s.Read(out) } +func (s *sha3rw) SumIdempotent(out []byte) { _, _ = s.Clone().Read(out) } + +type ( + item struct { + node []byte + z uint32 + } + stackNode []item +) + +func (p *params) NewStack(z uint32) stackNode { + s := make([]item, z) + c := cursor(make([]byte, z*p.n)) + for i := range s { + s[i].node = c.Next(p.n) + } + + return s[:0] +} + +func (s stackNode) isEmpty() bool { return len(s) == 0 } +func (s stackNode) top() item { return s[len(s)-1] } +func (s *stackNode) push(v item) { + next := len(*s) + *s = (*s)[:next+1] + (*s)[next].z = v.z + copy((*s)[next].node, v.node) +} + +func (s *stackNode) pop() (v item) { + last := len(*s) - 1 + if last >= 0 { + v = (*s)[last] + *s = (*s)[:last] + } + return +} + +func (s *stackNode) Clear() { + *s = (*s)[:cap(*s)] + for i := range *s { + clearSlice(&(*s)[i].node) + } + clear((*s)[:]) +} + +type cursor []byte + +func (c *cursor) Rest() []byte { return (*c)[:] } +func (c *cursor) Next(n uint32) (out []byte) { + if len(*c) >= int(n) { + out = (*c)[:n] + *c = (*c)[n:] + } + return +} + +func clearSlice(s *[]byte) { clear(*s); *s = nil } diff --git a/vendor/github.com/cloudflare/circl/sign/slhdsa/wotsp.go b/vendor/github.com/cloudflare/circl/sign/slhdsa/wotsp.go new file mode 100644 index 0000000000..5438c5ca52 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/slhdsa/wotsp.go @@ -0,0 +1,142 @@ +package slhdsa + +// See FIPS 205 -- Section 5 +// Winternitz One-Time Signature Plus Scheme + +const ( + wotsW uint32 = 16 // wotsW is w = 2^lg_w, where lg_w = 4. + wotsLen2 uint32 = 3 // wotsLen2 is len_2 fixed to 3. +) + +type ( + wotsPublicKey []byte // n bytes + wotsSignature []byte // wotsLen()*n bytes +) + +func (p *params) wotsSigSize() uint32 { return p.wotsLen() * p.n } +func (p *params) wotsLen() uint32 { return p.wotsLen1() + wotsLen2 } +func (p *params) wotsLen1() uint32 { return 2 * p.n } + +func (ws *wotsSignature) fromBytes(p *params, c *cursor) { + *ws = c.Next(p.wotsSigSize()) +} + +// See FIPS 205 -- Section 5 -- Algorithm 5. +func (s *state) chain( + x []byte, index, steps uint32, addr address, +) (out []byte) { + out = x + s.F.address.Set(addr) + for j := index; j < index+steps; j++ { + s.F.address.SetHashAddress(j) + s.F.SetMessage(out) + out = s.F.Final() + } + return +} + +// See FIPS 205 -- Section 5.1 -- Algorithm 6. +func (s *statePriv) wotsPkGen(addr address) wotsPublicKey { + s.PRF.address.Set(addr) + s.PRF.address.SetTypeAndClear(addressWotsPrf) + s.PRF.address.SetKeyPairAddress(addr.GetKeyPairAddress()) + + s.T.address.Set(addr) + s.T.address.SetTypeAndClear(addressWotsPk) + s.T.address.SetKeyPairAddress(addr.GetKeyPairAddress()) + + s.T.Reset() + wotsLen := s.wotsLen() + for i := range wotsLen { + s.PRF.address.SetChainAddress(i) + sk := s.PRF.Final() + + addr.SetChainAddress(i) + tmpi := s.chain(sk, 0, wotsW-1, addr) + + s.T.WriteMessage(tmpi) + } + + return s.T.Final() +} + +// See FIPS 205 -- Section 5.2 -- Algorithm 7. +func (s *statePriv) wotsSign(sig wotsSignature, msg []byte, addr address) { + if len(msg) != int(s.wotsLen1()/2) { + panic(ErrMsgLen) + } + + curSig := cursor(sig) + wotsLen1 := s.wotsLen1() + csum := wotsLen1 * (wotsW - 1) + + s.PRF.address.Set(addr) + s.PRF.address.SetTypeAndClear(addressWotsPrf) + s.PRF.address.SetKeyPairAddress(addr.GetKeyPairAddress()) + + // Signs every nibble of the message and computes the checksum. + for i := range wotsLen1 { + s.PRF.address.SetChainAddress(i) + sk := s.PRF.Final() + + addr.SetChainAddress(i) + msgi := uint32((msg[i/2] >> ((1 - (i & 1)) << 2)) & 0xF) + sigi := s.chain(sk, 0, msgi, addr) + copy(curSig.Next(s.n), sigi) + csum -= msgi + } + + // Lastly, every nibble of the checksum is also signed. + for i := range wotsLen2 { + s.PRF.address.SetChainAddress(wotsLen1 + i) + sk := s.PRF.Final() + + addr.SetChainAddress(wotsLen1 + i) + csumi := (csum >> (8 - 4*i)) & 0xF + sigi := s.chain(sk, 0, csumi, addr) + copy(curSig.Next(s.n), sigi) + } +} + +// See FIPS 205 -- Section 5.3 -- Algorithm 8. +func (s *state) wotsPkFromSig( + sig wotsSignature, msg []byte, addr address, +) wotsPublicKey { + if len(msg) != int(s.wotsLen1()/2) { + panic(ErrMsgLen) + } + + wotsLen1 := s.wotsLen1() + csum := wotsLen1 * (wotsW - 1) + + s.T.address.Set(addr) + s.T.address.SetTypeAndClear(addressWotsPk) + s.T.address.SetKeyPairAddress(addr.GetKeyPairAddress()) + + s.T.Reset() + curSig := cursor(sig) + + // Signs every nibble of the message, computes the checksum, and + // feeds each signature to the T function. + for i := range wotsLen1 { + addr.SetChainAddress(i) + msgi := uint32((msg[i/2] >> ((1 - (i & 1)) << 2)) & 0xF) + sigi := s.chain(curSig.Next(s.n), msgi, wotsW-1-msgi, addr) + + s.T.WriteMessage(sigi) + csum -= msgi + } + + // Every nibble of the checksum is also signed feeding the signature + // to the T function. + for i := range wotsLen2 { + addr.SetChainAddress(wotsLen1 + i) + csumi := (csum >> (8 - 4*i)) & 0xF + sigi := s.chain(curSig.Next(s.n), csumi, wotsW-1-csumi, addr) + + s.T.WriteMessage(sigi) + } + + // Generates the public key as the output of the T function. + return s.T.Final() +} diff --git a/vendor/github.com/cloudflare/circl/sign/slhdsa/xmss.go b/vendor/github.com/cloudflare/circl/sign/slhdsa/xmss.go new file mode 100644 index 0000000000..ef896f4bb0 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/sign/slhdsa/xmss.go @@ -0,0 +1,111 @@ +package slhdsa + +// See FIPS 205 -- Section 6 +// eXtended Merkle Signature Scheme (XMSS) extends the WOTS+ signature +// scheme into one that can sign multiple messages. + +type ( + xmssPublicKey []byte // n bytes + xmssSignature struct { + wotsSig wotsSignature // wotsSigSize() bytes + authPath []byte // hPrime*n bytes + } // wotsSigSize() + hPrime*n bytes +) + +func (p *params) xmssPkSize() uint32 { return p.n } +func (p *params) xmssAuthPathSize() uint32 { return p.hPrime * p.n } +func (p *params) xmssSigSize() uint32 { + return p.wotsSigSize() + p.xmssAuthPathSize() +} + +func (xs *xmssSignature) fromBytes(p *params, c *cursor) { + xs.wotsSig.fromBytes(p, c) + xs.authPath = c.Next(p.xmssAuthPathSize()) +} + +// See FIPS 205 -- Section 6.1 -- Algorithm 9 -- Iterative version. +// +// This is a stack-based implementation that computes the tree leaves +// in order (from the left to the right). +// Its recursive version can be found at xmss_test.go file. +func (s *statePriv) xmssNodeIter( + stack stackNode, root []byte, i, z uint32, addr address, +) { + if !(z <= s.hPrime && i < (1<<(s.hPrime-z))) { + panic(ErrTree) + } + + s.H.address.Set(addr) + s.H.address.SetTypeAndClear(addressTree) + + twoZ := uint32(1) << z + iTwoZ := i << z + for k := range twoZ { + li := iTwoZ + k + lz := uint32(0) + + addr.SetTypeAndClear(addressWotsHash) + addr.SetKeyPairAddress(li) + node := s.wotsPkGen(addr) + + for !stack.isEmpty() && stack.top().z == lz { + left := stack.pop() + li = (li - 1) >> 1 + lz = lz + 1 + + s.H.address.SetTreeHeight(lz) + s.H.address.SetTreeIndex(li) + s.H.SetMsgs(left.node, node) + node = s.H.Final() + } + + stack.push(item{node, lz}) + } + + copy(root, stack.pop().node) +} + +// See FIPS 205 -- Section 6.2 -- Algorithm 10. +func (s *statePriv) xmssSign( + stack stackNode, sig xmssSignature, msg []byte, idx uint32, addr address, +) { + authPath := cursor(sig.authPath) + for j := range s.hPrime { + k := (idx >> j) ^ 1 + s.xmssNodeIter(stack, authPath.Next(s.n), k, j, addr) + } + + addr.SetTypeAndClear(addressWotsHash) + addr.SetKeyPairAddress(idx) + s.wotsSign(sig.wotsSig, msg, addr) +} + +// See FIPS 205 -- Section 6.3 -- Algorithm 11. +func (s *state) xmssPkFromSig( + out xmssPublicKey, msg []byte, sig xmssSignature, idx uint32, addr address, +) { + addr.SetTypeAndClear(addressWotsHash) + addr.SetKeyPairAddress(idx) + pk := xmssPublicKey(s.wotsPkFromSig(sig.wotsSig, msg, addr)) + + treeIdx := idx + s.H.address.Set(addr) + s.H.address.SetTypeAndClear(addressTree) + + authPath := cursor(sig.authPath) + for k := range s.hPrime { + if (idx>>k)&0x1 == 0 { + treeIdx = treeIdx >> 1 + s.H.SetMsgs(pk, authPath.Next(s.n)) + } else { + treeIdx = (treeIdx - 1) >> 1 + s.H.SetMsgs(authPath.Next(s.n), pk) + } + + s.H.address.SetTreeHeight(k + 1) + s.H.address.SetTreeIndex(treeIdx) + pk = s.H.Final() + } + + copy(out, pk) +} diff --git a/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x.go b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x.go new file mode 100644 index 0000000000..66b942cdf1 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x.go @@ -0,0 +1,163 @@ +// Package keccakf1600 provides a two and four-way Keccak-f[1600] permutation in parallel. +// +// Keccak-f[1600] is the permutation underlying several algorithms such as +// Keccak, SHA3 and SHAKE. Running two or four permutations in parallel is +// useful in some scenarios like in hash-based signatures. +// +// # Limitations +// +// Note that not all the architectures support SIMD instructions. This package +// uses AVX2 instructions that are available in some AMD64 architectures +// and NEON instructions that are available in some ARM64 architectures. +// +// For those systems not supporting these, the package still provides the +// expected functionality by means of a generic and slow implementation. +// The recommendation is to beforehand verify IsEnabledX4() and IsEnabledX2() +// to determine if the current system supports the SIMD implementation. +package keccakf1600 + +import ( + "runtime" + "unsafe" + + "github.com/cloudflare/circl/internal/sha3" + "golang.org/x/sys/cpu" +) + +// StateX4 contains state for the four-way permutation including the four +// interleaved [25]uint64 buffers. Call Initialize() before use to initialize +// and get a pointer to the interleaved buffer. +type StateX4 struct { + // Go guarantees a to be aligned on 8 bytes, whereas we need it to be + // aligned on 32 bytes for bet performance. Thus we leave some headroom + // to be able to move the start of the state. + + // 4 x 25 uint64s for the interleaved states and three uint64s headroom + // to fix alignment. + a [103]uint64 + + // Offset into a that is 32 byte aligned. + offset int + + // If true, permute will use 12-round keccak instead of 24-round keccak + turbo bool +} + +// StateX2 contains state for the two-way permutation including the two +// interleaved [25]uint64 buffers. Call Initialize() before use to initialize +// and get a pointer to the interleaved buffer. +type StateX2 struct { + // Go guarantees a to be aligned on 8 bytes, whereas we need it to be + // aligned on 32 bytes for bet performance. Thus we leave some headroom + // to be able to move the start of the state. + + // 2 x 25 uint64s for the interleaved states and three uint64s headroom + // to fix alignment. + a [53]uint64 + + // Offset into a that is 32 byte aligned. + offset int + + // If true, permute will use 12-round keccak instead of 24-round keccak + turbo bool +} + +// IsEnabledX4 returns true if the architecture supports a four-way SIMD +// implementation provided in this package. +func IsEnabledX4() bool { return cpu.X86.HasAVX2 } + +// IsEnabledX2 returns true if the architecture supports a two-way SIMD +// implementation provided in this package. +func IsEnabledX2() bool { return enabledX2 } + +// Initialize the state and returns the buffer on which the four permutations +// will act: a uint64 slice of length 100. The first permutation will act +// on {a[0], a[4], ..., a[96]}, the second on {a[1], a[5], ..., a[97]}, etc. +// If turbo is true, applies 12-round variant instead of the usual 24. +func (s *StateX4) Initialize(turbo bool) []uint64 { + s.turbo = turbo + rp := unsafe.Pointer(&s.a[0]) //nolint:gosec + + // uint64s are always aligned by a multiple of 8. Compute the remainder + // of the address modulo 32 divided by 8. + rem := (int(uintptr(rp)&31) >> 3) + + if rem != 0 { + s.offset = 4 - rem + } + + // The slice we return will be aligned on 32 byte boundary. + return s.a[s.offset : s.offset+100] +} + +// Initialize the state and returns the buffer on which the two permutations +// will act: a uint64 slice of length 50. The first permutation will act +// on {a[0], a[2], ..., a[48]} and the second on {a[1], a[3], ..., a[49]}. +// If turbo is true, applies 12-round variant instead of the usual 24. +func (s *StateX2) Initialize(turbo bool) []uint64 { + s.turbo = turbo + rp := unsafe.Pointer(&s.a[0]) //nolint:gosec + + // uint64s are always aligned by a multiple of 8. Compute the remainder + // of the address modulo 32 divided by 8. + rem := (int(uintptr(rp)&31) >> 3) + + if rem != 0 { + s.offset = 4 - rem + } + + // The slice we return will be aligned on 32 byte boundary. + return s.a[s.offset : s.offset+50] +} + +// Permute performs the four parallel Keccak-f[1600]s interleaved on the slice +// returned from Initialize(). +func (s *StateX4) Permute() { + if IsEnabledX4() { + permuteSIMDx4(s.a[s.offset:], s.turbo) + } else { + permuteScalarX4(s.a[s.offset:], s.turbo) // A slower generic implementation. + } +} + +// Permute performs the two parallel Keccak-f[1600]s interleaved on the slice +// returned from Initialize(). +func (s *StateX2) Permute() { + if IsEnabledX2() { + permuteSIMDx2(s.a[s.offset:], s.turbo) + } else { + permuteScalarX2(s.a[s.offset:], s.turbo) // A slower generic implementation. + } +} + +func permuteScalarX4(a []uint64, turbo bool) { + var buf [25]uint64 + for i := 0; i < 4; i++ { + for j := 0; j < 25; j++ { + buf[j] = a[4*j+i] + } + sha3.KeccakF1600(&buf, turbo) + for j := 0; j < 25; j++ { + a[4*j+i] = buf[j] + } + } +} + +func permuteScalarX2(a []uint64, turbo bool) { + var buf [25]uint64 + for i := 0; i < 2; i++ { + for j := 0; j < 25; j++ { + buf[j] = a[2*j+i] + } + sha3.KeccakF1600(&buf, turbo) + for j := 0; j < 25; j++ { + a[2*j+i] = buf[j] + } + } +} + +var enabledX2 bool + +func init() { + enabledX2 = runtime.GOARCH == "arm64" && runtime.GOOS == "darwin" +} diff --git a/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.go b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.go new file mode 100644 index 0000000000..0cb9692c32 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.go @@ -0,0 +1,13 @@ +//go:build arm64 && go1.16 && !purego +// +build arm64,go1.16,!purego + +package keccakf1600 + +import "github.com/cloudflare/circl/internal/sha3" + +func permuteSIMDx2(state []uint64, turbo bool) { f1600x2ARM(&state[0], &sha3.RC, turbo) } + +func permuteSIMDx4(state []uint64, turbo bool) { permuteScalarX4(state, turbo) } + +//go:noescape +func f1600x2ARM(state *uint64, rc *[24]uint64, turbo bool) diff --git a/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.s b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.s new file mode 100644 index 0000000000..998aeca5b4 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x2_arm64.s @@ -0,0 +1,136 @@ +// +build arm64,go1.16,!purego + +// Taken from https://github.com/bwesterb/armed-keccak + +#include "textflag.h" + +// func f1600x2ARM(state *uint64, rc *[24]uint64, turbo bool) +TEXT ·f1600x2ARM(SB), NOSPLIT, $0-17 + MOVD state+0(FP), R0 + MOVD rc+8(FP), R1 + MOVD R0, R2 + MOVD $24, R3 + + VLD1.P 64(R0), [ V0.B16, V1.B16, V2.B16, V3.B16] + VLD1.P 64(R0), [ V4.B16, V5.B16, V6.B16, V7.B16] + VLD1.P 64(R0), [ V8.B16, V9.B16, V10.B16, V11.B16] + VLD1.P 64(R0), [V12.B16, V13.B16, V14.B16, V15.B16] + VLD1.P 64(R0), [V16.B16, V17.B16, V18.B16, V19.B16] + VLD1.P 64(R0), [V20.B16, V21.B16, V22.B16, V23.B16] + VLD1.P (R0), [V24.B16] + + MOVBU turbo+16(FP), R4 + CBZ R4, loop + + SUB $12, R3, R3 + ADD $96, R1, R1 + +loop: + // Execute theta but without xorring into the state yet. + VEOR3 V10.B16, V5.B16, V0.B16, V25.B16 + VEOR3 V11.B16, V6.B16, V1.B16, V26.B16 + VEOR3 V12.B16, V7.B16, V2.B16, V27.B16 + VEOR3 V13.B16, V8.B16, V3.B16, V28.B16 + VEOR3 V14.B16, V9.B16, V4.B16, V29.B16 + + VEOR3 V20.B16, V15.B16, V25.B16, V25.B16 + VEOR3 V21.B16, V16.B16, V26.B16, V26.B16 + VEOR3 V22.B16, V17.B16, V27.B16, V27.B16 + VEOR3 V23.B16, V18.B16, V28.B16, V28.B16 + VEOR3 V24.B16, V19.B16, V29.B16, V29.B16 + + // Xor parities from step theta into the state at the same time as + // exeuting rho and pi. + VRAX1 V26.D2, V29.D2, V30.D2 + VRAX1 V29.D2, V27.D2, V29.D2 + VRAX1 V27.D2, V25.D2, V27.D2 + VRAX1 V25.D2, V28.D2, V25.D2 + VRAX1 V28.D2, V26.D2, V28.D2 + + VEOR V30.B16, V0.B16, V0.B16 + VMOV V1.B16, V31.B16 + + VXAR $20, V27.D2, V6.D2, V1.D2 + VXAR $44, V25.D2, V9.D2, V6.D2 + VXAR $3 , V28.D2, V22.D2, V9.D2 + VXAR $25, V25.D2, V14.D2, V22.D2 + VXAR $46, V30.D2, V20.D2, V14.D2 + VXAR $2 , V28.D2, V2.D2, V20.D2 + VXAR $21, V28.D2, V12.D2, V2.D2 + VXAR $39, V29.D2, V13.D2, V12.D2 + VXAR $56, V25.D2, V19.D2, V13.D2 + VXAR $8 , V29.D2, V23.D2, V19.D2 + VXAR $23, V30.D2, V15.D2, V23.D2 + VXAR $37, V25.D2, V4.D2, V15.D2 + VXAR $50, V25.D2, V24.D2, V4.D2 + VXAR $62, V27.D2, V21.D2, V24.D2 + VXAR $9 , V29.D2, V8.D2, V21.D2 + VXAR $19, V27.D2, V16.D2, V8.D2 + VXAR $28, V30.D2, V5.D2, V16.D2 + VXAR $36, V29.D2, V3.D2, V5.D2 + VXAR $43, V29.D2, V18.D2, V3.D2 + VXAR $49, V28.D2, V17.D2, V18.D2 + VXAR $54, V27.D2, V11.D2, V17.D2 + VXAR $58, V28.D2, V7.D2, V11.D2 + VXAR $61, V30.D2, V10.D2, V7.D2 + VXAR $63, V27.D2, V31.D2, V10.D2 + + // Chi + VBCAX V1.B16, V2.B16, V0.B16, V25.B16 + VBCAX V2.B16, V3.B16, V1.B16, V26.B16 + VBCAX V3.B16, V4.B16, V2.B16, V2.B16 + VBCAX V4.B16, V0.B16, V3.B16, V3.B16 + VBCAX V0.B16, V1.B16, V4.B16, V4.B16 + VMOV V25.B16, V0.B16 + VMOV V26.B16, V1.B16 + + VBCAX V6.B16, V7.B16, V5.B16, V25.B16 + VBCAX V7.B16, V8.B16, V6.B16, V26.B16 + VBCAX V8.B16, V9.B16, V7.B16, V7.B16 + VBCAX V9.B16, V5.B16, V8.B16, V8.B16 + VBCAX V5.B16, V6.B16, V9.B16, V9.B16 + VMOV V25.B16, V5.B16 + VMOV V26.B16, V6.B16 + + VBCAX V11.B16, V12.B16, V10.B16, V25.B16 + VBCAX V12.B16, V13.B16, V11.B16, V26.B16 + VBCAX V13.B16, V14.B16, V12.B16, V12.B16 + VBCAX V14.B16, V10.B16, V13.B16, V13.B16 + VBCAX V10.B16, V11.B16, V14.B16, V14.B16 + VMOV V25.B16, V10.B16 + VMOV V26.B16, V11.B16 + + VBCAX V16.B16, V17.B16, V15.B16, V25.B16 + VBCAX V17.B16, V18.B16, V16.B16, V26.B16 + VBCAX V18.B16, V19.B16, V17.B16, V17.B16 + VBCAX V19.B16, V15.B16, V18.B16, V18.B16 + VBCAX V15.B16, V16.B16, V19.B16, V19.B16 + VMOV V25.B16, V15.B16 + VMOV V26.B16, V16.B16 + + VBCAX V21.B16, V22.B16, V20.B16, V25.B16 + VBCAX V22.B16, V23.B16, V21.B16, V26.B16 + VBCAX V23.B16, V24.B16, V22.B16, V22.B16 + VBCAX V24.B16, V20.B16, V23.B16, V23.B16 + VBCAX V20.B16, V21.B16, V24.B16, V24.B16 + VMOV V25.B16, V20.B16 + VMOV V26.B16, V21.B16 + + // Iota + VLD1R.P 8(R1), [V25.D2] + VEOR V25.B16, V0.B16, V0.B16 + + SUBS $1, R3, R3 + CBNZ R3, loop + + MOVD R2, R0 + + VST1.P [ V0.B16, V1.B16, V2.B16, V3.B16], 64(R0) + VST1.P [ V4.B16, V5.B16, V6.B16, V7.B16], 64(R0) + VST1.P [ V8.B16, V9.B16, V10.B16, V11.B16], 64(R0) + VST1.P [V12.B16, V13.B16, V14.B16, V15.B16], 64(R0) + VST1.P [V16.B16, V17.B16, V18.B16, V19.B16], 64(R0) + VST1.P [V20.B16, V21.B16, V22.B16, V23.B16], 64(R0) + VST1.P [V24.B16], (R0) + + RET diff --git a/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.go b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.go new file mode 100644 index 0000000000..bf5b865d0b --- /dev/null +++ b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.go @@ -0,0 +1,10 @@ +//go:build amd64 && !purego +// +build amd64,!purego + +package keccakf1600 + +import "github.com/cloudflare/circl/internal/sha3" + +func permuteSIMDx4(state []uint64, turbo bool) { f1600x4AVX2(&state[0], &sha3.RC, turbo) } + +func permuteSIMDx2(state []uint64, turbo bool) { permuteScalarX2(state, turbo) } diff --git a/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.s b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.s new file mode 100644 index 0000000000..67b64550c2 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4_amd64.s @@ -0,0 +1,899 @@ +// Code generated by command: go run src.go -out ../../f1600x4_amd64.s -stubs ../../f1600x4stubs_amd64.go -pkg keccakf1600. DO NOT EDIT. + +//go:build amd64 && !purego + +#include "textflag.h" + +// func f1600x4AVX2(state *uint64, rc *[24]uint64, turbo bool) +// Requires: AVX, AVX2 +TEXT ·f1600x4AVX2(SB), NOSPLIT, $0-17 + MOVQ state+0(FP), AX + MOVQ rc+8(FP), CX + MOVQ $0x0000000000000006, DX + MOVBQZX turbo+16(FP), BX + TESTQ BX, BX + JZ loop + MOVQ $0x0000000000000003, DX + ADDQ $0x60, CX + +loop: + VMOVDQA (AX), Y0 + VMOVDQA 32(AX), Y1 + VMOVDQA 64(AX), Y2 + VMOVDQA 96(AX), Y3 + VMOVDQA 128(AX), Y4 + VPXOR 160(AX), Y0, Y0 + VPXOR 192(AX), Y1, Y1 + VPXOR 224(AX), Y2, Y2 + VPXOR 256(AX), Y3, Y3 + VPXOR 288(AX), Y4, Y4 + VPXOR 320(AX), Y0, Y0 + VPXOR 352(AX), Y1, Y1 + VPXOR 384(AX), Y2, Y2 + VPXOR 416(AX), Y3, Y3 + VPXOR 448(AX), Y4, Y4 + VPXOR 480(AX), Y0, Y0 + VPXOR 512(AX), Y1, Y1 + VPXOR 544(AX), Y2, Y2 + VPXOR 576(AX), Y3, Y3 + VPXOR 608(AX), Y4, Y4 + VPXOR 640(AX), Y0, Y0 + VPXOR 672(AX), Y1, Y1 + VPXOR 704(AX), Y2, Y2 + VPXOR 736(AX), Y3, Y3 + VPXOR 768(AX), Y4, Y4 + VPSLLQ $0x01, Y1, Y5 + VPSLLQ $0x01, Y2, Y6 + VPSLLQ $0x01, Y3, Y7 + VPSLLQ $0x01, Y4, Y8 + VPSLLQ $0x01, Y0, Y9 + VPSRLQ $0x3f, Y1, Y10 + VPSRLQ $0x3f, Y2, Y11 + VPSRLQ $0x3f, Y3, Y12 + VPSRLQ $0x3f, Y4, Y13 + VPSRLQ $0x3f, Y0, Y14 + VPOR Y5, Y10, Y10 + VPOR Y6, Y11, Y11 + VPOR Y7, Y12, Y12 + VPOR Y8, Y13, Y13 + VPOR Y9, Y14, Y14 + VPXOR Y10, Y4, Y10 + VPXOR Y11, Y0, Y11 + VPXOR Y12, Y1, Y12 + VPXOR Y13, Y2, Y13 + VPXOR Y14, Y3, Y14 + VPXOR (AX), Y10, Y0 + VPXOR 192(AX), Y11, Y1 + VPXOR 384(AX), Y12, Y2 + VPXOR 576(AX), Y13, Y3 + VPXOR 768(AX), Y14, Y4 + VPSLLQ $0x2c, Y1, Y6 + VPSLLQ $0x2b, Y2, Y7 + VPSLLQ $0x15, Y3, Y8 + VPSLLQ $0x0e, Y4, Y9 + VPSRLQ $0x14, Y1, Y1 + VPSRLQ $0x15, Y2, Y2 + VPSRLQ $0x2b, Y3, Y3 + VPSRLQ $0x32, Y4, Y4 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VPBROADCASTQ (CX), Y0 + VPXOR Y0, Y5, Y5 + VMOVDQA Y5, (AX) + VMOVDQA Y6, 192(AX) + VMOVDQA Y7, 384(AX) + VMOVDQA Y8, 576(AX) + VMOVDQA Y9, 768(AX) + VPXOR 96(AX), Y13, Y0 + VPXOR 288(AX), Y14, Y1 + VPXOR 320(AX), Y10, Y2 + VPXOR 512(AX), Y11, Y3 + VPXOR 704(AX), Y12, Y4 + VPSLLQ $0x1c, Y0, Y5 + VPSLLQ $0x14, Y1, Y6 + VPSLLQ $0x03, Y2, Y7 + VPSLLQ $0x2d, Y3, Y8 + VPSLLQ $0x3d, Y4, Y9 + VPSRLQ $0x24, Y0, Y0 + VPSRLQ $0x2c, Y1, Y1 + VPSRLQ $0x3d, Y2, Y2 + VPSRLQ $0x13, Y3, Y3 + VPSRLQ $0x03, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 320(AX) + VMOVDQA Y6, 512(AX) + VMOVDQA Y7, 704(AX) + VMOVDQA Y8, 96(AX) + VMOVDQA Y9, 288(AX) + VPXOR 32(AX), Y11, Y0 + VPXOR 224(AX), Y12, Y1 + VPXOR 416(AX), Y13, Y2 + VPXOR 608(AX), Y14, Y3 + VPXOR 640(AX), Y10, Y4 + VPSLLQ $0x01, Y0, Y5 + VPSLLQ $0x06, Y1, Y6 + VPSLLQ $0x19, Y2, Y7 + VPSLLQ $0x08, Y3, Y8 + VPSLLQ $0x12, Y4, Y9 + VPSRLQ $0x3f, Y0, Y0 + VPSRLQ $0x3a, Y1, Y1 + VPSRLQ $0x27, Y2, Y2 + VPSRLQ $0x38, Y3, Y3 + VPSRLQ $0x2e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 640(AX) + VMOVDQA Y6, 32(AX) + VMOVDQA Y7, 224(AX) + VMOVDQA Y8, 416(AX) + VMOVDQA Y9, 608(AX) + VPXOR 128(AX), Y14, Y0 + VPXOR 160(AX), Y10, Y1 + VPXOR 352(AX), Y11, Y2 + VPXOR 544(AX), Y12, Y3 + VPXOR 736(AX), Y13, Y4 + VPSLLQ $0x1b, Y0, Y5 + VPSLLQ $0x24, Y1, Y6 + VPSLLQ $0x0a, Y2, Y7 + VPSLLQ $0x0f, Y3, Y8 + VPSLLQ $0x38, Y4, Y9 + VPSRLQ $0x25, Y0, Y0 + VPSRLQ $0x1c, Y1, Y1 + VPSRLQ $0x36, Y2, Y2 + VPSRLQ $0x31, Y3, Y3 + VPSRLQ $0x08, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 160(AX) + VMOVDQA Y6, 352(AX) + VMOVDQA Y7, 544(AX) + VMOVDQA Y8, 736(AX) + VMOVDQA Y9, 128(AX) + VPXOR 64(AX), Y12, Y0 + VPXOR 256(AX), Y13, Y1 + VPXOR 448(AX), Y14, Y2 + VPXOR 480(AX), Y10, Y3 + VPXOR 672(AX), Y11, Y4 + VPSLLQ $0x3e, Y0, Y5 + VPSLLQ $0x37, Y1, Y6 + VPSLLQ $0x27, Y2, Y7 + VPSLLQ $0x29, Y3, Y8 + VPSLLQ $0x02, Y4, Y9 + VPSRLQ $0x02, Y0, Y0 + VPSRLQ $0x09, Y1, Y1 + VPSRLQ $0x19, Y2, Y2 + VPSRLQ $0x17, Y3, Y3 + VPSRLQ $0x3e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 480(AX) + VMOVDQA Y6, 672(AX) + VMOVDQA Y7, 64(AX) + VMOVDQA Y8, 256(AX) + VMOVDQA Y9, 448(AX) + VMOVDQA (AX), Y0 + VMOVDQA 32(AX), Y1 + VMOVDQA 64(AX), Y2 + VMOVDQA 96(AX), Y3 + VMOVDQA 128(AX), Y4 + VPXOR 160(AX), Y0, Y0 + VPXOR 192(AX), Y1, Y1 + VPXOR 224(AX), Y2, Y2 + VPXOR 256(AX), Y3, Y3 + VPXOR 288(AX), Y4, Y4 + VPXOR 320(AX), Y0, Y0 + VPXOR 352(AX), Y1, Y1 + VPXOR 384(AX), Y2, Y2 + VPXOR 416(AX), Y3, Y3 + VPXOR 448(AX), Y4, Y4 + VPXOR 480(AX), Y0, Y0 + VPXOR 512(AX), Y1, Y1 + VPXOR 544(AX), Y2, Y2 + VPXOR 576(AX), Y3, Y3 + VPXOR 608(AX), Y4, Y4 + VPXOR 640(AX), Y0, Y0 + VPXOR 672(AX), Y1, Y1 + VPXOR 704(AX), Y2, Y2 + VPXOR 736(AX), Y3, Y3 + VPXOR 768(AX), Y4, Y4 + VPSLLQ $0x01, Y1, Y5 + VPSLLQ $0x01, Y2, Y6 + VPSLLQ $0x01, Y3, Y7 + VPSLLQ $0x01, Y4, Y8 + VPSLLQ $0x01, Y0, Y9 + VPSRLQ $0x3f, Y1, Y10 + VPSRLQ $0x3f, Y2, Y11 + VPSRLQ $0x3f, Y3, Y12 + VPSRLQ $0x3f, Y4, Y13 + VPSRLQ $0x3f, Y0, Y14 + VPOR Y5, Y10, Y10 + VPOR Y6, Y11, Y11 + VPOR Y7, Y12, Y12 + VPOR Y8, Y13, Y13 + VPOR Y9, Y14, Y14 + VPXOR Y10, Y4, Y10 + VPXOR Y11, Y0, Y11 + VPXOR Y12, Y1, Y12 + VPXOR Y13, Y2, Y13 + VPXOR Y14, Y3, Y14 + VPXOR (AX), Y10, Y0 + VPXOR 512(AX), Y11, Y1 + VPXOR 224(AX), Y12, Y2 + VPXOR 736(AX), Y13, Y3 + VPXOR 448(AX), Y14, Y4 + VPSLLQ $0x2c, Y1, Y6 + VPSLLQ $0x2b, Y2, Y7 + VPSLLQ $0x15, Y3, Y8 + VPSLLQ $0x0e, Y4, Y9 + VPSRLQ $0x14, Y1, Y1 + VPSRLQ $0x15, Y2, Y2 + VPSRLQ $0x2b, Y3, Y3 + VPSRLQ $0x32, Y4, Y4 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VPBROADCASTQ 8(CX), Y0 + VPXOR Y0, Y5, Y5 + VMOVDQA Y5, (AX) + VMOVDQA Y6, 512(AX) + VMOVDQA Y7, 224(AX) + VMOVDQA Y8, 736(AX) + VMOVDQA Y9, 448(AX) + VPXOR 576(AX), Y13, Y0 + VPXOR 288(AX), Y14, Y1 + VPXOR 640(AX), Y10, Y2 + VPXOR 352(AX), Y11, Y3 + VPXOR 64(AX), Y12, Y4 + VPSLLQ $0x1c, Y0, Y5 + VPSLLQ $0x14, Y1, Y6 + VPSLLQ $0x03, Y2, Y7 + VPSLLQ $0x2d, Y3, Y8 + VPSLLQ $0x3d, Y4, Y9 + VPSRLQ $0x24, Y0, Y0 + VPSRLQ $0x2c, Y1, Y1 + VPSRLQ $0x3d, Y2, Y2 + VPSRLQ $0x13, Y3, Y3 + VPSRLQ $0x03, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 640(AX) + VMOVDQA Y6, 352(AX) + VMOVDQA Y7, 64(AX) + VMOVDQA Y8, 576(AX) + VMOVDQA Y9, 288(AX) + VPXOR 192(AX), Y11, Y0 + VPXOR 704(AX), Y12, Y1 + VPXOR 416(AX), Y13, Y2 + VPXOR 128(AX), Y14, Y3 + VPXOR 480(AX), Y10, Y4 + VPSLLQ $0x01, Y0, Y5 + VPSLLQ $0x06, Y1, Y6 + VPSLLQ $0x19, Y2, Y7 + VPSLLQ $0x08, Y3, Y8 + VPSLLQ $0x12, Y4, Y9 + VPSRLQ $0x3f, Y0, Y0 + VPSRLQ $0x3a, Y1, Y1 + VPSRLQ $0x27, Y2, Y2 + VPSRLQ $0x38, Y3, Y3 + VPSRLQ $0x2e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 480(AX) + VMOVDQA Y6, 192(AX) + VMOVDQA Y7, 704(AX) + VMOVDQA Y8, 416(AX) + VMOVDQA Y9, 128(AX) + VPXOR 768(AX), Y14, Y0 + VPXOR 320(AX), Y10, Y1 + VPXOR 32(AX), Y11, Y2 + VPXOR 544(AX), Y12, Y3 + VPXOR 256(AX), Y13, Y4 + VPSLLQ $0x1b, Y0, Y5 + VPSLLQ $0x24, Y1, Y6 + VPSLLQ $0x0a, Y2, Y7 + VPSLLQ $0x0f, Y3, Y8 + VPSLLQ $0x38, Y4, Y9 + VPSRLQ $0x25, Y0, Y0 + VPSRLQ $0x1c, Y1, Y1 + VPSRLQ $0x36, Y2, Y2 + VPSRLQ $0x31, Y3, Y3 + VPSRLQ $0x08, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 320(AX) + VMOVDQA Y6, 32(AX) + VMOVDQA Y7, 544(AX) + VMOVDQA Y8, 256(AX) + VMOVDQA Y9, 768(AX) + VPXOR 384(AX), Y12, Y0 + VPXOR 96(AX), Y13, Y1 + VPXOR 608(AX), Y14, Y2 + VPXOR 160(AX), Y10, Y3 + VPXOR 672(AX), Y11, Y4 + VPSLLQ $0x3e, Y0, Y5 + VPSLLQ $0x37, Y1, Y6 + VPSLLQ $0x27, Y2, Y7 + VPSLLQ $0x29, Y3, Y8 + VPSLLQ $0x02, Y4, Y9 + VPSRLQ $0x02, Y0, Y0 + VPSRLQ $0x09, Y1, Y1 + VPSRLQ $0x19, Y2, Y2 + VPSRLQ $0x17, Y3, Y3 + VPSRLQ $0x3e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 160(AX) + VMOVDQA Y6, 672(AX) + VMOVDQA Y7, 384(AX) + VMOVDQA Y8, 96(AX) + VMOVDQA Y9, 608(AX) + VMOVDQA (AX), Y0 + VMOVDQA 32(AX), Y1 + VMOVDQA 64(AX), Y2 + VMOVDQA 96(AX), Y3 + VMOVDQA 128(AX), Y4 + VPXOR 160(AX), Y0, Y0 + VPXOR 192(AX), Y1, Y1 + VPXOR 224(AX), Y2, Y2 + VPXOR 256(AX), Y3, Y3 + VPXOR 288(AX), Y4, Y4 + VPXOR 320(AX), Y0, Y0 + VPXOR 352(AX), Y1, Y1 + VPXOR 384(AX), Y2, Y2 + VPXOR 416(AX), Y3, Y3 + VPXOR 448(AX), Y4, Y4 + VPXOR 480(AX), Y0, Y0 + VPXOR 512(AX), Y1, Y1 + VPXOR 544(AX), Y2, Y2 + VPXOR 576(AX), Y3, Y3 + VPXOR 608(AX), Y4, Y4 + VPXOR 640(AX), Y0, Y0 + VPXOR 672(AX), Y1, Y1 + VPXOR 704(AX), Y2, Y2 + VPXOR 736(AX), Y3, Y3 + VPXOR 768(AX), Y4, Y4 + VPSLLQ $0x01, Y1, Y5 + VPSLLQ $0x01, Y2, Y6 + VPSLLQ $0x01, Y3, Y7 + VPSLLQ $0x01, Y4, Y8 + VPSLLQ $0x01, Y0, Y9 + VPSRLQ $0x3f, Y1, Y10 + VPSRLQ $0x3f, Y2, Y11 + VPSRLQ $0x3f, Y3, Y12 + VPSRLQ $0x3f, Y4, Y13 + VPSRLQ $0x3f, Y0, Y14 + VPOR Y5, Y10, Y10 + VPOR Y6, Y11, Y11 + VPOR Y7, Y12, Y12 + VPOR Y8, Y13, Y13 + VPOR Y9, Y14, Y14 + VPXOR Y10, Y4, Y10 + VPXOR Y11, Y0, Y11 + VPXOR Y12, Y1, Y12 + VPXOR Y13, Y2, Y13 + VPXOR Y14, Y3, Y14 + VPXOR (AX), Y10, Y0 + VPXOR 352(AX), Y11, Y1 + VPXOR 704(AX), Y12, Y2 + VPXOR 256(AX), Y13, Y3 + VPXOR 608(AX), Y14, Y4 + VPSLLQ $0x2c, Y1, Y6 + VPSLLQ $0x2b, Y2, Y7 + VPSLLQ $0x15, Y3, Y8 + VPSLLQ $0x0e, Y4, Y9 + VPSRLQ $0x14, Y1, Y1 + VPSRLQ $0x15, Y2, Y2 + VPSRLQ $0x2b, Y3, Y3 + VPSRLQ $0x32, Y4, Y4 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VPBROADCASTQ 16(CX), Y0 + VPXOR Y0, Y5, Y5 + VMOVDQA Y5, (AX) + VMOVDQA Y6, 352(AX) + VMOVDQA Y7, 704(AX) + VMOVDQA Y8, 256(AX) + VMOVDQA Y9, 608(AX) + VPXOR 736(AX), Y13, Y0 + VPXOR 288(AX), Y14, Y1 + VPXOR 480(AX), Y10, Y2 + VPXOR 32(AX), Y11, Y3 + VPXOR 384(AX), Y12, Y4 + VPSLLQ $0x1c, Y0, Y5 + VPSLLQ $0x14, Y1, Y6 + VPSLLQ $0x03, Y2, Y7 + VPSLLQ $0x2d, Y3, Y8 + VPSLLQ $0x3d, Y4, Y9 + VPSRLQ $0x24, Y0, Y0 + VPSRLQ $0x2c, Y1, Y1 + VPSRLQ $0x3d, Y2, Y2 + VPSRLQ $0x13, Y3, Y3 + VPSRLQ $0x03, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 480(AX) + VMOVDQA Y6, 32(AX) + VMOVDQA Y7, 384(AX) + VMOVDQA Y8, 736(AX) + VMOVDQA Y9, 288(AX) + VPXOR 512(AX), Y11, Y0 + VPXOR 64(AX), Y12, Y1 + VPXOR 416(AX), Y13, Y2 + VPXOR 768(AX), Y14, Y3 + VPXOR 160(AX), Y10, Y4 + VPSLLQ $0x01, Y0, Y5 + VPSLLQ $0x06, Y1, Y6 + VPSLLQ $0x19, Y2, Y7 + VPSLLQ $0x08, Y3, Y8 + VPSLLQ $0x12, Y4, Y9 + VPSRLQ $0x3f, Y0, Y0 + VPSRLQ $0x3a, Y1, Y1 + VPSRLQ $0x27, Y2, Y2 + VPSRLQ $0x38, Y3, Y3 + VPSRLQ $0x2e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 160(AX) + VMOVDQA Y6, 512(AX) + VMOVDQA Y7, 64(AX) + VMOVDQA Y8, 416(AX) + VMOVDQA Y9, 768(AX) + VPXOR 448(AX), Y14, Y0 + VPXOR 640(AX), Y10, Y1 + VPXOR 192(AX), Y11, Y2 + VPXOR 544(AX), Y12, Y3 + VPXOR 96(AX), Y13, Y4 + VPSLLQ $0x1b, Y0, Y5 + VPSLLQ $0x24, Y1, Y6 + VPSLLQ $0x0a, Y2, Y7 + VPSLLQ $0x0f, Y3, Y8 + VPSLLQ $0x38, Y4, Y9 + VPSRLQ $0x25, Y0, Y0 + VPSRLQ $0x1c, Y1, Y1 + VPSRLQ $0x36, Y2, Y2 + VPSRLQ $0x31, Y3, Y3 + VPSRLQ $0x08, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 640(AX) + VMOVDQA Y6, 192(AX) + VMOVDQA Y7, 544(AX) + VMOVDQA Y8, 96(AX) + VMOVDQA Y9, 448(AX) + VPXOR 224(AX), Y12, Y0 + VPXOR 576(AX), Y13, Y1 + VPXOR 128(AX), Y14, Y2 + VPXOR 320(AX), Y10, Y3 + VPXOR 672(AX), Y11, Y4 + VPSLLQ $0x3e, Y0, Y5 + VPSLLQ $0x37, Y1, Y6 + VPSLLQ $0x27, Y2, Y7 + VPSLLQ $0x29, Y3, Y8 + VPSLLQ $0x02, Y4, Y9 + VPSRLQ $0x02, Y0, Y0 + VPSRLQ $0x09, Y1, Y1 + VPSRLQ $0x19, Y2, Y2 + VPSRLQ $0x17, Y3, Y3 + VPSRLQ $0x3e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 320(AX) + VMOVDQA Y6, 672(AX) + VMOVDQA Y7, 224(AX) + VMOVDQA Y8, 576(AX) + VMOVDQA Y9, 128(AX) + VMOVDQA (AX), Y0 + VMOVDQA 32(AX), Y1 + VMOVDQA 64(AX), Y2 + VMOVDQA 96(AX), Y3 + VMOVDQA 128(AX), Y4 + VPXOR 160(AX), Y0, Y0 + VPXOR 192(AX), Y1, Y1 + VPXOR 224(AX), Y2, Y2 + VPXOR 256(AX), Y3, Y3 + VPXOR 288(AX), Y4, Y4 + VPXOR 320(AX), Y0, Y0 + VPXOR 352(AX), Y1, Y1 + VPXOR 384(AX), Y2, Y2 + VPXOR 416(AX), Y3, Y3 + VPXOR 448(AX), Y4, Y4 + VPXOR 480(AX), Y0, Y0 + VPXOR 512(AX), Y1, Y1 + VPXOR 544(AX), Y2, Y2 + VPXOR 576(AX), Y3, Y3 + VPXOR 608(AX), Y4, Y4 + VPXOR 640(AX), Y0, Y0 + VPXOR 672(AX), Y1, Y1 + VPXOR 704(AX), Y2, Y2 + VPXOR 736(AX), Y3, Y3 + VPXOR 768(AX), Y4, Y4 + VPSLLQ $0x01, Y1, Y5 + VPSLLQ $0x01, Y2, Y6 + VPSLLQ $0x01, Y3, Y7 + VPSLLQ $0x01, Y4, Y8 + VPSLLQ $0x01, Y0, Y9 + VPSRLQ $0x3f, Y1, Y10 + VPSRLQ $0x3f, Y2, Y11 + VPSRLQ $0x3f, Y3, Y12 + VPSRLQ $0x3f, Y4, Y13 + VPSRLQ $0x3f, Y0, Y14 + VPOR Y5, Y10, Y10 + VPOR Y6, Y11, Y11 + VPOR Y7, Y12, Y12 + VPOR Y8, Y13, Y13 + VPOR Y9, Y14, Y14 + VPXOR Y10, Y4, Y10 + VPXOR Y11, Y0, Y11 + VPXOR Y12, Y1, Y12 + VPXOR Y13, Y2, Y13 + VPXOR Y14, Y3, Y14 + VPXOR (AX), Y10, Y0 + VPXOR 32(AX), Y11, Y1 + VPXOR 64(AX), Y12, Y2 + VPXOR 96(AX), Y13, Y3 + VPXOR 128(AX), Y14, Y4 + VPSLLQ $0x2c, Y1, Y6 + VPSLLQ $0x2b, Y2, Y7 + VPSLLQ $0x15, Y3, Y8 + VPSLLQ $0x0e, Y4, Y9 + VPSRLQ $0x14, Y1, Y1 + VPSRLQ $0x15, Y2, Y2 + VPSRLQ $0x2b, Y3, Y3 + VPSRLQ $0x32, Y4, Y4 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VPBROADCASTQ 24(CX), Y0 + VPXOR Y0, Y5, Y5 + VMOVDQA Y5, (AX) + VMOVDQA Y6, 32(AX) + VMOVDQA Y7, 64(AX) + VMOVDQA Y8, 96(AX) + VMOVDQA Y9, 128(AX) + VPXOR 256(AX), Y13, Y0 + VPXOR 288(AX), Y14, Y1 + VPXOR 160(AX), Y10, Y2 + VPXOR 192(AX), Y11, Y3 + VPXOR 224(AX), Y12, Y4 + VPSLLQ $0x1c, Y0, Y5 + VPSLLQ $0x14, Y1, Y6 + VPSLLQ $0x03, Y2, Y7 + VPSLLQ $0x2d, Y3, Y8 + VPSLLQ $0x3d, Y4, Y9 + VPSRLQ $0x24, Y0, Y0 + VPSRLQ $0x2c, Y1, Y1 + VPSRLQ $0x3d, Y2, Y2 + VPSRLQ $0x13, Y3, Y3 + VPSRLQ $0x03, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 160(AX) + VMOVDQA Y6, 192(AX) + VMOVDQA Y7, 224(AX) + VMOVDQA Y8, 256(AX) + VMOVDQA Y9, 288(AX) + VPXOR 352(AX), Y11, Y0 + VPXOR 384(AX), Y12, Y1 + VPXOR 416(AX), Y13, Y2 + VPXOR 448(AX), Y14, Y3 + VPXOR 320(AX), Y10, Y4 + VPSLLQ $0x01, Y0, Y5 + VPSLLQ $0x06, Y1, Y6 + VPSLLQ $0x19, Y2, Y7 + VPSLLQ $0x08, Y3, Y8 + VPSLLQ $0x12, Y4, Y9 + VPSRLQ $0x3f, Y0, Y0 + VPSRLQ $0x3a, Y1, Y1 + VPSRLQ $0x27, Y2, Y2 + VPSRLQ $0x38, Y3, Y3 + VPSRLQ $0x2e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 320(AX) + VMOVDQA Y6, 352(AX) + VMOVDQA Y7, 384(AX) + VMOVDQA Y8, 416(AX) + VMOVDQA Y9, 448(AX) + VPXOR 608(AX), Y14, Y0 + VPXOR 480(AX), Y10, Y1 + VPXOR 512(AX), Y11, Y2 + VPXOR 544(AX), Y12, Y3 + VPXOR 576(AX), Y13, Y4 + VPSLLQ $0x1b, Y0, Y5 + VPSLLQ $0x24, Y1, Y6 + VPSLLQ $0x0a, Y2, Y7 + VPSLLQ $0x0f, Y3, Y8 + VPSLLQ $0x38, Y4, Y9 + VPSRLQ $0x25, Y0, Y0 + VPSRLQ $0x1c, Y1, Y1 + VPSRLQ $0x36, Y2, Y2 + VPSRLQ $0x31, Y3, Y3 + VPSRLQ $0x08, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 480(AX) + VMOVDQA Y6, 512(AX) + VMOVDQA Y7, 544(AX) + VMOVDQA Y8, 576(AX) + VMOVDQA Y9, 608(AX) + VPXOR 704(AX), Y12, Y0 + VPXOR 736(AX), Y13, Y1 + VPXOR 768(AX), Y14, Y2 + VPXOR 640(AX), Y10, Y3 + VPXOR 672(AX), Y11, Y4 + VPSLLQ $0x3e, Y0, Y5 + VPSLLQ $0x37, Y1, Y6 + VPSLLQ $0x27, Y2, Y7 + VPSLLQ $0x29, Y3, Y8 + VPSLLQ $0x02, Y4, Y9 + VPSRLQ $0x02, Y0, Y0 + VPSRLQ $0x09, Y1, Y1 + VPSRLQ $0x19, Y2, Y2 + VPSRLQ $0x17, Y3, Y3 + VPSRLQ $0x3e, Y4, Y4 + VPOR Y5, Y0, Y0 + VPOR Y6, Y1, Y1 + VPOR Y7, Y2, Y2 + VPOR Y8, Y3, Y3 + VPOR Y9, Y4, Y4 + VPANDN Y2, Y1, Y5 + VPANDN Y3, Y2, Y6 + VPANDN Y4, Y3, Y7 + VPANDN Y0, Y4, Y8 + VPANDN Y1, Y0, Y9 + VPXOR Y0, Y5, Y5 + VPXOR Y1, Y6, Y6 + VPXOR Y2, Y7, Y7 + VPXOR Y3, Y8, Y8 + VPXOR Y4, Y9, Y9 + VMOVDQA Y5, 640(AX) + VMOVDQA Y6, 672(AX) + VMOVDQA Y7, 704(AX) + VMOVDQA Y8, 736(AX) + VMOVDQA Y9, 768(AX) + ADDQ $0x20, CX + SUBQ $0x00000001, DX + JNZ loop + RET diff --git a/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4stubs_amd64.go b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4stubs_amd64.go new file mode 100644 index 0000000000..102fdd04d1 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/simd/keccakf1600/f1600x4stubs_amd64.go @@ -0,0 +1,8 @@ +// Code generated by command: go run src.go -out ../../f1600x4_amd64.s -stubs ../../f1600x4stubs_amd64.go -pkg keccakf1600. DO NOT EDIT. + +//go:build amd64 && !purego + +package keccakf1600 + +//go:noescape +func f1600x4AVX2(state *uint64, rc *[24]uint64, turbo bool) diff --git a/vendor/github.com/cloudflare/circl/simd/keccakf1600/fallback.go b/vendor/github.com/cloudflare/circl/simd/keccakf1600/fallback.go new file mode 100644 index 0000000000..0da75e9b77 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/simd/keccakf1600/fallback.go @@ -0,0 +1,8 @@ +//go:build (!amd64 && !arm64) || (arm64 && !go1.16) || purego +// +build !amd64,!arm64 arm64,!go1.16 purego + +package keccakf1600 + +func permuteSIMDx2(state []uint64, turbo bool) { permuteScalarX2(state, turbo) } + +func permuteSIMDx4(state []uint64, turbo bool) { permuteScalarX4(state, turbo) } diff --git a/vendor/github.com/cloudflare/circl/xof/k12/k12.go b/vendor/github.com/cloudflare/circl/xof/k12/k12.go new file mode 100644 index 0000000000..bbd33d117d --- /dev/null +++ b/vendor/github.com/cloudflare/circl/xof/k12/k12.go @@ -0,0 +1,400 @@ +// k12 implements the KangarooTwelve XOF. +// +// KangarooTwelve is being standardised at the CFRG working group +// of the IRTF. This package implements draft 10. +// +// https://datatracker.ietf.org/doc/draft-irtf-cfrg-kangarootwelve/10/ +package k12 + +import ( + "encoding/binary" + + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/simd/keccakf1600" +) + +const chunkSize = 8192 // aka B + +// KangarooTwelve splits the message into chunks of 8192 bytes each. +// The first chunk is absorbed directly in a TurboSHAKE128 instance, which +// we call the stalk. The subsequent chunks aren't absorbed directly, but +// instead their hash is absorbed: they're like leafs on a stalk. +// If we have a fast TurboSHAKE128 available, we buffer chunks until we have +// enough to do the parallel TurboSHAKE128. If not, we absorb directly into +// a separate TurboSHAKE128 state. + +type State struct { + initialTodo int // Bytes left to absorb for the first chunk. + + stalk sha3.State + + context []byte // context string "C" provided by the user + + // buffer of incoming data so we can do parallel TurboSHAKE128: + // nil when we haven't absorbed the first chunk yet; + // empty if we have, but we do not have a fast parallel TurboSHAKE128; + // and chunkSize*lanes in length if we have. + buf []byte + + offset int // offset in buf or bytes written to leaf + + // Number of chunk hashes ("CV_i") absorbed into the stalk. + chunk uint + + // TurboSHAKE128 instance to compute the leaf in case we don't have + // a fast parallel TurboSHAKE128, viz when lanes == 1. + leaf *sha3.State + + lanes uint8 // number of TurboSHAKE128s to compute in parallel +} + +// NewDraft10 creates a new instance of Kangaroo12 draft version -10. +func NewDraft10(c []byte) State { + var lanes byte = 1 + + if keccakf1600.IsEnabledX4() { + lanes = 4 + } else if keccakf1600.IsEnabledX2() { + lanes = 2 + } + + return newDraft10(c, lanes) +} + +func newDraft10(c []byte, lanes byte) State { + return State{ + initialTodo: chunkSize, + stalk: sha3.NewTurboShake128(0x07), + context: c, + lanes: lanes, + } +} + +func (s *State) Reset() { + s.initialTodo = chunkSize + s.stalk.Reset() + s.stalk.SwitchDS(0x07) + s.buf = nil + s.offset = 0 + s.chunk = 0 +} + +func (s *State) Clone() State { + stalk := s.stalk.Clone().(*sha3.State) + ret := State{ + initialTodo: s.initialTodo, + stalk: *stalk, + context: s.context, + offset: s.offset, + chunk: s.chunk, + lanes: s.lanes, + } + + if s.leaf != nil { + ret.leaf = s.leaf.Clone().(*sha3.State) + } + + if s.buf != nil { + ret.buf = make([]byte, len(s.buf)) + copy(ret.buf, s.buf) + } + + return ret +} + +func Draft10Sum(hash []byte, msg []byte, c []byte) { + // TODO Tweak number of lanes depending on the length of the message + s := NewDraft10(c) + _, _ = s.Write(msg) + _, _ = s.Read(hash) +} + +func (s *State) Write(p []byte) (int, error) { + written := len(p) + + // The first chunk is written directly to the stalk. + if s.initialTodo > 0 { + taken := s.initialTodo + if len(p) < taken { + taken = len(p) + } + headP := p[:taken] + _, _ = s.stalk.Write(headP) + s.initialTodo -= taken + p = p[taken:] + } + + if len(p) == 0 { + return written, nil + } + + // If this is the first bit of data written after the initial chunk, + // we're out of the fast-path and allocate some buffers. + if s.buf == nil { + if s.lanes != 1 { + s.buf = make([]byte, int(s.lanes)*chunkSize) + } else { + // We create the buffer to signal we're past the first chunk, + // but do not use it. + s.buf = make([]byte, 0) + h := sha3.NewTurboShake128(0x0B) + s.leaf = &h + } + _, _ = s.stalk.Write([]byte{0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) + s.stalk.SwitchDS(0x06) + } + + // If we're just using one lane, we don't need to cache in a buffer + // for parallel hashing. Instead, we feed directly to TurboSHAKE. + if s.lanes == 1 { + for len(p) > 0 { + // Write to current leaf. + to := chunkSize - s.offset + if len(p) < to { + to = len(p) + } + _, _ = s.leaf.Write(p[:to]) + p = p[to:] + s.offset += to + + // Did we fill the chunk? + if s.offset == chunkSize { + var cv [32]byte + _, _ = s.leaf.Read(cv[:]) + _, _ = s.stalk.Write(cv[:]) + s.leaf.Reset() + s.offset = 0 + s.chunk++ + } + } + + return written, nil + } + + // If we can't fill all our lanes or the buffer isn't empty, we write the + // data to the buffer. + if s.offset != 0 || len(p) < len(s.buf) { + to := len(s.buf) - s.offset + if len(p) < to { + to = len(p) + } + p2 := p[:to] + p = p[to:] + copy(s.buf[s.offset:], p2) + s.offset += to + } + + // Absorb the buffer if we filled it + if s.offset == len(s.buf) { + s.writeX(s.buf) + s.offset = 0 + } + + // Note that at this point we may assume that s.offset = 0 if len(p) != 0 + if len(p) != 0 && s.offset != 0 { + panic("shouldn't happen") + } + + // Absorb a bunch of chunks at the same time. + if len(p) >= int(s.lanes)*chunkSize { + p = s.writeX(p) + } + + // Put the remainder in the buffer. + if len(p) > 0 { + copy(s.buf, p) + s.offset = len(p) + } + + return written, nil +} + +// Absorb a multiple of a multiple of lanes * chunkSize. +// Returns the remainder. +func (s *State) writeX(p []byte) []byte { + switch s.lanes { + case 4: + return s.writeX4(p) + default: + return s.writeX2(p) + } +} + +func (s *State) writeX4(p []byte) []byte { + for len(p) >= 4*chunkSize { + var x4 keccakf1600.StateX4 + a := x4.Initialize(true) + + for offset := 0; offset < 48*168; offset += 168 { + for i := 0; i < 21; i++ { + a[i*4] ^= binary.LittleEndian.Uint64( + p[8*i+offset:], + ) + a[i*4+1] ^= binary.LittleEndian.Uint64( + p[chunkSize+8*i+offset:], + ) + a[i*4+2] ^= binary.LittleEndian.Uint64( + p[chunkSize*2+8*i+offset:], + ) + a[i*4+3] ^= binary.LittleEndian.Uint64( + p[chunkSize*3+8*i+offset:], + ) + } + + x4.Permute() + } + + for i := 0; i < 16; i++ { + a[i*4] ^= binary.LittleEndian.Uint64( + p[8*i+48*168:], + ) + a[i*4+1] ^= binary.LittleEndian.Uint64( + p[chunkSize+8*i+48*168:], + ) + a[i*4+2] ^= binary.LittleEndian.Uint64( + p[chunkSize*2+8*i+48*168:], + ) + a[i*4+3] ^= binary.LittleEndian.Uint64( + p[chunkSize*3+8*i+48*168:], + ) + } + + a[16*4] ^= 0x0b + a[16*4+1] ^= 0x0b + a[16*4+2] ^= 0x0b + a[16*4+3] ^= 0x0b + a[20*4] ^= 0x80 << 56 + a[20*4+1] ^= 0x80 << 56 + a[20*4+2] ^= 0x80 << 56 + a[20*4+3] ^= 0x80 << 56 + + x4.Permute() + + var buf [32 * 4]byte + for i := 0; i < 4; i++ { + binary.LittleEndian.PutUint64(buf[8*i:], a[4*i]) + binary.LittleEndian.PutUint64(buf[32+8*i:], a[4*i+1]) + binary.LittleEndian.PutUint64(buf[32*2+8*i:], a[4*i+2]) + binary.LittleEndian.PutUint64(buf[32*3+8*i:], a[4*i+3]) + } + + _, _ = s.stalk.Write(buf[:]) + p = p[chunkSize*4:] + s.chunk += 4 + } + + return p +} + +func (s *State) writeX2(p []byte) []byte { + // TODO On M2 Pro, 1/3 of the time is spent on this function + // and LittleEndian.Uint64 excluding the actual permutation. + // Rewriting in assembler might be worthwhile. + for len(p) >= 2*chunkSize { + var x2 keccakf1600.StateX2 + a := x2.Initialize(true) + + for offset := 0; offset < 48*168; offset += 168 { + for i := 0; i < 21; i++ { + a[i*2] ^= binary.LittleEndian.Uint64( + p[8*i+offset:], + ) + a[i*2+1] ^= binary.LittleEndian.Uint64( + p[chunkSize+8*i+offset:], + ) + } + + x2.Permute() + } + + for i := 0; i < 16; i++ { + a[i*2] ^= binary.LittleEndian.Uint64( + p[8*i+48*168:], + ) + a[i*2+1] ^= binary.LittleEndian.Uint64( + p[chunkSize+8*i+48*168:], + ) + } + + a[16*2] ^= 0x0b + a[16*2+1] ^= 0x0b + a[20*2] ^= 0x80 << 56 + a[20*2+1] ^= 0x80 << 56 + + x2.Permute() + + var buf [32 * 2]byte + for i := 0; i < 4; i++ { + binary.LittleEndian.PutUint64(buf[8*i:], a[2*i]) + binary.LittleEndian.PutUint64(buf[32+8*i:], a[2*i+1]) + } + + _, _ = s.stalk.Write(buf[:]) + p = p[chunkSize*2:] + s.chunk += 2 + } + + return p +} + +func (s *State) Read(p []byte) (int, error) { + if s.stalk.IsAbsorbing() { + // Write context string C + _, _ = s.Write(s.context) + + // Write length_encode( |C| ) + var buf [9]byte + binary.BigEndian.PutUint64(buf[:8], uint64(len(s.context))) + + // Find first non-zero digit in big endian encoding of context length + i := 0 + for buf[i] == 0 && i < 8 { + i++ + } + + buf[8] = byte(8 - i) // number of bytes to represent |C| + _, _ = s.Write(buf[i:]) + + // We need to write the chunk number if we're past the first chunk. + if s.buf != nil { + // Write last remaining chunk(s) + var cv [32]byte + if s.lanes == 1 { + if s.offset != 0 { + _, _ = s.leaf.Read(cv[:]) + _, _ = s.stalk.Write(cv[:]) + s.chunk++ + } + } else { + remainingBuf := s.buf[:s.offset] + for len(remainingBuf) > 0 { + h := sha3.NewTurboShake128(0x0B) + to := chunkSize + if len(remainingBuf) < to { + to = len(remainingBuf) + } + _, _ = h.Write(remainingBuf[:to]) + _, _ = h.Read(cv[:]) + _, _ = s.stalk.Write(cv[:]) + s.chunk++ + remainingBuf = remainingBuf[to:] + } + } + + // Write length_encode( chunk ) + binary.BigEndian.PutUint64(buf[:8], uint64(s.chunk)) + + // Find first non-zero digit in big endian encoding of number of chunks + i = 0 + for buf[i] == 0 && i < 8 { + i++ + } + + buf[8] = byte(8 - i) // number of bytes to represent number of chunks. + _, _ = s.stalk.Write(buf[i:]) + _, _ = s.stalk.Write([]byte{0xff, 0xff}) + } + } + + return s.stalk.Read(p) +} diff --git a/vendor/github.com/cloudflare/circl/xof/xof.go b/vendor/github.com/cloudflare/circl/xof/xof.go new file mode 100644 index 0000000000..33485cac57 --- /dev/null +++ b/vendor/github.com/cloudflare/circl/xof/xof.go @@ -0,0 +1,85 @@ +// Package xof provides an interface for eXtendable-Output Functions. +// +// # Available Functions +// +// SHAKE functions are defined in FIPS-202, see https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf. +// BLAKE2Xb and BLAKE2Xs are defined in https://www.blake2.net/blake2x.pdf. +package xof + +import ( + "io" + + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/xof/k12" + + "golang.org/x/crypto/blake2b" + "golang.org/x/crypto/blake2s" +) + +// XOF defines the interface to hash functions that support arbitrary-length output. +type XOF interface { + // Write absorbs more data into the XOF's state. It panics if called + // after Read. + io.Writer + + // Read reads more output from the XOF. It returns io.EOF if the limit + // has been reached. + io.Reader + + // Clone returns a copy of the XOF in its current state. + Clone() XOF + + // Reset restores the XOF to its initial state and discards all data appended by Write. + Reset() +} + +type ID uint + +const ( + SHAKE128 ID = iota + 1 + SHAKE256 + BLAKE2XB + BLAKE2XS + K12D10 +) + +func (x ID) New() XOF { + switch x { + case SHAKE128: + s := sha3.NewShake128() + return shakeBody{&s} + case SHAKE256: + s := sha3.NewShake256() + return shakeBody{&s} + case BLAKE2XB: + x, _ := blake2b.NewXOF(blake2b.OutputLengthUnknown, nil) + return blake2xb{x} + case BLAKE2XS: + x, _ := blake2s.NewXOF(blake2s.OutputLengthUnknown, nil) + return blake2xs{x} + case K12D10: + x := k12.NewDraft10([]byte{}) + return k12d10{&x} + default: + panic("crypto: requested unavailable XOF function") + } +} + +type shakeBody struct{ sha3.ShakeHash } + +func (s shakeBody) Clone() XOF { return shakeBody{s.ShakeHash.Clone()} } + +type blake2xb struct{ blake2b.XOF } + +func (s blake2xb) Clone() XOF { return blake2xb{s.XOF.Clone()} } + +type blake2xs struct{ blake2s.XOF } + +func (s blake2xs) Clone() XOF { return blake2xs{s.XOF.Clone()} } + +type k12d10 struct{ *k12.State } + +func (s k12d10) Clone() XOF { + x := s.State.Clone() + return k12d10{&x} +} diff --git a/vendor/github.com/containerd/log/.gitattributes b/vendor/github.com/containerd/log/.gitattributes new file mode 100644 index 0000000000..6313b56c57 --- /dev/null +++ b/vendor/github.com/containerd/log/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/vendor/github.com/containerd/log/.golangci.yml b/vendor/github.com/containerd/log/.golangci.yml index a695775df4..5c3bdd766c 100644 --- a/vendor/github.com/containerd/log/.golangci.yml +++ b/vendor/github.com/containerd/log/.golangci.yml @@ -1,30 +1,50 @@ +version: "2" linters: enable: - - exportloopref # Checks for pointers to enclosing loop variables - - gofmt - - goimports + - copyloopvar + - dupword - gosec + - govet - ineffassign - misspell - nolintlint - revive - staticcheck - - tenv # Detects using os.Setenv instead of t.Setenv since Go 1.17 - unconvert - unused - - vet - - dupword # Checks for duplicate words in the source code disable: - errcheck + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - api + - cluster + - design + - docs + - docs/man + - releases + - reports + - test +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - api + - cluster + - design + - docs + - docs/man + - releases + - reports + - test run: timeout: 5m - skip-dirs: - - api - - cluster - - design - - docs - - docs/man - - releases - - reports - - test # e2e scripts diff --git a/vendor/github.com/containerd/log/context.go b/vendor/github.com/containerd/log/context.go index 20153066f3..e43ca0b100 100644 --- a/vendor/github.com/containerd/log/context.go +++ b/vendor/github.com/containerd/log/context.go @@ -40,8 +40,11 @@ package log import ( "context" "fmt" + "io" + "log/slog" "github.com/sirupsen/logrus" + lslog "github.com/sirupsen/logrus/hooks/slog" ) // G is a shorthand for [GetLogger]. @@ -108,10 +111,17 @@ const ( PanicLevel Level = logrus.PanicLevel ) -// SetLevel sets log level globally. It returns an error if the given -// level is not supported. +// levelValue is a log level accepted by [SetLevel]. +type levelValue interface { + string | Level | slog.Level | lslog.Level | lslog.SlogLevel +} + +// SetLevel sets the global log level. // -// level can be one of: +// The level may be specified as a string, a [Level], a [slog.Level], an +// [lslog.Level], or an [lslog.SlogLevel]. +// +// String levels are parsed using [logrus.ParseLevel] and may be one of: // // - "trace" ([TraceLevel]) // - "debug" ([DebugLevel]) @@ -120,10 +130,34 @@ const ( // - "error" ([ErrorLevel]) // - "fatal" ([FatalLevel]) // - "panic" ([PanicLevel]) -func SetLevel(level string) error { - lvl, err := logrus.ParseLevel(level) - if err != nil { - return err +// +// slog levels are mapped to Logrus levels using the mapping defined by +// [lslog.SlogLevel]. [lslog.Level] values are accepted directly as their +// underlying Logrus level. +// +// SetLevel returns an error if a string level is not supported. +func SetLevel[T levelValue](level T) error { + var lvl Level + + switch l := any(level).(type) { + case string: + var err error + lvl, err = logrus.ParseLevel(l) + if err != nil { + return err + } + + case Level: + lvl = l + + case slog.Level: + lvl = lslog.SlogLevel(l).Level() + + case lslog.Level: + lvl = Level(l) + + case lslog.SlogLevel: + lvl = l.Level() } L.Logger.SetLevel(lvl) @@ -149,21 +183,39 @@ const ( // SetFormat sets the log output format ([TextFormat] or [JSONFormat]). func SetFormat(format OutputFormat) error { + if slogOut != nil { + var handler slog.Handler + switch format { + case TextFormat: + handler = slog.NewTextHandler(slogOut, &slog.HandlerOptions{Level: loggerLevel{}}) + case JSONFormat: + handler = slog.NewJSONHandler(slogOut, &slog.HandlerOptions{Level: loggerLevel{}}) + default: + return fmt.Errorf("unknown log format: %s", format) + } + slog.SetDefault(slog.New(handler)) + + // Keep logrus formatting and output disabled, as both are handled by slog. + L.Logger.SetFormatter(discardFormatter{}) + L.Logger.SetOutput(io.Discard) + return nil + } + switch format { case TextFormat: L.Logger.SetFormatter(&logrus.TextFormatter{ TimestampFormat: RFC3339NanoFixed, FullTimestamp: true, }) - return nil case JSONFormat: L.Logger.SetFormatter(&logrus.JSONFormatter{ TimestampFormat: RFC3339NanoFixed, }) - return nil default: return fmt.Errorf("unknown log format: %s", format) } + + return nil } // WithLogger returns a new context with the provided logger. Use in diff --git a/vendor/github.com/containerd/log/slog.go b/vendor/github.com/containerd/log/slog.go new file mode 100644 index 0000000000..6e230ca8ef --- /dev/null +++ b/vendor/github.com/containerd/log/slog.go @@ -0,0 +1,66 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package log + +import ( + "io" + "log/slog" + "sync" + + "github.com/sirupsen/logrus" + lslog "github.com/sirupsen/logrus/hooks/slog" +) + +// slogOut is used to set the slog logger when setting output format. +var slogOut io.Writer + +// slogOnce guards UseSlog so repeated calls do not stack up hooks or +// reset slogOut to the discard writer installed on the first call. +var slogOnce sync.Once + +func UseSlog() { + slogOnce.Do(func() { + L.Logger.SetNoLock() + L.Logger.AddHook(slogHook{}) + slogOut = L.Logger.Out + + // Disable logrus formatting and output, as both are handled by slog. + L.Logger.SetFormatter(discardFormatter{}) + L.Logger.SetOutput(io.Discard) + }) +} + +type slogHook struct{} + +func (slogHook) Levels() []logrus.Level { + return logrus.AllLevels +} + +func (slogHook) Fire(entry *logrus.Entry) error { + return lslog.NewHook(slog.Default(), nil).Fire(entry) +} + +// loggerLevel exposes the current Logrus logger level as a slog.Leveler. +type loggerLevel struct{} + +func (loggerLevel) Level() slog.Level { + return lslog.Level(L.Logger.GetLevel()).Level() +} + +type discardFormatter struct{} + +func (discardFormatter) Format(*logrus.Entry) ([]byte, error) { return nil, nil } diff --git a/vendor/github.com/coreos/go-oidc/v3/oidc/jwks.go b/vendor/github.com/coreos/go-oidc/v3/oidc/jwks.go index eab30aabb8..b90e67aad0 100644 --- a/vendor/github.com/coreos/go-oidc/v3/oidc/jwks.go +++ b/vendor/github.com/coreos/go-oidc/v3/oidc/jwks.go @@ -278,6 +278,20 @@ func (j *jwkJSON) UnmarshalJSON(data []byte) error { } var jwk jose.JSONWebKey if err := json.Unmarshal(key, &jwk); err != nil { + // Ignore keys with types that go-jose doesn't support, such as + // OKP keys with Ed448 or X448 curves. Some providers include + // them in their key sets without an "alg" value, so the check + // above doesn't catch them. + // + // https://datatracker.ietf.org/doc/html/rfc7517#section-5 + // + // Implementations SHOULD ignore JWKs within a JWK Set that use + // "kty" (key type) values that are not understood by them, that + // are missing required members, or for which values are out of + // the supported ranges. + if errors.Is(err, jose.ErrUnsupportedKeyType) { + continue + } return err } j.Keys = append(j.Keys, jwk) diff --git a/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md b/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md index 6d016d05c0..f8fbb6b62f 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md +++ b/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md @@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ## +## [0.7.0] - 2025-06-17 ## + +> You talk of times of peace for all, and then prepare for war. + +### Changed ### +- Update to `cyphar.com/go-pathrs@0.2.5`, which included a build-time API + breakage that we needed to work around. The API of this library is unchanged + by this, but users should make sure to update to `v0.7.0` of + `filepath-securejoin` if they use the `libpathrs` built tag and have update + to `libpathrs` `v0.2.5`. + ## [0.6.1] - 2025-11-19 ## > At last up jumped the cunning spider, and fiercely held her fast. diff --git a/vendor/github.com/cyphar/filepath-securejoin/VERSION b/vendor/github.com/cyphar/filepath-securejoin/VERSION index ee6cdce3c2..faef31a435 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/VERSION +++ b/vendor/github.com/cyphar/filepath-securejoin/VERSION @@ -1 +1 @@ -0.6.1 +0.7.0 diff --git a/vendor/github.com/evanphx/json-patch/v5/internal/json/decode.go b/vendor/github.com/evanphx/json-patch/v5/internal/json/decode.go new file mode 100644 index 0000000000..e9bb0efe77 --- /dev/null +++ b/vendor/github.com/evanphx/json-patch/v5/internal/json/decode.go @@ -0,0 +1,1385 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Represents JSON data structure using native Go types: booleans, floats, +// strings, arrays, and maps. + +package json + +import ( + "encoding" + "encoding/base64" + "fmt" + "reflect" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf16" + "unicode/utf8" +) + +// Unmarshal parses the JSON-encoded data and stores the result +// in the value pointed to by v. If v is nil or not a pointer, +// Unmarshal returns an InvalidUnmarshalError. +// +// Unmarshal uses the inverse of the encodings that +// Marshal uses, allocating maps, slices, and pointers as necessary, +// with the following additional rules: +// +// To unmarshal JSON into a pointer, Unmarshal first handles the case of +// the JSON being the JSON literal null. In that case, Unmarshal sets +// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into +// the value pointed at by the pointer. If the pointer is nil, Unmarshal +// allocates a new value for it to point to. +// +// To unmarshal JSON into a value implementing the Unmarshaler interface, +// Unmarshal calls that value's UnmarshalJSON method, including +// when the input is a JSON null. +// Otherwise, if the value implements encoding.TextUnmarshaler +// and the input is a JSON quoted string, Unmarshal calls that value's +// UnmarshalText method with the unquoted form of the string. +// +// To unmarshal JSON into a struct, Unmarshal matches incoming object +// keys to the keys used by Marshal (either the struct field name or its tag), +// preferring an exact match but also accepting a case-insensitive match. By +// default, object keys which don't have a corresponding struct field are +// ignored (see Decoder.DisallowUnknownFields for an alternative). +// +// To unmarshal JSON into an interface value, +// Unmarshal stores one of these in the interface value: +// +// bool, for JSON booleans +// float64, for JSON numbers +// string, for JSON strings +// []interface{}, for JSON arrays +// map[string]interface{}, for JSON objects +// nil for JSON null +// +// To unmarshal a JSON array into a slice, Unmarshal resets the slice length +// to zero and then appends each element to the slice. +// As a special case, to unmarshal an empty JSON array into a slice, +// Unmarshal replaces the slice with a new empty slice. +// +// To unmarshal a JSON array into a Go array, Unmarshal decodes +// JSON array elements into corresponding Go array elements. +// If the Go array is smaller than the JSON array, +// the additional JSON array elements are discarded. +// If the JSON array is smaller than the Go array, +// the additional Go array elements are set to zero values. +// +// To unmarshal a JSON object into a map, Unmarshal first establishes a map to +// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal +// reuses the existing map, keeping existing entries. Unmarshal then stores +// key-value pairs from the JSON object into the map. The map's key type must +// either be any string type, an integer, implement json.Unmarshaler, or +// implement encoding.TextUnmarshaler. +// +// If the JSON-encoded data contain a syntax error, Unmarshal returns a SyntaxError. +// +// If a JSON value is not appropriate for a given target type, +// or if a JSON number overflows the target type, Unmarshal +// skips that field and completes the unmarshaling as best it can. +// If no more serious errors are encountered, Unmarshal returns +// an UnmarshalTypeError describing the earliest such error. In any +// case, it's not guaranteed that all the remaining fields following +// the problematic one will be unmarshaled into the target object. +// +// The JSON null value unmarshals into an interface, map, pointer, or slice +// by setting that Go value to nil. Because null is often used in JSON to mean +// “not present,” unmarshaling a JSON null into any other Go type has no effect +// on the value and produces no error. +// +// When unmarshaling quoted strings, invalid UTF-8 or +// invalid UTF-16 surrogate pairs are not treated as an error. +// Instead, they are replaced by the Unicode replacement +// character U+FFFD. +func Unmarshal(data []byte, v any) error { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + d := ds.Get().(*decodeState) + defer ds.Put(d) + //var d decodeState + d.useNumber = true + err := checkValid(data, &d.scan) + if err != nil { + return err + } + + d.init(data) + return d.unmarshal(v) +} + +var ds = sync.Pool{ + New: func() any { + return new(decodeState) + }, +} + +func UnmarshalWithKeys(data []byte, v any) ([]string, error) { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + + d := ds.Get().(*decodeState) + defer ds.Put(d) + //var d decodeState + d.useNumber = true + err := checkValid(data, &d.scan) + if err != nil { + return nil, err + } + + d.init(data) + err = d.unmarshal(v) + if err != nil { + return nil, err + } + + return d.lastKeys, nil +} + +func UnmarshalValid(data []byte, v any) error { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + d := ds.Get().(*decodeState) + defer ds.Put(d) + //var d decodeState + d.useNumber = true + + d.init(data) + return d.unmarshal(v) +} + +func UnmarshalValidWithKeys(data []byte, v any) ([]string, error) { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + + d := ds.Get().(*decodeState) + defer ds.Put(d) + //var d decodeState + d.useNumber = true + + d.init(data) + err := d.unmarshal(v) + if err != nil { + return nil, err + } + + return d.lastKeys, nil +} + +// Unmarshaler is the interface implemented by types +// that can unmarshal a JSON description of themselves. +// The input can be assumed to be a valid encoding of +// a JSON value. UnmarshalJSON must copy the JSON data +// if it wishes to retain the data after returning. +// +// By convention, to approximate the behavior of Unmarshal itself, +// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op. +type Unmarshaler interface { + UnmarshalJSON([]byte) error +} + +// An UnmarshalTypeError describes a JSON value that was +// not appropriate for a value of a specific Go type. +type UnmarshalTypeError struct { + Value string // description of JSON value - "bool", "array", "number -5" + Type reflect.Type // type of Go value it could not be assigned to + Offset int64 // error occurred after reading Offset bytes + Struct string // name of the struct type containing the field + Field string // the full path from root node to the field +} + +func (e *UnmarshalTypeError) Error() string { + if e.Struct != "" || e.Field != "" { + return "json: cannot unmarshal " + e.Value + " into Go struct field " + e.Struct + "." + e.Field + " of type " + e.Type.String() + } + return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() +} + +// An UnmarshalFieldError describes a JSON object key that +// led to an unexported (and therefore unwritable) struct field. +// +// Deprecated: No longer used; kept for compatibility. +type UnmarshalFieldError struct { + Key string + Type reflect.Type + Field reflect.StructField +} + +func (e *UnmarshalFieldError) Error() string { + return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() +} + +// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. +// (The argument to Unmarshal must be a non-nil pointer.) +type InvalidUnmarshalError struct { + Type reflect.Type +} + +func (e *InvalidUnmarshalError) Error() string { + if e.Type == nil { + return "json: Unmarshal(nil)" + } + + if e.Type.Kind() != reflect.Pointer { + return "json: Unmarshal(non-pointer " + e.Type.String() + ")" + } + return "json: Unmarshal(nil " + e.Type.String() + ")" +} + +func (d *decodeState) unmarshal(v any) error { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Pointer || rv.IsNil() { + return &InvalidUnmarshalError{reflect.TypeOf(v)} + } + + d.scan.reset() + d.scanWhile(scanSkipSpace) + // We decode rv not rv.Elem because the Unmarshaler interface + // test must be applied at the top level of the value. + err := d.value(rv) + if err != nil { + return d.addErrorContext(err) + } + return d.savedError +} + +// A Number represents a JSON number literal. +type Number string + +// String returns the literal text of the number. +func (n Number) String() string { return string(n) } + +// Float64 returns the number as a float64. +func (n Number) Float64() (float64, error) { + return strconv.ParseFloat(string(n), 64) +} + +// Int64 returns the number as an int64. +func (n Number) Int64() (int64, error) { + return strconv.ParseInt(string(n), 10, 64) +} + +// An errorContext provides context for type errors during decoding. +type errorContext struct { + Struct reflect.Type + FieldStack []string +} + +// decodeState represents the state while decoding a JSON value. +type decodeState struct { + data []byte + off int // next read offset in data + opcode int // last read result + scan scanner + errorContext *errorContext + savedError error + useNumber bool + disallowUnknownFields bool + lastKeys []string +} + +// readIndex returns the position of the last byte read. +func (d *decodeState) readIndex() int { + return d.off - 1 +} + +// phasePanicMsg is used as a panic message when we end up with something that +// shouldn't happen. It can indicate a bug in the JSON decoder, or that +// something is editing the data slice while the decoder executes. +const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?" + +func (d *decodeState) init(data []byte) *decodeState { + d.data = data + d.off = 0 + d.savedError = nil + if d.errorContext != nil { + d.errorContext.Struct = nil + // Reuse the allocated space for the FieldStack slice. + d.errorContext.FieldStack = d.errorContext.FieldStack[:0] + } + return d +} + +// saveError saves the first err it is called with, +// for reporting at the end of the unmarshal. +func (d *decodeState) saveError(err error) { + if d.savedError == nil { + d.savedError = d.addErrorContext(err) + } +} + +// addErrorContext returns a new error enhanced with information from d.errorContext +func (d *decodeState) addErrorContext(err error) error { + if d.errorContext != nil && (d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0) { + switch err := err.(type) { + case *UnmarshalTypeError: + err.Struct = d.errorContext.Struct.Name() + err.Field = strings.Join(d.errorContext.FieldStack, ".") + } + } + return err +} + +// skip scans to the end of what was started. +func (d *decodeState) skip() { + s, data, i := &d.scan, d.data, d.off + depth := len(s.parseState) + for { + op := s.step(s, data[i]) + i++ + if len(s.parseState) < depth { + d.off = i + d.opcode = op + return + } + } +} + +// scanNext processes the byte at d.data[d.off]. +func (d *decodeState) scanNext() { + if d.off < len(d.data) { + d.opcode = d.scan.step(&d.scan, d.data[d.off]) + d.off++ + } else { + d.opcode = d.scan.eof() + d.off = len(d.data) + 1 // mark processed EOF with len+1 + } +} + +// scanWhile processes bytes in d.data[d.off:] until it +// receives a scan code not equal to op. +func (d *decodeState) scanWhile(op int) { + s, data, i := &d.scan, d.data, d.off + for i < len(data) { + newOp := s.step(s, data[i]) + i++ + if newOp != op { + d.opcode = newOp + d.off = i + return + } + } + + d.off = len(data) + 1 // mark processed EOF with len+1 + d.opcode = d.scan.eof() +} + +// rescanLiteral is similar to scanWhile(scanContinue), but it specialises the +// common case where we're decoding a literal. The decoder scans the input +// twice, once for syntax errors and to check the length of the value, and the +// second to perform the decoding. +// +// Only in the second step do we use decodeState to tokenize literals, so we +// know there aren't any syntax errors. We can take advantage of that knowledge, +// and scan a literal's bytes much more quickly. +func (d *decodeState) rescanLiteral() { + data, i := d.data, d.off +Switch: + switch data[i-1] { + case '"': // string + for ; i < len(data); i++ { + switch data[i] { + case '\\': + i++ // escaped char + case '"': + i++ // tokenize the closing quote too + break Switch + } + } + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': // number + for ; i < len(data); i++ { + switch data[i] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '.', 'e', 'E', '+', '-': + default: + break Switch + } + } + case 't': // true + i += len("rue") + case 'f': // false + i += len("alse") + case 'n': // null + i += len("ull") + } + if i < len(data) { + d.opcode = stateEndValue(&d.scan, data[i]) + } else { + d.opcode = scanEnd + } + d.off = i + 1 +} + +// value consumes a JSON value from d.data[d.off-1:], decoding into v, and +// reads the following byte ahead. If v is invalid, the value is discarded. +// The first byte of the value has been read already. +func (d *decodeState) value(v reflect.Value) error { + switch d.opcode { + default: + panic(phasePanicMsg) + + case scanBeginArray: + if v.IsValid() { + if err := d.array(v); err != nil { + return err + } + } else { + d.skip() + } + d.scanNext() + + case scanBeginObject: + if v.IsValid() { + if err := d.object(v); err != nil { + return err + } + } else { + d.skip() + } + d.scanNext() + + case scanBeginLiteral: + // All bytes inside literal return scanContinue op code. + start := d.readIndex() + d.rescanLiteral() + + if v.IsValid() { + if err := d.literalStore(d.data[start:d.readIndex()], v, false); err != nil { + return err + } + } + } + return nil +} + +type unquotedValue struct{} + +// valueQuoted is like value but decodes a +// quoted string literal or literal null into an interface value. +// If it finds anything other than a quoted string literal or null, +// valueQuoted returns unquotedValue{}. +func (d *decodeState) valueQuoted() any { + switch d.opcode { + default: + panic(phasePanicMsg) + + case scanBeginArray, scanBeginObject: + d.skip() + d.scanNext() + + case scanBeginLiteral: + v := d.literalInterface() + switch v.(type) { + case nil, string: + return v + } + } + return unquotedValue{} +} + +// indirect walks down v allocating pointers as needed, +// until it gets to a non-pointer. +// If it encounters an Unmarshaler, indirect stops and returns that. +// If decodingNull is true, indirect stops at the first settable pointer so it +// can be set to nil. +func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { + // Issue #24153 indicates that it is generally not a guaranteed property + // that you may round-trip a reflect.Value by calling Value.Addr().Elem() + // and expect the value to still be settable for values derived from + // unexported embedded struct fields. + // + // The logic below effectively does this when it first addresses the value + // (to satisfy possible pointer methods) and continues to dereference + // subsequent pointers as necessary. + // + // After the first round-trip, we set v back to the original value to + // preserve the original RW flags contained in reflect.Value. + v0 := v + haveAddr := false + + // If v is a named type and is addressable, + // start with its address, so that if the type has pointer methods, + // we find them. + if v.Kind() != reflect.Pointer && v.Type().Name() != "" && v.CanAddr() { + haveAddr = true + v = v.Addr() + } + for { + // Load value from interface, but only if the result will be + // usefully addressable. + if v.Kind() == reflect.Interface && !v.IsNil() { + e := v.Elem() + if e.Kind() == reflect.Pointer && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Pointer) { + haveAddr = false + v = e + continue + } + } + + if v.Kind() != reflect.Pointer { + break + } + + if decodingNull && v.CanSet() { + break + } + + // Prevent infinite loop if v is an interface pointing to its own address: + // var v interface{} + // v = &v + if v.Elem().Kind() == reflect.Interface && v.Elem().Elem() == v { + v = v.Elem() + break + } + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Unmarshaler); ok { + return u, nil, reflect.Value{} + } + if !decodingNull { + if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { + return nil, u, reflect.Value{} + } + } + } + + if haveAddr { + v = v0 // restore original value after round-trip Value.Addr().Elem() + haveAddr = false + } else { + v = v.Elem() + } + } + return nil, nil, v +} + +// array consumes an array from d.data[d.off-1:], decoding into v. +// The first byte of the array ('[') has been read already. +func (d *decodeState) array(v reflect.Value) error { + // Check for unmarshaler. + u, ut, pv := indirect(v, false) + if u != nil { + start := d.readIndex() + d.skip() + return u.UnmarshalJSON(d.data[start:d.off]) + } + if ut != nil { + d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + } + v = pv + + // Check type of target. + switch v.Kind() { + case reflect.Interface: + if v.NumMethod() == 0 { + // Decoding into nil interface? Switch to non-reflect code. + ai := d.arrayInterface() + v.Set(reflect.ValueOf(ai)) + return nil + } + // Otherwise it's invalid. + fallthrough + default: + d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + case reflect.Array, reflect.Slice: + break + } + + i := 0 + for { + // Look ahead for ] - can only happen on first iteration. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndArray { + break + } + + // Get element of array, growing if necessary. + if v.Kind() == reflect.Slice { + // Grow slice if necessary + if i >= v.Cap() { + newcap := v.Cap() + v.Cap()/2 + if newcap < 4 { + newcap = 4 + } + newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) + reflect.Copy(newv, v) + v.Set(newv) + } + if i >= v.Len() { + v.SetLen(i + 1) + } + } + + if i < v.Len() { + // Decode into element. + if err := d.value(v.Index(i)); err != nil { + return err + } + } else { + // Ran out of fixed array: skip. + if err := d.value(reflect.Value{}); err != nil { + return err + } + } + i++ + + // Next token must be , or ]. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndArray { + break + } + if d.opcode != scanArrayValue { + panic(phasePanicMsg) + } + } + + if i < v.Len() { + if v.Kind() == reflect.Array { + // Array. Zero the rest. + z := reflect.Zero(v.Type().Elem()) + for ; i < v.Len(); i++ { + v.Index(i).Set(z) + } + } else { + v.SetLen(i) + } + } + if i == 0 && v.Kind() == reflect.Slice { + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) + } + return nil +} + +var nullLiteral = []byte("null") +var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() + +// object consumes an object from d.data[d.off-1:], decoding into v. +// The first byte ('{') of the object has been read already. +func (d *decodeState) object(v reflect.Value) error { + // Check for unmarshaler. + u, ut, pv := indirect(v, false) + if u != nil { + start := d.readIndex() + d.skip() + return u.UnmarshalJSON(d.data[start:d.off]) + } + if ut != nil { + d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + } + v = pv + t := v.Type() + + // Decoding into nil interface? Switch to non-reflect code. + if v.Kind() == reflect.Interface && v.NumMethod() == 0 { + oi := d.objectInterface() + v.Set(reflect.ValueOf(oi)) + return nil + } + + var fields structFields + + // Check type of target: + // struct or + // map[T1]T2 where T1 is string, an integer type, + // or an encoding.TextUnmarshaler + switch v.Kind() { + case reflect.Map: + // Map key must either have string kind, have an integer kind, + // or be an encoding.TextUnmarshaler. + switch t.Key().Kind() { + case reflect.String, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + default: + if !reflect.PointerTo(t.Key()).Implements(textUnmarshalerType) { + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) + d.skip() + return nil + } + } + if v.IsNil() { + v.Set(reflect.MakeMap(t)) + } + case reflect.Struct: + fields = cachedTypeFields(t) + // ok + default: + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) + d.skip() + return nil + } + + var mapElem reflect.Value + var origErrorContext errorContext + if d.errorContext != nil { + origErrorContext = *d.errorContext + } + + var keys []string + + for { + // Read opening " of string key or closing }. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if d.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read key. + start := d.readIndex() + d.rescanLiteral() + item := d.data[start:d.readIndex()] + key, ok := unquoteBytes(item) + if !ok { + panic(phasePanicMsg) + } + + keys = append(keys, string(key)) + + // Figure out field corresponding to key. + var subv reflect.Value + destring := false // whether the value is wrapped in a string to be decoded first + + if v.Kind() == reflect.Map { + elemType := t.Elem() + if !mapElem.IsValid() { + mapElem = reflect.New(elemType).Elem() + } else { + mapElem.Set(reflect.Zero(elemType)) + } + subv = mapElem + } else { + var f *field + if i, ok := fields.nameIndex[string(key)]; ok { + // Found an exact name match. + f = &fields.list[i] + } else { + // Fall back to the expensive case-insensitive + // linear search. + for i := range fields.list { + ff := &fields.list[i] + if ff.equalFold(ff.nameBytes, key) { + f = ff + break + } + } + } + if f != nil { + subv = v + destring = f.quoted + for _, i := range f.index { + if subv.Kind() == reflect.Pointer { + if subv.IsNil() { + // If a struct embeds a pointer to an unexported type, + // it is not possible to set a newly allocated value + // since the field is unexported. + // + // See https://golang.org/issue/21357 + if !subv.CanSet() { + d.saveError(fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", subv.Type().Elem())) + // Invalidate subv to ensure d.value(subv) skips over + // the JSON value without assigning it to subv. + subv = reflect.Value{} + destring = false + break + } + subv.Set(reflect.New(subv.Type().Elem())) + } + subv = subv.Elem() + } + subv = subv.Field(i) + } + if d.errorContext == nil { + d.errorContext = new(errorContext) + } + d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name) + d.errorContext.Struct = t + } else if d.disallowUnknownFields { + d.saveError(fmt.Errorf("json: unknown field %q", key)) + } + } + + // Read : before value. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode != scanObjectKey { + panic(phasePanicMsg) + } + d.scanWhile(scanSkipSpace) + + if destring { + switch qv := d.valueQuoted().(type) { + case nil: + if err := d.literalStore(nullLiteral, subv, false); err != nil { + return err + } + case string: + if err := d.literalStore([]byte(qv), subv, true); err != nil { + return err + } + default: + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) + } + } else { + if err := d.value(subv); err != nil { + return err + } + } + + // Write value back to map; + // if using struct, subv points into struct already. + if v.Kind() == reflect.Map { + kt := t.Key() + var kv reflect.Value + switch { + case reflect.PointerTo(kt).Implements(textUnmarshalerType): + kv = reflect.New(kt) + if err := d.literalStore(item, kv, true); err != nil { + return err + } + kv = kv.Elem() + case kt.Kind() == reflect.String: + kv = reflect.ValueOf(key).Convert(kt) + default: + switch kt.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := string(key) + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || reflect.Zero(kt).OverflowInt(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) + break + } + kv = reflect.ValueOf(n).Convert(kt) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + s := string(key) + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || reflect.Zero(kt).OverflowUint(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) + break + } + kv = reflect.ValueOf(n).Convert(kt) + default: + panic("json: Unexpected key type") // should never occur + } + } + if kv.IsValid() { + v.SetMapIndex(kv, subv) + } + } + + // Next token must be , or }. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.errorContext != nil { + // Reset errorContext to its original state. + // Keep the same underlying array for FieldStack, to reuse the + // space and avoid unnecessary allocs. + d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] + d.errorContext.Struct = origErrorContext.Struct + } + if d.opcode == scanEndObject { + break + } + if d.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + + if v.Kind() == reflect.Map { + d.lastKeys = keys + } + return nil +} + +// convertNumber converts the number literal s to a float64 or a Number +// depending on the setting of d.useNumber. +func (d *decodeState) convertNumber(s string) (any, error) { + if d.useNumber { + return Number(s), nil + } + f, err := strconv.ParseFloat(s, 64) + if err != nil { + return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeOf(0.0), Offset: int64(d.off)} + } + return f, nil +} + +var numberType = reflect.TypeOf(Number("")) + +// literalStore decodes a literal stored in item into v. +// +// fromQuoted indicates whether this literal came from unwrapping a +// string from the ",string" struct tag option. this is used only to +// produce more helpful error messages. +func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) error { + // Check for unmarshaler. + if len(item) == 0 { + //Empty string given + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return nil + } + isNull := item[0] == 'n' // null + u, ut, pv := indirect(v, isNull) + if u != nil { + return u.UnmarshalJSON(item) + } + if ut != nil { + if item[0] != '"' { + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return nil + } + val := "number" + switch item[0] { + case 'n': + val = "null" + case 't', 'f': + val = "bool" + } + d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())}) + return nil + } + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + return ut.UnmarshalText(s) + } + + v = pv + + switch c := item[0]; c { + case 'n': // null + // The main parser checks that only true and false can reach here, + // but if this was a quoted string input, it could be anything. + if fromQuoted && string(item) != "null" { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + break + } + switch v.Kind() { + case reflect.Interface, reflect.Pointer, reflect.Map, reflect.Slice: + v.Set(reflect.Zero(v.Type())) + // otherwise, ignore null for primitives/string + } + case 't', 'f': // true, false + value := item[0] == 't' + // The main parser checks that only true and false can reach here, + // but if this was a quoted string input, it could be anything. + if fromQuoted && string(item) != "true" && string(item) != "false" { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + break + } + switch v.Kind() { + default: + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) + } + case reflect.Bool: + v.SetBool(value) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(value)) + } else { + d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) + } + } + + case '"': // string + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + switch v.Kind() { + default: + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + case reflect.Slice: + if v.Type().Elem().Kind() != reflect.Uint8 { + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) + n, err := base64.StdEncoding.Decode(b, s) + if err != nil { + d.saveError(err) + break + } + v.SetBytes(b[:n]) + case reflect.String: + if v.Type() == numberType && !isValidNumber(string(s)) { + return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item) + } + v.SetString(string(s)) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(string(s))) + } else { + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + } + } + + default: // number + if c != '-' && (c < '0' || c > '9') { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + s := string(item) + switch v.Kind() { + default: + if v.Kind() == reflect.String && v.Type() == numberType { + // s must be a valid number, because it's + // already been tokenized. + v.SetString(s) + break + } + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) + case reflect.Interface: + n, err := d.convertNumber(s) + if err != nil { + d.saveError(err) + break + } + if v.NumMethod() != 0 { + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.Set(reflect.ValueOf(n)) + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || v.OverflowInt(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetInt(n) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || v.OverflowUint(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetUint(n) + + case reflect.Float32, reflect.Float64: + n, err := strconv.ParseFloat(s, v.Type().Bits()) + if err != nil || v.OverflowFloat(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetFloat(n) + } + } + return nil +} + +// The xxxInterface routines build up a value to be stored +// in an empty interface. They are not strictly necessary, +// but they avoid the weight of reflection in this common case. + +// valueInterface is like value but returns interface{} +func (d *decodeState) valueInterface() (val any) { + switch d.opcode { + default: + panic(phasePanicMsg) + case scanBeginArray: + val = d.arrayInterface() + d.scanNext() + case scanBeginObject: + val = d.objectInterface() + d.scanNext() + case scanBeginLiteral: + val = d.literalInterface() + } + return +} + +// arrayInterface is like array but returns []interface{}. +func (d *decodeState) arrayInterface() []any { + var v = make([]any, 0) + for { + // Look ahead for ] - can only happen on first iteration. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndArray { + break + } + + v = append(v, d.valueInterface()) + + // Next token must be , or ]. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndArray { + break + } + if d.opcode != scanArrayValue { + panic(phasePanicMsg) + } + } + return v +} + +// objectInterface is like object but returns map[string]interface{}. +func (d *decodeState) objectInterface() map[string]any { + m := make(map[string]any) + for { + // Read opening " of string key or closing }. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if d.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read string key. + start := d.readIndex() + d.rescanLiteral() + item := d.data[start:d.readIndex()] + key, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + + // Read : before value. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode != scanObjectKey { + panic(phasePanicMsg) + } + d.scanWhile(scanSkipSpace) + + // Read value. + m[key] = d.valueInterface() + + // Next token must be , or }. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndObject { + break + } + if d.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + return m +} + +// literalInterface consumes and returns a literal from d.data[d.off-1:] and +// it reads the following byte ahead. The first byte of the literal has been +// read already (that's how the caller knows it's a literal). +func (d *decodeState) literalInterface() any { + // All bytes inside literal return scanContinue op code. + start := d.readIndex() + d.rescanLiteral() + + item := d.data[start:d.readIndex()] + + switch c := item[0]; c { + case 'n': // null + return nil + + case 't', 'f': // true, false + return c == 't' + + case '"': // string + s, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + return s + + default: // number + if c != '-' && (c < '0' || c > '9') { + panic(phasePanicMsg) + } + n, err := d.convertNumber(string(item)) + if err != nil { + d.saveError(err) + } + return n + } +} + +// getu4 decodes \uXXXX from the beginning of s, returning the hex value, +// or it returns -1. +func getu4(s []byte) rune { + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + return -1 + } + var r rune + for _, c := range s[2:6] { + switch { + case '0' <= c && c <= '9': + c = c - '0' + case 'a' <= c && c <= 'f': + c = c - 'a' + 10 + case 'A' <= c && c <= 'F': + c = c - 'A' + 10 + default: + return -1 + } + r = r*16 + rune(c) + } + return r +} + +// unquote converts a quoted JSON string literal s into an actual string t. +// The rules are different than for Go, so cannot use strconv.Unquote. +func unquote(s []byte) (t string, ok bool) { + s, ok = unquoteBytes(s) + t = string(s) + return +} + +func unquoteBytes(s []byte) (t []byte, ok bool) { + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + return + } + s = s[1 : len(s)-1] + + // Check for unusual characters. If there are none, + // then no unquoting is needed, so return a slice of the + // original bytes. + r := 0 + for r < len(s) { + c := s[r] + if c == '\\' || c == '"' || c < ' ' { + break + } + if c < utf8.RuneSelf { + r++ + continue + } + rr, size := utf8.DecodeRune(s[r:]) + if rr == utf8.RuneError && size == 1 { + break + } + r += size + } + if r == len(s) { + return s, true + } + + b := make([]byte, len(s)+2*utf8.UTFMax) + w := copy(b, s[0:r]) + for r < len(s) { + // Out of room? Can only happen if s is full of + // malformed UTF-8 and we're replacing each + // byte with RuneError. + if w >= len(b)-2*utf8.UTFMax { + nb := make([]byte, (len(b)+utf8.UTFMax)*2) + copy(nb, b[0:w]) + b = nb + } + switch c := s[r]; { + case c == '\\': + r++ + if r >= len(s) { + return + } + switch s[r] { + default: + return + case '"', '\\', '/', '\'': + b[w] = s[r] + r++ + w++ + case 'b': + b[w] = '\b' + r++ + w++ + case 'f': + b[w] = '\f' + r++ + w++ + case 'n': + b[w] = '\n' + r++ + w++ + case 'r': + b[w] = '\r' + r++ + w++ + case 't': + b[w] = '\t' + r++ + w++ + case 'u': + r-- + rr := getu4(s[r:]) + if rr < 0 { + return + } + r += 6 + if utf16.IsSurrogate(rr) { + rr1 := getu4(s[r:]) + if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { + // A valid pair; consume. + r += 6 + w += utf8.EncodeRune(b[w:], dec) + break + } + // Invalid surrogate; fall back to replacement rune. + rr = unicode.ReplacementChar + } + w += utf8.EncodeRune(b[w:], rr) + } + + // Quote, control characters are invalid. + case c == '"', c < ' ': + return + + // ASCII + case c < utf8.RuneSelf: + b[w] = c + r++ + w++ + + // Coerce to well-formed UTF-8. + default: + rr, size := utf8.DecodeRune(s[r:]) + r += size + w += utf8.EncodeRune(b[w:], rr) + } + } + return b[0:w], true +} diff --git a/vendor/github.com/evanphx/json-patch/v5/internal/json/encode.go b/vendor/github.com/evanphx/json-patch/v5/internal/json/encode.go new file mode 100644 index 0000000000..2e6eca4487 --- /dev/null +++ b/vendor/github.com/evanphx/json-patch/v5/internal/json/encode.go @@ -0,0 +1,1486 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package json implements encoding and decoding of JSON as defined in +// RFC 7159. The mapping between JSON and Go values is described +// in the documentation for the Marshal and Unmarshal functions. +// +// See "JSON and Go" for an introduction to this package: +// https://golang.org/doc/articles/json_and_go.html +package json + +import ( + "bytes" + "encoding" + "encoding/base64" + "fmt" + "math" + "reflect" + "sort" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +// Marshal returns the JSON encoding of v. +// +// Marshal traverses the value v recursively. +// If an encountered value implements the Marshaler interface +// and is not a nil pointer, Marshal calls its MarshalJSON method +// to produce JSON. If no MarshalJSON method is present but the +// value implements encoding.TextMarshaler instead, Marshal calls +// its MarshalText method and encodes the result as a JSON string. +// The nil pointer exception is not strictly necessary +// but mimics a similar, necessary exception in the behavior of +// UnmarshalJSON. +// +// Otherwise, Marshal uses the following type-dependent default encodings: +// +// Boolean values encode as JSON booleans. +// +// Floating point, integer, and Number values encode as JSON numbers. +// +// String values encode as JSON strings coerced to valid UTF-8, +// replacing invalid bytes with the Unicode replacement rune. +// So that the JSON will be safe to embed inside HTML