Caution
This FrodoKEM implementation is conformant with FrodoKEM specification @ https://frodokem.org/files/FrodoKEM-standard_proposal-20230314.pdf. I also try to make it timing leakage free, using dudect
(see https://github.com/oreparaz/dudect) -based tests, but be informed that this implementation is not yet audited. If you consider using it in production, be careful !
FrodoKEM: Practical Quantum-secure Key Encapsulation from Generic Lattices
FrodoKEM is a post-quantum key encapsulation mechanism (KEM), based on the hardness of learning with errors (LWE) problem, which has close connections to conjectured-hard problems on generic, algebraically unstructured lattices, offering IND-CCA security. FrodoKEM is built on top of FrodoPKE, which is a public key encryption (PKE) algorithm, can be used for encrypting fixed length messages, offering IND-CPA security.
Scheme | What does it offer ? |
---|---|
FrodoPKE | Lets you encrypt a fixed length message M, using your peer's public key, resulting in a cipher text, which can only be decrypted by respective peer's secret key. |
FrodoKEM | Helps in establishing secure communication channel between two parties - (a) starting communication over insecure channel, (b) later on begins using some authenticated encryption (AEAD) scheme for encrypting their messages, using the common key ( = shared secret ) that both of them arrived at by using the KEM scheme. |
Here I'm maintaining a header-only, easy-to-use ( see below ) C++20 library, offering FrodoKEM API, for three security levels, each for two usage scenarios ( i.e. static and ephemeral ).
Note
Right now this library only provides you with FrodoKEM implementation s.t. generation of matrix A
always uses SHAKE128 Xof. I've not yet implemented AES128 backed matrix A
generation logic.
Scheme | Target Security Level |
---|---|
(e)Frodo-640 KEM | NIST-I |
(e)Frodo-976 KEM | NIST-III |
(e)Frodo-1344 KEM | NIST-V |
Note
(STATIC): Long term use of same keypair s.t. many cipher texts can be computed per public key. KEM variants whose names look like Frodo-{640, 976, 1344} KEM.
Note
(EPHEMERAL): Only small number of cipher texts are produced per public key. Begins with an e
i.e. eFrodo-{640,976,1344} KEM.
While working on this implementation, I've mainly followed the FrodoKEM specification @ https://frodokem.org/files/FrodoKEM-standard_proposal-20230314.pdf. Though for certain function implementations, I found an older version of specifiction, living @ https://frodokem.org/files/FrodoKEM-specification-20210604.pdf, more comprehensive. I suggest you go through them for an in-depth understanding of the scheme.
- A C++ compiler with support for C++20 standard library.
$ g++ --version
g++ (Ubuntu 13.2.0-4ubuntu3) 13.2.0
$ clang++ --version
Ubuntu clang version 17.0.2 (1~exp1ubuntu2.1)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
- Build tools.
$ make --version
GNU Make 4.3
$ cmake --version
cmake version 3.27.4
- For testing functional correctness of FrodoKEM and its components, you need to globally install
google-test
headers and library. Follow the guide @ https://github.com/google/googletest/tree/main/googletest#standalone-cmake-project. - For benchmarking FrodoKEM algorithms, you must have
google-benchmark
headers and library available in$PATH
. I found the installation guide @ https://github.com/google/benchmark#installation helpful.
Note
If you are on a machine running GNU/Linux kernel and you want to obtain CPU cycle count for KEM algorithms, you should consider building google-benchmark
library with libPFM support, following the step-by-step guide @ https://gist.github.com/itzmeanjan/05dc3e946f635d00c5e0b21aae6203a7. Find more about libPFM @ https://perfmon2.sourceforge.net.
Tip
Git submodule based dependencies will generally be imported automatically, but in case that doesn't work, you can manually initialize and update them by issuing $ git submodule update --init
from inside the root of this repository.
For ensuring functional correctness of FrodoKEM and its constituting components, issue following command. Issuing following command also runs necessary tests, which ensures that this FrodoKEM implementation is conformant with the specification, by checking keypair/ cipher text/ shared secret values for given seeds, using known answer tests (KATs).
Note
Known Answer Tests (KATs) living in this directory are computed by following (reproducible) steps, described in the gist @ https://gist.github.com/itzmeanjan/38d506a69073bdeb0933245401f42186.
make -j # Run tests without any sort of sanitizers
make asan_test -j # Run tests with AddressSanitizer enabled
make ubsan_test -j # Run tests with UndefinedBehaviourSanitizer enabled
[13/13] FrodoKEM.Frodo1344KEMKAT (1838 ms)
PASSED TESTS (13/13):
5 ms: build/test.out FrodoKEM.ZqEncodeDecode
6 ms: build/test.out FrodoKEM.MatrixEncodeDecode
11 ms: build/test.out FrodoKEM.MatrixPackUnpack
11 ms: build/test.out FrodoKEM.MatrixTranspose
17 ms: build/test.out FrodoKEM.MatrixAddSub
18 ms: build/test.out FrodoKEM.Lemma2_18
203 ms: build/test.out FrodoKEM.KeygenEncapsDecaps
529 ms: build/test.out FrodoKEM.eFrodo640KEMKAT
747 ms: build/test.out FrodoKEM.Frodo640KEMKAT
1044 ms: build/test.out FrodoKEM.Frodo976KEMKAT
1173 ms: build/test.out FrodoKEM.eFrodo976KEMKAT
1792 ms: build/test.out FrodoKEM.eFrodo1344KEMKAT
1838 ms: build/test.out FrodoKEM.Frodo1344KEMKAT
You can run timing leakage tests, using dudect
; execute following
Note
dudect
is integrated into this library implementation of FrodoKEM to find any sort of timing leakages. It checks for constant-timeness of key generation, encapsulation and decapsulation function implementations, for only one variant i.e. frodo640.
# Can only be built and run on x86_64 machine.
make dudect_test_build -j
# Before running the constant-time tests, it's a good idea to put all CPU cores on "performance" mode.
# You may find the guide @ https://github.com/google/benchmark/blob/main/docs/reducing_variance.md helpful.
# Given FrodoKEM operations is slow, compared to Kyber/ Saber, following tests are required to be
# run for longer, so that we can collect enough execution timing samples.
timeout 4h taskset -c 0 ./build/dudect/test_frodo640_keygen.out
timeout 4h taskset -c 0 ./build/dudect/test_frodo640_encaps.out
timeout 4h taskset -c 0 ./build/dudect/test_frodo640_decaps.out
Tip
dudect
documentation says if t
statistic is < 10
, we're probably good, yes probably. You may want to read dudect
documentation @ https://github.com/oreparaz/dudect. Also you might find the original paper @ https://ia.cr/2016/1123 interesting.
# frodo640-keygen
...
meas: 0.06 M, max t: +2.71, max tau: 1.15e-02, (5/tau)^2: 1.88e+05. For the moment, maybe constant time.
meas: 0.06 M, max t: +2.90, max tau: 1.22e-02, (5/tau)^2: 1.68e+05. For the moment, maybe constant time.
meas: 0.06 M, max t: +2.92, max tau: 1.23e-02, (5/tau)^2: 1.66e+05. For the moment, maybe constant time.
meas: 0.06 M, max t: +2.49, max tau: 1.03e-02, (5/tau)^2: 2.35e+05. For the moment, maybe constant time.
meas: 0.06 M, max t: +2.27, max tau: 9.31e-03, (5/tau)^2: 2.88e+05. For the moment, maybe constant time.
meas: 0.06 M, max t: +2.23, max tau: 9.14e-03, (5/tau)^2: 2.99e+05. For the moment, maybe constant time.
meas: 0.06 M, max t: +2.38, max tau: 9.63e-03, (5/tau)^2: 2.70e+05. For the moment, maybe constant time.
meas: 0.06 M, max t: +2.23, max tau: 8.96e-03, (5/tau)^2: 3.11e+05. For the moment, maybe constant time.
meas: 0.43 M, max t: +2.21, max tau: 3.38e-03, (5/tau)^2: 2.19e+06. For the moment, maybe constant time.
meas: 0.43 M, max t: +2.22, max tau: 3.38e-03, (5/tau)^2: 2.19e+06. For the moment, maybe constant time.
meas: 0.06 M, max t: +2.43, max tau: 9.58e-03, (5/tau)^2: 2.73e+05. For the moment, maybe constant time.
meas: 0.06 M, max t: +2.42, max tau: 9.50e-03, (5/tau)^2: 2.77e+05. For the moment, maybe constant time.
meas: 0.07 M, max t: +2.65, max tau: 1.03e-02, (5/tau)^2: 2.35e+05. For the moment, maybe constant time.
# frodo640-encaps
...
meas: 2.35 M, max t: +1.98, max tau: 1.29e-03, (5/tau)^2: 1.50e+07. For the moment, maybe constant time.
meas: 2.43 M, max t: +1.91, max tau: 1.22e-03, (5/tau)^2: 1.67e+07. For the moment, maybe constant time.
meas: 2.52 M, max t: +1.87, max tau: 1.18e-03, (5/tau)^2: 1.79e+07. For the moment, maybe constant time.
meas: 2.61 M, max t: +2.00, max tau: 1.24e-03, (5/tau)^2: 1.62e+07. For the moment, maybe constant time.
meas: 2.69 M, max t: +1.69, max tau: 1.03e-03, (5/tau)^2: 2.35e+07. For the moment, maybe constant time.
meas: 2.78 M, max t: +1.59, max tau: 9.53e-04, (5/tau)^2: 2.75e+07. For the moment, maybe constant time.
meas: 2.86 M, max t: +1.70, max tau: 1.01e-03, (5/tau)^2: 2.46e+07. For the moment, maybe constant time.
meas: 2.90 M, max t: +1.71, max tau: 1.01e-03, (5/tau)^2: 2.47e+07. For the moment, maybe constant time.
meas: 2.98 M, max t: +1.69, max tau: 9.76e-04, (5/tau)^2: 2.63e+07. For the moment, maybe constant time.
meas: 3.07 M, max t: +1.67, max tau: 9.56e-04, (5/tau)^2: 2.74e+07. For the moment, maybe constant time.
meas: 3.15 M, max t: +1.76, max tau: 9.94e-04, (5/tau)^2: 2.53e+07. For the moment, maybe constant time.
# frodo640-decaps
...
meas: 6.24 M, max t: +1.30, max tau: 5.21e-04, (5/tau)^2: 9.21e+07. For the moment, maybe constant time.
meas: 5.97 M, max t: +1.38, max tau: 5.65e-04, (5/tau)^2: 7.84e+07. For the moment, maybe constant time.
meas: 6.07 M, max t: +1.57, max tau: 6.38e-04, (5/tau)^2: 6.15e+07. For the moment, maybe constant time.
meas: 6.16 M, max t: +1.61, max tau: 6.47e-04, (5/tau)^2: 5.97e+07. For the moment, maybe constant time.
meas: 6.25 M, max t: +1.34, max tau: 5.37e-04, (5/tau)^2: 8.66e+07. For the moment, maybe constant time.
meas: 6.34 M, max t: +1.36, max tau: 5.41e-04, (5/tau)^2: 8.53e+07. For the moment, maybe constant time.
meas: 6.43 M, max t: +1.34, max tau: 5.28e-04, (5/tau)^2: 8.98e+07. For the moment, maybe constant time.
meas: 6.52 M, max t: +1.42, max tau: 5.55e-04, (5/tau)^2: 8.13e+07. For the moment, maybe constant time.
meas: 6.61 M, max t: +1.38, max tau: 5.37e-04, (5/tau)^2: 8.66e+07. For the moment, maybe constant time.
meas: 5.28 M, max t: +1.26, max tau: 5.49e-04, (5/tau)^2: 8.30e+07. For the moment, maybe constant time.
meas: 6.80 M, max t: +1.27, max tau: 4.88e-04, (5/tau)^2: 1.05e+08. For the moment, maybe constant time.
For benchmarking all instantiations of FrodoKEM keygen/ encaps/ decaps algorithms, issue following command.
make benchmark # If you haven't built google-benchmark library with libPFM support.
make perf # Must do if you have built google-benchmark library with libPFM support.
Caution
When benchmarking, ensure that all your CPU cores are running in performance mode. You may find the guide @ https://github.com/google/benchmark/blob/2dd015df/docs/reducing_variance.md helpful.
Note
make perf
- was issued when collecting following benchmark results. Notice, CYCLES column, denoting latency of FrodoKEM routines, in terms of CPU cycles h/w event.
Compiled with gcc version 13.2.0 (Ubuntu 13.2.0-4ubuntu3).
$ uname -srm
Linux 6.5.0-17-generic x86_64
2024-02-11T20:56:26+04:00
Running ./build/perf.out
Run on (16 X 2235.51 MHz CPU s)
CPU Caches:
L1 Data 48 KiB (x8)
L1 Instruction 32 KiB (x8)
L2 Unified 1280 KiB (x8)
L3 Unified 18432 KiB (x1)
Load Average: 0.27, 0.21, 0.27
-----------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations CYCLES items_per_second
-----------------------------------------------------------------------------------------------
frodo1344-encaps_mean 6.62 ms 6.62 ms 10 30.4711M 151.067/s
frodo1344-encaps_median 6.62 ms 6.62 ms 10 30.4514M 151.068/s
frodo1344-encaps_stddev 0.019 ms 0.019 ms 10 95.7336k 0.432687/s
frodo1344-encaps_cv 0.29 % 0.29 % 10 0.31% 0.29%
frodo1344-encaps_min 6.59 ms 6.59 ms 10 30.3396M 150.346/s
frodo1344-encaps_max 6.65 ms 6.65 ms 10 30.6488M 151.722/s
efrodo976-decaps_mean 3.51 ms 3.51 ms 10 16.1006M 285.133/s
efrodo976-decaps_median 3.51 ms 3.51 ms 10 16.0825M 285.288/s
efrodo976-decaps_stddev 0.015 ms 0.015 ms 10 68.8345k 1.2265/s
efrodo976-decaps_cv 0.43 % 0.43 % 10 0.43% 0.43%
efrodo976-decaps_min 3.48 ms 3.48 ms 10 15.9793M 283.321/s
efrodo976-decaps_max 3.53 ms 3.53 ms 10 16.2091M 287.518/s
efrodo640-decaps_mean 1.55 ms 1.55 ms 10 7.12353M 643.616/s
efrodo640-decaps_median 1.55 ms 1.55 ms 10 7.12147M 643.999/s
efrodo640-decaps_stddev 0.006 ms 0.006 ms 10 25.6908k 2.4091/s
efrodo640-decaps_cv 0.38 % 0.37 % 10 0.36% 0.37%
efrodo640-decaps_min 1.54 ms 1.54 ms 10 7.07939M 639.377/s
efrodo640-decaps_max 1.56 ms 1.56 ms 10 7.17499M 648.448/s
efrodo976-keygen_mean 3.48 ms 3.48 ms 10 16.2829M 287.503/s
efrodo976-keygen_median 3.48 ms 3.48 ms 10 16.279M 287.55/s
efrodo976-keygen_stddev 0.012 ms 0.012 ms 10 49.513k 0.957008/s
efrodo976-keygen_cv 0.33 % 0.33 % 10 0.30% 0.33%
efrodo976-keygen_min 3.46 ms 3.46 ms 10 16.1973M 285.756/s
efrodo976-keygen_max 3.50 ms 3.50 ms 10 16.3747M 289.112/s
frodo1344-decaps_mean 6.60 ms 6.60 ms 10 30.3498M 151.488/s
frodo1344-decaps_median 6.60 ms 6.60 ms 10 30.3725M 151.415/s
frodo1344-decaps_stddev 0.017 ms 0.017 ms 10 86.6302k 0.391924/s
frodo1344-decaps_cv 0.26 % 0.26 % 10 0.29% 0.26%
frodo1344-decaps_min 6.57 ms 6.57 ms 10 30.174M 151.051/s
frodo1344-decaps_max 6.62 ms 6.62 ms 10 30.461M 152.156/s
frodo640-decaps_mean 1.56 ms 1.56 ms 10 7.1362M 642.162/s
frodo640-decaps_median 1.56 ms 1.56 ms 10 7.13334M 642.333/s
frodo640-decaps_stddev 0.004 ms 0.004 ms 10 21.6827k 1.50606/s
frodo640-decaps_cv 0.23 % 0.23 % 10 0.30% 0.23%
frodo640-decaps_min 1.55 ms 1.55 ms 10 7.10198M 639.988/s
frodo640-decaps_max 1.56 ms 1.56 ms 10 7.17464M 644.212/s
frodo976-decaps_mean 3.52 ms 3.52 ms 10 16.1165M 284.44/s
frodo976-decaps_median 3.51 ms 3.51 ms 10 16.1062M 284.576/s
frodo976-decaps_stddev 0.017 ms 0.016 ms 10 54.1092k 1.33077/s
frodo976-decaps_cv 0.47 % 0.47 % 10 0.34% 0.47%
frodo976-decaps_min 3.49 ms 3.49 ms 10 16.0302M 282.152/s
frodo976-decaps_max 3.54 ms 3.54 ms 10 16.2264M 286.515/s
efrodo640-keygen_mean 1.56 ms 1.56 ms 10 7.29768M 639.509/s
efrodo640-keygen_median 1.56 ms 1.56 ms 10 7.29686M 640.651/s
efrodo640-keygen_stddev 0.010 ms 0.010 ms 10 17.2719k 4.15551/s
efrodo640-keygen_cv 0.66 % 0.66 % 10 0.24% 0.65%
efrodo640-keygen_min 1.56 ms 1.56 ms 10 7.27065M 628.238/s
efrodo640-keygen_max 1.59 ms 1.59 ms 10 7.32187M 643.004/s
frodo976-keygen_mean 3.49 ms 3.49 ms 10 16.3317M 286.152/s
frodo976-keygen_median 3.49 ms 3.49 ms 10 16.3472M 286.174/s
frodo976-keygen_stddev 0.009 ms 0.009 ms 10 78.0192k 0.701863/s
frodo976-keygen_cv 0.25 % 0.25 % 10 0.48% 0.25%
frodo976-keygen_min 3.48 ms 3.48 ms 10 16.1404M 285.107/s
frodo976-keygen_max 3.51 ms 3.51 ms 10 16.4208M 287.108/s
efrodo1344-keygen_mean 6.26 ms 6.26 ms 10 29.2232M 159.801/s
efrodo1344-keygen_median 6.25 ms 6.25 ms 10 29.2266M 160.045/s
efrodo1344-keygen_stddev 0.038 ms 0.038 ms 10 89.8566k 0.95973/s
efrodo1344-keygen_cv 0.61 % 0.61 % 10 0.31% 0.60%
efrodo1344-keygen_min 6.23 ms 6.23 ms 10 29.0581M 157.176/s
efrodo1344-keygen_max 6.36 ms 6.36 ms 10 29.3706M 160.432/s
efrodo1344-decaps_mean 6.59 ms 6.59 ms 10 30.255M 151.683/s
efrodo1344-decaps_median 6.58 ms 6.58 ms 10 30.2235M 151.884/s
efrodo1344-decaps_stddev 0.032 ms 0.032 ms 10 119.694k 0.736086/s
efrodo1344-decaps_cv 0.49 % 0.49 % 10 0.40% 0.49%
efrodo1344-decaps_min 6.55 ms 6.55 ms 10 30.0595M 150.553/s
efrodo1344-decaps_max 6.64 ms 6.64 ms 10 30.4526M 152.673/s
efrodo1344-encaps_mean 6.62 ms 6.62 ms 10 30.3774M 151.013/s
efrodo1344-encaps_median 6.61 ms 6.61 ms 10 30.3647M 151.217/s
efrodo1344-encaps_stddev 0.039 ms 0.039 ms 10 113.925k 0.888824/s
efrodo1344-encaps_cv 0.60 % 0.59 % 10 0.38% 0.59%
efrodo1344-encaps_min 6.58 ms 6.58 ms 10 30.1723M 149.441/s
efrodo1344-encaps_max 6.69 ms 6.69 ms 10 30.5479M 152.05/s
frodo976-encaps_mean 3.54 ms 3.54 ms 10 16.1421M 282.434/s
frodo976-encaps_median 3.53 ms 3.53 ms 10 16.1647M 283.36/s
frodo976-encaps_stddev 0.050 ms 0.048 ms 10 93.7958k 3.77185/s
frodo976-encaps_cv 1.41 % 1.37 % 10 0.58% 1.34%
frodo976-encaps_min 3.50 ms 3.49 ms 10 16.0079M 272.683/s
frodo976-encaps_max 3.67 ms 3.67 ms 10 16.2651M 286.138/s
frodo1344-keygen_mean 6.27 ms 6.27 ms 10 29.1648M 159.567/s
frodo1344-keygen_median 6.26 ms 6.26 ms 10 29.227M 159.802/s
frodo1344-keygen_stddev 0.039 ms 0.039 ms 10 143.248k 0.986201/s
frodo1344-keygen_cv 0.62 % 0.62 % 10 0.49% 0.62%
frodo1344-keygen_min 6.21 ms 6.21 ms 10 28.8626M 157.785/s
frodo1344-keygen_max 6.34 ms 6.34 ms 10 29.2907M 161.026/s
frodo640-encaps_mean 1.57 ms 1.57 ms 10 7.18844M 636.403/s
frodo640-encaps_median 1.57 ms 1.57 ms 10 7.19561M 637.318/s
frodo640-encaps_stddev 0.009 ms 0.009 ms 10 20.6636k 3.73659/s
frodo640-encaps_cv 0.60 % 0.59 % 10 0.29% 0.59%
frodo640-encaps_min 1.56 ms 1.56 ms 10 7.15194M 626.363/s
frodo640-encaps_max 1.60 ms 1.60 ms 10 7.21422M 639.49/s
efrodo976-encaps_mean 3.53 ms 3.53 ms 10 16.1462M 283.676/s
efrodo976-encaps_median 3.53 ms 3.53 ms 10 16.1506M 283.667/s
efrodo976-encaps_stddev 0.018 ms 0.018 ms 10 54.7041k 1.42886/s
efrodo976-encaps_cv 0.51 % 0.51 % 10 0.34% 0.50%
efrodo976-encaps_min 3.50 ms 3.50 ms 10 16.0729M 280.773/s
efrodo976-encaps_max 3.56 ms 3.56 ms 10 16.2216M 285.517/s
frodo640-keygen_mean 1.57 ms 1.57 ms 10 7.29374M 636.722/s
frodo640-keygen_median 1.57 ms 1.57 ms 10 7.28768M 638.414/s
frodo640-keygen_stddev 0.016 ms 0.016 ms 10 29.3617k 6.5475/s
frodo640-keygen_cv 1.04 % 1.04 % 10 0.40% 1.03%
frodo640-keygen_min 1.55 ms 1.55 ms 10 7.2428M 623.181/s
frodo640-keygen_max 1.60 ms 1.60 ms 10 7.3373M 643.374/s
efrodo640-encaps_mean 1.57 ms 1.57 ms 10 7.1777M 638.021/s
efrodo640-encaps_median 1.57 ms 1.57 ms 10 7.17894M 637.668/s
efrodo640-encaps_stddev 0.006 ms 0.006 ms 10 26.5846k 2.40775/s
efrodo640-encaps_cv 0.38 % 0.38 % 10 0.37% 0.38%
efrodo640-encaps_min 1.56 ms 1.56 ms 10 7.1278M 634.345/s
efrodo640-encaps_max 1.58 ms 1.58 ms 10 7.22033M 642.807/s
Compiled with gcc version 13.2.0 (Ubuntu 13.2.0-4ubuntu3).
$ uname -srm
Linux 6.5.0-1009-raspi aarch64
2024-02-11T22:14:52+04:00
Running ./build/perf.out
Run on (4 X 1800 MHz CPU s)
CPU Caches:
L1 Data 32 KiB (x4)
L1 Instruction 48 KiB (x4)
L2 Unified 1024 KiB (x1)
Load Average: 1.60, 1.13, 0.77
-----------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations CYCLES items_per_second
-----------------------------------------------------------------------------------------------
frodo1344-encaps_mean 47.4 ms 47.4 ms 10 84.6791M 21.1338/s
frodo1344-encaps_median 46.6 ms 46.6 ms 10 83.2982M 21.4695/s
frodo1344-encaps_stddev 1.54 ms 1.54 ms 10 2.71976M 0.663789/s
frodo1344-encaps_cv 3.26 % 3.25 % 10 3.21% 3.14%
frodo1344-encaps_min 45.9 ms 45.9 ms 10 82.0799M 19.8866/s
frodo1344-encaps_max 50.3 ms 50.3 ms 10 89.8951M 21.7879/s
efrodo640-decaps_mean 9.68 ms 9.68 ms 10 17.3376M 103.352/s
efrodo640-decaps_median 9.63 ms 9.63 ms 10 17.2489M 103.866/s
efrodo640-decaps_stddev 0.105 ms 0.103 ms 10 182.922k 1.0873/s
efrodo640-decaps_cv 1.08 % 1.07 % 10 1.06% 1.05%
efrodo640-decaps_min 9.59 ms 9.59 ms 10 17.1955M 100.761/s
efrodo640-decaps_max 9.93 ms 9.92 ms 10 17.7819M 104.234/s
efrodo1344-encaps_mean 47.1 ms 47.1 ms 10 84.1601M 21.2586/s
efrodo1344-encaps_median 46.8 ms 46.7 ms 10 83.5835M 21.3983/s
efrodo1344-encaps_stddev 1.15 ms 1.15 ms 10 2.0118M 0.506047/s
efrodo1344-encaps_cv 2.44 % 2.43 % 10 2.39% 2.38%
efrodo1344-encaps_min 46.0 ms 45.9 ms 10 82.0646M 20.3409/s
efrodo1344-encaps_max 49.2 ms 49.2 ms 10 87.8076M 21.7769/s
frodo1344-decaps_mean 46.8 ms 46.8 ms 10 83.6376M 21.3951/s
frodo1344-decaps_median 46.4 ms 46.4 ms 10 82.9505M 21.5644/s
frodo1344-decaps_stddev 1.15 ms 1.16 ms 10 2.03636M 0.504859/s
frodo1344-decaps_cv 2.45 % 2.47 % 10 2.43% 2.36%
frodo1344-decaps_min 46.0 ms 46.0 ms 10 82.2246M 20.0637/s
frodo1344-decaps_max 49.8 ms 49.8 ms 10 89.0684M 21.7499/s
efrodo640-encaps_mean 9.89 ms 9.89 ms 10 17.709M 101.33/s
efrodo640-encaps_median 9.62 ms 9.62 ms 10 17.2474M 103.942/s
efrodo640-encaps_stddev 0.437 ms 0.437 ms 10 764.988k 4.31709/s
efrodo640-encaps_cv 4.42 % 4.42 % 10 4.32% 4.26%
efrodo640-encaps_min 9.60 ms 9.59 ms 10 17.1873M 94.8031/s
efrodo640-encaps_max 10.6 ms 10.5 ms 10 18.8679M 104.235/s
frodo976-decaps_mean 27.9 ms 27.9 ms 10 49.932M 35.8486/s
frodo976-decaps_median 27.6 ms 27.6 ms 10 49.303M 36.2868/s
frodo976-decaps_stddev 0.770 ms 0.770 ms 10 1.36128M 0.94769/s
frodo976-decaps_cv 2.76 % 2.76 % 10 2.73% 2.64%
frodo976-decaps_min 27.4 ms 27.4 ms 10 49.0373M 33.5564/s
frodo976-decaps_max 29.8 ms 29.8 ms 10 53.2898M 36.49/s
frodo640-keygen_mean 6.90 ms 6.90 ms 10 12.3493M 144.994/s
frodo640-keygen_median 6.85 ms 6.85 ms 10 12.2692M 146.055/s
frodo640-keygen_stddev 0.074 ms 0.074 ms 10 118.811k 1.54981/s
frodo640-keygen_cv 1.07 % 1.07 % 10 0.96% 1.07%
frodo640-keygen_min 6.83 ms 6.83 ms 10 12.2382M 142.624/s
frodo640-keygen_max 7.01 ms 7.01 ms 10 12.5443M 146.386/s
efrodo640-keygen_mean 6.85 ms 6.85 ms 10 12.2714M 145.947/s
efrodo640-keygen_median 6.85 ms 6.84 ms 10 12.2607M 146.097/s
efrodo640-keygen_stddev 0.018 ms 0.016 ms 10 20.1735k 0.335968/s
efrodo640-keygen_cv 0.27 % 0.23 % 10 0.16% 0.23%
efrodo640-keygen_min 6.84 ms 6.84 ms 10 12.2545M 145.342/s
efrodo640-keygen_max 6.88 ms 6.88 ms 10 12.3093M 146.231/s
frodo976-keygen_mean 14.5 ms 14.5 ms 10 25.9959M 68.8309/s
frodo976-keygen_median 14.5 ms 14.5 ms 10 25.9689M 68.9324/s
frodo976-keygen_stddev 0.059 ms 0.057 ms 10 91.1154k 0.270653/s
frodo976-keygen_cv 0.41 % 0.40 % 10 0.35% 0.39%
frodo976-keygen_min 14.5 ms 14.5 ms 10 25.9162M 68.1511/s
frodo976-keygen_max 14.7 ms 14.7 ms 10 26.2227M 69.0961/s
frodo976-encaps_mean 27.6 ms 27.6 ms 10 49.3442M 36.2609/s
frodo976-encaps_median 27.5 ms 27.5 ms 10 49.1757M 36.3873/s
frodo976-encaps_stddev 0.185 ms 0.181 ms 10 308.288k 0.236214/s
frodo976-encaps_cv 0.67 % 0.66 % 10 0.62% 0.65%
frodo976-encaps_min 27.4 ms 27.4 ms 10 49.1213M 35.7161/s
frodo976-encaps_max 28.0 ms 28.0 ms 10 50.0886M 36.4385/s
efrodo1344-decaps_mean 46.8 ms 46.8 ms 10 83.6398M 21.3944/s
efrodo1344-decaps_median 46.4 ms 46.4 ms 10 83.0595M 21.5446/s
efrodo1344-decaps_stddev 0.927 ms 0.927 ms 10 1.62053M 0.411193/s
efrodo1344-decaps_cv 1.98 % 1.98 % 10 1.94% 1.92%
efrodo1344-decaps_min 46.0 ms 46.0 ms 10 82.3521M 20.3773/s
efrodo1344-decaps_max 49.1 ms 49.1 ms 10 87.685M 21.7198/s
frodo640-decaps_mean 9.80 ms 9.80 ms 10 17.5542M 102.19/s
frodo640-decaps_median 9.64 ms 9.63 ms 10 17.2581M 103.812/s
frodo640-decaps_stddev 0.380 ms 0.379 ms 10 667.139k 3.70384/s
frodo640-decaps_cv 3.88 % 3.87 % 10 3.80% 3.62%
frodo640-decaps_min 9.59 ms 9.59 ms 10 17.1901M 93.0409/s
frodo640-decaps_max 10.8 ms 10.7 ms 10 19.2309M 104.302/s
efrodo976-encaps_mean 28.0 ms 28.0 ms 10 50.0138M 35.7767/s
efrodo976-encaps_median 27.8 ms 27.8 ms 10 49.6357M 36.018/s
efrodo976-encaps_stddev 0.624 ms 0.625 ms 10 1.09564M 0.780385/s
efrodo976-encaps_cv 2.23 % 2.24 % 10 2.19% 2.18%
efrodo976-encaps_min 27.5 ms 27.5 ms 10 49.1357M 34.0789/s
efrodo976-encaps_max 29.3 ms 29.3 ms 10 52.4383M 36.4127/s
efrodo976-keygen_mean 14.6 ms 14.6 ms 10 26.0988M 68.5479/s
efrodo976-keygen_median 14.5 ms 14.5 ms 10 26.0037M 68.8383/s
efrodo976-keygen_stddev 0.136 ms 0.134 ms 10 216.209k 0.620174/s
efrodo976-keygen_cv 0.93 % 0.92 % 10 0.83% 0.90%
efrodo976-keygen_min 14.5 ms 14.5 ms 10 25.949M 67.121/s
efrodo976-keygen_max 14.9 ms 14.9 ms 10 26.6001M 68.9562/s
frodo640-encaps_mean 9.86 ms 9.86 ms 10 17.6547M 101.601/s
frodo640-encaps_median 9.62 ms 9.62 ms 10 17.2337M 103.966/s
frodo640-encaps_stddev 0.385 ms 0.386 ms 10 680.556k 3.82278/s
frodo640-encaps_cv 3.91 % 3.91 % 10 3.85% 3.76%
frodo640-encaps_min 9.57 ms 9.57 ms 10 17.1531M 94.0607/s
frodo640-encaps_max 10.6 ms 10.6 ms 10 19.0328M 104.479/s
efrodo976-decaps_mean 27.7 ms 27.7 ms 10 49.5708M 36.111/s
efrodo976-decaps_median 27.4 ms 27.4 ms 10 49.0488M 36.4792/s
efrodo976-decaps_stddev 0.637 ms 0.640 ms 10 1.1341M 0.800265/s
efrodo976-decaps_cv 2.30 % 2.31 % 10 2.29% 2.22%
efrodo976-decaps_min 27.4 ms 27.4 ms 10 49.0179M 34.108/s
efrodo976-decaps_max 29.3 ms 29.3 ms 10 52.4395M 36.5323/s
efrodo1344-keygen_mean 27.5 ms 27.5 ms 10 49.2267M 36.3677/s
efrodo1344-keygen_median 27.5 ms 27.5 ms 10 49.231M 36.3591/s
efrodo1344-keygen_stddev 0.042 ms 0.034 ms 10 42.4153k 0.0451281/s
efrodo1344-keygen_cv 0.15 % 0.12 % 10 0.09% 0.12%
efrodo1344-keygen_min 27.4 ms 27.4 ms 10 49.1579M 36.3173/s
efrodo1344-keygen_max 27.6 ms 27.5 ms 10 49.2842M 36.4382/s
frodo1344-keygen_mean 27.5 ms 27.5 ms 10 49.2686M 36.3289/s
frodo1344-keygen_median 27.5 ms 27.5 ms 10 49.1584M 36.4076/s
frodo1344-keygen_stddev 0.147 ms 0.143 ms 10 215.554k 0.18671/s
frodo1344-keygen_cv 0.53 % 0.52 % 10 0.44% 0.51%
frodo1344-keygen_min 27.4 ms 27.4 ms 10 49.1308M 35.8653/s
frodo1344-keygen_max 27.9 ms 27.9 ms 10 49.8054M 36.4467/s
Compiled with Apple clang version 15.0.0 (clang-1500.1.0.2.5).
$ uname -srm
Darwin 23.3.0 arm64
2024-02-10T19:45:50+04:00
Running ./build/bench.out
Run on (10 X 24 MHz CPU s)
CPU Caches:
L1 Data 64 KiB
L1 Instruction 128 KiB
L2 Unified 4096 KiB (x10)
Load Average: 6.99, 4.42, 4.17
------------------------------------------------------------------------------------
Benchmark Time CPU Iterations items_per_second
------------------------------------------------------------------------------------
frodo1344-decaps_mean 15.4 ms 15.3 ms 10 65.2019/s
frodo1344-decaps_median 15.3 ms 15.3 ms 10 65.4979/s
frodo1344-decaps_stddev 0.180 ms 0.180 ms 10 0.745988/s
frodo1344-decaps_cv 1.17 % 1.17 % 10 1.14%
frodo1344-decaps_min 15.3 ms 15.3 ms 10 63.1579/s
frodo1344-decaps_max 15.9 ms 15.8 ms 10 65.5337/s
frodo1344-encaps_mean 15.3 ms 15.3 ms 10 65.496/s
frodo1344-encaps_median 15.3 ms 15.3 ms 10 65.5554/s
frodo1344-encaps_stddev 0.045 ms 0.043 ms 10 0.184255/s
frodo1344-encaps_cv 0.29 % 0.28 % 10 0.28%
frodo1344-encaps_min 15.3 ms 15.2 ms 10 64.9749/s
frodo1344-encaps_max 15.5 ms 15.4 ms 10 65.5848/s
efrodo640-keygen_mean 2.00 ms 1.99 ms 10 502.681/s
efrodo640-keygen_median 1.99 ms 1.98 ms 10 505.387/s
efrodo640-keygen_stddev 0.032 ms 0.028 ms 10 6.86121/s
efrodo640-keygen_cv 1.62 % 1.41 % 10 1.36%
efrodo640-keygen_min 1.99 ms 1.98 ms 10 483.437/s
efrodo640-keygen_max 2.09 ms 2.07 ms 10 505.442/s
frodo640-decaps_mean 3.65 ms 3.64 ms 10 275.062/s
frodo640-decaps_median 3.64 ms 3.63 ms 10 275.551/s
frodo640-decaps_stddev 0.018 ms 0.016 ms 10 1.20987/s
frodo640-decaps_cv 0.48 % 0.44 % 10 0.44%
frodo640-decaps_min 3.64 ms 3.63 ms 10 271.84/s
frodo640-decaps_max 3.69 ms 3.68 ms 10 275.755/s
efrodo1344-decaps_mean 15.3 ms 15.2 ms 10 65.5787/s
efrodo1344-decaps_median 15.3 ms 15.2 ms 10 65.5991/s
efrodo1344-decaps_stddev 0.023 ms 0.017 ms 10 0.0714561/s
efrodo1344-decaps_cv 0.15 % 0.11 % 10 0.11%
efrodo1344-decaps_min 15.2 ms 15.2 ms 10 65.4398/s
efrodo1344-decaps_max 15.3 ms 15.3 ms 10 65.6402/s
frodo976-keygen_mean 4.07 ms 4.06 ms 10 246.485/s
frodo976-keygen_median 4.07 ms 4.06 ms 10 246.496/s
frodo976-keygen_stddev 0.004 ms 0.002 ms 10 0.148473/s
frodo976-keygen_cv 0.11 % 0.06 % 10 0.06%
frodo976-keygen_min 4.06 ms 4.05 ms 10 246.246/s
frodo976-keygen_max 4.08 ms 4.06 ms 10 246.64/s
frodo640-keygen_mean 1.99 ms 1.98 ms 10 504.964/s
frodo640-keygen_median 1.99 ms 1.98 ms 10 505.631/s
frodo640-keygen_stddev 0.006 ms 0.005 ms 10 1.19111/s
frodo640-keygen_cv 0.32 % 0.24 % 10 0.24%
frodo640-keygen_min 1.98 ms 1.98 ms 10 502.698/s
frodo640-keygen_max 2.00 ms 1.99 ms 10 505.752/s
efrodo1344-keygen_mean 7.59 ms 7.56 ms 10 132.279/s
efrodo1344-keygen_median 7.58 ms 7.55 ms 10 132.416/s
efrodo1344-keygen_stddev 0.027 ms 0.025 ms 10 0.431867/s
efrodo1344-keygen_cv 0.35 % 0.33 % 10 0.33%
efrodo1344-keygen_min 7.55 ms 7.55 ms 10 131.07/s
efrodo1344-keygen_max 7.65 ms 7.63 ms 10 132.49/s
frodo976-decaps_mean 5.54 ms 5.52 ms 10 181.069/s
frodo976-decaps_median 5.53 ms 5.51 ms 10 181.368/s
frodo976-decaps_stddev 0.026 ms 0.015 ms 10 0.48885/s
frodo976-decaps_cv 0.47 % 0.27 % 10 0.27%
frodo976-decaps_min 5.51 ms 5.51 ms 10 179.991/s
frodo976-decaps_max 5.59 ms 5.56 ms 10 181.432/s
efrodo640-encaps_mean 3.66 ms 3.64 ms 10 274.572/s
efrodo640-encaps_median 3.65 ms 3.64 ms 10 274.841/s
efrodo640-encaps_stddev 0.013 ms 0.012 ms 10 0.868905/s
efrodo640-encaps_cv 0.34 % 0.32 % 10 0.32%
efrodo640-encaps_min 3.64 ms 3.64 ms 10 272.149/s
efrodo640-encaps_max 3.69 ms 3.67 ms 10 275.082/s
frodo1344-keygen_mean 7.61 ms 7.58 ms 10 131.971/s
frodo1344-keygen_median 7.58 ms 7.55 ms 10 132.449/s
frodo1344-keygen_stddev 0.052 ms 0.054 ms 10 0.929096/s
frodo1344-keygen_cv 0.68 % 0.71 % 10 0.70%
frodo1344-keygen_min 7.57 ms 7.55 ms 10 129.565/s
frodo1344-keygen_max 7.74 ms 7.72 ms 10 132.477/s
efrodo1344-encaps_mean 15.3 ms 15.3 ms 10 65.4314/s
efrodo1344-encaps_median 15.3 ms 15.3 ms 10 65.5241/s
efrodo1344-encaps_stddev 0.048 ms 0.052 ms 10 0.221589/s
efrodo1344-encaps_cv 0.32 % 0.34 % 10 0.34%
efrodo1344-encaps_min 15.3 ms 15.3 ms 10 64.8406/s
efrodo1344-encaps_max 15.5 ms 15.4 ms 10 65.5518/s
frodo976-encaps_mean 5.55 ms 5.53 ms 10 180.743/s
frodo976-encaps_median 5.55 ms 5.53 ms 10 180.809/s
frodo976-encaps_stddev 0.007 ms 0.005 ms 10 0.16868/s
frodo976-encaps_cv 0.13 % 0.09 % 10 0.09%
frodo976-encaps_min 5.54 ms 5.53 ms 10 180.28/s
frodo976-encaps_max 5.57 ms 5.55 ms 10 180.854/s
efrodo640-decaps_mean 3.67 ms 3.65 ms 10 274.383/s
efrodo640-decaps_median 3.64 ms 3.63 ms 10 275.68/s
efrodo640-decaps_stddev 0.088 ms 0.045 ms 10 3.26627/s
efrodo640-decaps_cv 2.39 % 1.22 % 10 1.19%
efrodo640-decaps_min 3.64 ms 3.63 ms 10 265.425/s
efrodo640-decaps_max 3.92 ms 3.77 ms 10 275.755/s
frodo640-encaps_mean 3.65 ms 3.64 ms 10 274.956/s
frodo640-encaps_median 3.65 ms 3.63 ms 10 275.11/s
frodo640-encaps_stddev 0.008 ms 0.004 ms 10 0.31175/s
frodo640-encaps_cv 0.22 % 0.11 % 10 0.11%
frodo640-encaps_min 3.64 ms 3.63 ms 10 274.123/s
frodo640-encaps_max 3.66 ms 3.65 ms 10 275.136/s
efrodo976-encaps_mean 5.59 ms 5.56 ms 10 179.794/s
efrodo976-encaps_median 5.56 ms 5.53 ms 10 180.765/s
efrodo976-encaps_stddev 0.096 ms 0.077 ms 10 2.42502/s
efrodo976-encaps_cv 1.71 % 1.39 % 10 1.35%
efrodo976-encaps_min 5.55 ms 5.53 ms 10 173.032/s
efrodo976-encaps_max 5.86 ms 5.78 ms 10 180.831/s
efrodo976-keygen_mean 4.07 ms 4.06 ms 10 246.432/s
efrodo976-keygen_median 4.07 ms 4.05 ms 10 246.648/s
efrodo976-keygen_stddev 0.014 ms 0.007 ms 10 0.402812/s
efrodo976-keygen_cv 0.35 % 0.16 % 10 0.16%
efrodo976-keygen_min 4.05 ms 4.05 ms 10 245.645/s
efrodo976-keygen_max 4.10 ms 4.07 ms 10 246.734/s
efrodo976-decaps_mean 5.56 ms 5.53 ms 10 180.721/s
efrodo976-decaps_median 5.53 ms 5.51 ms 10 181.336/s
efrodo976-decaps_stddev 0.076 ms 0.061 ms 10 1.93287/s
efrodo976-decaps_cv 1.36 % 1.10 % 10 1.07%
efrodo976-decaps_min 5.53 ms 5.51 ms 10 175.226/s
efrodo976-decaps_max 5.77 ms 5.71 ms 10 181.439/s
FrodoKEM is a header-only C++20 library, which is fairly easy to use.
- Clone the repository.
- Import dependencies, by enabling git submodule.
# First clone the repository, and then
pushd frodokem
git submodule update --init
popd
- Write programs, which makes use of FrodoKEM API, by including proper header file(s), living inside
./include
directory, using functions/ constants from proper namespace.
Interested in using ? | Then include | Namespace of interest |
---|---|---|
Frodo-640 KEM | include/frodo640_kem.hpp |
frodo640_kem:: |
Frodo-976 KEM | include/frodo976_kem.hpp |
frodo976_kem:: |
Frodo-1344 KEM | include/frodo1344_kem.hpp |
frodo1344_kem:: |
eFrodo-640 KEM | include/efrodo640_kem.hpp |
efrodo640_kem:: |
eFrodo-976 KEM | include/efrodo976_kem.hpp |
efrodo976_kem:: |
eFrodo-1344 KEM | include/efrodo1344_kem.hpp |
efrodo1344_kem:: |
- Finally compile your program, while letting your compiler know where it can find FrodoKEM headers (
./include
), along withsha3
(./sha3/include
) andsubtle
(./subtle/include
) header files.
Let's see how to use Frodo-640 KEM API.
- First, generate a public/ private keypair, using seeds. Key generation routine takes following three seeds.
- 16 -bytes seed
s
- 32 -byte seed
seedSE
- 16 -bytes seed
z
#include "frodo640_kem.hpp"
#include <vector>
#include <span>
int
main()
{
constexpr size_t S_LEN = 16;
constexpr size_t SEED_SE_LEN = 32;
constexpr size_t Z_LEN = 16;
std::vector<uint8_t> s(S_LEN, 0);
std::vector<uint8_t> seedSE(SEED_SE_LEN, 0);
std::vector<uint8_t> z(Z_LEN, 0);
std::vector<uint8_t> pkey(frodo640_kem::PUB_KEY_LEN, 0);
std::vector<uint8_t> skey(frodo640_kem::SEC_KEY_LEN, 0);
std::span<uint8_t, S_LEN> _s{ s };
std::span<uint8_t, SEED_SE_LEN> _seedSE{ seedSE };
std::span<uint8_t, Z_LEN> _z{ z };
std::span<uint8_t, frodo640_kem::PUB_KEY_LEN> _pkey{ pkey };
std::span<uint8_t, frodo640_kem::SEC_KEY_LEN> _skey{ skey };
// Pseudo-random number generator
prng::prng_t prng;
prng.read(_s);
prng.read(_seedSE);
prng.read(_z);
frodo640_kem::keygen(_s, _seedSE, _z, _pkey, _skey);
// ...
}
- Let's now try to encapsulate a 16 -bytes shared secret using recipient's public key, producing a cipher text, which can be shared with the recipient. Encapsulation routine takes two other inputs too.
- A 16 -bytes key
ÎĽ
- And a 32 -bytes
salt
Note In case you're trying to use eFrodoKEM-{640, 976, 1344} API, you'll notice that it doesn't take a salt as input during key encapsulation. That is only required if you're using FrodoKEM in static settings, not in ephemeral one.
int
main()
{
// Key generation
// ...
constexpr size_t ÎĽ_LEN = 16;
constexpr size_t SALT_LEN = 32;
constexpr size_t SS_LEN = 16;
std::vector<uint8_t> ÎĽ(ÎĽ_LEN, 0);
std::vector<uint8_t> salt(SALT_LEN, 0);
std::vector<uint8_t> ss0(SS_LEN, 0);
std::vector<uint8_t> cipher(frodo640_kem::CIPHER_LEN, 0);
std::span<uint8_t, ÎĽ_LEN> _ÎĽ{ ÎĽ };
std::span<uint8_t, SALT_LEN> _salt{ salt };
std::span<uint8_t, SS_LEN> _ss0{ ss0 };
std::span<uint8_t, frodo640_kem::CIPHER_LEN> _cipher{ cipher };
prng.read(_ÎĽ);
prng.read(_salt);
frodo640_kem::encaps(_ÎĽ, _salt, _pkey, _cipher, _ss0);
// ...
}
- Finally recipient has the cipher text ( and its secret key, obviously ) which can now be decapsulated, computing 16 -bytes shared secret, which the sending party also arrived at. This shared secret can now be used for encrypting their communication with symmetric key constructions, say AEAD schemes.
// ...
#include <algorithm>
#include <cassert>
int
main()
{
// Key generation
// ...
// Encapsulation
// ...
std::vector<uint8_t> ss1(SS_LEN, 0);
std::span<uint8_t, SS_LEN> _ss1{ ss1 };
frodo640_kem::decaps(_skey, _cipher, _ss1);
// ensure that both parties arrived at same shared secret !
assert(std::ranges::equal(_ss0, _ss1));
return 0;
}
I keep example programs demonstrating usage of {e}FrodoKEM-640 API in the ./examples directory. You may go through them for better understanding of Frodo KEM API surface.
$ g++ -std=c++20 -O3 -march=native -Wall -I include -I sha3/include -I subtle/include examples/frodo640_kem.cpp && ./a.out
Frodo-640 KEM
Public Key : 646348792d425d1171a5252c8d3ffa49119ee9a3cbca78c7bdcccb6743146ea369a81b13450434b089c06d77947106be649abb1129b2023a87db083c8837b2fe69a722a1b0391d2c4b295a9b08e7e2b0cacbc31320819e30dd139db85de0e78126c15ca426b150bc6ec9b43928562eb67358b99c6d3076f507192f61f3a364e8530bbda3669ffc8b30965e94fcd7a1acb65c7c9f3ad344561c0c3879a5a2a76633f40fd1cb2e1e4d9a5f6064f3ab9c5b87397caf522ffd10ec00073dc053cbb6535cd0aac901331364cb2f6ea00361e74a86364d06a07c0eba7a99f351848bfbc1eb4953d183d8d301c8f35562e324c302a58f380c7569ec30d9cb58b955902fa869f15e17f74ae52590242330886640c92913559f8f73e791a44be5caaf40a94d3cf1c54b1f3b0bd19507b14a27f083007021d313c10c94150b0ae73d36f7d2bbbf097d68248753ce53fe1c677eb2aa0790bdca2bad197622ce6859e87192685d9772b1b9ef8b49e2d3930a2050b25aac8bcbcb249375bc07f78bf73fedc7a3155db1bd1a1000a9ddb385fc072fd8d6d3e8cbd2f4888784a5544265d045b425da586f74a125d5f9b3995457b03597c9668016d35b14d3e586895dadbcc17cba8fa7c18d8ad8548ccc35721c3213010dbd20159a1a2467e820984cfc4130a68c9a91c41e5f740ea38150eefc6478d63ada37c277d39019ad5846f83423a9b4803a777107f60a1b8a3f9bce18bca76bc3963cc5bf2e0287eb62f08b7645902a762eb35255a37f4a39b7b1daf25c0f9cf0336dbb6370ca5c84a4e9d815bdee9ddcdb9915cad439215050b5e8bfa9685bc84a2ea6a2b458deb1646a7d5e64e4ad33f01c7f0152504e9da458c2af0cc02d9efbb401adc1427bdc5b7d76e8e42ec4fd685421c6a201814811a33184a3dd884d960cd3219887a5193d1c15ada5556d9704a362e582e77065611936d2ac0526628a4f96f4fa022cf7851ad81fd5ea95770eedcc8a9f5d9df9311de818a02c4655e2442af3646f6865a8ccc5e5dfeeec18fa2f59005d8a76213379117fda808d0368a2658a9fd2a69b6daf80f64a82a50ddeef29915cb815b58c0a76068b7094aae04d099ea09c5497a7b2f3a39fd01a255e38079f73ced92469225555096ec481077454cbf840c1f968929d157682e1e96b0ce9b61278912ed25521a86bc11339370e4d5f01fad64e4a77798ea45b3b24009b7c2744d131758db54269b7436b9b981a2834f126067f3d204aa5483f5862c25160984415becd08d37b85834557d5bdd7c9fd57fedc88b70ebc499baf9e4a6cac0978dfe93ed67134bf329b84c27b8ca5cddda8bb94bcc367133983b5d0cd6a0fe97bb8cbe4f883d70be0776d154578ff39387ba7527d785a8cbc053c47b40b10eb15d6157278dc094dd0eaaa320960b4bde764a2bb933bd9c8a8bfc11cbdb84f8fcaed325e887fa07032b190172a1945f972af9cbef18127c2afbbb7159e03bedd42376b61f100216b8dbb9c453bf13ee04b5e096ec48a97514426e5e7b05e4c639debed61b1e9194e583724e5cfae91f467177ea09d8ce612ed76397dced3ce4ab48427967cc9d923c2ac6301886ebc75a3208dbfb3daedfd50f88b850b3580098f9106bb4f1d3aea3338f6e045305c0ded9224848021fb0e900442250e7761ddfd41ac456263bcae46074fcb3bcd8a34d4d54157d876fd385e53575a087dd66e1052737e5a1d4d39752317d38f39beb2613d10c9fb91ba4510dc6ff05693575a43134447d1dae6d3feb50e4adf940155972ba1d5e15a03843d8d3c665260988e0b9e44e2adcc2c73e9b0af399c2b1d55826e9ea167b411542cd33f1d89881e9fa706f58fc24287298f4b91fc57b5b1ac4e8578a0e0d7238f66c79a87f2d045d3fe29561259e683dd8d58b5ca3fe6888a93850cbffe8815e25c03c5f28ed1d47f7adc1f0cc93c5cdae4c5b2b682de541fd86c453007f27b89c6872864fff189b79149b72ea272c9cdd7c64623ad6b79204d2c223146174c9fd4d4e341cc5e5ad31a264b92b1fe09111edd9f5443dbdc85415b9546a8224a7d31fd4b975e22dc0d01a88a23ec1632bf91587c4b8ce3c95951e4e1c39f23221f2e95459b90c86cf6875a6c64be7972d868d96d306af84a8e85f7c0a4cc6fd08829a776cd489c5ab8750aa409efa3b37c6a9729794c7f192ad4896c9d53381a87518a48d84699f8d0a12dfb9ce6689587865ce3b245965df68b67a5a1e39d7a1ecf3dd1ba4a8f4a3f07d0206d438c41bd5bc4b23f2f2dde475d147db5940f23dc1bb897b54f9d38f4c6da615df3a9234e9465c6f99e73fedb158729eb0af138297b7fbf3ff9161b0956cf2bcc84333615388c2253d551061005ffc7f9572daeb6282c6d216fa3590eac8a48c379891776230472cded6da404c0a828df13cee3189605fff24d4e72226259f6d90b8c51c14693e3c966383f60df9964837abb0298c8b26d786b36196f348f6f267c21b34d0a89aa3ac983aa517023c2f9e7108a2a8fd30f03750f3d793b241a3ee80a6d65ca16227e74810ba193188c7464179e16ac1681758a71514923a8515327bccab98074f77a791fc429a94e66453f514b66ed9efb08139bae27d0c10dd1d85122fb4aba555c2928d75b828083eb4d1c4e86300c44332a453f824fe5c9adc69aad138b742f7c40c04c83fab9beac766818775a62d7cb6b0f683e3802cbd6276397326d5c3949a78a8f391186f358976c8231ed94ae1c7235f04ca635b0cd4c7aecb80df60ae335c5963bab7bcf4c6936e49613b6b6726a6deada0639f2ed141e55d94f171b1bc22d1468e9f6a5d1a6b0c00938290a4e3a8ed102300e4a28fa5088a762d3782da6032093885d01c94aff812f95373bf801478446a9dbd7fed9a92dcda6fe2e93d820a2aa9ffcdb3b768951c2e091e350bdb5a6cc6583561a2bd31444d558dddf1316b006ce9dbb61c57a7831ac99a0ff694339fd1037f8202da457d58a01a4881678559b4aa92805fe829214b8e4f170505d3885bfcd842524df955e976b2afc4d536bc1a4a65517683cd431a9dd272ee518e8424cd4d5929621a0239e746c37760b2f10dfa98365ee9e4bdd7e8024da54a61ade27dab78b9bd0236c75c8a908692981149347e881f2baaceedc01c26ac272cbe9c4daabdec86f02ab2b6120da4a11213eceb0e2d7791d34dd997085f4aa280d141f379b294f3a86cd24045802b883efdc81cd3e71ab9619ec98f307d990239a5ed931c83aa18cd5a76832eab6d06f5ef9f299e82de2a17fc339b01334d2cee0b7efe73977528a2b72f7474d05799149faba3c0d759c3839721163082003f7925fb5100081f332716ab30e0414daccbf64577a8ffcaea9c307ef29c8c2749c2b478a10ac21c129b180dc53ff402596c71542e316fb23fec567beb83481f92314727fbb66c0bed3615ffa5a151f30a8efa9660b5b4d766f8cf3f10d7f2f330c1b6a0c7976f007f48fc7b7998e8dc5574ad5f7b519d9fae0a93bd791153675cdd6971ab0af098e11b77be4ade90e76537d9791bf5aa33dac31586743707729191de3d5463e8ba6daeb30b6b0d8ab98ae7b13f9d783ae6beb0114fa8e5f13da3421dfefac5039f64eaa0acd0e59c1e55c7c1f2ad300d8b2c36fe87d438153ed709d5a9e486ebb9d51be3adb26da623ff2ff2bcf18c9e0435322cf915dc181061c64947949a897e39e41a2741c5071fe0cb053f00acfe583f830adefffdfdba48e0caadcae01eecc356935ab413ffc60cabc18e2c8ea7987d635027562295358a99db0069f24fb155244bd5112ece4d442f56e8dd99cf6ad9da9891f11d181d234051c64ba2fc05f3b97916a3f5d5131266992aa12bc50dfb9bd60202989035d0586081485661f9ea6a6669030998b937bbf2a634b8b0a0650639c683b1c1db0a873a24fcf5aa97c215ad709df79a24b29b87a009e5c813cade160d4210c31c9aa0716c76bbf49065396ce254f8227abfabe1b4ed51f9e4420c3e158f638b74fc0d4af0ca9e23a0d13b19cd9e385d1daf5af774759b51d8466a2bdb6298169724434ebaa7f9fb179f8ede5924196fc5be919f0ea2c7823df334f1dd62610b4f9e33815638b3f5ec678aa7df8142aa97dea538983a31244a10d84fa7d70181b3a76ff48f717c9fd313bcaf2e67bfe7e9af1ebbffc16318e89b570eb33b953994c1c48d10ce1dee35cae46c47f7165021d00d5bf58bc9cdff7026b8eb9a7ad2a530c3fa2b71995b16a89f3f779279d78acfcc62ee54014b322881822cf9281b9c3e4a52e21bf568e5250b58e00248e8786c122410fdcfe6652538bd7ac6266e9a2b92186552ecf3164636d67d63998e18fc543090d16557354e0da68ddba3dec1b17c56b6db99eb5fc91c316fb2e34e85428804cc73deea0b235d4d814439d7b3b6146f4772c7c8a2119ddd26c596c610375d43e33fb2f649e09d4dd2d3bd3ccb4921fc9ced8c3d368d23d2530a023c9f602a962641dce3c7832945eace9485d6556ab6c93097372268bf7cb9e6be8494faa5102bdc336da7150fb440fc0d0eb85485515602175dd8d9fabd0c67bff62a0ca04dfdfee8bcafcbb5f1005a7d5bf7b5ca620d237daefd0559b0412b9e3ee4c5c1f3cde50d59eaa4f7f35f583eaed1af87d0a8ff6666ebd668657682b9bb0482d559ecc9983ecd4aa9cfa3a0b512eac25cc37aed8728b38954ae7700a05777a5979c031a456124596443cd0f72bb3176b08a8c689e8c195f43bf951e48907a1fffe81d484eb0205e21db666c23aaa3493da69397a2ab14160e6cac657df7785b6926cc7122f7e3d80fbb5fc4bca2c65e966000d2d1c072394369cba82eb9cd988eba5bf0ea401e71b42bb3fdfe8bdc6e0f26bb6a2d87cfd9f6f531818037c57d35066e74669f1b89ccb4ca22519ac95cceac37955e0ff55ff1ca3bd9cb248826b3de7b1da0f48598551e1f71a23adb6a4984d931aaa5c62cdd8c20b36cbc1d4f03a1336724f8a4547395208c3926956e4d4eff24f21c537fef4813055aeb7b8afccb66bec8e23cd5c4e120adf0843c578c37ae926ea428bca9b87c32fe88f04edc599a83d5107ab7d4a48372e52dba097783fd1d4cbcc73ad1d715fea55900cd4916f3310a7519ae7c6cb418afba5e610a3eb22cdbe44f5c91891d044779af12c68bc74c02ed2b2a64109c98e0391b9a00a2aaf1c18ad3145bff267aa15699806534dd8e31ac5b7a03c8345c3ef6a939a478e3a7ca949eb440ca9755899536efa5c3ede950ce02101f69a428567024214df3276564de7fa2045d1ec4c71bac433054c370b31d06a6e19e0d173b2cc4f0000195d41933f508d0add2f38849b45123d48a9c00327091438148c8059082ce2d3ce3f9afde1dea1acc21b681278b16600b4546f1b9ef2c2bbadbecbfc7b8c9366f853a9e14dfe1d6898c8fd1bb42518d3eed66411787dec59c1d11baeed714ad6373f36480ff379141769310635e1a1ec80ff70caacdbacd798ddc372cd7d2553cf362372e16dc0cf034b937bd0ddfc5755303cbb4406f66b113fd154e3464df92bb47de38b77cdc95e773bbae3f975921f2a7216321bf518c7610a048a45faa53db2fb68a17a996ade9ffbee2bdc7fb6dbac2f37c3ee4348fe9e09d979130bca1301a0274f608b791e9c01225185d2b9a6ee90b6b41d4b7a9e60edf5275582190d4d9b08bd40cc3e9d893320cb036b84aea91803c3d592bd319501a3f6b86c2b5bfd5233e9b54c2e991fab463039f6cb85879a13dda78421110eadfb1dd3494dbc90359b1bc8cf93c92314ba02fec1638caea1bc02879c8d0e5754ade07177354901200078be96d64dc51ffb6d634abc7f2528103a1f47285505adab976a589938dc9ac9959d73d048cbef2afab12618c9a57e0b6ce6d58870ad0d5eed8e77ef41b219d8bff06ca7f5b5158f2728e4d311a35f4803b62b6dd3a0f49dccba03216dcbc0eaa96c13dad9d7d894777613a596009f410021e6b78b0de126e5e9772b7d3bb2dac23619faef5c558e44c2f990aa538365a6ae2e1d83b02929b7f4f2a4abcbed8dd6153918ebae883150bca4e820ccb445cd47a733ab42fdc37b56fc08046f7aca4c69d63902424ef77e41a27b4ca0693bb1e69d06fb63e17b7286259de684cecd7744bb30f82c4499dac3868cbaf7b677b388f7500be80dbbc02426372901cf66c27280dfe74d420fe1b67c94a208a6549ea5d6df4011b513daf5f4c1f84cb39a1d467e2011b1c1cc3ce336a7616543bf866e76e393fd2ba693871393d08d8f00b5bfd26bee4492db49fff2e496805c0da4226f775af127444d6fc5de5b9d4c32ccbf7bdf5928ac8fff7e28eb5b502c10ff2437f53df4657e985d6a0f38ce6f76cf5e410217ff16aa728ca4f5baa1f2c90ec649469eeba0e3f3f8964349321865f84997849ce3e9c6cf7e6e3b7fc5e376c1950b2556b506d844db799749f03e93c3c898e7b5d8a079ed5756f6378d38ceb7f8142cac469cf8a2ec1006edcb4c9110571b57da577f57c1be80f99580d8aa32c38723342bc341438e8930b024c1c7aa00ce1a7579deaf68651dd2d307863d16fafe4896e89db778944f7170b341b4115ae11a39a85a0f822eab45e11174c9915c79d08189b2457e5e78b2153868e1b20b327df182042f1ea74cc01861f036112438cffb3e1c5b2af4d995056e757389369e52d4aa234cb2968c059ba5a193857ee1d0dc99e210cdb0865badf4d5d1c5e6a4f0f5407f134ca18805fa1ac16355ed19badda65a4e2dbe5118f3aca8ac147dc3bdd318779e44ee490e187ce76a3c2523749cfd4d771d4bef98946819a1d04e1ecf8fca053be32303a48f9d409da2d20d384d1aaa23fed14ced459bdf38b03faa10d05002c9bfb81da7747b0871db1ae52b0e6d69220d4cfb6351b3071a8a5c107bdcd06dd70d04b445a5237be1e92e5ef65e4d94b1f7693930368bc86e3ba38613b3456b1ea3d24fe016ebdedef73ea453ada21f85468460be58287a222056a72e87387fba7eb1941e3fde98152eb713f87459e62d70a3177c26372fe5a9d78398fd522f128d2c9b4ee27670e9d8760b7534f61cf31e828195fb160de04b73a2f0b6e5400d655e7e2b05cc3d50a496ad7097fc4a25e2e5339d105296eefc32c2e227ad994a5aa48d231af143d34c4b19489c55a6ac5d501b5f92953fdcd150f162c88b25189ab9dcf68674f0e3f7ecec329671287939b7ed4a842051b89fce01f8a55a8facce5820ee62375fca135fe8f82bb15c31e21efd6d142c46f53163d23354e6ac1b9b07228469616cb7dc9ba077f4f3ed2dd2f063c5e3c23a35ce4aecf03adae589442c8b706c90a0374c41151089f0177793cf2c5802f63b8e62011ba3ab2dda0a03e80f0dbdc9a7d91224c7072ebe6a8e5728ca5108afee66bb12fc14044ed4d5c1aeb7ff602d61b2c6b887c1ef6cbc6c0920b0aeb6f1fe454fd44b263cbfdd730b086fd73a7b3a0040bebfd78dc3c7456c54d560bc62de4ca822e46c26af576b8d5333f478e27e4234a26795899cb50cb7bc6635bb803cf60f923033000847ad355001b77c4b4b52859c3b81551bcf636939826a53e987e9eabfa12b3196701c9bd24c7f8a1d0223a0072620a579b122717acfaf72beb1ec8415769f0c245c68ac94f619a399d2d773e8816120c9e342158f91f90bc2af2c417e6221322fabb79e50ec88269b7f0670231016e1bf56861d231d5b8e5aa491863e28610512af47a413455cdc4d3425a7680f43b257b55d7de0803966fc3d65e498bb2a3f711954b8c28e7d45aff0244f8ba66fb2e95bc074f5473bbcf31195eda7e91c41f4d50b2f83afdd40dd377ff723cb45cf0ab53e6f00e2a20ea02b9629f96cb5f1ba50b71b3c86c1944ebc96d298d90db3e7785c49e2cd0a8532358ed815ffbc808372094b88f58c0db7494a33fb7564e9b2f93e8a0e115d8282aa71ac76a11f4c51aadbfb3dad467f2a6c8cdd56927eec137cf1dd9a532b783e0f866935aedacf96cd4c7d0d056c688d5863bc265b74903b9108e19d19ee6b15f9c95929ab64ca596acd0753b987f39620fe9735e5aaa4856305eb328755188e09f3bf3d85a4f0dd078156926d46be9f77013f4db0a1ee83bbfefa17e01176fb8560d065de45cfbd1e8336be62b3108c026d1e765c7c34f2cf5a39e88a72e97f6b331ead87ecc4bcca3a4ed1ae6b1ad845549e558d83568bd2be1efe254a9ee5a9aa405c80cc4e8f96ea03cb054e9bc969a91526d18507eda3abab3a3f8f96696494ae51957f0ea4b055011dd262e5288017ce2e41a13c6bb4ee3958c0208fdeceb5ea0691d65ffd3747408f8f2b18c60e9b50efd455ac2f6f0b0f3bf224127a3e2a59931b950846e10f9f08eb5e8955d4421a84a34e43898ca68f9a2ae0fa572fde0c556896fb741600ac1e5682af4a5bb3d67a367c814bd0ccc8e43a00fcf9de1710b422110d9aa2f9d8a9693f894cedd6700e597b4f8158d79c457365effcd44e060c9949a6bf78f3d8b365c975ad0c6275de364de4070a33df7fd88772eac4aab68de9ca12ae1aad5fa596976a288e3963b81007e35c6af1e55bd932ad0548586aadd172a306e289421e624b4115cf4aa2fd4e92cd6763984a7006ab45ddf67632e956d353c585dc8711aca316f27d234ebe19f780a8400b38861bff784a1aab785fa7c7e72453d5d35b0b786b59049da1848df5c636eecaa127731170b4f539562961ccce6ea2e61f7da21c0ec605a5ad4c13e96788f64cf1ba2e51fd44d05114c5337b3844f166cfc6b74d13c12add07911598abdeefa2ee723c44867042e14a620cdb878fd527a81a963f10330e9d7fb7a935ee398aa5a3fefa2a405c93882d9b9c0b9bb62611c824dad71473b5e13a2c5897172af0e189b1e3bc95e4925ce879edd1661c1462bcfc036c985515154e842eff0741ddfdb9426d8b92b18c537d5c8e96b20cedba8e46c5b3e30978d132393f358359b964a6583ee82db781ce7bf47c877d83237dd80be849a9fb5183a9e769c13f6fa42fffa02b7e66a6fb4236f680757b053526d70658b37de1b4e09c3399aa044f1e61821fe3ac5c02e1a8df78d625d4745a01812622f2af53b42d2dd7b7989379f855bfeca19fab37bb78d6d4829fcdbb81ce1975d34c8ee0a974f2b5b82a374bd56468e46b529a7f8aa761359bd1c38c599786182b3f4f0c94f6c2f0668d93a97ea7d9bd3f78f5b4e816468c84261a5e5beb63aa56bc5f4ba47f2918ba336f912743f554b66a836c9be5492b5b8f019bd384eeb00bd55dce3deb63011753dd47b73153106fdf6fe8864ea3e3928484645f676a727bb12f87fbe5889e568d1e8a85acd9385ec358d93131a8c5f2c86a7d43e811c00be1fc676c8a75f0143a03eeae54e47fd8edab7d10a4f27da33e1690218a6bd6354e66caec8cedeaa4c7b165be48a2333a0d87916a2c9fa0b6ed102f0edf3887283bb9f80c3817ae0358a0478364025d10be33d44d798df9d0cdb5891a748fb525ef8e02ac9e571e3322f35cb38e7633e6e8e00ee7bea80d58ae02c7b5230443e9390c9dd01183630b82ba6b552c6516242a3b6089c0fefd8473b9b8695b85d49a3106c1e03b554ac5c3c3af67d460c1bd2318184488a19b78e99226c71de0caf78871e9e3a0bc6ef1ff6ff1d7a450cfcc580ff187d4350fa84434da0805cd446a7fa4c85616ee3eee4c0a8e7b4801d0bdf855fca7d92f0e96f298cac958ea6629e3011fa5b4f746533e5b11a5c9f076fd4742831849230451ecad594af773abf4f8fe1c4d310446badeef2b1863f34530fb4998a859015b1edd56fc995dbe02d7737543b51f3dd99beefda6516747dc2e12d37eb6dee29efa7c3e9345e6b677ffee3bec42da96b2403c5c5f54bd770219bdfd3cef3f7026775a27119a6ea3045cca287e6be892bcdf8fb6304dc688150ea7b4a0d261781c108e4e060044cce2fda679180de854b318d3db1830d8c807ddaccc6325eee48ab533dc37064814148ebba0d99443819def76892feb09f96a0c0338d014b4db9e3117b8ce16051e3c8672f97a2cd7d7efdd41bb24745d843e0495755596da1c78f52706cc4605f5e17bd1d7a77b60a7f8a36af1f28d1161f240b55b0447fbcc42b638b145b6ce8b2eb55e706ea2afc3168dc7b8c6f3d854d100f435de883245facc1a6381fd4fde66402cb5f3ea397dc387cac8e74a0ce577c98d8324b6737a9054badc66ec734ef45415ddf258b7158ef87893f95ebd590af50a0a22db09ce4fcdca29db52722c13a2f44cf3db9c611c035eaf358df4d5fc0bc50f71bf5d57f70a7484fe51518c5244d9215643d6c2b1f0f22ba8691e7132296cbe4ebe099e272350e26209642dd38650b1150a1ab21609bd26c59b4bfd23f130caef9df217060905749bb0b319152ecfb6c97f1ee16d1b39bf06dc03702396ef4ebf010e9823e0eb01c1024d5eb1e33620a230cca0ab7593fc04ba4217e9111816c0d4a2d4ed8205c7ac6f623ef9ed3af492be6624609969b61127c191965b345b836a2125c705fd5e906cb13b60cb04dfa7abca3615df724d21a16664291205f216575d56f1f1bdd2f12553239c65647e492002a5b059f1298d75e9c572f1a34d73faace492f8927f927faf072b0a8cd6d2e8b957adb12d2e7bbe63c4376aa80f1dfa3115070cf343f07a6fd02bd5816cc57968da0c5c723443ec1f2729ac1d30794f58ac4abf0e6b78dd110e86828bfd141a39f00e142c9f7bdd369267693121cdb4496c72cf9d39f168783b18b63fefa59b39d5db610a77c759db774a19208838e4da3606517d2464cdd7a473ed1a2840320f8fb27e61f6fb0e273e47d8ad3b33b9d3197952b757b97d752eee1a2ccd59799401f8e19824eb66a36d249d99b9eadbf6dc1ef7b64dad646fbc737b484077d69900555ca7da509685a4b4d385e9a2c19de7ca9ff6eee41ac35ee2522d1580725bec2be8ddcb93fefb15673de18890637f966af3cfb3c4e847fadeb6087b500e970b31632ca249f1912443e325a7f5de54ac9e7205d2a9f73e05effe9308068a87e2a4d9612b6ba95dc8e88387140e05044a5a58850cb2a97fc8b641ffcd7ee6ac127fec428cac8cdc22b372ab3e6c0b934b161ac8231668fdea8f624d6ae8dff25e1fb12335b3208a39621c3d61d4c7968d1a8411abe4e4d59f940644a357f9b89f886948e4f23c9df35537b3f9ae3d028bc29f7bbc44beb88ae4a3db537ddb3c7feba751610ee82331b933d8393bfee563631ec5dabb2f07cbadd91a2df5b4fd7e12c54adfc3babae29399d4e301bce0792de0402a268ffc83dc150340c6ff34fa2d2bdb69e18cbd67597c2454ef275a6877c171d2b923beca07eb7470117748fd5fe5ac4f45904f168acfadf098862f83b7fa7a2e093d03cc3468135c5f45dc76bec6882d55aabf54ab0d82f51396dba5b50080893c1673992f30b185dd1e5ab79274bdfc8071e13093afd20224942c887024abf98d1133040dc9f420f7a23baa440067cb5cfe45b87a761fd882ec3dc00f0e264da114a49dc6799d3b60e223e00d1e5af39d8dac7160db91677a86b0348ce45422ac947045dcd7257ed795c04c7178abca9a7dbbbe29b47628f243b0015ddad61ca7d4b5e185189bea6edfeddd3828a155468b222654118331cc681d3cadcedc60230c7e747695e84e4ed21468845a7b5728357f6bca59af7263f452a34de6e3767d3edfd3eaf4b3888214c2696216dfc27b694371de0abc2c817e3a5e609a8a870b1bc2ce01fa547f18eacec248711db2175597db478435e4cb7103882010cde9db525bf7852ed21979bf5aa4bc7db4cfa8c91416ec8d9f41e548962f4f308b29c256a9c4131018abacdf90d4939cf2c5b22bc7f94d413981218fdff2ac767cd4f69ed82a93ff8fda981b4bcf9133a53249681479714463646875bac2311709de460772d4fafc9629c2147a5d28e875267381d96185036a731ea10028bea9cba94d851e6a766323a4c3bd18fff20d6a6f32d1040db9fa8547a62fcfc2292b3afe094267ca8c70ea6f7fe812b54979d8113ed34940f81cdbaf456f4726e2622e1da07abb6cc4ebd639a87c0a7167ffc0cfa6914263a01dc8c284b9f473475b86157403842ccd93142efe171c00a730f090f38f371b22af32857908e3496eb3fee252c4738b6a0b071fe083a354da305e4d10806ccfa5d23a3adf3e3d55dcdb838b90382408ae94231c9bc1ab002e8b22f65e9d1293a36ca55b07a5f17c673b75b6b0c7d75e4d325d9c448baf39b976a5456bee391f22f7dd044909a0d22fb2819e31cde11fd1722a10642552bfb2b31c6c6835d16bf34608722e8dea214be8cc1211657596a63b61b1778b3c53f407255f1bc55d9c9b4e739b16bf4d4e3028d7ed6c8c6184788a6b206baefa4d8111bf6087d57f1863b7f7517cdab2e5a4a708aaa23620df7b970fba29373ffefb47fb147a83817e0adb8ad266de4b12e8c3c278053e0dabb641d1aed5450f9e75a48b543637ac86beb277c97949cf197cb05c0d7c2d84497b8846bfb3acbb892a91a59794f3f86261cfa911987b0a04bad451ff67f5897b63d9a010db87e48094365bb7ebd4999eab40f2f0bf8b2f66371812c9e7b37e0780dc006688418ea80710fd1c0582eaa22eaa67c3a89f499bf7d09d5f74e23395b365ff5f1646549cddcc4495b8de5d5e6a965b5d0623b30215ead7f0ad104d8c3e66cd68b22dd862aee69d9635edad2517b82090bb656bfae4083101131de7a1b17cf54d4d38f9e09fe99698101e9fc44927ed47a3ccb8f18e81763627d037ecfd05464f70403507af064f0fd0b927ae464d35b5a4800927dceeda24959145e630060d58563cbb77366238fbd8571b55a4d6d0037903bce2e004ffeaa2acae3f3ad30980ac47503ff25a3cc157c4f4bc472a9dfcc8b6a807e4c9fe8e452abf115ef1d3382f8206a61a8a9d412e43313cb2561679e735c340c0acdd039c741b191accecca69474a81fad8680b8fc8b086f683d80e9e29bd3a18a444d3311f5af85b9b1bafc332fa2ac43daaa16464fda989989ebbc35f7df515a47d73dd9e408f7b69a38e24a6b1809f5db224fc53487598b6708eaaefccaed1561f623e660045f12ff704965ad7a7b3634ad8a203a9364d0d0411ce5412798f93d3d840f63a9c9731e18af3dbcb0e97bd9191a422002cd12904dc1fe8e1e4cfe9b981d7d97f849eec08d0e3854562ea599d5b2104bb4acc2e6dee4b33b6318ac5f07163d3e932340bf8afb85b278ef152ded3d104ac0e9e8bc62fec535a37a729d8fe8fce1e159ec7fcdd6a194f46343144cd99575e1aee100eb0f9f045d5417a4076119ecb6dc349de5a7f441063a991b73a7c839fdf21094de72a15e1776fbccd9dc881c14e5b85253dec082c5ce58dc7739cde8c7ef665dea4f238b8ad904858b46a8ad093e4477a764dcb89aeb053c92da3667639be9288036c858469d76048fe5f9a2a83ef7c8794d74ed0034ef5df77fef79ba3a7d01da6232193d2bb0aafe63255e50fcf187892e80e2f498b3f8dd67f737aaab2d3663351fb13c6f04d67a23187be471b
Secret Key : 2c51ba7939a4b99767a2b75990698032646348792d425d1171a5252c8d3ffa49119ee9a3cbca78c7bdcccb6743146ea369a81b13450434b089c06d77947106be649abb1129b2023a87db083c8837b2fe69a722a1b0391d2c4b295a9b08e7e2b0cacbc31320819e30dd139db85de0e78126c15ca426b150bc6ec9b43928562eb67358b99c6d3076f507192f61f3a364e8530bbda3669ffc8b30965e94fcd7a1acb65c7c9f3ad344561c0c3879a5a2a76633f40fd1cb2e1e4d9a5f6064f3ab9c5b87397caf522ffd10ec00073dc053cbb6535cd0aac901331364cb2f6ea00361e74a86364d06a07c0eba7a99f351848bfbc1eb4953d183d8d301c8f35562e324c302a58f380c7569ec30d9cb58b955902fa869f15e17f74ae52590242330886640c92913559f8f73e791a44be5caaf40a94d3cf1c54b1f3b0bd19507b14a27f083007021d313c10c94150b0ae73d36f7d2bbbf097d68248753ce53fe1c677eb2aa0790bdca2bad197622ce6859e87192685d9772b1b9ef8b49e2d3930a2050b25aac8bcbcb249375bc07f78bf73fedc7a3155db1bd1a1000a9ddb385fc072fd8d6d3e8cbd2f4888784a5544265d045b425da586f74a125d5f9b3995457b03597c9668016d35b14d3e586895dadbcc17cba8fa7c18d8ad8548ccc35721c3213010dbd20159a1a2467e820984cfc4130a68c9a91c41e5f740ea38150eefc6478d63ada37c277d39019ad5846f83423a9b4803a777107f60a1b8a3f9bce18bca76bc3963cc5bf2e0287eb62f08b7645902a762eb35255a37f4a39b7b1daf25c0f9cf0336dbb6370ca5c84a4e9d815bdee9ddcdb9915cad439215050b5e8bfa9685bc84a2ea6a2b458deb1646a7d5e64e4ad33f01c7f0152504e9da458c2af0cc02d9efbb401adc1427bdc5b7d76e8e42ec4fd685421c6a201814811a33184a3dd884d960cd3219887a5193d1c15ada5556d9704a362e582e77065611936d2ac0526628a4f96f4fa022cf7851ad81fd5ea95770eedcc8a9f5d9df9311de818a02c4655e2442af3646f6865a8ccc5e5dfeeec18fa2f59005d8a76213379117fda808d0368a2658a9fd2a69b6daf80f64a82a50ddeef29915cb815b58c0a76068b7094aae04d099ea09c5497a7b2f3a39fd01a255e38079f73ced92469225555096ec481077454cbf840c1f968929d157682e1e96b0ce9b61278912ed25521a86bc11339370e4d5f01fad64e4a77798ea45b3b24009b7c2744d131758db54269b7436b9b981a2834f126067f3d204aa5483f5862c25160984415becd08d37b85834557d5bdd7c9fd57fedc88b70ebc499baf9e4a6cac0978dfe93ed67134bf329b84c27b8ca5cddda8bb94bcc367133983b5d0cd6a0fe97bb8cbe4f883d70be0776d154578ff39387ba7527d785a8cbc053c47b40b10eb15d6157278dc094dd0eaaa320960b4bde764a2bb933bd9c8a8bfc11cbdb84f8fcaed325e887fa07032b190172a1945f972af9cbef18127c2afbbb7159e03bedd42376b61f100216b8dbb9c453bf13ee04b5e096ec48a97514426e5e7b05e4c639debed61b1e9194e583724e5cfae91f467177ea09d8ce612ed76397dced3ce4ab48427967cc9d923c2ac6301886ebc75a3208dbfb3daedfd50f88b850b3580098f9106bb4f1d3aea3338f6e045305c0ded9224848021fb0e900442250e7761ddfd41ac456263bcae46074fcb3bcd8a34d4d54157d876fd385e53575a087dd66e1052737e5a1d4d39752317d38f39beb2613d10c9fb91ba4510dc6ff05693575a43134447d1dae6d3feb50e4adf940155972ba1d5e15a03843d8d3c665260988e0b9e44e2adcc2c73e9b0af399c2b1d55826e9ea167b411542cd33f1d89881e9fa706f58fc24287298f4b91fc57b5b1ac4e8578a0e0d7238f66c79a87f2d045d3fe29561259e683dd8d58b5ca3fe6888a93850cbffe8815e25c03c5f28ed1d47f7adc1f0cc93c5cdae4c5b2b682de541fd86c453007f27b89c6872864fff189b79149b72ea272c9cdd7c64623ad6b79204d2c223146174c9fd4d4e341cc5e5ad31a264b92b1fe09111edd9f5443dbdc85415b9546a8224a7d31fd4b975e22dc0d01a88a23ec1632bf91587c4b8ce3c95951e4e1c39f23221f2e95459b90c86cf6875a6c64be7972d868d96d306af84a8e85f7c0a4cc6fd08829a776cd489c5ab8750aa409efa3b37c6a9729794c7f192ad4896c9d53381a87518a48d84699f8d0a12dfb9ce6689587865ce3b245965df68b67a5a1e39d7a1ecf3dd1ba4a8f4a3f07d0206d438c41bd5bc4b23f2f2dde475d147db5940f23dc1bb897b54f9d38f4c6da615df3a9234e9465c6f99e73fedb158729eb0af138297b7fbf3ff9161b0956cf2bcc84333615388c2253d551061005ffc7f9572daeb6282c6d216fa3590eac8a48c379891776230472cded6da404c0a828df13cee3189605fff24d4e72226259f6d90b8c51c14693e3c966383f60df9964837abb0298c8b26d786b36196f348f6f267c21b34d0a89aa3ac983aa517023c2f9e7108a2a8fd30f03750f3d793b241a3ee80a6d65ca16227e74810ba193188c7464179e16ac1681758a71514923a8515327bccab98074f77a791fc429a94e66453f514b66ed9efb08139bae27d0c10dd1d85122fb4aba555c2928d75b828083eb4d1c4e86300c44332a453f824fe5c9adc69aad138b742f7c40c04c83fab9beac766818775a62d7cb6b0f683e3802cbd6276397326d5c3949a78a8f391186f358976c8231ed94ae1c7235f04ca635b0cd4c7aecb80df60ae335c5963bab7bcf4c6936e49613b6b6726a6deada0639f2ed141e55d94f171b1bc22d1468e9f6a5d1a6b0c00938290a4e3a8ed102300e4a28fa5088a762d3782da6032093885d01c94aff812f95373bf801478446a9dbd7fed9a92dcda6fe2e93d820a2aa9ffcdb3b768951c2e091e350bdb5a6cc6583561a2bd31444d558dddf1316b006ce9dbb61c57a7831ac99a0ff694339fd1037f8202da457d58a01a4881678559b4aa92805fe829214b8e4f170505d3885bfcd842524df955e976b2afc4d536bc1a4a65517683cd431a9dd272ee518e8424cd4d5929621a0239e746c37760b2f10dfa98365ee9e4bdd7e8024da54a61ade27dab78b9bd0236c75c8a908692981149347e881f2baaceedc01c26ac272cbe9c4daabdec86f02ab2b6120da4a11213eceb0e2d7791d34dd997085f4aa280d141f379b294f3a86cd24045802b883efdc81cd3e71ab9619ec98f307d990239a5ed931c83aa18cd5a76832eab6d06f5ef9f299e82de2a17fc339b01334d2cee0b7efe73977528a2b72f7474d05799149faba3c0d759c3839721163082003f7925fb5100081f332716ab30e0414daccbf64577a8ffcaea9c307ef29c8c2749c2b478a10ac21c129b180dc53ff402596c71542e316fb23fec567beb83481f92314727fbb66c0bed3615ffa5a151f30a8efa9660b5b4d766f8cf3f10d7f2f330c1b6a0c7976f007f48fc7b7998e8dc5574ad5f7b519d9fae0a93bd791153675cdd6971ab0af098e11b77be4ade90e76537d9791bf5aa33dac31586743707729191de3d5463e8ba6daeb30b6b0d8ab98ae7b13f9d783ae6beb0114fa8e5f13da3421dfefac5039f64eaa0acd0e59c1e55c7c1f2ad300d8b2c36fe87d438153ed709d5a9e486ebb9d51be3adb26da623ff2ff2bcf18c9e0435322cf915dc181061c64947949a897e39e41a2741c5071fe0cb053f00acfe583f830adefffdfdba48e0caadcae01eecc356935ab413ffc60cabc18e2c8ea7987d635027562295358a99db0069f24fb155244bd5112ece4d442f56e8dd99cf6ad9da9891f11d181d234051c64ba2fc05f3b97916a3f5d5131266992aa12bc50dfb9bd60202989035d0586081485661f9ea6a6669030998b937bbf2a634b8b0a0650639c683b1c1db0a873a24fcf5aa97c215ad709df79a24b29b87a009e5c813cade160d4210c31c9aa0716c76bbf49065396ce254f8227abfabe1b4ed51f9e4420c3e158f638b74fc0d4af0ca9e23a0d13b19cd9e385d1daf5af774759b51d8466a2bdb6298169724434ebaa7f9fb179f8ede5924196fc5be919f0ea2c7823df334f1dd62610b4f9e33815638b3f5ec678aa7df8142aa97dea538983a31244a10d84fa7d70181b3a76ff48f717c9fd313bcaf2e67bfe7e9af1ebbffc16318e89b570eb33b953994c1c48d10ce1dee35cae46c47f7165021d00d5bf58bc9cdff7026b8eb9a7ad2a530c3fa2b71995b16a89f3f779279d78acfcc62ee54014b322881822cf9281b9c3e4a52e21bf568e5250b58e00248e8786c122410fdcfe6652538bd7ac6266e9a2b92186552ecf3164636d67d63998e18fc543090d16557354e0da68ddba3dec1b17c56b6db99eb5fc91c316fb2e34e85428804cc73deea0b235d4d814439d7b3b6146f4772c7c8a2119ddd26c596c610375d43e33fb2f649e09d4dd2d3bd3ccb4921fc9ced8c3d368d23d2530a023c9f602a962641dce3c7832945eace9485d6556ab6c93097372268bf7cb9e6be8494faa5102bdc336da7150fb440fc0d0eb85485515602175dd8d9fabd0c67bff62a0ca04dfdfee8bcafcbb5f1005a7d5bf7b5ca620d237daefd0559b0412b9e3ee4c5c1f3cde50d59eaa4f7f35f583eaed1af87d0a8ff6666ebd668657682b9bb0482d559ecc9983ecd4aa9cfa3a0b512eac25cc37aed8728b38954ae7700a05777a5979c031a456124596443cd0f72bb3176b08a8c689e8c195f43bf951e48907a1fffe81d484eb0205e21db666c23aaa3493da69397a2ab14160e6cac657df7785b6926cc7122f7e3d80fbb5fc4bca2c65e966000d2d1c072394369cba82eb9cd988eba5bf0ea401e71b42bb3fdfe8bdc6e0f26bb6a2d87cfd9f6f531818037c57d35066e74669f1b89ccb4ca22519ac95cceac37955e0ff55ff1ca3bd9cb248826b3de7b1da0f48598551e1f71a23adb6a4984d931aaa5c62cdd8c20b36cbc1d4f03a1336724f8a4547395208c3926956e4d4eff24f21c537fef4813055aeb7b8afccb66bec8e23cd5c4e120adf0843c578c37ae926ea428bca9b87c32fe88f04edc599a83d5107ab7d4a48372e52dba097783fd1d4cbcc73ad1d715fea55900cd4916f3310a7519ae7c6cb418afba5e610a3eb22cdbe44f5c91891d044779af12c68bc74c02ed2b2a64109c98e0391b9a00a2aaf1c18ad3145bff267aa15699806534dd8e31ac5b7a03c8345c3ef6a939a478e3a7ca949eb440ca9755899536efa5c3ede950ce02101f69a428567024214df3276564de7fa2045d1ec4c71bac433054c370b31d06a6e19e0d173b2cc4f0000195d41933f508d0add2f38849b45123d48a9c00327091438148c8059082ce2d3ce3f9afde1dea1acc21b681278b16600b4546f1b9ef2c2bbadbecbfc7b8c9366f853a9e14dfe1d6898c8fd1bb42518d3eed66411787dec59c1d11baeed714ad6373f36480ff379141769310635e1a1ec80ff70caacdbacd798ddc372cd7d2553cf362372e16dc0cf034b937bd0ddfc5755303cbb4406f66b113fd154e3464df92bb47de38b77cdc95e773bbae3f975921f2a7216321bf518c7610a048a45faa53db2fb68a17a996ade9ffbee2bdc7fb6dbac2f37c3ee4348fe9e09d979130bca1301a0274f608b791e9c01225185d2b9a6ee90b6b41d4b7a9e60edf5275582190d4d9b08bd40cc3e9d893320cb036b84aea91803c3d592bd319501a3f6b86c2b5bfd5233e9b54c2e991fab463039f6cb85879a13dda78421110eadfb1dd3494dbc90359b1bc8cf93c92314ba02fec1638caea1bc02879c8d0e5754ade07177354901200078be96d64dc51ffb6d634abc7f2528103a1f47285505adab976a589938dc9ac9959d73d048cbef2afab12618c9a57e0b6ce6d58870ad0d5eed8e77ef41b219d8bff06ca7f5b5158f2728e4d311a35f4803b62b6dd3a0f49dccba03216dcbc0eaa96c13dad9d7d894777613a596009f410021e6b78b0de126e5e9772b7d3bb2dac23619faef5c558e44c2f990aa538365a6ae2e1d83b02929b7f4f2a4abcbed8dd6153918ebae883150bca4e820ccb445cd47a733ab42fdc37b56fc08046f7aca4c69d63902424ef77e41a27b4ca0693bb1e69d06fb63e17b7286259de684cecd7744bb30f82c4499dac3868cbaf7b677b388f7500be80dbbc02426372901cf66c27280dfe74d420fe1b67c94a208a6549ea5d6df4011b513daf5f4c1f84cb39a1d467e2011b1c1cc3ce336a7616543bf866e76e393fd2ba693871393d08d8f00b5bfd26bee4492db49fff2e496805c0da4226f775af127444d6fc5de5b9d4c32ccbf7bdf5928ac8fff7e28eb5b502c10ff2437f53df4657e985d6a0f38ce6f76cf5e410217ff16aa728ca4f5baa1f2c90ec649469eeba0e3f3f8964349321865f84997849ce3e9c6cf7e6e3b7fc5e376c1950b2556b506d844db799749f03e93c3c898e7b5d8a079ed5756f6378d38ceb7f8142cac469cf8a2ec1006edcb4c9110571b57da577f57c1be80f99580d8aa32c38723342bc341438e8930b024c1c7aa00ce1a7579deaf68651dd2d307863d16fafe4896e89db778944f7170b341b4115ae11a39a85a0f822eab45e11174c9915c79d08189b2457e5e78b2153868e1b20b327df182042f1ea74cc01861f036112438cffb3e1c5b2af4d995056e757389369e52d4aa234cb2968c059ba5a193857ee1d0dc99e210cdb0865badf4d5d1c5e6a4f0f5407f134ca18805fa1ac16355ed19badda65a4e2dbe5118f3aca8ac147dc3bdd318779e44ee490e187ce76a3c2523749cfd4d771d4bef98946819a1d04e1ecf8fca053be32303a48f9d409da2d20d384d1aaa23fed14ced459bdf38b03faa10d05002c9bfb81da7747b0871db1ae52b0e6d69220d4cfb6351b3071a8a5c107bdcd06dd70d04b445a5237be1e92e5ef65e4d94b1f7693930368bc86e3ba38613b3456b1ea3d24fe016ebdedef73ea453ada21f85468460be58287a222056a72e87387fba7eb1941e3fde98152eb713f87459e62d70a3177c26372fe5a9d78398fd522f128d2c9b4ee27670e9d8760b7534f61cf31e828195fb160de04b73a2f0b6e5400d655e7e2b05cc3d50a496ad7097fc4a25e2e5339d105296eefc32c2e227ad994a5aa48d231af143d34c4b19489c55a6ac5d501b5f92953fdcd150f162c88b25189ab9dcf68674f0e3f7ecec329671287939b7ed4a842051b89fce01f8a55a8facce5820ee62375fca135fe8f82bb15c31e21efd6d142c46f53163d23354e6ac1b9b07228469616cb7dc9ba077f4f3ed2dd2f063c5e3c23a35ce4aecf03adae589442c8b706c90a0374c41151089f0177793cf2c5802f63b8e62011ba3ab2dda0a03e80f0dbdc9a7d91224c7072ebe6a8e5728ca5108afee66bb12fc14044ed4d5c1aeb7ff602d61b2c6b887c1ef6cbc6c0920b0aeb6f1fe454fd44b263cbfdd730b086fd73a7b3a0040bebfd78dc3c7456c54d560bc62de4ca822e46c26af576b8d5333f478e27e4234a26795899cb50cb7bc6635bb803cf60f923033000847ad355001b77c4b4b52859c3b81551bcf636939826a53e987e9eabfa12b3196701c9bd24c7f8a1d0223a0072620a579b122717acfaf72beb1ec8415769f0c245c68ac94f619a399d2d773e8816120c9e342158f91f90bc2af2c417e6221322fabb79e50ec88269b7f0670231016e1bf56861d231d5b8e5aa491863e28610512af47a413455cdc4d3425a7680f43b257b55d7de0803966fc3d65e498bb2a3f711954b8c28e7d45aff0244f8ba66fb2e95bc074f5473bbcf31195eda7e91c41f4d50b2f83afdd40dd377ff723cb45cf0ab53e6f00e2a20ea02b9629f96cb5f1ba50b71b3c86c1944ebc96d298d90db3e7785c49e2cd0a8532358ed815ffbc808372094b88f58c0db7494a33fb7564e9b2f93e8a0e115d8282aa71ac76a11f4c51aadbfb3dad467f2a6c8cdd56927eec137cf1dd9a532b783e0f866935aedacf96cd4c7d0d056c688d5863bc265b74903b9108e19d19ee6b15f9c95929ab64ca596acd0753b987f39620fe9735e5aaa4856305eb328755188e09f3bf3d85a4f0dd078156926d46be9f77013f4db0a1ee83bbfefa17e01176fb8560d065de45cfbd1e8336be62b3108c026d1e765c7c34f2cf5a39e88a72e97f6b331ead87ecc4bcca3a4ed1ae6b1ad845549e558d83568bd2be1efe254a9ee5a9aa405c80cc4e8f96ea03cb054e9bc969a91526d18507eda3abab3a3f8f96696494ae51957f0ea4b055011dd262e5288017ce2e41a13c6bb4ee3958c0208fdeceb5ea0691d65ffd3747408f8f2b18c60e9b50efd455ac2f6f0b0f3bf224127a3e2a59931b950846e10f9f08eb5e8955d4421a84a34e43898ca68f9a2ae0fa572fde0c556896fb741600ac1e5682af4a5bb3d67a367c814bd0ccc8e43a00fcf9de1710b422110d9aa2f9d8a9693f894cedd6700e597b4f8158d79c457365effcd44e060c9949a6bf78f3d8b365c975ad0c6275de364de4070a33df7fd88772eac4aab68de9ca12ae1aad5fa596976a288e3963b81007e35c6af1e55bd932ad0548586aadd172a306e289421e624b4115cf4aa2fd4e92cd6763984a7006ab45ddf67632e956d353c585dc8711aca316f27d234ebe19f780a8400b38861bff784a1aab785fa7c7e72453d5d35b0b786b59049da1848df5c636eecaa127731170b4f539562961ccce6ea2e61f7da21c0ec605a5ad4c13e96788f64cf1ba2e51fd44d05114c5337b3844f166cfc6b74d13c12add07911598abdeefa2ee723c44867042e14a620cdb878fd527a81a963f10330e9d7fb7a935ee398aa5a3fefa2a405c93882d9b9c0b9bb62611c824dad71473b5e13a2c5897172af0e189b1e3bc95e4925ce879edd1661c1462bcfc036c985515154e842eff0741ddfdb9426d8b92b18c537d5c8e96b20cedba8e46c5b3e30978d132393f358359b964a6583ee82db781ce7bf47c877d83237dd80be849a9fb5183a9e769c13f6fa42fffa02b7e66a6fb4236f680757b053526d70658b37de1b4e09c3399aa044f1e61821fe3ac5c02e1a8df78d625d4745a01812622f2af53b42d2dd7b7989379f855bfeca19fab37bb78d6d4829fcdbb81ce1975d34c8ee0a974f2b5b82a374bd56468e46b529a7f8aa761359bd1c38c599786182b3f4f0c94f6c2f0668d93a97ea7d9bd3f78f5b4e816468c84261a5e5beb63aa56bc5f4ba47f2918ba336f912743f554b66a836c9be5492b5b8f019bd384eeb00bd55dce3deb63011753dd47b73153106fdf6fe8864ea3e3928484645f676a727bb12f87fbe5889e568d1e8a85acd9385ec358d93131a8c5f2c86a7d43e811c00be1fc676c8a75f0143a03eeae54e47fd8edab7d10a4f27da33e1690218a6bd6354e66caec8cedeaa4c7b165be48a2333a0d87916a2c9fa0b6ed102f0edf3887283bb9f80c3817ae0358a0478364025d10be33d44d798df9d0cdb5891a748fb525ef8e02ac9e571e3322f35cb38e7633e6e8e00ee7bea80d58ae02c7b5230443e9390c9dd01183630b82ba6b552c6516242a3b6089c0fefd8473b9b8695b85d49a3106c1e03b554ac5c3c3af67d460c1bd2318184488a19b78e99226c71de0caf78871e9e3a0bc6ef1ff6ff1d7a450cfcc580ff187d4350fa84434da0805cd446a7fa4c85616ee3eee4c0a8e7b4801d0bdf855fca7d92f0e96f298cac958ea6629e3011fa5b4f746533e5b11a5c9f076fd4742831849230451ecad594af773abf4f8fe1c4d310446badeef2b1863f34530fb4998a859015b1edd56fc995dbe02d7737543b51f3dd99beefda6516747dc2e12d37eb6dee29efa7c3e9345e6b677ffee3bec42da96b2403c5c5f54bd770219bdfd3cef3f7026775a27119a6ea3045cca287e6be892bcdf8fb6304dc688150ea7b4a0d261781c108e4e060044cce2fda679180de854b318d3db1830d8c807ddaccc6325eee48ab533dc37064814148ebba0d99443819def76892feb09f96a0c0338d014b4db9e3117b8ce16051e3c8672f97a2cd7d7efdd41bb24745d843e0495755596da1c78f52706cc4605f5e17bd1d7a77b60a7f8a36af1f28d1161f240b55b0447fbcc42b638b145b6ce8b2eb55e706ea2afc3168dc7b8c6f3d854d100f435de883245facc1a6381fd4fde66402cb5f3ea397dc387cac8e74a0ce577c98d8324b6737a9054badc66ec734ef45415ddf258b7158ef87893f95ebd590af50a0a22db09ce4fcdca29db52722c13a2f44cf3db9c611c035eaf358df4d5fc0bc50f71bf5d57f70a7484fe51518c5244d9215643d6c2b1f0f22ba8691e7132296cbe4ebe099e272350e26209642dd38650b1150a1ab21609bd26c59b4bfd23f130caef9df217060905749bb0b319152ecfb6c97f1ee16d1b39bf06dc03702396ef4ebf010e9823e0eb01c1024d5eb1e33620a230cca0ab7593fc04ba4217e9111816c0d4a2d4ed8205c7ac6f623ef9ed3af492be6624609969b61127c191965b345b836a2125c705fd5e906cb13b60cb04dfa7abca3615df724d21a16664291205f216575d56f1f1bdd2f12553239c65647e492002a5b059f1298d75e9c572f1a34d73faace492f8927f927faf072b0a8cd6d2e8b957adb12d2e7bbe63c4376aa80f1dfa3115070cf343f07a6fd02bd5816cc57968da0c5c723443ec1f2729ac1d30794f58ac4abf0e6b78dd110e86828bfd141a39f00e142c9f7bdd369267693121cdb4496c72cf9d39f168783b18b63fefa59b39d5db610a77c759db774a19208838e4da3606517d2464cdd7a473ed1a2840320f8fb27e61f6fb0e273e47d8ad3b33b9d3197952b757b97d752eee1a2ccd59799401f8e19824eb66a36d249d99b9eadbf6dc1ef7b64dad646fbc737b484077d69900555ca7da509685a4b4d385e9a2c19de7ca9ff6eee41ac35ee2522d1580725bec2be8ddcb93fefb15673de18890637f966af3cfb3c4e847fadeb6087b500e970b31632ca249f1912443e325a7f5de54ac9e7205d2a9f73e05effe9308068a87e2a4d9612b6ba95dc8e88387140e05044a5a58850cb2a97fc8b641ffcd7ee6ac127fec428cac8cdc22b372ab3e6c0b934b161ac8231668fdea8f624d6ae8dff25e1fb12335b3208a39621c3d61d4c7968d1a8411abe4e4d59f940644a357f9b89f886948e4f23c9df35537b3f9ae3d028bc29f7bbc44beb88ae4a3db537ddb3c7feba751610ee82331b933d8393bfee563631ec5dabb2f07cbadd91a2df5b4fd7e12c54adfc3babae29399d4e301bce0792de0402a268ffc83dc150340c6ff34fa2d2bdb69e18cbd67597c2454ef275a6877c171d2b923beca07eb7470117748fd5fe5ac4f45904f168acfadf098862f83b7fa7a2e093d03cc3468135c5f45dc76bec6882d55aabf54ab0d82f51396dba5b50080893c1673992f30b185dd1e5ab79274bdfc8071e13093afd20224942c887024abf98d1133040dc9f420f7a23baa440067cb5cfe45b87a761fd882ec3dc00f0e264da114a49dc6799d3b60e223e00d1e5af39d8dac7160db91677a86b0348ce45422ac947045dcd7257ed795c04c7178abca9a7dbbbe29b47628f243b0015ddad61ca7d4b5e185189bea6edfeddd3828a155468b222654118331cc681d3cadcedc60230c7e747695e84e4ed21468845a7b5728357f6bca59af7263f452a34de6e3767d3edfd3eaf4b3888214c2696216dfc27b694371de0abc2c817e3a5e609a8a870b1bc2ce01fa547f18eacec248711db2175597db478435e4cb7103882010cde9db525bf7852ed21979bf5aa4bc7db4cfa8c91416ec8d9f41e548962f4f308b29c256a9c4131018abacdf90d4939cf2c5b22bc7f94d413981218fdff2ac767cd4f69ed82a93ff8fda981b4bcf9133a53249681479714463646875bac2311709de460772d4fafc9629c2147a5d28e875267381d96185036a731ea10028bea9cba94d851e6a766323a4c3bd18fff20d6a6f32d1040db9fa8547a62fcfc2292b3afe094267ca8c70ea6f7fe812b54979d8113ed34940f81cdbaf456f4726e2622e1da07abb6cc4ebd639a87c0a7167ffc0cfa6914263a01dc8c284b9f473475b86157403842ccd93142efe171c00a730f090f38f371b22af32857908e3496eb3fee252c4738b6a0b071fe083a354da305e4d10806ccfa5d23a3adf3e3d55dcdb838b90382408ae94231c9bc1ab002e8b22f65e9d1293a36ca55b07a5f17c673b75b6b0c7d75e4d325d9c448baf39b976a5456bee391f22f7dd044909a0d22fb2819e31cde11fd1722a10642552bfb2b31c6c6835d16bf34608722e8dea214be8cc1211657596a63b61b1778b3c53f407255f1bc55d9c9b4e739b16bf4d4e3028d7ed6c8c6184788a6b206baefa4d8111bf6087d57f1863b7f7517cdab2e5a4a708aaa23620df7b970fba29373ffefb47fb147a83817e0adb8ad266de4b12e8c3c278053e0dabb641d1aed5450f9e75a48b543637ac86beb277c97949cf197cb05c0d7c2d84497b8846bfb3acbb892a91a59794f3f86261cfa911987b0a04bad451ff67f5897b63d9a010db87e48094365bb7ebd4999eab40f2f0bf8b2f66371812c9e7b37e0780dc006688418ea80710fd1c0582eaa22eaa67c3a89f499bf7d09d5f74e23395b365ff5f1646549cddcc4495b8de5d5e6a965b5d0623b30215ead7f0ad104d8c3e66cd68b22dd862aee69d9635edad2517b82090bb656bfae4083101131de7a1b17cf54d4d38f9e09fe99698101e9fc44927ed47a3ccb8f18e81763627d037ecfd05464f70403507af064f0fd0b927ae464d35b5a4800927dceeda24959145e630060d58563cbb77366238fbd8571b55a4d6d0037903bce2e004ffeaa2acae3f3ad30980ac47503ff25a3cc157c4f4bc472a9dfcc8b6a807e4c9fe8e452abf115ef1d3382f8206a61a8a9d412e43313cb2561679e735c340c0acdd039c741b191accecca69474a81fad8680b8fc8b086f683d80e9e29bd3a18a444d3311f5af85b9b1bafc332fa2ac43daaa16464fda989989ebbc35f7df515a47d73dd9e408f7b69a38e24a6b1809f5db224fc53487598b6708eaaefccaed1561f623e660045f12ff704965ad7a7b3634ad8a203a9364d0d0411ce5412798f93d3d840f63a9c9731e18af3dbcb0e97bd9191a422002cd12904dc1fe8e1e4cfe9b981d7d97f849eec08d0e3854562ea599d5b2104bb4acc2e6dee4b33b6318ac5f07163d3e932340bf8afb85b278ef152ded3d104ac0e9e8bc62fec535a37a729d8fe8fce1e159ec7fcdd6a194f46343144cd99575e1aee100eb0f9f045d5417a4076119ecb6dc349de5a7f441063a991b73a7c839fdf21094de72a15e1776fbccd9dc881c14e5b85253dec082c5ce58dc7739cde8c7ef665dea4f238b8ad904858b46a8ad093e4477a764dcb89aeb053c92da3667639be9288036c858469d76048fe5f9a2a83ef7c8794d74ed0034ef5df77fef79ba3a7d01da6232193d2bb0aafe63255e50fcf187892e80e2f498b3f8dd67f737aaab2d3663351fb13c6f04d67a23187be471bfeffffff0300fffffefffcfffffffbffffff01000200020004000600fdff0400fdff0200fbfffefffeff01000500fcfffdff0000000001000100050000000400ffffffff010001000000fdff00000100010002000000fdfffdfffeffffff000001000200fefffeff0000fdff000002000400fffffefffaff010006000100000002000300fcff00000400fffffeff01000200fdff0000000005000100fbff04000400feff0000fefffdfffeff0000040002000300feff0000feffffff010004000100fffffeff01000000fbffffff0100ffff0300fefffffffdff0000ffff0000fbff030000000200feff010000000200fcff070001000200fefffaff000001000300fcfffdfffffffdff0000fcfffeff00000400fefffdff030003000300ffffffff04000100fbff02000100feff00000300feff01000000fbff02000200000001000000ffffffff0300fefffbff020004000500feff0400fdff0200ffff0200fcff0000010005000200fafffeff05000200020005000200feffffff0100fdff07000400fdff0400040000000200050000000300fcff030001000000000000000200feff000000000300feffffff02000700fbff0100fefffdffffff02000300fbffffff0300fcfffefffdfffefffdfffffffbffffff0200feff010001000100050005000000000001000400ffffffff0400fcfff9ff00000200030004000100feff0200feff0000fbfffdff0000faff0300fafffdfffefffeff0300fdff02000400fefffeff030000000100fffffdff02000300ffff02000100fcff0300fdff0400020003000700fefffcffffff0300fcff0100feff070001000400000003000200feff02000600f9fffeffffff0300fdff03000000fdff00000100040000000000fcff0000feff0400040002000000040000000100fdff0400fcff0000fdff0200fbff01000000fdfffdff0000fffffeff0300ffff0000fbffffff02000000fbff050002000500fffffcff0100fffffcff0100feffffff00000000feffffff01000100fffffdff0100fdff0100fdff0400fdff0200fdfffeff0200fcff000000000200fcff0200ffff01000300fdff0300fdffffff0200ffff0400fdfffcffffff0000fefffefffefffeff0100ffff00000100fcff01000200fffffbfffeffffff04000000feff0000fdff06000400000001000400fcff00000700fffffbff010000000200fdff0400ffff0200fffffdff0300ffff0000f8fffeffffff0500ffff0000fdffffff02000200ffff03000200ffff00000100fcff02000000010000000600feff01000300fcff0200fdff00000200feff040000000100020002000100fffffffffffffdff0200fcff01000300fdff010000000400fcff01000100020002000300ffff0500feff0100fbff0000000001000100010002000000fdff0000fffffbfffefffcff0500fffffcff03000200000003000100030000000400fdff00000000030002000100fefffcff020003000500ffffffff00000200fefffefffefffefffeff020001000100fdfffeff000000000000feff0100050001000300fdffffff0100040003000300fdff00000200ffff0200000001000200fdfffdff01000100fdfffeff0100feff02000300fffffbff00000000faff030003000400ffff00000300010001000100f9fffeff00000200fcffffff0100feff00000000fffffefffdff0300faffffffffff00000300feff0400040003000500ffff01000000fffffeff0100fffffeff0500ffff010001000000ffff0300ffff03000200000002000300ffff0200feffffff010000000000feff020001000100fbfffeff0000feff0200fdfffeff040004000200ffff05000000fefffffffdff0500fefffcffffff0100fcff0400020001000100000001000200fcfffeff0400060006000000fdfffdff0200fcff0200fefffbff0000fffffcfffcfffcfffbff0100fffffeff0400ffff02000100050004000000010003000500fdff000001000300fdff02000100ffff0300feffffff000001000400ffff0300feff0200ffff0200fdffffff0100f9fffcff00000100feffffff0000feff0000ffff0300feff030002000900ffff0100030000000000fcff000003000100030003000700fdfffbff00000200fefffdfffffffdff000002000400fffffdfffeff05000200fcff000001000000fefffcff0200faff010000000100020000000300feff0400fdff0000feff00000000fbfffdff0400030003000000ffff03000000020002000000feff0100fcff0300fcfffaff0000ffff0000fffffeff0500fffffffffdff050000000200feff0100fdffffff0100fffffdfffeff0200030002000200feffffffffff000005000300fcfffdfffcff010005000000fcff000000000000fffffeff0300000000000000ffff03000100fbff0700feff0300ffff0200fffffffffcfffffffeffffff02000000ffff000002000100fbfff9ff03000100fffffeffffff01000000feff020005000000fcff070002000000000003000300020000000100feff0300fbfffefffeff0200fffffeff020001000100ffff00000400fefffcff00000100fdff0200fcff0100ffff0500ffff0200fcff040000000200fffffffffffffbff0300fefff9ff00000200fdff030003000600fdff0000fdff00000500fcfffeff00000400ffff02000100fcff0000fcfffefffbfffeff000006000100020000000100fdff0300fcfffefffeffffff01000900fefffafffcff0000000007000200fffffeffffff02000000fcff0100feff0100fdff01000100feff0100ffff03000000ffff05000100fcfff9fffefffbff0200feffffff0000fbff010000000200000002000000030001000600fefffdff0000fdffffff01000500fdff0000000001000400fafffeff01000400fcfffbfffcff06000000000000000300fdff0000feff0200fffffeff0200fefffaff0200fcfffbff0300ffff02000000feff0200ffff020002000300fcfffbfffeffffff00000000fdff0200000000000200fdfffbff030001000600fffffcff0000fffffdff0000fcff0100fffffeff02000400000003000200fffffcfffeff0200fdff0000fefffefffaff01000000fdff010001000000ffff0000fbffffff00000100fdfffcff0100ffff000000000300fcff01000000ffff0200fefffeffffff04000000fefffeff04000300000003000300fffffeff03000000fafffffffefffffffffffbff0100fcff0100fbff0700040007000600fbffffff0200feff0200030001000200fbfffffffcfffdfffefff9fffefffdff000003000100fefffeff0100fdfffefffdffffff0300fcff0200ffff0300fefffeff0100fffff9fffffffcff00000000fafffefffcff0300000001000400fcff01000000020004000100feff04000100fefffcffffff00000000fdff0200fdff0300000000000400030001000200fcff0300fbff030000000400000003000600000000000400fffffafffeff0000fffffcfffafffefffafffcff0200020004000100faff0100fcff030000000200020000000300fdff0200fffffefffcfffdfffcff0200040003000000ffff0400f8ff02000200fefffeff030007000400fefffefffaff000002000600fffffefffffffaff010002000300fdffffffffffffff00000500fcfffcff040002000500020001000100feff00000400feff0000fcfffcfffdff02000500030001000400020000000000040001000000fcff0000ffff0000fffffbfffdff0000000001000200fcff010002000300fdff0100fefffefffefffeff0400050000000400020007000000fcff00000700fbff00000000fffffffffeff01000100fcfffefffdfffefffdff040004000200ffff0100fcfffffffeffffff0200fcff020005000300fefffffffffffdfffeff060001000500020000000500ffff0000fcfffffffffffdfffbff0100010003000100feff0000fefffdfffdfffffffbff01000400feff02000300feff0000fdfffdfff7fffeff03000100030000000000fcff050001000000feff00000200ffff0100feff00000500fdfffeff0000feff010007000200000002000500fbff0000fbff0400fdfffbfffeff0200fdfffdfffcfffeff0100fffffeff0000fdffffff020001000000fcfffcfffcfffeff0200feff0000020003000200fdfffeff0000ffffffff0000fffffeff0700fffffdff0100fdfffcff0000fdff05000000fefffeff0400fefffdfffdfffffffcfffeff0500fefffffffefffcfffdfffbff0000feff000002000300fefffefffeff0300ffff0000060006000300feff0200fefffafffcff04000800ffff020000000300020005000100feff01000200fffffefffeff0400fcffffff0100fcff030004000100f9ff0300ffff010000000000feff00000100ffff00000100fdfffdff0500feff00000000fffffdff0100ffff040000000500fcffffff050000000000fefffaff01000200fbff0600fdff010004000000feff0100feff02000100040000000100feff00000000ffff0100fafff9ff01000100000000000300ffffffff00000200feff0000fcfffcff0100fffffeff0200fffffcff00000600f9fffdffffff02000000fbfffefffffffdfffcff0300ffff0100fafffeff01000000ffff0000feff0500fdffffff0200fefffeff05000000ffff010002000400fefffcff030003000400fffffcffffff0300ffff0500fefffeff04000200fdff0300060003000100fcff0600fcfffefffffffefffbff010003000200050003000400fdff0200feff0200fdff0000fefffcff04000200feff0000ffff020003000100fefffcfffaffffff010002000100fbff0200010000000100fcffffff0500fdffffff00000200feff00000500fefffeffffff0500feff010006000200fdfffffffeffffff0000feff0200fffffffffefffbff0400000001000200020000000100ffff0100feff0100ffff0000fffffeffffff05000100ffff000004000000020005000100feff0000fbff0100feff0200fcffffff0100fcff000000000200ffff020002000300030001000200020000000500050002000100020003000000fcff05000500fffffffffafffeff00000300ffff05000300fafffafffdff0400ffff0300000001000400fefffdff040000000200ffff000000000100fcffffff0200010002000500fcffffff0400020004000200feff0000feff000000000200ffffffff01000600feff020004000200ffff0400fbfffeff01000300fffffbfffeff0400ffff0200feff0000060001000400fcff020000000300040001000000fdff0300feff00000200fffffeff0300fdff020000000500fffffefffbfffeff0300feff04000400feff0600fefffdfffcfffbff0200fbfffffffcff000003000300feff000001000300feff0300ffffffffffff02000300fdfffefffefff8ffffff0000fffffeff0200ffff0000fbfffeff03000300feff0300ffffffff0200fbff0100ffff020003000100feff0100feffffff06000000010002000300fefffffffdfffdff0400ffff01000200f9ff0500fefffdfffcfffeff0200fdfffafffeffffff020002000000fbfffcff010001000300fdff0100feff06000100fbff01000400fffffeff050000000300010001000200feff03000100fcfffeff0300ffffffff0100fcff0100fcff000000000200fdfffdff0100ffff040004000000000000000000010005000600fcff01000100ffff03000300fdfffffffdfffeffffffffff0400ffff0100fdff0000fdff0500fdff0300fafffeffffff040000000100fcfffdff0200fcff0100fdff0300ffffffffffffffff030003000300fcff0100010001000400ffff060000000300fffffffffcff020002000200fcff04000100000005000200feff0100fcff0000fffffeff01000400feff0300fffffbff000001000300ffff0500fdff05000400fcff0100f9ff000000000200feff030000000000000000000100fbff0000fdff0100feff0500fdfffdff00000000fffffdff0400ffff0200fcff020001000100060001000400ffff01000100fdff02000200fdff0200fcfffefffdff0400fffffbfffffffefffdff00000000f8ff0400fdff0300fbfffeff0200fdfffcff0200fdff0100030001000000fdff0100fbff05000000fefffeff0200030000000000ffff0100040001000200000000000100020002000500ffff0000fbfffeff0000feff010003000500fcff0100fefffdff040002000200fdfffdff0200feff0000000002000200fdff00000300fefffdff0300fdfffeffffff0000ffffffff030000000100fdff0200020006000300fdff0200fffffdff0300030005000100feffffff05000200fcfffcff00000000fdff02000600feff0100030001000200fffffeffffff00000000fcfffdfffcfffcff06000100030001000200ffff0600fbff010001000700fdff0100fdffffffffff0300fefffbff0000ffff02000400fffffdff0200060000000100feff0300020002000000fdff03000100ffff0000fcfffbfffdfffdff0000fdff0200fdfffeff01000200ffff0400feff0100feffffff0200fffffffffdff040001000200fffffbff02000100feff0000ffff0500fbfffdff020003000300060000000100feff0000fcfffcff0000feff0300feff0200fffffdff0100fffffeff01000000fefffbff0300fbfffdfffeff06000000fffffeff00000000fdff01000300fbff0000feff010000000000ffff02000000ffff0300050001000200fefffeff0000fdff0500fefffcffffff040005000000feff000000000000ffff0000ffff02000100010002000400fdfffeffffffffff0000ffff0200fdffffff0100ffff0500fefffcff0400feff040003000300fefffcffffff030003000000feff020007000000fcffffff0100fdff030000000200fcfffcff07000300feff0200000002000100feffffff0000feffffff0000fffffeff03000100ffff0000fdff0400feff01000400fefffbff0000fdff03000100000002000300fdfffefffefffffffdff03000100fcff0200040001000100feff000002000000ffff0400feff0600f9fffffffdff00000100020000000400010003000000feff0400fffffdff0300feff0200000001000100010001000000fffffdff0200fffffeffffff030002000100030002000300faff0300fcfffbff0400fffffeffffff05000200fdff01000200fdfffcfffffffefffdfffeff070001000000ffff0300ffff000001000100feff0200fcff0200feff0300fdfffdff0100feffffffffff00000500fcff0200fffffefffffffeff010004000200fdff000001000000fffffcff05000100feffffff0300f9ff0400010000000100000004000300010000000400faff0000fdff020005000000fcff000001000000000000000300feff0000ffff0400fdff02000100ffff0200fdff0000fdfffdff01000100feff0400010001000500feff020003000000010001000200fcff01000100fdfffffffaff0400feffffff0000fbfffdfffeff02000200fcff0000feff0000fefffbff0200fafffdff02000000feff0000fffffbfffeff03000000fffffefffffffcffffff0100f9ff06000100fdff0300fdffffff02000000feff0100ffff0100ffff05000500ffff00000000fbff0000fffffeff0300ffff0400000001000100fdff0300ffff0100ffffffff0100feff00000200fefffdff000002000100ffff07000300feff0200fcffffffffff0500ffff04000000feff040005000400000002000000fafffeff000001000000fcfffafffcff0000fbff0100050002000200040001000300ffff03000200feff0100fdfffaffffff010001000500020002000200ffff0000fffffeff0100ffff0200fefffcfffcfffcfffcff01000500f8ff0000fcfff9ffffff00000500ffff01000200faff0000ffff030004000000fffffcff00000400fffffdfffcff0300ffff010001000000feff02000100fffffeff0400feff0100f7ff0100feff0100fffffeff0300ffffffff0300fdffffffffffffff03000500000001000000ffff0100020001000600fffffcff0000fdfffffffbff0100030001000200fcff00000000010001000000010006000200030003000100fbff0000fcff0000fcffffff0000030005000100010001000200fefffffffefffafffdff0200000002000100fdff020000000000ffff020000000400020001000000feff0500ffff01000200020001000300fcfffbfffeff06000500ffff0000fdffffff000003000400f9ffffff00000500fcff000000000000fdffffff05000000fdff00000200fefffafffeff0200fbff0400000004000400fbfffefffeffffff0200fdfffcff01000300040004000500060002000100fdff0600fffffcff02000100fffffeff00000200fefffbfffffffffffcff000001000100fffffcfff9ff0200feff0000040002000200ffff0200feff02000000fffffbff0300000000000000ffff00000200030001000300fbff0600fcff0200fcff04000200fcff00000000fbfffdfffeff0300fdfffcff0300fbff0000f8ff0600feff0500fffffefffcff0100040002000200020001000200000004000000fcffffff03000300feff0500fffffeff04000400fffffffffefffeffffffffff0200fefffbfffffffdfffeff0100fdff01000000ffff0200fefffffffdff00000100fdff030002000200ffff0200030006000400feff0200030000000200000002000200fdfffaff0300fefffefffbff00000000feff05000200feff0400ffff0300030003000300010003000600fcff0100feff0100000002000100fcff0100040000000100000000000200040000000000feff040003000000fefffcff0200fdfffcff000004000200faff00000200feff00000100fffffeffffff0300010000000200fbff02000000fdff02000400fcfffeff0100000002000200fdffffff0100fdff020003000000fefffeff0100fefffeff010002000000ffff020000000000000000000300fbfffcfffefffefffeff0300fffffeffffff02000000fbff0100fdff02000000020001000100fefffdffffff02000000feff0100ffff0000fefffdff01000600ffff00000000fefffeff0100fdff0000fcff0000020002000300fffffdff0200fefffeff000000000000fdfffcff00000000feff00000200fffffbfffeff0400fcfffdfffeff0300ffff02000200fafffdfffcffffff00000000ffffffff000002000000000001000300ffff0000fffffefffefffcff00000000fcfffdfffdff00000000feffffffffffffff0000ffff0400fefffaff0200fafffeff000000000000030000000200fefffffffdfffeff0100000000000000faff0200fdfffeff0100faff03000000feff00000000030002000200feff0500000003000200ffff01000200fdfff9fffaff0200f9ff0300fefffeff0100fcff050003000100fffffeffffff0000000000000200fdff010001000000fefffdfffeff0000010005000400feff0200020000000500feff020001000100fdff02000200fdfffefffbfff9ff04000300ffffffff0400010005000100030000000200020005000000feff0200faff0300fafffdfffefffdff0100fffffeff0000fdfffaff01000300fefffdff0000fcff0200feff0000fefffeff04000400ffff040001000000fbff040002000500ffff050001000100030003000400fcfffcff0000feff00000100faff04000300fffffdff020006000400030001000300fcff0000ffff00000000fcff020001000000fdff030003000100020002000000feffffff0600fdffffff03000100fffffffffdff0400feff05000000ffff0200feffffff0400feff010002000100030003000000fdff0100fefffcfffefffdff04000000040009000000ffff01000100040000000500feff0000020002000200fefffffffcff040001000100020000000600fcfffdff0000fffffffffdff0300feff04000500feff0200ffff05000100010001000300fffffdff0300f9ff0600030000000000fdfffeff020000000100fdff0300010001000100fffffdff02000100fcfffbff060000000100ffff01000300fcfffdff01000000fdfffeff0000feff0100fcff01000200faff000001000000020003000400fffffffffefffdff0300ffff0000ffffffff0300020004000100fdff02000300ffff01000300ffff0200ffff000005000000ffff000001000000010000000500fefffeff0000020003000700ffff0100030000000400fdff010003000500fefffeff0000fcfffbff000001000200ffff0400ffff0500fffffeffffff0000fdffffff0000ffff0000fffffafffdff0100010002000000ffff0300ffff00000000050002000000020001000000fbff02000100fcff0000010001000800fcff0300ffff020002000000fcff0200feff00000100fefffdfffefffcff0000ffff00000400fffffdffffff0200ffffffff05000000fbff0100020003000400fcff00000000faff00000000fbff0000ffff02000300fcff01000100fdfffeff010001000100fefffcfffffffeff0000fdff0100fdff0000fdfffeff0500030004000100fdfffefffcff05000200ffff0100feff00000000ffff0000fdff020000000300060002000200040003000500ffffffffffff010000000100feffffff00000200faffffff0600ffff0400feff0900fdff03000400feff01000300f9ff00000400050000000000020000000300fefffcff0000faff0000ffff0100feff00000200020004000300fdff0200feff030007000000fffffdff090000000100fcfff7ff0600ffff0100fffffeffffff01000400feff0000fcff060002000100fcff0300fefffbff02000100fffffefffffffbff020002000200feff03000600feff02000000fcff01000000faff030002000200fdfffdffffff0100000000000000fcff0300feffffff0100080002000100050003000000ffff02000100010002000400fefffdff0100feff010002000000fcffffff0000fefffdff0000ffff000007000500ffff0300faff01000200fffffcff01000000040000000200040004000200ffffffff010001000300030001000200ffff0000fdff0000ffff000002000200fdff0200ffff0300fffff9ff0000fffffffffefffcffffff03000000faff0100fdfffeff0000020002000300010007000000090000000300010003000400f7ff0700feff010000000100020003000200ffff0300feff00000300fefffdff04000a000000fffffefffffffffffdfffcff0100010001000300feff000001000000fdffffffffff01000000ffff03000100fefffeffffff0000000001000100fefffdff0100f9ff010003000000fdff040001000300feff0000000001000000feff0100fefffdffffff01000200fffffdff00000100020002000000fdff000001000400fcffffff0000000000000300fcff0300feff0000fffffaff01000200fcff0500fcfffbfffdff01000400feff05000100010001000400ffff060005000100000000000300fdff04000000feff000001000000fdff0200fefffefffeff01000200050001000300feff0500fdfffafffcff00000200000002000300fffffeffffff0600030005000200fdff050000000100fdfffcff00000000050002000200020005000300f9ff020000000100fdff02000200fdff0200fefffefffbff0300ffff0400fefffeff0100feff0100fffffeff02000300fefffffffdff0100fefffffffbff05000100fdff010004000100040003000000000005000200fffffffffdff0100fbff0300fcff01000100fdfffffffeff000002000500fdff02000300feff0100fcfffcff0100fffffffffdff0200fbfffbff0300010003000300010000000100fcff0000ffff0200fdff0400ffff0100fcff050002000100010000000100010001000500010002000700fefffbfffefffffffaff03000500ffff0100fbff040000000100ffff0100ffffffff04000100fcfffdff05000600ffff0000ffff0200fdff0200f9ff0400020003000000ffff04000000fffffdfffdff0000fefffffffefffdff02000000ffff0100fcff00000200fdffffff0200fcff010002000600fcff02000300fffffefffcfffffffeff0100feff0100ffff0000000004000100000000000300feffffff03000200fdff01000600fdfffbff010001000600feff0200010007000100feff0000fcff0000faff0400fffffefffbff0100ffff0200fffffffffffffffffeffffff0300fdff04000000ffff0300feff00000000ffff0300010000000000ffff03000400ffff0000fdffffffffff0400fffffdff0100fbff03000100020004000400ffff02000300fefffdffffff0200ffff010007000200fbfffdff02000200ffff03000000ffff02000200feff0100020002000100010004000300fdffffff03000600feff00000000ffff0400fffffdff03000100030002000100010000000000fffffbff03000100fbfffeff04000000fcff01000100fdfff9fffeff0100fdfffffffeff0000ffff0400ffff0400010004000000fdfffbfffdff0100040000000300feff0100ffff04000000ffff000002000600ffffffffffff00000300050000000200ffff01000200fbfffffffffffeff0100faff0100fdff03000400ffff01000400feff02000700000000000100feff0100000000000200020001000300ffffffff0100000000000200fffffefffcff0100ffff0200fcff030002000100fdff00000600feff03000400fbff03000000030000000000fdff0100ffff0100fefffeff010003000100feff040001000000fcfffeffffffffff00000200fbff0100ffff01000200feff0200010000000100fcff0000feff01000000ffff00000100faff0200030001000000ffffffff0200ffff0200fdff01000400fdff0300fefffeff05000300fdff0000fffffffffefffeff0200020000000200fefffefffffffcff0100050000000300ffff010003000200fbff010000000400ffffffff00000300010003000500fffff8ff02000200fefffcfffefffdff04000300fffffeff01000000fcff0200feff0100ffff0200feff0200fdff020002000500fffffcff0300feffffff01000200feff020002000000ffff020003000200030002000200fcff010006000000feff030000000000fffffcfffdff03000100fefffeff02000000fdff02000000fdffffff03000500fcff0200feff0000fbff0100fdfffafffbfffdff05000000fffffffffffffdff0500fafffcff0000030001000400feff01000000fffffeff050001000500fffffafffdffffff0200010001000700feff0100ffffffff0300000002000100ffff000001000200fffffcff0200fcff0500fbfffdfffeff0000f9ff020000000000fffffeff01000100fcff0200fdff0100feff0500fcff02000100030001000100050004000200fcff0000fffffdfffeff010001000200fefffdff02000400fcfffcff0000fdfffffffbff00000800fdff02000300fdff0200fbff01000100ffff00000500fffffdfffdff0200050000000000fdff01000500fffffeffffff0100ffffffff0100020001000200fdffffff0000feff00000100fdff00000000faff0300fdff01000200020002000500fcff000003000000fdffffff0500070002000100ffffffffffffffff000000000200ffff05000100010005000100feffffff02000100feffffff010000000000fefffcfffaff020000000100ffff0100ffff000000000200ffff0200ffff000002000300fbffffff0400fbff0000fffffcff0300fbff0500feffffff00000000fefffdff0100020003000100fefffbff0000ffff0000fefffffffdfffdff020002000100070000000200fdff0600ffff0100ffffffff0300feff020003000400ffffffff0200fcff0100ffff0200fffffdfffdffffffffff02000400fdff0200fdfffffffaff04000300ffff010000000400000002000300ffff02000200fdfffeff0100fcff000000000200fbff0100fcffffff0100ffff0000000003000200010000000100fdfffefffcfffcff0000000001000300fffffbff06000200fdff0300fbff0500feff0100fefffefffffffcffffff02000000010002000100ffff04000400feff030002000100fffffefffaffffff04000000fcff0500feff02000300feff00000300fcff01000300ffff0000faff0100ffff0000fffffefffeff020000000100fcff06000100a620b486ac1046c6525cdd0bf862eedf
Cipher Text : 408d099ab76c11ea31aae22ef1634eecb2674ac93312b337587ffe0d4500ffb6f4a475ba4997b4e17de0c152b20608281958eae3868717151e1c96dbe7bb07567476b06ff34e0ab1f855de82ec7043ec7be3a65d9667e8bc8896dad936e7f7e378dc248b011a30ffc05563ec1d2b728fe1046b78d2c359723fc4526eaa8d506914130a6cbfc016137cc290e828b6f1aa835beb15ffaad53e2b2670814fcc642346617b580552959c7bda8e5fbdea138d14860ce5e18013b96362c5624cd197235a4473fd76f77966542a44bace25b6e4197be8e78f422ea2ee092a59a3a2f1592d24382e7d7c8ec231451913b2fcc290d7479462bdf5e31796ac242d94e1552ea2334287b1757042685e693f1b7d3e8a65abca2406bd305ee6d1892c3b90494b4e3ee993fbb63e7ec2e42f97cbf2043f4c321efd56ba64491edd18f605d7c1ca4f70c2cec0ccf1338acf7dc1ae01ad363b4b3553ec7d28681b97723499fe12ff7149ca31788a3903454cfadf6d2364c2622369e9bdf662960f584416986e420dfb7dfa689b8aaf08b7eaa3aae5cc161ccd157b12e6903295a5b9009b292fd155022dba42459321765d29152869ffca829b54f835f94e5004c0fe8a9d32207eff2a1af0354cd6783e571152f64c497cfa3dee95efe065c867646336d8e2b0eafd196931bf08047be7d5808071598f1f5b2b05f63acc4cec76b7fd3dd0568e0ed1b4f36d654c79dd4afcc6d2664ba495a4e339b8c467bf1f5bec32c8b2ccb080a9c94253a294b1a10367de8712dc4483b3fc93ccbe479a6aa9bd7f24f0a57181e7c0a920f52e84735f7ab1ba553af4f74c1b6614a3bf6962f1b1ea6936c9678e9fe5e082c088449d943744a6242b4f9158bd9db015791098099f3366befd51aa9ac1293b71905da55b337b168b2d089663d8113091ab649b8f77f3a3a7f387d1ba331b605ad9292410fa33caed06386f25290f5d92f461b6633a1358a0003c00d3dd841fdaba4fe42d531f2c2ec22fb50b9308c4ef077d25fb320b85dae40af3ede89a11cd500fbc3dd5acb2c1110c2453003095c33870656e444fae9cfa5aff9238f138a7388c36027a9456f7443a65c7850ac3ad62671dfa541ea5529231a7b501f8b7971421c90f61cc3327499492ab96480d43441ec07ddba122e4325c256ddecd5af7aabd502c81938ec19c3276749dbf9084482b878cd906dbac41ae5075055339f9ae7b847d6a7d2ae29d49734c008d24975179f21e136b64d24132d2b8208229c4b44784da1914060aaa213050c3280b7877e6880981fac1e4d7f4d6eb25f607c2d9320d2a09173bb88d99adda89922db1d1c31771709a560d8b4b54e3b5772753248ba4917e3830aee72141259662196413659eea66f79b5d4c847a3170ae499ecd2304001cf3270714c50e9cda16b19febd9a5682e16797a34e6db46ec6f7d094d84132b8c2c984ff1feb10103b0d4733698a0a7b8be9787970be4bd25bd5b7e7d7388f34accf3d2ec78cecc3825109a49b4441f9944d3dac5e7b44334ce5dcbcb51547bd3c71ba494df1f0c29357dc3bc8dffd8173881e753caf8017f91811946973f7e6daa83efb431c07561fda78883f3865dc081edf22757859c518f643e144922ecc8320d5eb42b78686b3fadfb4165101cbd1033f5cf08cf802e801196727d288ac9238d0f6f8c3e3d33acc42154df298cf09d0395f664148da98c2982c6b9a18106c48ba25de6d734dd2948f6139953524774df5d0819468df087d25ee10ab64ffc1cecf7917e13228708d3cd75d319ed09ca65990af12818bf08e006e40e78408081a0406ae1a714dc073ec0e4ff7e4a0a18cb55c787354b6cb98bebbb1de2bbf7d05aa989e8d7be3dc28a5a0c2612b16a741dcdc603ae204e7a4b5958aa3221e49c6b99db1682a89a57b04f28461b12b5cf265a760ef17c8857f067c14abe33f4dc5a881c001f19b7bbd38744704ada37e70eb479aeb844be5169e74bb9212923ca8179dad6b981ee07ef1c6ac6b69c1af4ed540f30f3e3950b746266f8c7e912abc0a29525d861590229d08ca4a302415327a2be527f0045c85623e8e46b18c47dadb51301aa2b4c13499cbd2c76123807962df9e005220f9aebcb868af256b46aad7923cd033640917af3dc6f113795b4d159257db45eb8bd98b02b0151cce8f677febc9d735167434e71879add1ab45ec3dd5261ecf8cb8149b84cd71d3050c40d7a36933e58b17f560488587e9513f769e565a59f3e2c9d381f328136a64eaf875827e3963c50869edd93bb18dcdd94ee7bea8c14c3462fa3e3f45d6640b5148ad6e1e6b1776485410392f53cd459f8aa8f79a7dd75d092447a8a6b2e393c887015d0ecbc26f6cbab8aac421b30b5f21da7bae5d5393ad28ac29d2ce02a34110f69368167478a020b2557e73d14e6b34e998418926aacc1e71065e9871ba856b8cd754a5a78e80bf1e6e6f3dd7a0ad7012a0f05645576cf021f57aad3437caf2ac0cce95e167d892621ef050f7e48be7b885d9cdfc2ab4cd5e8dfdfb82f22f033c6eac0d27dbd66740dbd4c81e4385b3efec4d83f92a196f49cf01e9353c28313fad1fce27dbb0f39f6488162d9c94f204518f12a9449761cfc17113edb0bddfc50753af732a592cb2f7324a7f55842f7d197eaa4ae946e5ac326b9f091b3efb33d76553009240ee5d5cdaa6f5a0ff30ba8f77ff890a79e2510929c17f6000489d7f2d13616184519904ccbcdf18600c38a7f792bc400b4fe02bc7f3eb0fcaad5037aef72b55e8f1c08788956b4d7576cbfcbf8b567e25b15204278245070dce829d9ecabda139cd8200617e00ea2a1ba509947e05caa6957c258e00e52c0a01e56d0ec5dae45f0733ed8dca42370e3d24319c056ed2be78311ba7ca8bbb896a1087f36b472132bdb639ab35a8a3e36f0f006e4897c5129d3e767a9e95568ca4dc899c92e5ef3a3679d1efe1cb78588633b36631e64a5ea2524244bf2b9005ba2bf1ad138b16d498607f6df2e436d2175c1bb26af3c3fcd5af2af3c81367b295d6484ce99f624a52c4036b188bc2e22edf7bb3c92514f54d38d0b035a3c3c2dc820cdb5ac16dd6443b4c9c39beccabefb4193a68361f861709db46cf1e42b062ffbf0c0e412da6072cbf3fa0a65247cd116a76522096dfd4341077ebbdad1f6276d0eff5d697645b38b0e8ec3465f662f1f0ca51bd94dcab6eaf3f07d6dee078497be8cc52a68e4dbd4056af7d4c8140c346b5aff345630a90844f5d2e184b4c2e807fffb173734746dfe8b468fe350fbf5ecff11620021e86afd5cae380f40e08038db9db1c146e02a57f28a164b6ed9c4c5dd79e3c83c36a306411b15656a5a2de86ba7cae6cbdb0791e01909200aa69cf096fe3b14d1290eaf966de90a4db57d9548b67aec06e68ab0bbc1107b6df500a5d8b4764a929f02453b0a4d4f775e2cacb872da7ceae51cde120ebb4408fc02baf4ea06fa31a8d89b6834a232959cf97b2105670b8757783d4395cd167c1cb74f6d15f0fa3b2de89797bd7ecf81952175f29299e48a6097d5e19913d07a96f122e5bbc3329aacc1a15911e981c1e6963f09f16647127103a6529c3a2ca59658c380f1da434a40171a36fa13989f11a416ac1104e8f62dca52f17905e8c5d167341de02f3190a1e168fd192be47bc7840d50e1eb7fc4f990300f43e7fb3bca2b34b2a184d98d1d46a5e49642fdc758f722549862092b6de7b02b4f81487dac359c3d723c4e12f22464b1911f9616ec97b4e304e3794782e5b4f60f73fa5d417d400df160990f9e440e1e522e52d552f432c150786135f56013b8aefcf49780311fa53550d6fd0aae14eac8b7f8911da3516b34aa21e4dd6ff5ea75f2a816f53b036be954533e580e54446c43db83831941deef4c591982d55195250e13182cc36471aa742d1d177fdc4708e227a708cddcd8ace418ddec00ffda3a3089bcc6b350e1ade152fac699c3e2d9aef29d3f3f33b902ea0a2082b29def7567f66d6b8719849e40dd5c5fd8cd7a011ff89dacea32831271495530ef94d6d61101a90e4f484c77fb0430cec055e6efe9ee248df5ea8c92e638a3e7e827e746f50c92b4466825225a1b45aa3166ed2cc78536c5fcbcf622875a999667a67e56d08eb0f20e1aed9cad518f0a84768eda211c6cee843b0fc7a2f3644166df7db4d54a43ab4c70ff0bd44b806f2f8f4b25093faacdd44181be900b798d246edf6f9b387833410a1cbac56d939d61cf4d7ff1c72883ceda013ba2eb7392a71cb9c61bfb776402372a4d226a6609cb85a1c667fd3088356b41d594ad1ba08e34d146cb177f419f4787bcc16587bfac4ac35f7dea8f8e76fc2eca2ef99215efb62ca1be83bbaf105d763ee99a1802a92f7d3a0ba9343aea0b528a9ec0a75117055d85cd07fe207af43c07a542865236da2230872c4fc7b39fb1a65eefa4c6e96a4c930641ef9d2e6255e733bad1b6e3465081f0311fa6be90cdb5adca3350e3f0f8ccdbf957d01acab0c2652f7fcc771e4e2efdbbcd8dc8120093cc14a72350694921f6268bc95b4e054e7b04c43fa5fc658bcb7273b15946149b1c264d631df4e587ca33ecab857527b24b18dbafb21a82b2f13fa73e8f06a3fc6974b6fe510f3eaf37bfd060a0c3e9a2b8332eca8ad2a605d6fb011b71a8550a0336fa9c8ec1ad94190bb9e0327031f59e4868448f54c05eaefdef2c98c8cd5717dbf14de99d390655717929588ef5502865e6da082d6aa2c2f8bc3fd9aabffb13ddf5359f7a2a2f23d79e23814dcfd10453e224e588108c139d53f0dbf71fb3434055834bc9fd3aeff553e013e52b1e58c301e84dbac1ca385c71b02591f8f1411ce9695a7bc38cc305b6b19b8e1786babccf2ceedd71bc96fc2c7754c5e98da04b3b7dabe1205ead4997bbaa7ddb4edf06c2d0b7f77da36fb979549f3eacc81456e68db802d609527232bcec0c7da0f721a88e3ed3121f663dd8a6eb6019cf6905317880ebea9203bec496367c6d1db075214330e7963562f5b7a50cf950b58087186386f657c897d310be199cf2a5499e7ad71e4c2921faa1d70a864869c8e125d50fdb09b6590061fa84c2a9ae30fef57924476b7e118867026f8b3cea170d86386441ced1dcf8e47e1cbc67f5061d234167bdc97cc840b0bdf756b240ef5bc1edb680fb04d2bd889f347f8415d5cea270a5da0cc97b155e9ec5d8765673b363e30db59402bcca1ee2cf586ead81afcfb97ed078e1f843849261989dd5678ee4e004f2333e2378ede5974b8563894739aa84c697f8788390d1a9d564818e9de54981061f49cdd49c8d4a13b2b89e29f0ba3b2d3b64e65d3450e884ea39f2ee61954d2ebe70bffe0d9fc76d929aba4d633f48ab2206338c4cae25bed47d7369f673ced197bcfc3f11de273ce447e1b80e04591153d2533d4fbee5273aa816a132edba72ecf75cfbf3af9358e8d1be61f477c1706d3e1c2a6a69e831a090ff699ce2544296370709ffb834daa35ca4732a1381790016efd151dd6d1fee9082314761c8bc71ee070911953d620795b02ac0536b209222b504edd338a74a8f665f90d1ac1867705f5544ba9bdde5da4a9339ef09ac7d6af7fcdb10fdf8cbd5efa06b4a325e6c6002b8eb874c2c68f24aa3bcceebabb28db351f7b36033617dba57f4328c610f77c928fcbc66da9753bc4e5f5c92fdf0b7e8a48ca67a1e48db01d42c28c40088fc0c30d7a32b0552ec0f3968aee0650d1a6f48113e0c2c42b31539c0ac7ccf7a91d78d0a92d5a6eb985452f7f1332dd6a089e5f92e609f162055afca793eb80bc062542de98023c6565e898b33d5c384b622fd68997b40bd506f04cff7f0a73c0892db4749da2fe794254594c53a6dcd5a02b35e011b2d803dbb400699a7a9e85497918765f87d1468a6c5eac6735454765eac6046d87332903b33b646ef7d124c4a5258d766e597800ce6118e823068f2f1918092a457ffa0c66febe7d1da62e2265ce03b3ac024e828ce0d6327b826a8066c94fa10585f82471b94b2b1c281c1cb3a64d8693cad2ff869a4af664ef29edc2cfe2242cc7ab9fe8e8a530f7fc7e525f46c35480ede3826fb64d590347e2735d487b42ada147e2c772cf7072f952109569f54986560261eb056c52d30dd1377f9cfe675cca3e419f141e75fe81e37cae3f49f8e2a03eef322ba2f0dea29804896a961f3bb8c69716c9cb5262645c181af901934a569818d4bf2906afe7d9a714ccc46ec0d5340c107aac513ea96a41783700e8af7fc6223320a280750782df0fc463223fbaddd6517a3d62d8f1c4340fb701a3b1384107caa3020799bed6dbb71f474184d6f79d8a9fe6ec6d251ad415171135786b54c882e3df9b629c1cb97a3b7023df3a9784d3a9cba680d5b8c2c245fd61757065d7dd8375e99af2cf073a6b04226a51e6d45c9371328e7ae16b8baea74a3456ab2796562f3a38b30fe62a39e97dbf9aa9af7169ba5007b7c593b4f4297698e7f1ae9783ac54b5ba59fcd5e3ca5e3defc628b88e1b27c5a5d82023a9a7359686f66d052b0f48c5e31baea5197279f7e8b09102d1ad978cec07d698c31170fc72558aa42d82b192d1a11784400deb8a508624b6e91ea71ca6c6647a2ebaf8e6c9c4e8cfa75363dddc93513721bf88cbc31577b79d2bc19e5d0768c2db3ed8c0b039497fa2d7dd3d3b9b8ef85dac1f3e2adb807f3f0450095a0c3293f16d4384b09b737ce90c3a163d2db28e54f1f9f15feb0f9c111f7062e7227774aef7d5db75bf921dade60576fa09535408838f1d6da829e77c4e42892ab4d287aab2afdb9e62260e6c6454367c582b7737980247f89a2592227c63edde392f5947b055e53dbc72bae7165c3cf712a16a3e3011ee2d6998475d234cadd46f48be4e14b216be02c642741715220a88907efe7ae651fe57ff3d8687495a2741393cc5cb815167b3d7403aa016b8331484cdf4e4332d9c1be9159310abb593d5e07f61db9e051f4992cb719ebedf57b5379485c1dad57d29a526e3f68b10a4a4b4699690a8aaf9ff69f988242ae35636bedd8dffc9371a2f689dcc3881911b1853c85a0f087d4e1cab3b85e74f5a3f66009d33572bcf9655e4a809e9e6c84cb406fffec7a3b46d9010c4065351752c42e3da59b5f59e6ab2e1255c9cae105d65e00fe70f0c900f0366e457cf27b766a0c2205f653ab5cca36d95c71f0d1f58d88f83b4d59196adb2459a65f9dcc3a814427a3d6718225abeb6fa8dc26c06101d7ca5350322ae4166ffd8dd2109cd2b5ab8cd7658df4c9c97922e20411188d05c1c8ea108c049878dd93ecfd0e47a638b111dababc969ab0ffde8ab8a5845e270e433e8779b4ef174b8bf20249ff54e3f2bfa9e3ec1d27222107cf7d9cf17552980071f579f49fceb4a8b0e72f98420d2306778bd4b26436795bbbfa43a0907f92d27032addea78149fd8b419fb8e3dd11d33eb0dcfeb4f8bb2911b0cb79a7b1d7a62387e4c4358ba06cd36e4e6aeb8f74874867babc17931b2e3fe2e1eadcdaa9bd7da29c2829aa21a9805ea3966efb841a09177ed00d8aca7da53ea73c67e9d0d4bb2ab84daa2949da18e93c47db134b15c3bfc83c904177f2110f33262def9f91e01ce854e076f07c50afc06d176ea4498568bb7f55dc35b250ef8a057194d693c9c8b9f35fcedaca12691e73465f04563de803615f35efd9340c1dbc142b07cea383109148fe248911db8190c8363e087ef8f039f4341bea0f90fcaac77cd5213614f4750e8aea805003e5a44147b1da3a89fe8e08e984e4a24aa89ca3759fb0ea3594e808da09be3bc33ff5ceeb4f6f8a2594073bbf60b48704aeaf0fb7d749b13dbea5fdebcdb68acc5c81da1c6d5884c3d58c95ae5a881740a3329d1fd38b9ee25ed0f61bf8338ee1e70fed58fb0b5075deba126ac82f0fb0b84ac92435c009d088a93a6453cbd59325ffb1e71944dce6eb390824312d242c32d53a7bc5858f5795902388c583f021212d08eacd2434df38ada13fdeb0c0131e53ca63a3250ce5e1d65d8b3fe78138c66c95e3cad4cdc3e04bf896decf4b4ae439fea7b62fff6b258802e2226e0d4f0f5d3790853fcc9c2fc6c78b8e81328890afef5158fd7e2af7ae99340a08f2a60fc6060713b187de0f5e39e96f74c5a2049a187807c21583efe388dbf844997b4b4e6213a61a36b90aa5d826e79e33c8224c528e863af933266a060344e47a7f9abf3e20f95ac591d2cb4470f1109fb3995a6babdda59f77810073aed30ac17cff2bb441c7484ba3b7896d5fe6c956391e03a2307d18dc5fd6dde11a55e4b2b8a8505193d6a3b0e1eebf4ac3e19c1f4cb6003680fb55da6b845d0b49aafb25a2c5a25e6a8b695be7f3b2251851458a57d1ffe49dfe25e5917fd844961cfdcf7ea0c930544684be791c7fad057f6969a26c393d94a20ec6d808ebf9b2ce203d1570e9c8b53b9ccd6ce42f29f888a051190a6061faf5adbdf9eb1bb13c7b7ec2c5e28b1178dcd479bdfb9016cc28be199cb477575cd3de937bb1940de79c7c420df0a298f837160fb83bb4755be39c3b77a34e4da1db3fac215f976c2de00b95e45867386ec58c3950b31b3fa8a5dd8a9ffc40472c4c12bbaadd5e92cff6b3699f2337f8326c01b635bd4d6219834e6b815f2cfaf57e9af1ecb95a96895cd9d9947e7eef687b6ae62b4e441c883409cb96adc5a8a47efd505ee3a404e064fbb9369c5290ce9ee43c4520563b0395a3e74d7126c1d1f4233d2df1b1f422181b0fd760d0a6697224d27b7a548eb10a5e6ede95f5d21ec24c6dca0501adde7b96b5fa746196575f2907ec64beb82f587e50e2cdbfc4412f3ae214ff08543b82667a10c8affb514b2f16dc6606ab5047679100c3c5f94f3327e557663d17828381a7a7fed1d82ed953dd100ee8b83f9b7d7e89d07ac90b0b3c3450b7c7b0d49b40ec2b771cbf78424ef8d60beb67c61dbf5e34fac9e9e312e7aa55093db09e408019c8fdd737f30e61fb78dabfeb5dacba1d445b53f101f4b67418e9d3b9e54a2c44d8494b3278f108c33fad08f3bfdeca208bbbebb5c577d4e3a19d0e457fffca5980cc212ea2ac8d121023238cca6aa52ea4b756b75d6a2d6d3f6c555ee8175ed82a5c25d0cbd900a0b0ff3653f9cd0fcde2a8f290c2c4fb9d97fe6c6bdded37ea92a75598be26e288a3d87eadf22400181e01576ec8cb6504394d3e0f758740a6d6ca32561bc944b61ac9521059102fee3d90ac2375a6ca40a6fa673221e8fc464f4571a87ecb78eb9a737d4c73a2d587f60113cec54c5ac166273afd93025ec446a5b3da917ce382c9cccde9b98814693d1f16ddf137a69f63998a6e57855b5794e19f92c00f1f5440a62a589061917961b4b9946e23c5dad3d9515101ba5a15c8d1a817c3e799951e3261c451511c4b43c40ee4b8ee7c8a228517f144588d69df4454d1e1eb403477f796d942edb5819204597acf36cbe82a2ebf2f1fdfb5d65b998509cd6d252db41663b8164eb8e9b4deab8df6485856ba76e250b10fd7e61ff39c74adc30502a3f05a62152db3147d718edaf2b7b77a69b2d7538c212655451d0e879899dce8851dfb99a944b50e64217d3c1fec25300fdaa3f72b1dea217dd6c078a98feb8f8133a4b18f8316a06fa54e433bfc172f5d95a651ef77cc15c64cd01592b64dbbe62fe976f99cf6dc90c2e278e0babd0c8a27a1feae35cba6597e419a355014ec0daad9532efff3833302b18ba4ea85e12205ee24abed8eb96c7eaffd79d9d0848ec3a7d0f5fa350d5e35614d845ad3aa37e16bc32f9b3ba9e47e758ae13568a56bcda9958d4ee0bf6b3ef70b6f2f664ad249e2f143f1f83082fdea266a32b9696db6868db63ad2e110f453178e54f01cdd3c520b0c7e94c1eb1ae21ddefde64395792d040bcdb3f7a34ae0a643dd673ef276d3b3625cd0616f97c074bd61147b5da2b79c57422bb0bbb4f636386f7d697b91767e6062a4ab643174c5af9c1d50ab0eec5d58c26bf8677b0fbe85ae7ecb9631fa92c0a2949b5abff3af5dcd6ad8b60481851aeb24741e0df980c56d868f2b69d0ae3ac85cd54d461e1ecd80e0ada324b2fb165781092037f33d4215277d133eda01b96221a0d1c5ecebf0f9a76468db3e4c25d070a3ecab894662a86b4eee1f12ad9c524d1eee99a7c7c359c199ac232b73a8a30c966b57b6321351ce5f61354ae93f38bf7ab9d70dc23688d58edaf0122477f52b4fd5ac335aa2758723ab5d0a867243f6dbc9d4e7861e8569ccb10d1c236424c915635230a76e8824ced906d9ed33d26bab8fbc569d8ace19835772e7ea84a27b5f3e49a33480c97192a2a3488b07be0d3a56ddcb7e2db0074b4f22fa44dbae4172ccd0c9172dcad45b6714230dab76a1a8533a534365285765f66ca3f56c1306eea7733ed640cbd36f590208389a14a9ff339652835f96a94b84e51b05fd624b6a575e8572622f2c17327274158d228c2f56b5bc49b283ac2b64f5d9c762ecd4c5cb21c38faecd7e05a65a11ff78d083ad641954281b4c6b9f8ed72fe30887f405067c5b1dcfbc2f9136d551f22cbbd4ca431c774115c80e0a8048ceb497ffcf2656c4e7bf3f8b7ca5f2e40b388ebd06146340b9c27eff3869dc452cb742a8a86af0207ed6bc5176cdd1485bcbcdc61ea592454387c77a4953fd71450dddeea38e3cf1e6ba2ff9951cc8d6d27c4dbc5af71212efe6f5b8ed3a05d2687ed1289abc8f54b5920c5fa8a19e4a9f5c6bab12dc11e7747db21ee8ae207226a92cac5c51d058d6c8a481b1021eeee9d7dc4b6729205c02ba854f6c373e6a490cf743a9be010167d4ec54ce65b552ff83d092d38daf9bd3b47acdeb3b22837128ffcca2305cd92eedcb4a66ff2ab7fa79682e1b14a1aada976fffaba2c71e4f06925095e355cd15914cf8291449f8932026d1df9c2b4e04a98b52309678cab4c5b4e1459a0df384c45f7ca53b3e63dbbe527f6267707c0730a34ea8f888050a9267bf993ed4a80f09dcaf1f5be8b4b9591a1342d48912e448d01ebfa6bbbaef8a9c5b8a1c5ca2fdaafd76fe48d900b44930916a3d02ff8572e173375ee55197bdc5ad2c87c873640ee5b8e8cc782fe130c08d9d84b47c137d84107c9814daae796cea354196844ef34c6ee164a1870e5fddae6348054128a2b1179a41579a17194369730755549ac3ffd84503d63e80b50cc303aa59f5fe27f202114d807b33c32f8a09ab8bc5d327f5f4d02601dc4e5058898b4a289c85c6169990889efad3123ca815983f98618b15379674fbacd8b4265c66780aa7c217ff8fb95e78f474e7e51da780a5778fe955968c5225886e59193917cd9f4dda8829e369b798d77cdbe2ce98305fe3f383eb86ec081ddf1f950726059f7dd57bb3d8b56e989802ec4ce0d98638cc79d28a447c55dcf70f82610c8696ad7085aa078442e4f572721c0ec77d60f5d58c77e6b654f51af35ae1e697aab1fb1871cda0a4203042cff075a5387ee6bb8b3c42ecbfec57fd9f7a1ea034769566735ab15148c1b8da28ed8dae03ec700c2a3021b32d090622ef2637e2c4f21bf8a37b961e4a9c86a150da78bce1c869f6ea40ede8065597c8c541269d456287713c16e88a3f4d551919a48819a08dddc9900f5aea764dbde1ed1c8652faaa2c6c7d52d1c9221d22c4a99dd9383ff16c2574d07f578c9cd9af8b6dbc64ce7645475880ce3b1dcb68c7ff57113bcd93d9a804c42c0931948af193cb7105a21d39571b3f3b00b381c41058f5eb2d5ee15ef8cb032cbc4ce642e86ffc3690fbb10e62d9cf4647fde0eb8f9c83c1d90b138121977b6efacddedc4a1a8f0ed00c5ce7ba6e7b4666f24fd9a04240049dc650955d5432c3743a203308ab76f0a7696d5cf0e731b937a8d0e101fb6dff5622d84b516810d1d4ee6d6b44a9f180f131621de0e055ab4804984c57bed5dc67aae0cafd0d2a9ecd71fae17910e0f86bd96c66fd90104920c8fba93c1a4effe1149b36c5c5cf3750623d5a1ae3d168a1de5bb29a9f875cfc6031dfb3d13132df0b0f3a91aa2c7fe01d34c6db939069adb605faf5446f487242a41340172523a678bc94d62d5ce5132f07b9dd51a1347b73e56970595520816422142a3bd4842203d78cc7a62f193dba81e07552d27aae0be67a7ce79b16ffb04c931f6b12ed7e1fe1bd716b96d27f78ea3f5df64fff88064f79a92ef9b6ff6e71cde20570c0b1f1ec379f5206e1ddccea96cd9e8955c96cee43dbf841733dae7ec5f9f7904fad6509ef65de1209abdbb44417a2eb9c81225ae1550210c1f2f21f7d1ff7f244ca28044e68ae731c7869ac35e3d7b7eeb8b3b8277688dd33d6ac3701512963d0dab21713bed4cc88ae44a68f0d81ae4d1591893fb0c2e1a9b52b38b4ad2efbb1663046db11dc488da00a53d09c585421acd70e08f87c24e44bda5a2fb6be3fd9f59c08efa9069d1cd7073f5711ce65b37177b7199bfe469a231b32f1c43a030701c1e1c47f1f4b04304b69f780b72d0cfb004cd9483f0a39e8a5eeaecefca5336093d2a8ec6ea9e585c7d779e612d062c73d734239ae1b4217d7d37f214dc52ccf3b55037395a3e77a9e390cd792fd9ee27f48ff940f1602c524c1b47dbc0a81f54ff300fecc4ae81a744965e4c332b5fc378128908dbcf99eaf2db51d4373653a839240ddb2daa1be70355488866ac7ca557d11a6e5e4fb53d8c2747ad832d5ca5cb3b0fbbe878e73d733f4ac4f8806d59e4b13da211cfa32d1ad73c7d69a86940ab824424e590ce4373ffe28107099e14f08610ceb2598610772d3aa4b549a519a51551564984f6465177627bca6b5e6163660f24c134a27bf465089b58ce6c25080e323e1ae2b3d3e7f5c3ea53e497a6a18382a35bf50114ee14f7b25f689a08c07e6f75a4affd925b9534f3c63d38f684fc54dfcfd789ffef0d883cfc05791e084e8c1dbd3664e24d3b2180c083e5f4b7c8b3fdaf415a89b050420e5e8b744fbf9e1e55f4dd1dce8206e3a849d98042efa361407bbe15293c0e8c522a50cf098e0049f6b8c999b97292030b11bf0f140da3eece9079354620c40a8f9ea16b97c156245681f0ead3c8645f3d1b3703342f602b96e076be391abe207f02406a7eb28c706b67e88c7af831ae2aa5f7d25d22e82500e46fa666ede695cac96dd4ff90e9af9e6b90f62a94b82a02473011960abc190e3133943098cbe84edc575f697024371ed7c476a8fae929334550230c5bafbe749ce62a15ae8ec5e667ba4166455587411506cf6fb857fa6505fffbc8c2365fa8f1c175e1a80be987ab185e9a57ac8a3d25e17331264ba98052f9955208100c9f583770b16752a973fdcf5ae58f11d4b4a521508c414a59e57d5dbac11cf5d6fad9fb4cb9d06fb00312a1f13f6194e9f5067d83b3df01cf7bce89f39d8bbbcee86bb1a7da3ac9c6345b9c877a001fd3611b3719754cf31981baef26080b8c21400924b96d2e2013bf056d094cdfb3338f476d3ae05a70823a0174db644bcfd545df4d447c3bf5ffe98c1d284401b81020eb8c546f14bb09f49c7a8fdf569cdd2c1bc665ffa910477b978a618483a73104639d47d343af86b5315e6857eeb419ffe13fcf0a30ddfe5ffb81f86c03ea1522ef9996de253b4b59fe9fd712806ad2edfe3ce4e692af164cd12bbc01bd53bb4e16a5a8a280eef8a0b56964cf38af1dc104f36e776e9641044b58aaecca0b76243f2a56740e1fe631bd448e99488365b3ccb2c5c995184d4a0c56e5161ba165b1323f7ecda6c94e3
Shared Secret : ebad3b0a0a8b82188a75d3a415b405b
Caution
Before you consider using Psuedo Random Number Generator which comes with this library implementation, I strongly advice you to go through include/prng.hpp.
Note
Looking at API documentation, in header files, can give you good idea of how to use FrodoKEM API. Note, this library doesn't expose any raw pointer based interface, rather everything is wrapped under statically defined std::span
- which one can easily create from std::{array, vector}
. I opt for using statically defined std::span
based function interfaces because we always know, at compile-time, how many bytes the seeds/ keys/ cipher-texts/ shared-secrets are, for various different Frodo parameters. This gives much better type safety and compile-time error reporting.